@@ -3,6 +3,8 @@ import * as path from 'path';
3
3
import * as cxschema from '@aws-cdk/cloud-assembly-schema' ;
4
4
import * as cxapi from '@aws-cdk/cx-api' ;
5
5
import { CloudAssemblyBuilder } from '@aws-cdk/cx-api' ;
6
+ // eslint-disable-next-line import/no-extraneous-dependencies
7
+ import { expect } from '@jest/globals' ;
6
8
import { WorkGraph } from '../lib/util/work-graph' ;
7
9
import { WorkGraphBuilder } from '../lib/util/work-graph-builder' ;
8
10
import { AssetBuildNode , AssetPublishNode , StackNode , WorkNode } from '../lib/util/work-graph-types' ;
@@ -16,6 +18,25 @@ afterEach(() => {
16
18
rootBuilder . delete ( ) ;
17
19
} ) ;
18
20
21
+ function superset < A > ( xs : A [ ] ) : Set < A > {
22
+ const ret = new Set ( xs ) ;
23
+ ( ret as any ) . isSuperset = true ;
24
+ return ret ;
25
+ }
26
+
27
+ expect . addEqualityTesters ( [
28
+ function ( exp : unknown , act : unknown ) : boolean | undefined {
29
+ if ( exp instanceof Set && isIterable ( act ) ) {
30
+ if ( ( exp as any ) . isSuperset ) {
31
+ const actSet = new Set ( act ) ;
32
+ return Array . from ( exp as any ) . every ( ( x ) => actSet . has ( x ) ) ;
33
+ }
34
+ return this . equals ( Array . from ( exp ) . sort ( ) , Array . from ( act ) . sort ( ) ) ;
35
+ }
36
+ return undefined ;
37
+ } ,
38
+ ] ) ;
39
+
19
40
describe ( 'with some stacks and assets' , ( ) => {
20
41
let assembly : cxapi . CloudAssembly ;
21
42
beforeEach ( ( ) => {
@@ -28,34 +49,34 @@ describe('with some stacks and assets', () => {
28
49
29
50
expect ( assertableNode ( graph . node ( 'stack2' ) ) ) . toEqual ( expect . objectContaining ( {
30
51
type : 'stack' ,
31
- dependencies : expect . arrayContaining ( [ 'F1:D1-publish ' ] ) ,
32
- } as StackNode ) ) ;
52
+ dependencies : superset ( [ 'publish-F1-add54bdbcb ' ] ) ,
53
+ } as Partial < StackNode > ) ) ;
33
54
} ) ;
34
55
35
56
test ( 'asset publishing step depends on asset building step' , ( ) => {
36
57
const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
37
58
38
- expect ( graph . node ( 'F1:D1-publish ' ) ) . toEqual ( expect . objectContaining ( {
59
+ expect ( graph . node ( 'publish-F1-add54bdbcb ' ) ) . toEqual ( expect . objectContaining ( {
39
60
type : 'asset-publish' ,
40
- dependencies : new Set ( [ 'F1-build ' ] ) ,
41
- } as Partial < AssetPublishNode > ) ) ;
61
+ dependencies : superset ( [ 'build- F1-a533139934 ' ] ) ,
62
+ } satisfies Partial < AssetPublishNode > ) ) ;
42
63
} ) ;
43
64
44
65
test ( 'with prebuild off, asset building inherits dependencies from their parent stack' , ( ) => {
45
66
const graph = new WorkGraphBuilder ( false ) . build ( assembly . artifacts ) ;
46
67
47
- expect ( graph . node ( 'F1-build ' ) ) . toEqual ( expect . objectContaining ( {
68
+ expect ( graph . node ( 'build- F1-a533139934 ' ) ) . toEqual ( expect . objectContaining ( {
48
69
type : 'asset-build' ,
49
- dependencies : new Set ( [ 'stack0' , 'stack1' ] ) ,
70
+ dependencies : superset ( [ 'stack0' , 'stack1' ] ) ,
50
71
} as Partial < AssetBuildNode > ) ) ;
51
72
} ) ;
52
73
53
74
test ( 'with prebuild on, assets only have their own dependencies' , ( ) => {
54
75
const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
55
76
56
- expect ( graph . node ( 'F1-build ' ) ) . toEqual ( expect . objectContaining ( {
77
+ expect ( graph . node ( 'build- F1-a533139934 ' ) ) . toEqual ( expect . objectContaining ( {
57
78
type : 'asset-build' ,
58
- dependencies : new Set ( [ 'stack0' ] ) ,
79
+ dependencies : superset ( [ 'stack0' ] ) ,
59
80
} as Partial < AssetBuildNode > ) ) ;
60
81
} ) ;
61
82
} ) ;
@@ -84,13 +105,16 @@ test('can handle nested assemblies', async () => {
84
105
85
106
let workDone = 0 ;
86
107
const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
108
+
87
109
await graph . doParallel ( 10 , {
88
110
deployStack : async ( ) => { workDone += 1 ; } ,
89
111
buildAsset : async ( ) => { } ,
90
112
publishAsset : async ( ) => { workDone += 1 ; } ,
91
113
} ) ;
92
114
93
- expect ( workDone ) . toEqual ( 8 ) ;
115
+ // The asset is shared between parent assembly and nested assembly, but the stacks will be deployed
116
+ // 3 stacks + 1 asset + 3 stacks (1 reused asset)
117
+ expect ( workDone ) . toEqual ( 7 ) ;
94
118
} ) ;
95
119
96
120
test ( 'dependencies on unselected artifacts are silently ignored' , async ( ) => {
@@ -143,8 +167,8 @@ describe('tests that use assets', () => {
143
167
const traversal = await traverseAndRecord ( graph ) ;
144
168
145
169
expect ( traversal ) . toEqual ( [
146
- ' work-graph-builder.test.js-build' ,
147
- ' work-graph-builder.test.js:D1-publish' ,
170
+ expect . stringMatching ( / ^ b u i l d - w o r k - g r a p h - b u i l d e r .t e s t .j s - . * $ / ) ,
171
+ expect . stringMatching ( / ^ p u b l i s h - w o r k - g r a p h - b u i l d e r .t e s t .j s - . * $ / ) ,
148
172
'StackA' ,
149
173
'StackB' ,
150
174
] ) ;
@@ -205,11 +229,56 @@ describe('tests that use assets', () => {
205
229
const traversal = await traverseAndRecord ( graph ) ;
206
230
207
231
expect ( traversal ) . toEqual ( [
208
- 'abcdef-build' ,
209
- 'abcdef:D1-publish' ,
210
- 'abcdef:D2-publish' ,
232
+ expect . stringMatching ( / ^ b u i l d - a b c d e f - .* $ / ) ,
233
+ expect . stringMatching ( / ^ p u b l i s h - a b c d e f - .* $ / ) ,
234
+ expect . stringMatching ( / ^ p u b l i s h - a b c d e f - .* $ / ) ,
235
+ 'StackA' ,
236
+ expect . stringMatching ( / ^ p u b l i s h - a b c d e f - .* $ / ) ,
237
+ 'StackB' ,
238
+ ] ) ;
239
+ } ) ;
240
+
241
+ test ( 'different parameters for the same named definition are both published' , async ( ) => {
242
+ addStack ( rootBuilder , 'StackA' , {
243
+ environment : 'aws://11111/us-east-1' ,
244
+ dependencies : [ 'StackA.assets' ] ,
245
+ } ) ;
246
+ addAssets ( rootBuilder , 'StackA.assets' , {
247
+ files : {
248
+ abcdef : {
249
+ source : { path : __dirname } ,
250
+ destinations : {
251
+ D : { bucketName : 'bucket1' , objectKey : 'key' } ,
252
+ } ,
253
+ } ,
254
+ } ,
255
+ } ) ;
256
+
257
+ addStack ( rootBuilder , 'StackB' , {
258
+ environment : 'aws://11111/us-east-1' ,
259
+ dependencies : [ 'StackB.assets' , 'StackA' ] ,
260
+ } ) ;
261
+ addAssets ( rootBuilder , 'StackB.assets' , {
262
+ files : {
263
+ abcdef : {
264
+ source : { path : __dirname } ,
265
+ destinations : {
266
+ D : { bucketName : 'bucket2' , objectKey : 'key' } ,
267
+ } ,
268
+ } ,
269
+ } ,
270
+ } ) ;
271
+
272
+ const assembly = rootBuilder . buildAssembly ( ) ;
273
+
274
+ const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
275
+ const traversal = await traverseAndRecord ( graph ) ;
276
+
277
+ expect ( traversal ) . toEqual ( [
278
+ expect . stringMatching ( / ^ b u i l d - a b c d e f - .* $ / ) ,
279
+ expect . stringMatching ( / ^ p u b l i s h - a b c d e f - .* $ / ) ,
211
280
'StackA' ,
212
- ' abcdef:D3-publish' ,
281
+ expect . stringMatching ( / ^ p u b l i s h - a b c d e f - . * $ / ) ,
213
282
'StackB' ,
214
283
] ) ;
215
284
} ) ;
@@ -302,4 +371,8 @@ async function traverseAndRecord(graph: WorkGraph) {
302
371
publishAsset : async ( node ) => { ret . push ( node . id ) ; } ,
303
372
} ) ;
304
373
return ret ;
374
+ }
375
+
376
+ function isIterable ( x : unknown ) : x is Iterable < any > {
377
+ return x && typeof x === 'object' && ( x as any ) [ Symbol . iterator ] ;
305
378
}
0 commit comments