Skip to content

Commit 775eeab

Browse files
committed
convert e2e test to streaming
1 parent 61ba8b8 commit 775eeab

2 files changed

Lines changed: 73 additions & 136 deletions

File tree

dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export class LocalLambdaStack extends Stack {
113113
SENTRY_DSN: dsn,
114114
SENTRY_TRACES_SAMPLE_RATE: 1.0,
115115
SENTRY_DEBUG: true,
116-
SENTRY_TRACE_LIFECYCLE: 'static',
117116
NODE_OPTIONS: `--import=@sentry/aws-serverless/awslambda-auto`,
118117
},
119118
},
Lines changed: 73 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,85 @@
1-
import { waitForTransaction } from '@sentry-internal/test-utils';
1+
import type { SerializedStreamedSpan } from '@sentry-internal/test-utils';
2+
import { collectStreamedSpans, getSpanOp } from '@sentry-internal/test-utils';
23
import { InvokeCommand } from '@aws-sdk/client-lambda';
34
import { test, expect } from './lambda-fixtures';
45

5-
test.describe('NPM package', () => {
6-
test('tracing in CJS works', async ({ lambdaClient }) => {
7-
const transactionEventPromise = waitForTransaction('aws-serverless', transactionEvent => {
8-
return transactionEvent?.transaction === 'NpmTracingCjs';
9-
});
10-
11-
await lambdaClient.send(
12-
new InvokeCommand({
13-
FunctionName: 'NpmTracingCjs',
14-
Payload: JSON.stringify({}),
15-
}),
16-
);
17-
18-
const transactionEvent = await transactionEventPromise;
19-
20-
// shows the SDK sent a transaction
21-
expect(transactionEvent.transaction).toEqual('NpmTracingCjs'); // name should be the function name
22-
expect(transactionEvent.contexts?.trace).toEqual({
23-
data: {
24-
'sentry.sample_rate': 1,
25-
'sentry.segment.name.source': 'custom',
26-
'sentry.origin': 'auto.aws_lambda',
27-
'sentry.op': 'function.aws',
28-
'cloud.account.id': '012345678912',
29-
'cloud.platform': 'aws_lambda',
30-
'cloud.provider': 'aws',
31-
'faas.execution': expect.any(String),
32-
'faas.id': 'arn:aws:lambda:us-east-1:012345678912:function:NpmTracingCjs',
33-
'faas.name': 'NpmTracingCjs',
34-
'faas.coldstart': true,
35-
'sentry.kind': 'server',
36-
},
37-
op: 'function.aws',
38-
origin: 'auto.aws_lambda',
39-
span_id: expect.stringMatching(/[a-f0-9]{16}/),
40-
status: 'ok',
41-
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
42-
});
43-
44-
expect(transactionEvent.spans).toHaveLength(2);
6+
// This app runs with `traceLifecycle: 'stream'`, the SDK default. The `aws-serverless-layer` app
7+
// covers the `'static'` lifecycle, so between the two both lifecycles stay under test.
8+
9+
function assertLambdaTrace(spans: SerializedStreamedSpan[], functionName: string): void {
10+
const segmentSpan = spans.find(span => span.is_segment);
11+
12+
// `function.aws` span names are low cardinality: the function name, never the invocation URL.
13+
expect(segmentSpan?.name).toBe(functionName);
14+
expect(segmentSpan?.status).toBe('ok');
15+
expect(getSpanOp(segmentSpan!)).toBe('function.aws');
16+
17+
expect(segmentSpan?.attributes).toMatchObject({
18+
'sentry.op': { value: 'function.aws', type: 'string' },
19+
'sentry.origin': { value: 'auto.aws_lambda', type: 'string' },
20+
'sentry.kind': { value: 'server', type: 'string' },
21+
'sentry.segment.name.source': { value: 'custom', type: 'string' },
22+
'cloud.account.id': { value: '012345678912', type: 'string' },
23+
'cloud.platform': { value: 'aws_lambda', type: 'string' },
24+
'cloud.provider': { value: 'aws', type: 'string' },
25+
'faas.coldstart': { value: true, type: 'boolean' },
26+
'faas.execution': { value: expect.any(String), type: 'string' },
27+
'faas.id': { value: `arn:aws:lambda:us-east-1:012345678912:function:${functionName}`, type: 'string' },
28+
// The name the span is named after also stays on the span, so it survives a rename.
29+
'faas.name': { value: functionName, type: 'string' },
30+
// Streamed spans have no event contexts, so the `aws.lambda` context the transaction used to
31+
// carry is stamped onto the segment span by `awsLambdaIntegration`.
32+
'aws.lambda.function_name': { value: functionName, type: 'string' },
33+
'aws.lambda.invoked_function_arn': {
34+
value: `arn:aws:lambda:us-east-1:012345678912:function:${functionName}`,
35+
type: 'string',
36+
},
37+
'aws.lambda.aws_request_id': { value: expect.any(String), type: 'string' },
38+
'aws.cloudwatch.logs.log_group': { value: expect.any(String), type: 'string' },
39+
'aws.cloudwatch.logs.log_stream': { value: expect.any(String), type: 'string' },
40+
});
4541

46-
// shows that the Otel Http instrumentation is working
47-
expect(transactionEvent.spans).toContainEqual(
48-
expect.objectContaining({
49-
data: expect.objectContaining({
50-
'sentry.op': 'http.client',
51-
'sentry.origin': 'auto.http.client',
52-
'url.full': 'http://example.com/',
53-
}),
54-
description: 'GET http://example.com/',
55-
op: 'http.client',
42+
// shows that the Otel Http instrumentation is working
43+
expect(spans).toContainEqual(
44+
expect.objectContaining({
45+
name: 'GET example.com',
46+
parent_span_id: segmentSpan?.span_id,
47+
attributes: expect.objectContaining({
48+
'sentry.op': { value: 'http.client', type: 'string' },
49+
'sentry.origin': { value: 'auto.http.client', type: 'string' },
50+
'url.full': { value: 'http://example.com/', type: 'string' },
5651
}),
57-
);
58-
59-
// shows that the manual span creation is working
60-
expect(transactionEvent.spans).toContainEqual(
61-
expect.objectContaining({
62-
data: expect.objectContaining({
63-
'sentry.op': 'manual',
64-
'sentry.origin': 'manual',
65-
}),
66-
description: 'manual-span',
67-
op: 'manual',
52+
}),
53+
);
54+
55+
// shows that the manual span creation is working
56+
expect(spans).toContainEqual(
57+
expect.objectContaining({
58+
name: 'manual-span',
59+
parent_span_id: segmentSpan?.span_id,
60+
attributes: expect.objectContaining({
61+
'sentry.op': { value: 'manual', type: 'string' },
62+
'sentry.origin': { value: 'manual', type: 'string' },
6863
}),
69-
);
70-
71-
// shows that the SDK source is correctly detected
72-
expect(transactionEvent.sdk?.packages).toContainEqual(
73-
expect.objectContaining({ name: 'npm:@sentry/aws-serverless' }),
74-
);
75-
});
64+
}),
65+
);
66+
}
7667

77-
test('tracing in ESM works', async ({ lambdaClient }) => {
78-
const transactionEventPromise = waitForTransaction('aws-serverless', transactionEvent => {
79-
return transactionEvent?.transaction === 'NpmTracingEsm';
80-
});
68+
test.describe('NPM package', () => {
69+
for (const [label, functionName] of [
70+
['CJS', 'NpmTracingCjs'],
71+
['ESM', 'NpmTracingEsm'],
72+
] as const) {
73+
test(`tracing in ${label} works`, async ({ lambdaClient }) => {
74+
const spansPromise = collectStreamedSpans('aws-serverless', spansOfTrace =>
75+
spansOfTrace.some(span => span.is_segment && span.name === functionName),
76+
);
8177

82-
await lambdaClient.send(
83-
new InvokeCommand({
84-
FunctionName: 'NpmTracingEsm',
85-
Payload: JSON.stringify({}),
86-
}),
87-
);
78+
await lambdaClient.send(new InvokeCommand({ FunctionName: functionName, Payload: JSON.stringify({}) }));
8879

89-
const transactionEvent = await transactionEventPromise;
80+
const spans = await spansPromise;
9081

91-
// shows the SDK sent a transaction
92-
expect(transactionEvent.transaction).toEqual('NpmTracingEsm'); // name should be the function name
93-
expect(transactionEvent.contexts?.trace).toEqual({
94-
data: {
95-
'sentry.sample_rate': 1,
96-
'sentry.segment.name.source': 'custom',
97-
'sentry.origin': 'auto.aws_lambda',
98-
'sentry.op': 'function.aws',
99-
'cloud.account.id': '012345678912',
100-
'cloud.platform': 'aws_lambda',
101-
'cloud.provider': 'aws',
102-
'faas.execution': expect.any(String),
103-
'faas.id': 'arn:aws:lambda:us-east-1:012345678912:function:NpmTracingEsm',
104-
'faas.name': 'NpmTracingEsm',
105-
'faas.coldstart': true,
106-
'sentry.kind': 'server',
107-
},
108-
op: 'function.aws',
109-
origin: 'auto.aws_lambda',
110-
span_id: expect.stringMatching(/[a-f0-9]{16}/),
111-
status: 'ok',
112-
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
82+
assertLambdaTrace(spans, functionName);
11383
});
114-
115-
expect(transactionEvent.spans).toHaveLength(2);
116-
117-
// shows that the Otel Http instrumentation is working
118-
expect(transactionEvent.spans).toContainEqual(
119-
expect.objectContaining({
120-
data: expect.objectContaining({
121-
'sentry.op': 'http.client',
122-
'sentry.origin': 'auto.http.client',
123-
'url.full': 'http://example.com/',
124-
}),
125-
description: 'GET http://example.com/',
126-
op: 'http.client',
127-
}),
128-
);
129-
130-
// shows that the manual span creation is working
131-
expect(transactionEvent.spans).toContainEqual(
132-
expect.objectContaining({
133-
data: expect.objectContaining({
134-
'sentry.op': 'manual',
135-
'sentry.origin': 'manual',
136-
}),
137-
description: 'manual-span',
138-
op: 'manual',
139-
}),
140-
);
141-
142-
// shows that the SDK source is correctly detected
143-
expect(transactionEvent.sdk?.packages).toContainEqual(
144-
expect.objectContaining({ name: 'npm:@sentry/aws-serverless' }),
145-
);
146-
});
84+
}
14785
});

0 commit comments

Comments
 (0)