Skip to content

Commit edf84ef

Browse files
committed
improve and add baggage-related tests
1 parent aad4429 commit edf84ef

File tree

7 files changed

+136
-22
lines changed

7 files changed

+136
-22
lines changed

packages/nextjs/src/utils/withSentry.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
logger,
88
objectify,
99
parseAndFreezeBaggageIfNecessary,
10-
parseBaggageString,
1110
stripUrlQueryAndFragment,
1211
} from '@sentry/utils';
1312
import * as domain from 'domain';

packages/node/test/handlers.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as sentryHub from '@sentry/hub';
33
import { Hub } from '@sentry/hub';
44
import { Transaction } from '@sentry/tracing';
55
import { Baggage, Runtime } from '@sentry/types';
6-
import { SentryError } from '@sentry/utils';
6+
import { isBaggageEmpty, isBaggageFrozen, SentryError } from '@sentry/utils';
77
import * as http from 'http';
88
import * as net from 'net';
99

@@ -368,7 +368,9 @@ describe('tracingHandler', () => {
368368
expect(transaction.traceId).toEqual('12312012123120121231201212312012');
369369
expect(transaction.parentSpanId).toEqual('1121201211212012');
370370
expect(transaction.sampled).toEqual(false);
371-
expect(transaction.metadata?.baggage).toBeUndefined();
371+
expect(transaction.metadata?.baggage).toBeDefined();
372+
expect(isBaggageEmpty(transaction.metadata?.baggage)).toBeTruthy();
373+
expect(isBaggageFrozen(transaction.metadata?.baggage)).toBeTruthy();
372374
});
373375

