Skip to content

Commit f3916d1

Browse files
authored
chore(tests): address integration test flakiness (#1669)
* chore: traces retrieval * chore: secure string uniqueness * chore: update e2e command * chore: update test names * chore: remove layer flag * chore: remove layer flag * chore: remove STS client from devDeps tracer * chore: restore retryOptions
1 parent e442c3d commit f3916d1

15 files changed

+191
-328
lines changed

Diff for: .github/workflows/run-e2e-tests.yml

+8-50
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
contents: read
2020
strategy:
2121
matrix:
22-
package: [logger, metrics, tracer, parameters, idempotency]
22+
package: [layers, packages/logger, packages/metrics, packages/tracer, packages/parameters, packages/idempotency]
2323
version: [14, 16, 18]
2424
fail-fast: false
2525
steps:
@@ -55,56 +55,14 @@ jobs:
5555
role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }}
5656
aws-region: eu-west-1
5757
mask-aws-account-id: true
58-
- name: Run integration tests on utils
59-
run: |
60-
RUNTIME=nodejs${{ matrix.version }}x npm run test:e2e -w packages/${{ matrix.package }}
61-
layer-e2e-tests:
62-
runs-on: ubuntu-latest
63-
env:
64-
NODE_ENV: dev
65-
PR_NUMBER: ${{ inputs.prNumber }}
66-
permissions:
67-
id-token: write # needed to interact with GitHub's OIDC Token endpoint.
68-
contents: read
69-
strategy:
70-
fail-fast: false
71-
matrix:
72-
version: [14, 16, 18]
73-
steps:
74-
- name: Checkout Repo
75-
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
76-
# If we pass a PR Number when triggering the workflow we will retrieve the PR info and get its headSHA
77-
- name: Extract PR details
78-
id: extract_PR_details
79-
if: ${{ inputs.prNumber != '' }}
80-
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
81-
with:
82-
script: |
83-
const script = require('.github/scripts/get_pr_info.js');
84-
await script({github, context, core});
85-
# Only if a PR Number was passed and the headSHA of the PR extracted,
86-
# we checkout the PR at that point in time
87-
- name: Checkout PR code
88-
if: ${{ inputs.prNumber != '' }}
89-
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
90-
with:
91-
ref: ${{ steps.extract_PR_details.outputs.headSHA }}
92-
- name: Setup NodeJS
93-
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
94-
with:
95-
# Always use version 18
96-
node-version: 18
97-
- name: Setup dependencies
98-
uses: ./.github/actions/cached-node-modules
99-
- name: "Configure AWS credentials"
100-
uses: aws-actions/configure-aws-credentials@04b98b3f9e85f563fb061be8751a0352327246b0 # v3.0.1
101-
with:
102-
role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }}
103-
aws-region: eu-west-1
104-
mask-aws-account-id: true
10558
- name: Create layer files
59+
if: ${{ matrix.package == 'layers' }}
10660
run: |
10761
export VERSION=latest
10862
bash .github/scripts/setup_tmp_layer_files.sh
109-
- name: Run integration test on layers
110-
run: RUNTIME=nodejs${{ matrix.version }}x npm run test:e2e -w layers
63+
- name: Run integration tests on utils
64+
env:
65+
RUNTIME: nodejs${{ matrix.version }}x
66+
CI: true
67+
JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: true
68+
run: npm run test:e2e -w ${{ matrix.package }}

Diff for: layers/src/layer-publisher-stack.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export interface LayerPublisherStackProps extends StackProps {
1313
readonly layerName?: string;
1414
readonly powertoolsPackageVersion?: string;
1515
readonly ssmParameterLayerArn: string;
16-
readonly removeLayerVersion?: boolean;
1716
}
1817

