Skip to content

Commit ea06f7d

Browse files
authored
fix(integ-tests): cannot make two or more identical assertions (#27380)
This PR resolves errors in the integration test library when users run identical assertions multiple times. This change ensures that each use of `awsApiCall`, `httpApiCall`, and `invokeFunction` has a unique identifier, even when multiple identical assertions are used in the same context. We introduced a `uniqueAssertionId` function in the `DeployAssert` construct that maintains backward compatibility with the old id rendering scheme, but prevents the use of conflicting construct ids by tracking the usage of ids and differentiating them where there's a conflict. Closes #22043, #23049 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 5893b3f commit ea06f7d

File tree

10 files changed

+221
-22
lines changed

10 files changed

+221
-22
lines changed

packages/@aws-cdk/integ-tests-alpha/lib/assertions/private/deploy-assert.ts

+22-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export class DeployAssert extends Construct implements IDeployAssert {
5050
}
5151

5252
public scope: Stack;
53+
private assertionIdCounts = new Map<string, number>();
5354

5455
constructor(scope: Construct, props?: DeployAssertProps) {
5556
super(scope, 'Default');
@@ -65,7 +66,7 @@ export class DeployAssert extends Construct implements IDeployAssert {
6566
hash = md5hash(this.scope.resolve(parameters));
6667
} catch {}
6768

68-
return new AwsApiCall(this.scope, `AwsApiCall${service}${api}${hash}`, {
69+
return new AwsApiCall(this.scope, this.uniqueAssertionId(`AwsApiCall${service}${api}${hash}`), {
6970
api,
7071
service,
7172
parameters,
@@ -87,15 +88,15 @@ export class DeployAssert extends Construct implements IDeployAssert {
8788
const parsedUrl = new URL(url);
8889
append = `${parsedUrl.hostname}${parsedUrl.pathname}`;
8990
}
90-
return new HttpApiCall(this.scope, `HttpApiCall${append}${hash}`, {
91+
return new HttpApiCall(this.scope, this.uniqueAssertionId(`HttpApiCall${append}${hash}`), {
9192
url,
9293
fetchOptions: options,
9394
});
9495
}
9596

9697
public invokeFunction(props: LambdaInvokeFunctionProps): IApiCall {
9798
const hash = md5hash(this.scope.resolve(props));
98-
return new LambdaInvokeFunction(this.scope, `LambdaInvoke${hash}`, props);
99+
return new LambdaInvokeFunction(this.scope, this.uniqueAssertionId(`LambdaInvoke${hash}`), props);
99100
}
100101

101102
public expect(id: string, expected: ExpectedResult, actual: ActualResult): void {
@@ -104,4 +105,22 @@ export class DeployAssert extends Construct implements IDeployAssert {
104105
actual,
105106
});
106107
}
108+
109+
/**
110+
* Gets a unique logical id based on a proposed assertion id.
111+
*/
112+
private uniqueAssertionId(id: string): string {
113+
const count = this.assertionIdCounts.get(id);
114+
115+
if (count === undefined) {
116+
// If we've never seen this id before, we'll return the id unchanged
117+
// to maintain backward compatibility.
118+
this.assertionIdCounts.set(id, 1);
119+
return id;
120+
}
121+
122+
// Otherwise, we'll increment the counter and return a unique id.
123+
this.assertionIdCounts.set(id, count + 1);
124+
return `${id}${count}`;
125+
}
107126
}

packages/@aws-cdk/integ-tests-alpha/test/assertions/deploy-assert.test.ts

+45
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ describe('DeployAssert', () => {
5757
},
5858
});
5959
});
60+
61+
test('multiple identical calls can be configured', () => {
62+
// GIVEN
63+
const app = new App();
64+
65+
// WHEN
66+
const deployAssert = new DeployAssert(app);
67+
deployAssert.invokeFunction({ functionName: 'my-func' });
68+
deployAssert.invokeFunction({ functionName: 'my-func' });
69+
70+
// THEN
71+
const template = Template.fromStack(deployAssert.scope);
72+
template.resourceCountIs('AWS::Lambda::Function', 1);
73+
template.resourceCountIs('Custom::DeployAssert@SdkCallLambdainvoke', 2);
74+
});
6075
});
6176

6277
describe('assertions', () => {
@@ -145,6 +160,21 @@ describe('DeployAssert', () => {
145160
template.resourceCountIs('Custom::DeployAssert@SdkCallMyServiceMyApi2', 1);
146161
});
147162

163+
test('multiple identical calls can be configured', () => {
164+
// GIVEN
165+
const app = new App();
166+
167+
// WHEN
168+
const deployAssert = new DeployAssert(app);
169+
deployAssert.awsApiCall('MyService', 'MyApi');
170+
deployAssert.awsApiCall('MyService', 'MyApi');
171+
172+
// THEN
173+
const template = Template.fromStack(deployAssert.scope);
174+
template.resourceCountIs('AWS::Lambda::Function', 1);
175+
template.resourceCountIs('Custom::DeployAssert@SdkCallMyServiceMyApi', 2);
176+
});
177+
148178
test('custom resource type length is truncated when greater than 60 characters', () => {
149179
// GIVEN
150180
const app = new App();
@@ -203,6 +233,21 @@ describe('DeployAssert', () => {
203233
template.resourceCountIs('Custom::DeployAssert@HttpCallexamplecomtest789', 1);
204234
});
205235

236+
test('multiple identical calls can be configured', () => {
237+
// GIVEN
238+
const app = new App();
239+
240+
// WHEN
241+
const deployAssert = new DeployAssert(app);
242+
deployAssert.httpApiCall('https://example.com/test');
243+
deployAssert.httpApiCall('https://example.com/test');
244+
245+
// THEN
246+
const template = Template.fromStack(deployAssert.scope);
247+
template.resourceCountIs('AWS::Lambda::Function', 1);
248+
template.resourceCountIs('Custom::DeployAssert@HttpCallexamplecomtest', 2);
249+
});
250+
206251
test('call with fetch options', () => {
207252
// GIVEN
208253
const app = new App();

packages/@aws-cdk/integ-tests-alpha/test/assertions/providers/integ.assertions.js.snapshot/Assertions.assets.json

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

packages/@aws-cdk/integ-tests-alpha/test/assertions/providers/integ.assertions.js.snapshot/AssertionsTestDefaultTestDeployAssertDC0672BB.assets.json

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

packages/@aws-cdk/integ-tests-alpha/test/assertions/providers/integ.assertions.js.snapshot/AssertionsTestDefaultTestDeployAssertDC0672BB.template.json

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

packages/@aws-cdk/integ-tests-alpha/test/assertions/providers/integ.assertions.js.snapshot/cdk.out

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

packages/@aws-cdk/integ-tests-alpha/test/assertions/providers/integ.assertions.js.snapshot/integ.json

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

packages/@aws-cdk/integ-tests-alpha/test/assertions/providers/integ.assertions.js.snapshot/manifest.json

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

0 commit comments

Comments
 (0)