From 7587aa04be39114469b75b4312711bf918b8aa4e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 6 Nov 2026 14:06:06 +0100 Subject: [PATCH] fix(integ-runner): region not passed when deploying tests The current version of the integ-runner does not pass the `CDK_DEFAULT_ACCOUNT` and `CDK_DEFAULT_REGION` environment variables to the app that's being tested if it is being deployed. This means that any feature that relies on the region being available, like lookups, doesn't work. Also tests that rely on `stack.accountId` and `stack.region` being resolved values (like the `ProductStack` tests) fail. Make sure the region gets resolved when we are synthesizing for deployments. --- .../integ-runner/lib/engines/cdk-interface.ts | 13 +++++++++++ .../integ-runner/lib/engines/toolkit-lib.ts | 2 +- .../integ-runner/lib/runner/cdk-test-app.ts | 17 +++++++++----- .../engines/toolkit-lib-snapshot-path.test.ts | 3 +++ .../test/engines/toolkit-lib.test.ts | 22 +++++++++++++++++++ .../@aws-cdk/integ-runner/test/helpers.ts | 4 ++-- 6 files changed, 52 insertions(+), 9 deletions(-) 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; }