Skip to content

Commit 02752d3

Browse files
authored
chore(core): verify stack artifacts are written in topological order (#8515)
Add a test to verify stacks are serialized to the manifest file in a topological order, based on their dependencies. By adding this test we are committing to maintain the topological order of the stacks in the manifest file, allowing users to consume it without needing to sort the stacks. Note that all of the CDK toolkit commands such as `cdk list` and `cdk deploy` already assume this and do not sort stacks upon execution. > see [`cdk list`](https://github.com/aws/aws-cdk/blob/master/packages/aws-cdk/lib/cdk-toolkit.ts#L264) and [`cdk deploy`](https://github.com/aws/aws-cdk/blob/master/packages/aws-cdk/lib/cdk-toolkit.ts#L111) for reference I have initially added the test in `cx-api` module but after more consideration I think it is better suited in the `core` module since we want to verify this behavior in the context of a CDK application. I have left both tests in this PR for the sake of discussion in the event the reviewer thinks this actually fits better in `cx-api`. helps #8436 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 1e6a8e9 commit 02752d3

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

Diff for: packages/@aws-cdk/core/test/test.app.ts

+26
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,32 @@ export = {
325325

326326
test.done();
327327
},
328+
329+
'stacks are written to the assembly file in a topological order'(test: Test) {
330+
// WHEN
331+
const assembly = withApp({}, (app) => {
332+
const stackC = new Stack(app, 'StackC');
333+
const stackD = new Stack(app, 'StackD');
334+
const stackA = new Stack(app, 'StackA');
335+
const stackB = new Stack(app, 'StackB');
336+
337+
// Create the following dependency order:
338+
// A ->
339+
// C -> D
340+
// B ->
341+
stackC.addDependency(stackA);
342+
stackC.addDependency(stackB);
343+
stackD.addDependency(stackC);
344+
});
345+
346+
// THEN
347+
const artifactsIds = assembly.artifacts.map(a => a.id);
348+
test.ok(artifactsIds.indexOf('StackA') < artifactsIds.indexOf('StackC'));
349+
test.ok(artifactsIds.indexOf('StackB') < artifactsIds.indexOf('StackC'));
350+
test.ok(artifactsIds.indexOf('StackC') < artifactsIds.indexOf('StackD'));
351+
352+
test.done();
353+
},
328354
};
329355

330356
class MyConstruct extends Construct {

Diff for: packages/@aws-cdk/cx-api/test/cloud-assembly-builder.test.ts

+58
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,62 @@ test('write and read nested cloud assembly artifact', () => {
166166

167167
const nested = art?.nestedAssembly;
168168
expect(nested?.artifacts.length).toEqual(0);
169+
});
170+
171+
test('artifcats are written in topological order', () => {
172+
// GIVEN
173+
const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'cloud-assembly-builder-tests'));
174+
const session = new cxapi.CloudAssemblyBuilder(outdir);
175+
const templateFile = 'foo.template.json';
176+
177+
const innerAsmDir = path.join(outdir, 'hello');
178+
new cxapi.CloudAssemblyBuilder(innerAsmDir).buildAssembly();
179+
180+
// WHEN
181+
182+
// Create the following dependency order:
183+
// A ->
184+
// C -> D
185+
// B ->
186+
session.addArtifact('artifact-D', {
187+
type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK,
188+
environment: 'aws://1222344/us-east-1',
189+
dependencies: ['artifact-C'],
190+
properties: {
191+
templateFile,
192+
},
193+
});
194+
195+
session.addArtifact('artifact-C', {
196+
type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK,
197+
environment: 'aws://1222344/us-east-1',
198+
dependencies: ['artifact-B', 'artifact-A'],
199+
properties: {
200+
templateFile,
201+
},
202+
});
203+
204+
session.addArtifact('artifact-B', {
205+
type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK,
206+
environment: 'aws://1222344/us-east-1',
207+
properties: {
208+
templateFile,
209+
},
210+
});
211+
212+
session.addArtifact('artifact-A', {
213+
type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK,
214+
environment: 'aws://1222344/us-east-1',
215+
properties: {
216+
templateFile,
217+
},
218+
});
219+
220+
const asm = session.buildAssembly();
221+
const artifactsIds = asm.artifacts.map(a => a.id);
222+
223+
// THEN
224+
expect(artifactsIds.indexOf('artifact-A')).toBeLessThan(artifactsIds.indexOf('artifact-C'));
225+
expect(artifactsIds.indexOf('artifact-B')).toBeLessThan(artifactsIds.indexOf('artifact-C'));
226+
expect(artifactsIds.indexOf('artifact-C')).toBeLessThan(artifactsIds.indexOf('artifact-D'));
169227
});

Diff for: packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ test('assets', () => {
8585
test('can-read-0.36.0', () => {
8686
// WHEN
8787
new CloudAssembly(path.join(FIXTURES, 'single-stack-0.36'));
88-
// THEN: no eexception
88+
// THEN: no exception
8989
expect(true).toBeTruthy();
9090
});
9191

0 commit comments

Comments
 (0)