1
1
import { createTransport } from '@sentry/core' ;
2
2
import { EventEnvelope , EventItem } from '@sentry/types' ;
3
- import { createEnvelope , serializeEnvelope } from '@sentry/utils' ;
3
+ import { createEnvelope , serializeEnvelope , addItemToEnvelope , createAttachmentEnvelopeItem } from '@sentry/utils' ;
4
4
import * as http from 'http' ;
5
5
import { TextEncoder } from 'util' ;
6
6
7
7
import { makeNodeTransport } from '../../src/transports' ;
8
+ import { createGunzip } from 'zlib' ;
8
9
9
10
jest . mock ( '@sentry/core' , ( ) => {
10
11
const actualCore = jest . requireActual ( '@sentry/core' ) ;
@@ -34,17 +35,21 @@ let testServer: http.Server | undefined;
34
35
35
36
function setupTestServer (
36
37
options : TestServerOptions ,
37
- requestInspector ?: ( req : http . IncomingMessage , body : string ) => void ,
38
+ requestInspector ?: ( req : http . IncomingMessage , body : string , raw : Uint8Array ) => void ,
38
39
) {
39
40
testServer = http . createServer ( ( req , res ) => {
40
- let body = '' ;
41
+ let chunks : Buffer [ ] = [ ] ;
41
42
42
- req . on ( 'data' , data => {
43
- body += data ;
43
+ const stream = req . headers [ 'content-encoding' ] === 'gzip' ? req . pipe ( createGunzip ( { } ) ) : req ;
44
+
45
+ stream . on ( 'error' , ( ) => { } ) ;
46
+
47
+ stream . on ( 'data' , data => {
48
+ chunks . push ( data ) ;
44
49
} ) ;
45
50
46
- req . on ( 'end' , ( ) => {
47
- requestInspector ?.( req , body ) ;
51
+ stream . on ( 'end' , ( ) => {
52
+ requestInspector ?.( req , chunks . join ( ) , Buffer . concat ( chunks ) ) ;
48
53
} ) ;
49
54
50
55
res . writeHead ( options . statusCode , options . responseHeaders ) ;
@@ -69,6 +74,16 @@ const EVENT_ENVELOPE = createEnvelope<EventEnvelope>({ event_id: 'aa3ff046696b4b
69
74
70
75
const SERIALIZED_EVENT_ENVELOPE = serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ;
71
76
77
+ const ATTACHMENT_ITEM = createAttachmentEnvelopeItem (
78
+ { filename : 'empty-file.bin' , data : new Uint8Array ( 50_000 ) } ,
79
+ new TextEncoder ( ) ,
80
+ ) ;
81
+ const EVENT_ATTACHMENT_ENVELOPE = addItemToEnvelope ( EVENT_ENVELOPE , ATTACHMENT_ITEM ) ;
82
+ const SERIALIZED_EVENT_ATTACHMENT_ENVELOPE = serializeEnvelope (
83
+ EVENT_ATTACHMENT_ENVELOPE ,
84
+ new TextEncoder ( ) ,
85
+ ) as Uint8Array ;
86
+
72
87
const defaultOptions = {
73
88
url : TEST_SERVER_URL ,
74
89
recordDroppedEvent : ( ) => undefined ,
@@ -236,104 +251,140 @@ describe('makeNewHttpTransport()', () => {
236
251
} ) ;
237
252
} ) ;
238
253
239
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (rate limit)' , async ( ) => {
240
- await setupTestServer ( {
241
- statusCode : RATE_LIMIT ,
242
- responseHeaders : { } ,
254
+ describe ( 'compression' , ( ) => {
255
+ it ( 'small envelopes should not be compressed' , async ( ) => {
256
+ await setupTestServer (
257
+ {
258
+ statusCode : SUCCESS ,
259
+ responseHeaders : { } ,
260
+ } ,
261
+ ( req , body ) => {
262
+ expect ( req . headers [ 'content-encoding' ] ) . toBeUndefined ( ) ;
263
+ expect ( body ) . toBe ( SERIALIZED_EVENT_ENVELOPE ) ;
264
+ } ,
265
+ ) ;
266
+
267
+ const transport = makeNodeTransport ( defaultOptions ) ;
268
+ await transport . send ( EVENT_ENVELOPE ) ;
243
269
} ) ;
244
270
245
- makeNodeTransport ( defaultOptions ) ;
246
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
271
+ it ( 'large envelopes should be compressed' , async ( ) => {
272
+ await setupTestServer (
273
+ {
274
+ statusCode : SUCCESS ,
275
+ responseHeaders : { } ,
276
+ } ,
277
+ ( req , _ , raw ) => {
278
+ expect ( req . headers [ 'content-encoding' ] ) . toEqual ( 'gzip' ) ;
279
+ expect ( raw . buffer ) . toStrictEqual ( SERIALIZED_EVENT_ATTACHMENT_ENVELOPE . buffer ) ;
280
+ } ,
281
+ ) ;
247
282
248
- const executorResult = registeredRequestExecutor ( {
249
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
250
- category : 'error' ,
283
+ const transport = makeNodeTransport ( defaultOptions ) ;
284
+ await transport . send ( EVENT_ATTACHMENT_ENVELOPE ) ;
251
285
} ) ;
286
+ } ) ;
252
287
253
- await expect ( executorResult ) . resolves . toEqual (
254
- expect . objectContaining ( {
288
+ describe ( 'should register TransportRequestExecutor that returns the correct object from server response' , ( ) => {
289
+ it ( 'rate limit' , async ( ) => {
290
+ await setupTestServer ( {
255
291
statusCode : RATE_LIMIT ,
256
- } ) ,
257
- ) ;
258
- } ) ;
292
+ responseHeaders : { } ,
293
+ } ) ;
259
294
260
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (OK)' , async ( ) => {
261
- await setupTestServer ( {
262
- statusCode : SUCCESS ,
263
- } ) ;
295
+ makeNodeTransport ( defaultOptions ) ;
296
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
264
297
265
- makeNodeTransport ( defaultOptions ) ;
266
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
298
+ const executorResult = registeredRequestExecutor ( {
299
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
300
+ category : 'error' ,
301
+ } ) ;
267
302
268
- const executorResult = registeredRequestExecutor ( {
269
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
270
- category : 'error' ,
303
+ await expect ( executorResult ) . resolves . toEqual (
304
+ expect . objectContaining ( {
305
+ statusCode : RATE_LIMIT ,
306
+ } ) ,
307
+ ) ;
271
308
} ) ;
272
309
273
- await expect ( executorResult ) . resolves . toEqual (
274
- expect . objectContaining ( {
310
+ it ( 'OK' , async ( ) => {
311
+ await setupTestServer ( {
275
312
statusCode : SUCCESS ,
276
- headers : {
277
- 'retry-after' : null ,
278
- 'x-sentry-rate-limits' : null ,
279
- } ,
280
- } ) ,
281
- ) ;
282
- } ) ;
313
+ } ) ;
283
314
284
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (OK with rate-limit headers)' , async ( ) => {
285
- await setupTestServer ( {
286
- statusCode : SUCCESS ,
287
- responseHeaders : {
288
- 'Retry-After' : '2700' ,
289
- 'X-Sentry-Rate-Limits' : '60::organization, 2700::organization' ,
290
- } ,
291
- } ) ;
315
+ makeNodeTransport ( defaultOptions ) ;
316
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
292
317
293
- makeNodeTransport ( defaultOptions ) ;
294
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
318
+ const executorResult = registeredRequestExecutor ( {
319
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
320
+ category : 'error' ,
321
+ } ) ;
295
322
296
- const executorResult = registeredRequestExecutor ( {
297
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
298
- category : 'error' ,
323
+ await expect ( executorResult ) . resolves . toEqual (
324
+ expect . objectContaining ( {
325
+ statusCode : SUCCESS ,
326
+ headers : {
327
+ 'retry-after' : null ,
328
+ 'x-sentry-rate-limits' : null ,
329
+ } ,
330
+ } ) ,
331
+ ) ;
299
332
} ) ;
300
333
301
- await expect ( executorResult ) . resolves . toEqual (
302
- expect . objectContaining ( {
334
+ it ( 'OK with rate-limit headers' , async ( ) => {
335
+ await setupTestServer ( {
303
336
statusCode : SUCCESS ,
304
- headers : {
305
- 'retry-after ' : '2700' ,
306
- 'x-sentry-rate-limits ' : '60::organization, 2700::organization' ,
337
+ responseHeaders : {
338
+ 'Retry-After ' : '2700' ,
339
+ 'X-Sentry-Rate-Limits ' : '60::organization, 2700::organization' ,
307
340
} ,
308
- } ) ,
309
- ) ;
310
- } ) ;
341
+ } ) ;
311
342
312
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (NOK with rate-limit headers)' , async ( ) => {
313
- await setupTestServer ( {
314
- statusCode : RATE_LIMIT ,
315
- responseHeaders : {
316
- 'Retry-After' : '2700' ,
317
- 'X-Sentry-Rate-Limits' : '60::organization, 2700::organization' ,
318
- } ,
319
- } ) ;
343
+ makeNodeTransport ( defaultOptions ) ;
344
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
320
345
321
- makeNodeTransport ( defaultOptions ) ;
322
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
346
+ const executorResult = registeredRequestExecutor ( {
347
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
348
+ category : 'error' ,
349
+ } ) ;
323
350
324
- const executorResult = registeredRequestExecutor ( {
325
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
326
- category : 'error' ,
351
+ await expect ( executorResult ) . resolves . toEqual (
352
+ expect . objectContaining ( {
353
+ statusCode : SUCCESS ,
354
+ headers : {
355
+ 'retry-after' : '2700' ,
356
+ 'x-sentry-rate-limits' : '60::organization, 2700::organization' ,
357
+ } ,
358
+ } ) ,
359
+ ) ;
327
360
} ) ;
328
361
329
- await expect ( executorResult ) . resolves . toEqual (
330
- expect . objectContaining ( {
362
+ it ( 'NOK with rate-limit headers' , async ( ) => {
363
+ await setupTestServer ( {
331
364
statusCode : RATE_LIMIT ,
332
- headers : {
333
- 'retry-after ' : '2700' ,
334
- 'x-sentry-rate-limits ' : '60::organization, 2700::organization' ,
365
+ responseHeaders : {
366
+ 'Retry-After ' : '2700' ,
367
+ 'X-Sentry-Rate-Limits ' : '60::organization, 2700::organization' ,
335
368
} ,
336
- } ) ,
337
- ) ;
369
+ } ) ;
370
+
371
+ makeNodeTransport ( defaultOptions ) ;
372
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
373
+
374
+ const executorResult = registeredRequestExecutor ( {
375
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
376
+ category : 'error' ,
377
+ } ) ;
378
+
379
+ await expect ( executorResult ) . resolves . toEqual (
380
+ expect . objectContaining ( {
381
+ statusCode : RATE_LIMIT ,
382
+ headers : {
383
+ 'retry-after' : '2700' ,
384
+ 'x-sentry-rate-limits' : '60::organization, 2700::organization' ,
385
+ } ,
386
+ } ) ,
387
+ ) ;
388
+ } ) ;
338
389
} ) ;
339
390
} ) ;
0 commit comments