Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9cfe4c7
add TextEncoder and TextDecoder to jsdom test environment
lobsterkatie Aug 18, 2021
37b4944
add TransactionMetadata to DebugMeta type
lobsterkatie Aug 18, 2021
2ec4722
add segment to user type
lobsterkatie Aug 18, 2021
f9ba96c
add TraceHeaders and SpanContext.getTraceHeaders() to types
lobsterkatie Aug 18, 2021
bbf472d
add base64 string functions
lobsterkatie Aug 18, 2021
9474a4e
fix circular dependency
lobsterkatie Aug 19, 2021
6728b26
move setting default environment to SDK initialization rather than ev…
lobsterkatie Aug 18, 2021
0af6717
remove unused traceHeaders function
lobsterkatie Aug 18, 2021
5e57193
polyfill Object.fromEntries for tracing tests
lobsterkatie Aug 18, 2021
5d53567
s/TRACEPARENT_REGEXP/SENTRY_TRACE_REGEX
lobsterkatie Aug 18, 2021
2a50338
s/extractTraceparentData/extractSentrytraceData
lobsterkatie Aug 18, 2021
54ac0d6
s/traceparent/sentrytrace in various spots
lobsterkatie Aug 19, 2021
58eeda9
add functions for computing tracestate and combined tracing headers
lobsterkatie Aug 19, 2021
a758e16
add tracestate header to outgoing requests
lobsterkatie Aug 19, 2021
a007a83
deprecate toTraceparent
lobsterkatie Aug 19, 2021
1a4336e
add extractTracestateData() function
lobsterkatie Aug 19, 2021
fcb41b3
make transactions accept metadata in their incoming transaction context
lobsterkatie Aug 19, 2021
f0f7ed6
propagate incoming tracestate headers
lobsterkatie Aug 19, 2021
9ab5a8f
extract and propagate tracestate data from <meta> tags
lobsterkatie Aug 19, 2021
08d9ba4
add missing tracestate when capturing transaction, if necessary
lobsterkatie Aug 19, 2021
5c6070e
only deal with envelope header data if we're using an envelope
lobsterkatie Aug 19, 2021
50819b6
add tracestate to envelope header
lobsterkatie Aug 19, 2021
756e855
clean up comments
lobsterkatie Aug 19, 2021
a0b5caf
add http header tests
lobsterkatie Aug 19, 2021
f1a0dbf
random cleanup
lobsterkatie Aug 19, 2021
6415a5a
don't stringify event data until the end
lobsterkatie Aug 19, 2021
15a2e85
rework and add request tests
lobsterkatie Aug 19, 2021
dd76840
remove redundant string test, add browser test for non-base64 string
lobsterkatie Aug 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add http header tests
  • Loading branch information
lobsterkatie committed Aug 23, 2021
commit a0b5cafc2a32b8c9968c1ee85b096ae5448234c4
248 changes: 248 additions & 0 deletions packages/tracing/test/httpheaders.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import * as sentryCore from '@sentry/core';
import { API } from '@sentry/core';
import { Hub } from '@sentry/hub';
import { SentryRequest } from '@sentry/types';
import * as utilsPackage from '@sentry/utils';
import { base64ToUnicode } from '@sentry/utils';

import { Span } from '../src/span';
import { Transaction } from '../src/transaction';
import { computeTracestateValue } from '../src/utils';

// TODO gather sentry-trace and tracestate tests here

function parseEnvelopeRequest(request: SentryRequest): any {
const [envelopeHeaderString, itemHeaderString, eventString] = request.body.split('\n');

return {
envelopeHeader: JSON.parse(envelopeHeaderString),
itemHeader: JSON.parse(itemHeaderString),
event: JSON.parse(eventString),
};
}

describe('sentry-trace', () => {
// TODO gather relevant tests here
});

