@@ -2,7 +2,7 @@ import * as path from 'path';
2
2
import { Writable , WritableOptions } from 'stream' ;
3
3
import { StringDecoder , NodeStringDecoder } from 'string_decoder' ;
4
4
import { diffTemplate , formatDifferences , ResourceDifference , ResourceImpact } from '@aws-cdk/cloudformation-diff' ;
5
- import { Diagnostic , DiagnosticReason , DestructiveChange } from '../workers/common' ;
5
+ import { Diagnostic , DiagnosticReason , DestructiveChange , SnapshotVerificationOptions } from '../workers/common' ;
6
6
import { canonicalizeTemplate } from './private/canonicalize-assets' ;
7
7
import { AssemblyManifestReader } from './private/cloud-assembly' ;
8
8
import { IntegRunnerOptions , IntegRunner , DEFAULT_SYNTH_OPTIONS } from './runner-base' ;
@@ -22,7 +22,8 @@ export class IntegSnapshotRunner extends IntegRunner {
22
22
*
23
23
* @returns any diagnostics and any destructive changes
24
24
*/
25
- public testSnapshot ( ) : { diagnostics : Diagnostic [ ] , destructiveChanges : DestructiveChange [ ] } {
25
+ public testSnapshot ( options : SnapshotVerificationOptions = { } ) : { diagnostics : Diagnostic [ ] , destructiveChanges : DestructiveChange [ ] } {
26
+ let doClean = true ;
26
27
try {
27
28
// read the existing snapshot
28
29
const expectedStacks = this . readAssembly ( this . snapshotDir ) ;
@@ -39,17 +40,19 @@ export class IntegSnapshotRunner extends IntegRunner {
39
40
// the cdkOutDir exists already, but for some reason generateActualSnapshot
40
41
// generates an incorrect snapshot and I have no idea why so synth again here
41
42
// to produce the "correct" snapshot
43
+ const env = {
44
+ ...DEFAULT_SYNTH_OPTIONS . env ,
45
+ CDK_CONTEXT_JSON : JSON . stringify ( this . getContext ( ) ) ,
46
+ } ;
42
47
this . cdk . synthFast ( {
43
48
execCmd : this . cdkApp . split ( ' ' ) ,
44
- env : {
45
- ...DEFAULT_SYNTH_OPTIONS . env ,
46
- CDK_CONTEXT_JSON : JSON . stringify ( this . getContext ( ) ) ,
47
- } ,
49
+ env,
48
50
output : this . cdkOutDir ,
49
51
} ) ;
50
52
51
53
// read the "actual" snapshot
52
- const actualStacks = this . readAssembly ( path . join ( this . directory , this . cdkOutDir ) ) ;
54
+ const actualDir = path . join ( this . directory , this . cdkOutDir ) ;
55
+ const actualStacks = this . readAssembly ( actualDir ) ;
53
56
// only diff stacks that are part of the test case
54
57
const actualStacksToDiff : Record < string , any > = { } ;
55
58
for ( const [ stackName , template ] of Object . entries ( actualStacks ) ) {
@@ -60,11 +63,45 @@ export class IntegSnapshotRunner extends IntegRunner {
60
63
61
64
// diff the existing snapshot (expected) with the integration test (actual)
62
65
const diagnostics = this . diffAssembly ( expectedStacksToDiff , actualStacksToDiff ) ;
66
+
67
+ if ( diagnostics . diagnostics . length ) {
68
+ // Attach additional messages to the first diagnostic
69
+ const additionalMessages : string [ ] = [ ] ;
70
+
71
+ if ( options . retain ) {
72
+ additionalMessages . push (
73
+ `(Failure retained) Expected: ${ path . relative ( process . cwd ( ) , this . snapshotDir ) } ` ,
74
+ ` Actual: ${ path . relative ( process . cwd ( ) , actualDir ) } ` ,
75
+ ) ,
76
+ doClean = false ;
77
+ }
78
+
79
+ if ( options . verbose ) {
80
+ // Show the command necessary to repro this
81
+ const envSet = Object . entries ( env )
82
+ . filter ( ( [ k , _ ] ) => k !== 'CDK_CONTEXT_JSON' )
83
+ . map ( ( [ k , v ] ) => `${ k } ='${ v } '` ) ;
84
+ const envCmd = envSet . length > 0 ? [ 'env' , ...envSet ] : [ ] ;
85
+
86
+ additionalMessages . push (
87
+ 'Repro:' ,
88
+ ` ${ [ ...envCmd , 'cdk synth' , `-a '${ this . cdkApp } '` , `-o '${ this . cdkOutDir } '` , ...Object . entries ( this . getContext ( ) ) . flatMap ( ( [ k , v ] ) => typeof v !== 'object' ? [ `-c '${ k } =${ v } '` ] : [ ] ) ] . join ( ' ' ) } ` ,
89
+ ) ;
90
+ }
91
+
92
+ diagnostics . diagnostics [ 0 ] = {
93
+ ...diagnostics . diagnostics [ 0 ] ,
94
+ additionalMessages,
95
+ } ;
96
+ }
97
+
63
98
return diagnostics ;
64
99
} catch ( e ) {
65
100
throw e ;
66
101
} finally {
67
- this . cleanup ( ) ;
102
+ if ( doClean ) {
103
+ this . cleanup ( ) ;
104
+ }
68
105
}
69
106
}
70
107
0 commit comments