diff --git a/packages/@aws-cdk/integ-runner/lib/engines/cdk-interface.ts b/packages/@aws-cdk/integ-runner/lib/engines/cdk-interface.ts index 6036b0dd7..15fee47bc 100644 --- a/packages/@aws-cdk/integ-runner/lib/engines/cdk-interface.ts +++ b/packages/@aws-cdk/integ-runner/lib/engines/cdk-interface.ts @@ -10,10 +10,23 @@ export type WatchEvents = { onClose?: (code: number | null) => void; }; +/** + * Synthesis purpose + * + * - 'snapshot' indicates that the synthesis is for creating a snapshot of the stack. + * - 'deployment' indicates that the synthesis is for an actual deployment. + */ +export type SynthesisPurpose = 'snapshot' | 'deployment'; + /** * Options to use with cdk synth */ export interface SynthOptions { + /** + * What the goal of this synthesis is. + */ + readonly purpose: SynthesisPurpose; + /** * The command to use to execute the app. * This is typically the same thing that normally diff --git a/packages/@aws-cdk/integ-runner/lib/engines/toolkit-lib.ts b/packages/@aws-cdk/integ-runner/lib/engines/toolkit-lib.ts index 81b42f970..965482018 100644 --- a/packages/@aws-cdk/integ-runner/lib/engines/toolkit-lib.ts +++ b/packages/@aws-cdk/integ-runner/lib/engines/toolkit-lib.ts @@ -154,7 +154,7 @@ export class ToolkitLibRunnerEngine implements ICdk { output: options.output, context: options.context, lookups: false, - resolveDefaultEnvironment: false, + resolveDefaultEnvironment: options.purpose === 'deployment', env: options.env, versionReporting: false, pathMetadata: false, diff --git a/packages/@aws-cdk/integ-runner/lib/runner/cdk-test-app.ts b/packages/@aws-cdk/integ-runner/lib/runner/cdk-test-app.ts index 4c2801398..7bab3e48e 100644 --- a/packages/@aws-cdk/integ-runner/lib/runner/cdk-test-app.ts +++ b/packages/@aws-cdk/integ-runner/lib/runner/cdk-test-app.ts @@ -4,7 +4,7 @@ import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, UNKNOWN_REGION } from '@aws-cdk import { type TestCase, type DefaultCdkOptions, RequireApproval } from '@aws-cdk/cloud-assembly-schema'; import * as fs from 'fs-extra'; import { IntegTestSuite, LegacyIntegTestSuite } from './integ-test-suite'; -import type { DeployOptions, DestroyOptions, ICdk, WatchEvents } from '../engines/cdk-interface'; +import type { DeployOptions, DestroyOptions, ICdk, SynthesisPurpose, WatchEvents } from '../engines/cdk-interface'; import * as logger from '../logger'; import * as recommendedFlagsFile from '../recommended-feature-flags.json'; import { flatten } from '../utils'; @@ -269,7 +269,7 @@ export class CdkTestApp { public async synthForSnapshotComparison(enableLookupsGuess: LegacyEnableLookups) { this.configureLegacyEnableLookups(enableLookupsGuess); - const suite = await this.synth(this.getContext('snapshot'), DEFAULT_SYNTH_OPTIONS.env); + const suite = await this.synth('snapshot', this.getContext('snapshot'), DEFAULT_SYNTH_OPTIONS.env); // Check if the enableLookups value has changed between the golden // snapshot and the actual snapshot. If it has, we need to re-synth the @@ -279,21 +279,21 @@ export class CdkTestApp { const actualEnableLookups = suite.enableLookups ?? false; if (actualEnableLookups !== this._legacyEnableLookups && this._legacyEnableLookups !== 'dont-care') { this.configureLegacyEnableLookups(actualEnableLookups); - return this.synth(this.getContext('snapshot'), DEFAULT_SYNTH_OPTIONS.env); + return this.synth('snapshot', this.getContext('snapshot'), DEFAULT_SYNTH_OPTIONS.env); } return suite; } public async synthForGoldenSnapshot(destructiveChanges: DestructiveChange[], enableLookups: LegacyEnableLookups) { this.configureLegacyEnableLookups(enableLookups); - await this.synth(this.getContext('snapshot'), DEFAULT_SYNTH_OPTIONS.env); + await this.synth('snapshot', this.getContext('snapshot'), DEFAULT_SYNTH_OPTIONS.env); await this.cleanupGoldenSnapshot(destructiveChanges); return this.testSuite; } public async synthForDeployment() { this.configureLegacyEnableLookups('dont-care'); - await this.synth(this.getContext('deployment'), {}); + await this.synth('deployment', this.getContext('deployment'), {}); return this.testSuite; } @@ -351,7 +351,11 @@ export class CdkTestApp { * determine whether to pass the context, and if the new actual snapshot has a * different value for `enableLookups`, we will throw away the old snapshot and synth again. */ - private async synth(context: Record, env: Record): Promise { + private async synth( + purpose: SynthesisPurpose, + context: Record, + env: Record, + ): Promise { const output = this.outputDirectory; // Remove the target directory, so that we don't have stale files from @@ -362,6 +366,7 @@ export class CdkTestApp { } await this.cdk.synth({ + purpose, app: this.appCommand, context, env, diff --git a/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib-snapshot-path.test.ts b/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib-snapshot-path.test.ts index 4db87d072..f45859adf 100644 --- a/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib-snapshot-path.test.ts +++ b/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib-snapshot-path.test.ts @@ -43,6 +43,7 @@ describe('ToolkitLibRunnerEngine - Snapshot Path Handling', () => { mockToolkit.synth.mockResolvedValue(mockLock as any); await engine.synth({ + purpose: 'snapshot', app: snapshotPath, }); @@ -64,6 +65,7 @@ describe('ToolkitLibRunnerEngine - Snapshot Path Handling', () => { mockToolkit.synth.mockResolvedValue(mockLock as any); await engine.synth({ + purpose: 'snapshot', app: appCommand, }); @@ -85,6 +87,7 @@ describe('ToolkitLibRunnerEngine - Snapshot Path Handling', () => { mockToolkit.synth.mockResolvedValue(mockLock as any); await engine.synth({ + purpose: 'snapshot', app: appPath, }); diff --git a/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib.test.ts b/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib.test.ts index dce773bb1..0206a4f93 100644 --- a/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib.test.ts +++ b/packages/@aws-cdk/integ-runner/test/engines/toolkit-lib.test.ts @@ -47,6 +47,7 @@ describe('ToolkitLibRunnerEngine', () => { mockToolkit.synth.mockImplementation((cx) => cx.produce() as any); await engine.synth({ + purpose: 'snapshot', app: 'cdk synth', output: 'cdk.out', context: { key: 'value' }, @@ -69,6 +70,26 @@ describe('ToolkitLibRunnerEngine', () => { expect(mockLock[Symbol.asyncDispose]).toHaveBeenCalled(); }); + it('purpose: deployment should lead to resolving default environment', async () => { + const mockCx = { produce: jest.fn() }; + const mockLock = { [Symbol.asyncDispose]: jest.fn(), cloudAssembly: { stacksRecursively: [] } }; + mockCx.produce.mockResolvedValue(mockLock); + mockToolkit.fromCdkApp.mockResolvedValue(mockCx as any); + mockToolkit.synth.mockImplementation((cx) => cx.produce() as any); + + await engine.synth({ + purpose: 'deployment', + app: 'cdk synth', + output: 'cdk.out', + context: { key: 'value' }, + env: { TEST: 'true' }, + }); + + expect(mockToolkit.fromCdkApp).toHaveBeenCalledWith('cdk synth', expect.objectContaining({ + resolveDefaultEnvironment: true, + })); + }); + it('should handle missing context error silently', async () => { const mockCx = { produce: jest.fn() }; mockCx.produce.mockRejectedValue(new Error('Missing context keys')); @@ -76,6 +97,7 @@ describe('ToolkitLibRunnerEngine', () => { mockToolkit.synth.mockImplementation((cx) => cx.produce() as any); await expect(engine.synth({ + purpose: 'snapshot', app: 'cdk synth', })).resolves.toBeUndefined(); }); diff --git a/packages/@aws-cdk/integ-runner/test/helpers.ts b/packages/@aws-cdk/integ-runner/test/helpers.ts index 452db0a29..fa166979e 100644 --- a/packages/@aws-cdk/integ-runner/test/helpers.ts +++ b/packages/@aws-cdk/integ-runner/test/helpers.ts @@ -112,7 +112,7 @@ export class MockCdkProvider { } // THEN - expect(this.mocks.synth).toHaveBeenCalledWith({ + expect(this.mocks.synth).toHaveBeenCalledWith(expect.objectContaining({ env: expect.objectContaining({ CDK_INTEG_ACCOUNT: '12345678', CDK_INTEG_REGION: 'test-region', @@ -120,7 +120,7 @@ export class MockCdkProvider { context: expect.any(Object), app: 'node test/test-data/' + integTestFile, output: expect.any(String), - }); + })); return results; }