Skip to content

Commit ee433ee

Browse files
committed
Add tests
1 parent 6398d06 commit ee433ee

File tree

1 file changed

+133
-85
lines changed

1 file changed

+133
-85
lines changed

packages/node/test/transports/http.test.ts

Lines changed: 133 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { createTransport } from '@sentry/core';
22
import { EventEnvelope, EventItem } from '@sentry/types';
3-
import { createEnvelope, serializeEnvelope } from '@sentry/utils';
3+
import { createEnvelope, serializeEnvelope, addItemToEnvelope, createAttachmentEnvelopeItem } from '@sentry/utils';
44
import * as http from 'http';
55
import { TextEncoder } from 'util';
66

77
import { makeNodeTransport } from '../../src/transports';
8+
import { createGunzip } from 'zlib';
89

910
jest.mock('@sentry/core', () => {
1011
const actualCore = jest.requireActual('@sentry/core');
@@ -34,17 +35,21 @@ let testServer: http.Server | undefined;
3435

3536
function setupTestServer(
3637
options: TestServerOptions,
37-
requestInspector?: (req: http.IncomingMessage, body: string) => void,
38+
requestInspector?: (req: http.IncomingMessage, body: string, raw: Uint8Array) => void,
3839
) {
3940
testServer = http.createServer((req, res) => {
40-
let body = '';
41+
let chunks: Buffer[] = [];
4142

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);
4449
});
4550

46-
req.on('end', () => {
47-
requestInspector?.(req, body);
51+
stream.on('end', () => {
52+
requestInspector?.(req, chunks.join(), Buffer.concat(chunks));
4853
});
4954

5055
res.writeHead(options.statusCode, options.responseHeaders);
@@ -69,6 +74,13 @@ const EVENT_ENVELOPE = createEnvelope<EventEnvelope>({ event_id: 'aa3ff046696b4b
6974

7075
const SERIALIZED_EVENT_ENVELOPE = serializeEnvelope(EVENT_ENVELOPE, new TextEncoder());
7176

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(EVENT_ATTACHMENT_ENVELOPE, new TextEncoder());
83+
7284
const defaultOptions = {
7385
url: TEST_SERVER_URL,
7486
recordDroppedEvent: () => undefined,
@@ -155,6 +167,40 @@ describe('makeNewHttpTransport()', () => {
155167
});
156168
});
157169

170+
describe('compression', () => {
171+
it('small envelopes should not be compressed', async () => {
172+
await setupTestServer(
173+
{
174+
statusCode: SUCCESS,
175+
responseHeaders: {},
176+
},
177+
(req, body) => {
178+
expect(req.headers['content-encoding']).toBeUndefined();
179+
expect(body).toBe(SERIALIZED_EVENT_ENVELOPE);
180+
},
181+
);
182+
183+
const transport = makeNodeTransport(defaultOptions);
184+
await transport.send(EVENT_ENVELOPE);
185+
});
186+
187+
it('large envelopes should be compressed', async () => {
188+
await setupTestServer(
189+
{
190+
statusCode: SUCCESS,
191+
responseHeaders: {},
192+
},
193+
(req, _, raw) => {
194+
expect(req.headers['content-encoding']).toEqual('gzip');
195+
expect(raw.buffer).toStrictEqual(SERIALIZED_EVENT_ATTACHMENT_ENVELOPE.buffer);
196+
},
197+
);
198+
199+
const transport = makeNodeTransport(defaultOptions);
200+
await transport.send(EVENT_ATTACHMENT_ENVELOPE);
201+
});
202+
});
203+
158204
describe('proxy', () => {
159205
it('can be configured through option', () => {
160206
makeNodeTransport({
@@ -236,104 +282,106 @@ describe('makeNewHttpTransport()', () => {
236282
});
237283
});
238284

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: {},
243-
});
244-
245-
makeNodeTransport(defaultOptions);
246-
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
247-
248-
const executorResult = registeredRequestExecutor({
249-
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
250-
category: 'error',
251-
});
252-
253-
await expect(executorResult).resolves.toEqual(
254-
expect.objectContaining({
285+
describe('should register TransportRequestExecutor that returns the correct object from server response', () => {
286+
it('rate limit', async () => {
287+
await setupTestServer({
255288
statusCode: RATE_LIMIT,
256-
}),
257-
);
258-
});
289+
responseHeaders: {},
290+
});
259291

260-
it('should register TransportRequestExecutor that returns the correct object from server response (OK)', async () => {
261-
await setupTestServer({
262-
statusCode: SUCCESS,
263-
});
292+
makeNodeTransport(defaultOptions);
293+
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
264294

265-
makeNodeTransport(defaultOptions);
266-
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
295+
const executorResult = registeredRequestExecutor({
296+
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
297+
category: 'error',
298+
});
267299

268-
const executorResult = registeredRequestExecutor({
269-
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
270-
category: 'error',
300+
await expect(executorResult).resolves.toEqual(
301+
expect.objectContaining({
302+
statusCode: RATE_LIMIT,
303+
}),
304+
);
271305
});
272306

273-
await expect(executorResult).resolves.toEqual(
274-
expect.objectContaining({
307+
it('OK', async () => {
308+
await setupTestServer({
275309
statusCode: SUCCESS,
276-
headers: {
277-
'retry-after': null,
278-
'x-sentry-rate-limits': null,
279-
},
280-
}),
281-
);
282-
});
310+
});
283311

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-
});
312+
makeNodeTransport(defaultOptions);
313+
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
292314

293-
makeNodeTransport(defaultOptions);
294-
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
315+
const executorResult = registeredRequestExecutor({
316+
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
317+
category: 'error',
318+
});
295319

296-
const executorResult = registeredRequestExecutor({
297-
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
298-
category: 'error',
320+
await expect(executorResult).resolves.toEqual(
321+
expect.objectContaining({
322+
statusCode: SUCCESS,
323+
headers: {
324+
'retry-after': null,
325+
'x-sentry-rate-limits': null,
326+
},
327+
}),
328+
);
299329
});
300330

301-
await expect(executorResult).resolves.toEqual(
302-
expect.objectContaining({
331+
it('OK with rate-limit headers', async () => {
332+
await setupTestServer({
303333
statusCode: SUCCESS,
304-
headers: {
305-
'retry-after': '2700',
306-
'x-sentry-rate-limits': '60::organization, 2700::organization',
334+
responseHeaders: {
335+
'Retry-After': '2700',
336+
'X-Sentry-Rate-Limits': '60::organization, 2700::organization',
307337
},
308-
}),
309-
);
310-
});
338+
});
311339

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-
});
340+
makeNodeTransport(defaultOptions);
341+
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
320342

321-
makeNodeTransport(defaultOptions);
322-
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
343+
const executorResult = registeredRequestExecutor({
344+
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
345+
category: 'error',
346+
});
323347

324-
const executorResult = registeredRequestExecutor({
325-
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
326-
category: 'error',
348+
await expect(executorResult).resolves.toEqual(
349+
expect.objectContaining({
350+
statusCode: SUCCESS,
351+
headers: {
352+
'retry-after': '2700',
353+
'x-sentry-rate-limits': '60::organization, 2700::organization',
354+
},
355+
}),
356+
);
327357
});
328358

329-
await expect(executorResult).resolves.toEqual(
330-
expect.objectContaining({
359+
it('NOK with rate-limit headers', async () => {
360+
await setupTestServer({
331361
statusCode: RATE_LIMIT,
332-
headers: {
333-
'retry-after': '2700',
334-
'x-sentry-rate-limits': '60::organization, 2700::organization',
362+
responseHeaders: {
363+
'Retry-After': '2700',
364+
'X-Sentry-Rate-Limits': '60::organization, 2700::organization',
335365
},
336-
}),
337-
);
366+
});
367+
368+
makeNodeTransport(defaultOptions);
369+
const registeredRequestExecutor = (createTransport as jest.Mock).mock.calls[0][1];
370+
371+
const executorResult = registeredRequestExecutor({
372+
body: serializeEnvelope(EVENT_ENVELOPE, new TextEncoder()),
373+
category: 'error',
374+
});
375+
376+
await expect(executorResult).resolves.toEqual(
377+
expect.objectContaining({
378+
statusCode: RATE_LIMIT,
379+
headers: {
380+
'retry-after': '2700',
381+
'x-sentry-rate-limits': '60::organization, 2700::organization',
382+
},
383+
}),
384+
);
385+
});
338386
});
339387
});

0 commit comments

Comments
 (0)