1918
export class LayerPublisherStack extends Stack {
@@ -25,7 +24,7 @@ export class LayerPublisherStack extends Stack {
2524
) {
2625
super(scope, id, props);
2726

28-
const { layerName, powertoolsPackageVersion, removeLayerVersion } = props;
27+
const { layerName, powertoolsPackageVersion } = props;
2928

3029
console.log(
3130
`publishing layer ${layerName} version : ${powertoolsPackageVersion}`
@@ -43,10 +42,6 @@ export class LayerPublisherStack extends Stack {
4342
// This is needed because the following regions do not support the compatibleArchitectures property #1400
4443
// ...(![ 'eu-south-2', 'eu-central-2', 'ap-southeast-4' ].includes(Stack.of(this).region) ? { compatibleArchitectures: [Architecture.X86_64] } : {}),
4544
code: Code.fromAsset(resolve(__dirname, '..', '..', 'tmp')),
46-
removalPolicy:
47-
removeLayerVersion === true
48-
? RemovalPolicy.DESTROY
49-
: RemovalPolicy.RETAIN,
5045
});
5146

5247
const layerPermission = new CfnLayerVersionPermission(

Diff for: layers/tests/e2e/layerPublisher.test.ts

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ describe(`Layers E2E tests, publisher stack`, () => {
6161
layerName: layerId,
6262
powertoolsPackageVersion: powerToolsPackageVersion,
6363
ssmParameterLayerArn: ssmParameterLayerName,
64-
removeLayerVersion: true,
6564
});
6665
const testLayerStack = new TestStack({
6766
stackNameProps: {

Diff for: package-lock.json

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: packages/logger/tests/e2e/basicFeatures.middy.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe(`Logger E2E tests, basic functionalities middy usage`, () => {
2525
const testStack = new TestStack({
2626
stackNameProps: {
2727
stackNamePrefix: RESOURCE_NAME_PREFIX,
28-
testName: 'AllFeatures-Decorator',
28+
testName: 'Basic-Middy',
2929
},
3030
});
3131

Diff for: packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ describe(`Parameters E2E tests, dynamoDB provider`, () => {
9999
const testStack = new TestStack({
100100
stackNameProps: {
101101
stackNamePrefix: RESOURCE_NAME_PREFIX,
102-
testName: 'DynamoDBProvider',
102+
testName: 'DynamoDB',
103103
},
104104
});
105105

Diff for: packages/parameters/tests/e2e/secretsProvider.class.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe(`Parameters E2E tests, Secrets Manager provider`, () => {
4040
const testStack = new TestStack({
4141
stackNameProps: {
4242
stackNamePrefix: RESOURCE_NAME_PREFIX,
43-
testName: 'SecretsProvider',
43+
testName: 'Secrets',
4444
},
4545
});
4646

Diff for: packages/parameters/tests/e2e/ssmProvider.class.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ describe(`Parameters E2E tests, SSM provider`, () => {
7474
const testStack = new TestStack({
7575
stackNameProps: {
7676
stackNamePrefix: RESOURCE_NAME_PREFIX,
77-
testName: 'AppConfig',
77+
testName: 'SSM',
7878
},
7979
});
8080

Diff for: packages/parameters/tests/helpers/resources.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
} from '@aws-lambda-powertools/testing-utils';
66
import {
77
concatenateResourceName,
8+
getRuntimeKey,
89
TestDynamodbTable,
910
TestNodejsFunction,
1011
} from '@aws-lambda-powertools/testing-utils';
@@ -57,7 +58,7 @@ class TestSecureStringParameter extends Construct {
5758

5859
const { value } = props;
5960

60-
const name = `/secure/${randomUUID()}`;
61+
const name = `/secure/${getRuntimeKey()}/${randomUUID()}`;
6162

6263
const secureStringCreator = new AwsCustomResource(
6364
testStack.stack,
@@ -202,6 +203,7 @@ class TestDynamodbTableWithItems extends TestDynamodbTable {
202203
policy: AwsCustomResourcePolicy.fromSdkCalls({
203204
resources: [this.tableArn],
204205
}),
206+
installLatestAwsSdk: false,
205207
});
206208
}
207209
}

Diff for: packages/tracer/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"devDependencies": {
3535
"@aws-lambda-powertools/testing-utils": "file:../testing",
3636
"@aws-sdk/client-dynamodb": "^3.360.0",
37-
"@aws-sdk/client-sts": "^3.360.0",
3837
"@aws-sdk/client-xray": "^3.360.0",
3938
"@types/promise-retry": "^1.1.3",
4039
"aws-sdk": "^2.1354.0",

Diff for: packages/tracer/tests/e2e/allFeatures.decorator.test.ts

+46-73
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
TestStack,
88
TestDynamodbTable,
99
} from '@aws-lambda-powertools/testing-utils';
10-
import { XRayClient } from '@aws-sdk/client-xray';
1110
import { join } from 'node:path';
1211
import { TracerTestNodejsFunction } from '../helpers/resources';
1312
import {
@@ -16,7 +15,6 @@ import {
1615
} from '../helpers/traceAssertions';
1716
import {
1817
getFirstSubsegment,
19-
getFunctionArn,
2018
getInvocationSubsegment,
2119
getTraces,
2220
invokeAllTestCases,
@@ -141,7 +139,6 @@ describe(`Tracer E2E tests, all features with decorator instantiation`, () => {
141139
);
142140
testTable.grantWriteData(fnCaptureResponseOff);
143141

144-
const xrayClient = new XRayClient({});
145142
const invocationCount = 3;
146143

147144
beforeAll(async () => {
@@ -178,28 +175,23 @@ describe(`Tracer E2E tests, all features with decorator instantiation`, () => {
178175
const { EXPECTED_CUSTOM_ERROR_MESSAGE: expectedCustomErrorMessage } =
179176
commonEnvironmentVars;
180177

181-
const tracesWhenAllFlagsEnabled = await getTraces(
182-
xrayClient,
178+
/**
179+
* The trace should have 4 segments:
180+
* 1. Lambda Context (AWS::Lambda)
181+
* 2. Lambda Function (AWS::Lambda::Function)
182+
* 4. DynamoDB (AWS::DynamoDB)
183+
* 4. Remote call (docs.powertools.aws.dev)
184+
*/
185+
const tracesWhenAllFlagsEnabled = await getTraces({
183186
startTime,
184-
await getFunctionArn(fnNameAllFlagsEnabled),
185-
invocationCount,
186-
4
187-
);
188-
189-
expect(tracesWhenAllFlagsEnabled.length).toBe(invocationCount);
187+
resourceName: fnNameAllFlagsEnabled,
188+
expectedTracesCount: invocationCount,
189+
expectedSegmentsCount: 4,
190+
});
190191

191192
// Assess
192193
for (let i = 0; i < invocationCount; i++) {
193194
const trace = tracesWhenAllFlagsEnabled[i];
194-
195-
/**
196-
* Expect the trace to have 4 segments:
197-
* 1. Lambda Context (AWS::Lambda)
198-
* 2. Lambda Function (AWS::Lambda::Function)
199-
* 4. DynamoDB (AWS::DynamoDB)
200-
* 4. Remote call (docs.powertools.aws.dev)
201-
*/
202-
expect(trace.Segments.length).toBe(4);
203195
const invocationSubsegment = getInvocationSubsegment(trace);
204196

205197
/**
@@ -246,13 +238,12 @@ describe(`Tracer E2E tests, all features with decorator instantiation`, () => {
246238
EXPECTED_CUSTOM_RESPONSE_VALUE: expectedCustomResponseValue,
247239
} = commonEnvironmentVars;
248240

249-
const tracesWhenAllFlagsEnabled = await getTraces(
250-
xrayClient,
241+
const tracesWhenAllFlagsEnabled = await getTraces({
251242
startTime,
252-
await getFunctionArn(fnNameAllFlagsEnabled),
253-
invocationCount,
254-
4
255-
);
243+
resourceName: fnNameAllFlagsEnabled,
244+
expectedTracesCount: invocationCount,
245+
expectedSegmentsCount: 4,
246+
});
256247

257248
for (let i = 0; i < invocationCount; i++) {
258249
const trace = tracesWhenAllFlagsEnabled[i];
@@ -291,30 +282,24 @@ describe(`Tracer E2E tests, all features with decorator instantiation`, () => {
291282
it(
292283
'should not capture error nor response when the flags are false',
293284
async () => {
294-
const tracesWithNoCaptureErrorOrResponse = await getTraces(
295-
xrayClient,
285+
/**
286+
* Expect the trace to have 4 segments:
287+
* 1. Lambda Context (AWS::Lambda)
288+
* 2. Lambda Function (AWS::Lambda::Function)
289+
* 3. DynamoDB (AWS::DynamoDB)
290+
* 4. Remote call (docs.powertools.aws.dev)
291+
*/
292+
const tracesWithNoCaptureErrorOrResponse = await getTraces({
296293
startTime,
297-
await getFunctionArn(fnNameNoCaptureErrorOrResponse),
298-
invocationCount,
299-
4
300-
);
301-
302-
expect(tracesWithNoCaptureErrorOrResponse.length).toBe(invocationCount);
294+
resourceName: fnNameNoCaptureErrorOrResponse,
295+
expectedTracesCount: invocationCount,
296+
expectedSegmentsCount: 4,
297+
});
303298

304299
// Assess
305300
for (let i = 0; i < invocationCount; i++) {
306301
const trace = tracesWithNoCaptureErrorOrResponse[i];
307-
308-
/**
309-
* Expect the trace to have 4 segments:
310-
* 1. Lambda Context (AWS::Lambda)
311-
* 2. Lambda Function (AWS::Lambda::Function)
312-
* 3. DynamoDB (AWS::DynamoDB)
313-
* 4. Remote call (docs.powertools.aws.dev)
314-
*/
315-
expect(trace.Segments.length).toBe(4);
316302
const invocationSubsegment = getInvocationSubsegment(trace);
317-
318303
/**
319304
* Invocation subsegment should have a subsegment '## index.handler' (default behavior for Tracer)
320305
* '## index.handler' subsegment should have 3 subsegments
@@ -358,30 +343,24 @@ describe(`Tracer E2E tests, all features with decorator instantiation`, () => {
358343
const { EXPECTED_CUSTOM_ERROR_MESSAGE: expectedCustomErrorMessage } =
359344
commonEnvironmentVars;
360345

361-
const tracesWithCaptureResponseFalse = await getTraces(
362-
xrayClient,
346+
/**
347+
* Expect the trace to have 4 segments:
348+
* 1. Lambda Context (AWS::Lambda)
349+
* 2. Lambda Function (AWS::Lambda::Function)
350+
* 3. DynamoDB (AWS::DynamoDB)
351+
* 4. Remote call (docs.powertools.aws.dev)
352+
*/
353+
const tracesWithCaptureResponseFalse = await getTraces({
363354
startTime,
364-
await getFunctionArn(fnNameCaptureResponseOff),
365-
invocationCount,
366-
4
367-
);
368-
369-
expect(tracesWithCaptureResponseFalse.length).toBe(invocationCount);
355+
resourceName: fnNameCaptureResponseOff,
356+
expectedTracesCount: invocationCount,
357+
expectedSegmentsCount: 4,
358+
});
370359

371360
// Assess
372361
for (let i = 0; i < invocationCount; i++) {
373362
const trace = tracesWithCaptureResponseFalse[i];
374-
375-
/**
376-
* Expect the trace to have 4 segments:
377-
* 1. Lambda Context (AWS::Lambda)
378-
* 2. Lambda Function (AWS::Lambda::Function)
379-
* 3. DynamoDB (AWS::DynamoDB)
380-
* 4. Remote call (docs.powertools.aws.dev)
381-
*/
382-
expect(trace.Segments.length).toBe(4);
383363
const invocationSubsegment = getInvocationSubsegment(trace);
384-
385364
/**
386365
* Invocation subsegment should have a subsegment '## index.handler' (default behavior for Tracer)
387366
* '## index.handler' subsegment should have 3 subsegments
@@ -428,22 +407,16 @@ describe(`Tracer E2E tests, all features with decorator instantiation`, () => {
428407
it(
429408
'should not capture any custom traces when disabled',
430409
async () => {
431-
const expectedNoOfTraces = 2;
432-
const tracesWithTracerDisabled = await getTraces(
433-
xrayClient,
410+
const tracesWithTracerDisabled = await getTraces({
434411
startTime,
435-
await getFunctionArn(fnNameTracerDisabled),
436-
invocationCount,
437-
expectedNoOfTraces
438-
);
439-
440-
expect(tracesWithTracerDisabled.length).toBe(invocationCount);
412+
resourceName: fnNameTracerDisabled,
413+
expectedTracesCount: invocationCount,
414+
expectedSegmentsCount: 2,
415+
});
441416

442417
// Assess
443418
for (let i = 0; i < invocationCount; i++) {
444419
const trace = tracesWithTracerDisabled[i];
445-
expect(trace.Segments.length).toBe(2);
446-
447420
/**
448421
* Expect no subsegment in the invocation
449422
*/

0 commit comments

Comments
 (0)