describe('tracestate', () => {
// grab these this way rather than importing them individually to get around TS's guards against instantiating
// abstract classes (using non-abstract classes would create a circular dependency)
const { BaseClient, BaseBackend } = sentryCore as any;

const dsn = 'https://[email protected]/12312012';
const environment = 'dogpark';
const release = 'off.leash.trail';
const hub = new Hub(
new BaseClient(BaseBackend, {
dsn,
environment,
release,
}),
);

describe('sentry tracestate', () => {
describe('lazy creation', () => {
const getNewTracestate = jest
.spyOn(Span.prototype as any, '_getNewTracestate')
.mockReturnValue('sentry=doGsaREgReaT');

beforeEach(() => {
jest.clearAllMocks();
});

afterAll(() => {
jest.restoreAllMocks();
});

describe('when creating a transaction', () => {
it('uses sentry tracestate passed to the transaction constructor rather than creating a new one', () => {
const transaction = new Transaction({
name: 'FETCH /ball',
metadata: { tracestate: { sentry: 'sentry=doGsaREgReaT' } },
});

expect(getNewTracestate).not.toHaveBeenCalled();
expect(transaction.metadata.tracestate?.sentry).toEqual('sentry=doGsaREgReaT');
});

it("doesn't create new sentry tracestate on transaction creation if none provided", () => {
const transaction = new Transaction({
name: 'FETCH /ball',
});

expect(transaction.metadata.tracestate?.sentry).toBeUndefined();
expect(getNewTracestate).not.toHaveBeenCalled();
});
});

describe('when getting outgoing request headers', () => {
it('uses existing sentry tracestate when getting tracing headers rather than creating new one', () => {
const transaction = new Transaction({
name: 'FETCH /ball',
metadata: { tracestate: { sentry: 'sentry=doGsaREgReaT' } },
});

expect(transaction.getTraceHeaders().tracestate).toEqual('sentry=doGsaREgReaT');
expect(getNewTracestate).not.toHaveBeenCalled();
});

it('creates and stores new sentry tracestate when getting tracing headers if none exists', () => {
const transaction = new Transaction({
name: 'FETCH /ball',
});

expect(transaction.metadata.tracestate?.sentry).toBeUndefined();

transaction.getTraceHeaders();

expect(getNewTracestate).toHaveBeenCalled();
expect(transaction.metadata.tracestate?.sentry).toEqual('sentry=doGsaREgReaT');
expect(transaction.getTraceHeaders().tracestate).toEqual('sentry=doGsaREgReaT');
});
});

describe('when getting envelope headers', () => {
// In real life, `transaction.finish()` calls `captureEvent()`, which eventually calls `eventToSentryRequest()`,
// which in turn calls `base64ToUnicode`. Here we're short circuiting that process a little, to avoid having to
// mock out more of the intermediate pieces.
jest
.spyOn(utilsPackage, 'base64ToUnicode')
.mockImplementation(base64 =>
base64 === 'doGsaREgReaT' ? '{"all the":"right stuff here"}' : '{"nope nope nope":"wrong"}',
);
jest.spyOn(hub, 'captureEvent').mockImplementation(event => {
expect(event).toEqual(
expect.objectContaining({ debug_meta: { tracestate: { sentry: 'sentry=doGsaREgReaT' } } }),
);

const envelope = parseEnvelopeRequest(sentryCore.eventToSentryRequest(event, new API(dsn)));
expect(envelope.envelopeHeader).toEqual(
expect.objectContaining({ trace: { 'all the': 'right stuff here' } }),
);

// `captureEvent` normally returns the event id
return '11212012041520131231201209082013'; //
});

it('uses existing sentry tracestate in envelope headers rather than creating a new one', () => {
// one here, and two inside the `captureEvent` implementation above
expect.assertions(3);

const transaction = new Transaction(
{
name: 'FETCH /ball',
metadata: { tracestate: { sentry: 'sentry=doGsaREgReaT' } },
sampled: true,
},
hub,
);

transaction.finish();

expect(getNewTracestate).not.toHaveBeenCalled();
});

it('creates new sentry tracestate for envelope header if none exists', () => {
// two here, and two inside the `captureEvent` implementation above
expect.assertions(4);

const transaction = new Transaction(
{
name: 'FETCH /ball',
sampled: true,
},
hub,
);

expect(transaction.metadata.tracestate?.sentry).toBeUndefined();

transaction.finish();

expect(getNewTracestate).toHaveBeenCalled();
});
});
});

describe('mutibility', () => {
it("won't include data set after transaction is created if there's an inherited value", () => {
expect.assertions(1);

const inheritedTracestate = `sentry=${computeTracestateValue({
trace_id: '12312012090820131231201209082013',
environment: 'dogpark',
release: 'off.leash.trail',
public_key: 'dogsarebadatkeepingsecrets',
})}`;

const transaction = new Transaction(
{
name: 'FETCH /ball',
metadata: {
tracestate: {
sentry: inheritedTracestate,
},
},
},
hub,
);

hub.withScope(scope => {
scope.setUser({ id: '1121', username: 'CharlieDog', ip_address: '11.21.20.12', segment: 'bigs' });

const tracestateValue = (transaction as any)._toTracestate().replace('sentry=', '');
const reinflatedTracestate = JSON.parse(base64ToUnicode(tracestateValue));

expect(reinflatedTracestate.user).toBeUndefined();
});
});

it("will include data set after transaction is created if there's no inherited value and `getTraceHeaders` hasn't been called", () => {
expect.assertions(2);

const transaction = new Transaction(
{
name: 'FETCH /ball',
},
hub,
);

hub.withScope(scope => {
scope.setUser({ id: '1121', username: 'CharlieDog', ip_address: '11.21.20.12', segment: 'bigs' });

const tracestateValue = (transaction as any)._toTracestate().replace('sentry=', '');
const reinflatedTracestate = JSON.parse(base64ToUnicode(tracestateValue));

expect(reinflatedTracestate.user.id).toEqual('1121');
expect(reinflatedTracestate.user.segment).toEqual('bigs');
});
});

it("won't include data set after first call to `getTraceHeaders`", () => {
expect.assertions(1);

const transaction = new Transaction(
{
name: 'FETCH /ball',
},
hub,
);

transaction.getTraceHeaders();

hub.withScope(scope => {
scope.setUser({ id: '1121', username: 'CharlieDog', ip_address: '11.21.20.12', segment: 'bigs' });

const tracestateValue = (transaction as any)._toTracestate().replace('sentry=', '');
const reinflatedTracestate = JSON.parse(base64ToUnicode(tracestateValue));

expect(reinflatedTracestate.user).toBeUndefined();
});
});
});
});

describe('third-party tracestate', () => {
// TODO gather relevant tests here
});
});