374376
it("pulls parent's data from tracing and baggage headers on the request", () => {
@@ -386,7 +388,7 @@ describe('tracingHandler', () => {
386388
expect(transaction.parentSpanId).toEqual('1121201211212012');
387389
expect(transaction.sampled).toEqual(false);
388390
expect(transaction.metadata?.baggage).toBeDefined();
389-
expect(transaction.metadata?.baggage).toEqual([{ version: '1.0', environment: 'production' }, ''] as Baggage);
391+
expect(transaction.metadata?.baggage).toEqual([{ version: '1.0', environment: 'production' }, '', true] as Baggage);
390392
});
391393

392394
it("pulls parent's baggage (sentry + third party entries) headers on the request", () => {
@@ -402,6 +404,7 @@ describe('tracingHandler', () => {
402404
expect(transaction.metadata?.baggage).toEqual([
403405
{ version: '1.0', environment: 'production' },
404406
'dogs=great,cats=boring',
407+
true,
405408
] as Baggage);
406409
});
407410

packages/tracing/src/browser/browsertracing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Hub } from '@sentry/hub';
22
import { EventProcessor, Integration, Transaction, TransactionContext } from '@sentry/types';
3-
import { getGlobalObject, logger, parseAndFreezeBaggageIfNecessary, parseBaggageString } from '@sentry/utils';
3+
import { getGlobalObject, logger, parseAndFreezeBaggageIfNecessary } from '@sentry/utils';
44

55
import { IS_DEBUG_BUILD } from '../flags';
66
import { startIdleTransaction } from '../hubextensions';

packages/tracing/src/span.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import { Baggage, Hub, Primitive, Span as SpanInterface, SpanContext, Transactio
44
import {
55
createBaggage,
66
dropUndefinedKeys,
7+
freezeBaggage,
78
isBaggageEmpty,
89
isBaggageFrozen,
10+
isSentryBaggageEmpty,
911
setBaggageValue,
1012
timestampWithMs,
1113
uuid4,
@@ -313,8 +315,10 @@ export class Span implements SpanInterface {
313315
public getBaggage(): Baggage | undefined {
314316
const existingBaggage = this.transaction && this.transaction.metadata.baggage;
315317

316-
const canModifyBaggage = !(existingBaggage && isBaggageFrozen(existingBaggage));
317-
const finalBaggage = canModifyBaggage ? this._getBaggageWithSentryValues(existingBaggage) : existingBaggage;
318+
const finalBaggage =
319+
!existingBaggage || (!isBaggageFrozen(existingBaggage) && isSentryBaggageEmpty(existingBaggage))
320+
? this._getBaggageWithSentryValues(existingBaggage)
321+
: existingBaggage;
318322

319323
return isBaggageEmpty(finalBaggage) ? undefined : finalBaggage;
320324
}
@@ -364,6 +368,8 @@ export class Span implements SpanInterface {
364368
environment && setBaggageValue(baggage, 'environment', environment);
365369
release && setBaggageValue(baggage, 'release', release);
366370

371+
freezeBaggage(baggage);
372+
367373
return baggage;
368374
}
369375
}

packages/tracing/test/browser/browsertracing.test.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { BrowserClient } from '@sentry/browser';
22
import { Hub, makeMain } from '@sentry/hub';
3-
import type { BaggageObj, BaseTransportOptions, ClientOptions } from '@sentry/types';
4-
import { getGlobalObject, InstrumentHandlerCallback, InstrumentHandlerType } from '@sentry/utils';
3+
import type { Baggage, BaggageObj, BaseTransportOptions, ClientOptions } from '@sentry/types';
4+
import {
5+
getGlobalObject,
6+
InstrumentHandlerCallback,
7+
InstrumentHandlerType,
8+
isBaggageEmpty,
9+
isSentryBaggageEmpty,
10+
} from '@sentry/utils';
511
import { JSDOM } from 'jsdom';
612

713
import {
@@ -228,7 +234,7 @@ describe('BrowserTracing', () => {
228234
parentSpanId: 'b6e54397b12a2a0f',
229235
parentSampled: true,
230236
metadata: {
231-
baggage: [{ release: '2.1.14' }, 'foo=bar'],
237+
baggage: [{ release: '2.1.14' }, 'foo=bar', true],
232238
},
233239
}),
234240
expect.any(Number),
@@ -390,7 +396,9 @@ describe('BrowserTracing', () => {
390396

391397
const headerContext = extractTraceDataFromMetaTags();
392398

393-
expect(headerContext).toBeUndefined();
399+
expect(headerContext).toBeDefined();
400+
expect(headerContext?.metadata?.baggage).toBeDefined();
401+
expect(isBaggageEmpty(headerContext?.metadata?.baggage as Baggage)).toBeTruthy();
394402
});
395403

396404
it('does not crash if the baggage header is malformed', () => {
@@ -406,12 +414,14 @@ describe('BrowserTracing', () => {
406414
expect(baggage && baggage[1]).toBeDefined();
407415
});
408416

409-
it("returns undefined if the header isn't there", () => {
417+
it("returns default object if the header isn't there", () => {
410418
document.head.innerHTML = '<meta name="dogs" content="12312012123120121231201212312012-1121201211212012-0">';
411419

412420
const headerContext = extractTraceDataFromMetaTags();
413421

414-
expect(headerContext).toBeUndefined();
422+
expect(headerContext).toBeDefined();
423+
expect(headerContext?.metadata?.baggage).toBeDefined();
424+
expect(isBaggageEmpty(headerContext?.metadata?.baggage as Baggage)).toBeTruthy();
415425
});
416426
});
417427

@@ -448,7 +458,7 @@ describe('BrowserTracing', () => {
448458
expect(baggage[1]).toEqual('foo=bar');
449459
});
450460

451-
it('adds Sentry baggage data to pageload transactions if not present in meta tags', () => {
461+
it('does not add Sentry baggage data to pageload transactions if sentry-trace data is present but passes on 3rd party baggage', () => {
452462
// make sampled false here, so we can see that it's being used rather than the tracesSampleRate-dictated one
453463
document.head.innerHTML =
454464
'<meta name="sentry-trace" content="12312012123120121231201212312012-1121201211212012-0">' +
@@ -465,8 +475,7 @@ describe('BrowserTracing', () => {
465475
expect(transaction.parentSpanId).toEqual('1121201211212012');
466476
expect(transaction.sampled).toBe(false);
467477
expect(baggage).toBeDefined();
468-
expect(baggage[0]).toBeDefined();
469-
expect(baggage[0]).toEqual({ environment: 'production', release: '1.0.0' });
478+
expect(isSentryBaggageEmpty(baggage)).toBeTruthy();
470479
expect(baggage[1]).toBeDefined();
471480
expect(baggage[1]).toEqual('foo=bar');
472481
});

packages/tracing/test/span.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,11 +424,11 @@ describe('Span', () => {
424424
expect(baggage && getThirdPartyBaggage(baggage)).toStrictEqual('');
425425
});
426426

427-
test('add Sentry baggage data to baggage if Sentry content is empty', () => {
427+
test('add Sentry baggage data to baggage if Sentry content is empty and baggage is mutable', () => {
428428
const transaction = new Transaction(
429429
{
430430
name: 'tx',
431-
metadata: { baggage: createBaggage({}, '') },
431+
metadata: { baggage: createBaggage({}, '', false) },
432432
},
433433
hub,
434434
);

packages/utils/test/baggage.test.ts

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import { Baggage } from '@sentry/types';
2+
13
import {
24
createBaggage,
5+
freezeBaggage,
36
getBaggageValue,
7+
isBaggageEmpty,
8+
isBaggageFrozen,
49
isSentryBaggageEmpty,
510
mergeAndSerializeBaggage,
11+
parseAndFreezeBaggageIfNecessary,
612
parseBaggageString,
713
serializeBaggage,
814
setBaggageValue,
@@ -11,15 +17,23 @@ import {
1117
describe('Baggage', () => {
1218
describe('createBaggage', () => {
1319
it.each([
14-
['creates an empty baggage instance', {}, [{}, '']],
20+
['creates an empty baggage instance', {}, [{}, '', false]],
1521
[
1622
'creates a baggage instance with initial values',
1723
{ environment: 'production', anyKey: 'anyValue' },
18-
[{ environment: 'production', anyKey: 'anyValue' }, ''],
24+
[{ environment: 'production', anyKey: 'anyValue' }, '', false],
1925
],
2026
])('%s', (_: string, input, output) => {
2127
expect(createBaggage(input)).toEqual(output);
2228
});
29+
30+
it('creates a baggage instance and marks it immutable if explicitly specified', () => {
31+
expect(createBaggage({ environment: 'production', anyKey: 'anyValue' }, '', true)).toEqual([
32+
{ environment: 'production', anyKey: 'anyValue' },
33+
'',
34+
true,
35+
]);
36+
});
2337
});
2438

2539
describe('getBaggageValue', () => {
@@ -40,6 +54,12 @@ describe('Baggage', () => {
4054
it.each([
4155
['sets a baggage item', createBaggage({}), 'environment', 'production'],
4256
['overwrites a baggage item', createBaggage({ environment: 'development' }), 'environment', 'production'],
57+
[
58+
'does not set a value if the passed baggage item is immutable',
59+
createBaggage({ environment: 'development' }, '', true),
60+
'environment',
61+
'development',
62+
],
4363
])('%s', (_: string, baggage, key, value) => {
4464
setBaggageValue(baggage, key, value);
4565
expect(getBaggageValue(baggage, key)).toEqual(value);
@@ -98,10 +118,21 @@ describe('Baggage', () => {
98118
});
99119
});
100120

121+
describe('isBaggageEmpty', () => {
122+
it.each([
123+
['returns true if the entire baggage tuple is empty', createBaggage({}), true],
124+
['returns false if the Sentry part of baggage is not empty', createBaggage({ release: '10.0.2' }), false],
125+
['returns false if the 3rd party part of baggage is not empty', createBaggage({}, 'foo=bar'), false],
126+
['returns false if both parts of baggage are not empty', createBaggage({ release: '10.0.2' }, 'foo=bar'), false],
127+
])('%s', (_: string, baggage, outcome) => {
128+
expect(isBaggageEmpty(baggage)).toEqual(outcome);
129+
});
130+
});
131+
101132
describe('isSentryBaggageEmpty', () => {
102133
it.each([
103-
['returns true if the modifyable part of baggage is empty', createBaggage({}), true],
104-
['returns false if the modifyable part of baggage is not empty', createBaggage({ release: '10.0.2' }), false],
134+
['returns true if the Sentry part of baggage is empty', createBaggage({}), true],
135+
['returns false if the Sentry part of baggage is not empty', createBaggage({ release: '10.0.2' }), false],
105136
])('%s', (_: string, baggage, outcome) => {
106137
expect(isSentryBaggageEmpty(baggage)).toEqual(outcome);
107138
});
@@ -129,4 +160,70 @@ describe('Baggage', () => {
129160
expect(mergeAndSerializeBaggage(baggage, headerBaggageString)).toEqual(outcome);
130161
});
131162
});
163+
164+
describe('parseAndFreezeBaggageIfNecessary', () => {
165+
it.each([
166+
[
167+
'returns an empty, mutable baggage object if both params are undefined',
168+
undefined,
169+
undefined,
170+
[{}, '', false] as Baggage,
171+
],
172+
[
173+
'returns an empty, immutable baggage object if sentry-trace header data is defined',
174+
undefined,
175+
{},
176+
[{}, '', true] as Baggage,
177+
],
178+
[
179+
'returns an empty, immutable baggage object if sentry-trace header data is a string',
180+
undefined,
181+
'123',
182+
[{}, '', true] as Baggage,
183+
],
184+
[
185+
'returns a non-empty, mutable baggage object if sentry-trace is not defined and only 3rd party baggage items are passed',
186+
'foo=bar',
187+
undefined,
188+
[{}, 'foo=bar', false] as Baggage,
189+
],
190+
[
191+
'returns a non-empty, immutable baggage object if sentry-trace is not defined and Sentry baggage items are passed',
192+
'sentry-environment=production,foo=bar',
193+
undefined,
194+
[{ environment: 'production' }, 'foo=bar', true] as Baggage,
195+
],
196+
[
197+
'returns a non-empty, immutable baggage object if sentry-trace is defined',
198+
'foo=bar',
199+
{},
200+
[{}, 'foo=bar', true] as Baggage,
201+
],
202+
])(
203+
'%s',
204+
(_: string, baggageString: string | undefined, sentryTraceData: any | string | undefined, result: Baggage) => {
205+
expect(parseAndFreezeBaggageIfNecessary(baggageString, sentryTraceData)).toEqual(result);
206+
},
207+
);
208+
});
209+
210+
describe('isBaggageFrozen', () => {
211+
it.each([
212+
['returns true if the baggage was set immutable', true],
213+
['returns false if the baggage was set mutable', false],
214+
])('%s', (_: string, outcome) => {
215+
const baggage: Baggage = [{}, '', outcome];
216+
expect(isBaggageFrozen(baggage)).toEqual(outcome);
217+
});
218+
});
219+
220+
describe('freezeBaggage', () => {
221+
it.each([
222+
['sets baggage immutable', [{}, '', false] as Baggage],
223+
['does not do anything when baggage is already immutable', [{}, '', true] as Baggage],
224+
])('%s', (_: string, baggage: Baggage) => {
225+
freezeBaggage(baggage);
226+
expect(baggage[2]).toEqual(true);
227+
});
228+
});
132229
});

0 commit comments

Comments
 (0)