From 110d2310374fde28bf43272e425196fd85347679 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 19 Nov 2024 12:33:40 +0100 Subject: [PATCH] chore: fix tests for future monorepo --- .../aws-cdk/test/api/assembly-versions.ts | 34 +++++++++++++++++++ .../aws-cdk/test/api/cloud-assembly.test.ts | 4 ++- packages/aws-cdk/test/api/exec.test.ts | 21 ++++++++++-- packages/aws-cdk/test/build.test.ts | 6 ++-- packages/aws-cdk/test/cdk-toolkit.test.ts | 10 +++--- packages/aws-cdk/test/util.ts | 4 ++- 6 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 packages/aws-cdk/test/api/assembly-versions.ts diff --git a/packages/aws-cdk/test/api/assembly-versions.ts b/packages/aws-cdk/test/api/assembly-versions.ts new file mode 100644 index 0000000000000..ae2ffe9558db8 --- /dev/null +++ b/packages/aws-cdk/test/api/assembly-versions.ts @@ -0,0 +1,34 @@ +import * as fs from 'fs'; +import * as cxapi from '@aws-cdk/cx-api'; +import { CloudAssembly } from '../../lib/api/cxapp/cloud-assembly'; + +/** + * The cloud-assembly-schema in the new monorepo will use its own package version as the schema version, which is always `0.0.0` when tests are running. + * + * If we want to test the CLI's behavior when presented with specific schema versions, we will have to + * mutate `manifest.json` on disk after writing it, and write the schema version that we want to test for in there. + * + * After we raise the schema version in the file on disk from `0.0.0` to + * `30.0.0`, `cx-api` will refuse to load `manifest.json` back, because the + * version is higher than its own package version ("Maximum schema version + * supported is 0.x.x, but found 30.0.0"), so we have to turn on `skipVersionCheck`. + */ +export function cxapiAssemblyWithForcedVersion(asm: cxapi.CloudAssembly, version: string) { + rewriteManifestVersion(asm.directory, version); + return new cxapi.CloudAssembly(asm.directory, { skipVersionCheck: true }); +} + +/** + * The CLI has its own CloudAssembly class which wraps the cxapi CloudAssembly class + */ +export function cliAssemblyWithForcedVersion(asm: CloudAssembly, version: string) { + rewriteManifestVersion(asm.directory, version); + return new CloudAssembly(new cxapi.CloudAssembly(asm.directory, { skipVersionCheck: true })); +} + +export function rewriteManifestVersion(directory: string, version: string) { + const manifestFile = `${directory}/manifest.json`; + const contents = JSON.parse(fs.readFileSync(`${directory}/manifest.json`, 'utf-8')); + contents.version = version; + fs.writeFileSync(manifestFile, JSON.stringify(contents, undefined, 2)); +} diff --git a/packages/aws-cdk/test/api/cloud-assembly.test.ts b/packages/aws-cdk/test/api/cloud-assembly.test.ts index 41ed23d68072a..5654c6390f2dd 100644 --- a/packages/aws-cdk/test/api/cloud-assembly.test.ts +++ b/packages/aws-cdk/test/api/cloud-assembly.test.ts @@ -2,6 +2,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { DefaultSelection } from '../../lib/api/cxapp/cloud-assembly'; import { MockCloudExecutable } from '../util'; +import { cliAssemblyWithForcedVersion } from './assembly-versions'; // behave like v2 process.env.CXAPI_DISABLE_SELECT_BY_ID = '1'; @@ -261,5 +262,6 @@ async function testNestedCloudAssembly({ env }: { env?: string; versionReporting }], }); - return cloudExec.synthesize(); + const asm = await cloudExec.synthesize(); + return cliAssemblyWithForcedVersion(asm, '30.0.0'); } diff --git a/packages/aws-cdk/test/api/exec.test.ts b/packages/aws-cdk/test/api/exec.test.ts index f3061678e3d77..ac9b634430086 100644 --- a/packages/aws-cdk/test/api/exec.test.ts +++ b/packages/aws-cdk/test/api/exec.test.ts @@ -1,7 +1,7 @@ /* eslint-disable import/order */ jest.mock('child_process'); import { bockfs } from '@aws-cdk/cdk-build-tools'; -import * as cxschema from 'aws-cdk-lib/cloud-assembly-schema'; +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from 'aws-cdk-lib'; import * as semver from 'semver'; import * as sinon from 'sinon'; @@ -13,6 +13,7 @@ import { testAssembly } from '../util'; import { mockSpawn } from '../util/mock-child_process'; import { MockSdkProvider } from '../util/mock-sdk'; import { RWLock } from '../../lib/api/util/rwlock'; +import { rewriteManifestVersion } from './assembly-versions'; let sdkProvider: MockSdkProvider; let config: Configuration; @@ -76,6 +77,8 @@ test('cli throws when manifest version > schema version', async () => { mockVersionNumber.restore(); } + await rewriteManifestVersion('cdk.out', `${mockManifestVersion}`); + const expectedError = 'This CDK CLI is not compatible with the CDK library used by your application. Please upgrade the CLI to the latest version.' + `\n(Cloud assembly schema version mismatch: Maximum schema version supported is ${semver.major(currentSchemaVersion)}.x.x, but found ${mockManifestVersion})`; @@ -90,6 +93,11 @@ test('cli does not throw when manifest version = schema version', async () => { const app = createApp(); app.synth(); + // Why do we have to do something here at all? Because `aws-cdk-lib` has its own version of `cloud-assembly-schema`, + // which will have real version `38.0.0`, different from the `0.0.0` version of `cloud-assembly-schema` that the CLI + // uses. + await rewriteManifestVersion('cdk.out', cxschema.Manifest.version()); + config.settings.set(['app'], 'cdk.out'); const { lock } = await execProgram(sdkProvider, config); @@ -97,13 +105,22 @@ test('cli does not throw when manifest version = schema version', async () => { }, TEN_SECOND_TIMEOUT); -test('cli does not throw when manifest version < schema version', async () => { +// Why do we have to do something here at all? Because `aws-cdk-lib` has its own version of `cloud-assembly-schema`, +// which will have real version `38.0.0`, different from the `0.0.0` version of `cloud-assembly-schema` that the CLI +// uses. +// +// Since our Cloud Assembly Schema version will be `0.0.0` and there is no such thing as `-1.0.0`, this test doesn't +// make any sense anymore. +// eslint-disable-next-line jest/no-disabled-tests +test.skip('cli does not throw when manifest version < schema version', async () => { const app = createApp(); const currentSchemaVersion = cxschema.Manifest.version(); app.synth(); + await rewriteManifestVersion('cdk.out', cxschema.Manifest.version()); + config.settings.set(['app'], 'cdk.out'); // this mock will cause the cli to think its exepcted schema version is diff --git a/packages/aws-cdk/test/build.test.ts b/packages/aws-cdk/test/build.test.ts index 52d389cb4abed..0e4e22c33bfb1 100644 --- a/packages/aws-cdk/test/build.test.ts +++ b/packages/aws-cdk/test/build.test.ts @@ -22,9 +22,9 @@ describe('buildAllStackAssets', () => { .toBeUndefined(); expect(buildStackAssets).toBeCalledTimes(3); - expect(buildStackAssets).toBeCalledWith(A); - expect(buildStackAssets).toBeCalledWith(B); - expect(buildStackAssets).toBeCalledWith(C); + expect(buildStackAssets).toHaveBeenCalledWith(A); + expect(buildStackAssets).toHaveBeenCalledWith(B); + expect(buildStackAssets).toHaveBeenCalledWith(C); }); test('errors', async () => { diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 241e5987014f1..e2fcefece707d 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -1062,7 +1062,7 @@ describe('watch', () => { }); fakeChokidarWatcherOn.readyCallback(); - expect(cdkDeployMock).toBeCalledWith(expect.objectContaining({ concurrency: 3 })); + expect(cdkDeployMock).toHaveBeenCalledWith(expect.objectContaining({ concurrency: 3 })); }); describe.each([HotswapMode.FALL_BACK, HotswapMode.HOTSWAP_ONLY])('%p mode', (hotswapMode) => { @@ -1078,7 +1078,7 @@ describe('watch', () => { }); fakeChokidarWatcherOn.readyCallback(); - expect(cdkDeployMock).toBeCalledWith(expect.objectContaining({ hotswap: hotswapMode })); + expect(cdkDeployMock).toHaveBeenCalledWith(expect.objectContaining({ hotswap: hotswapMode })); }); }); @@ -1094,7 +1094,7 @@ describe('watch', () => { }); fakeChokidarWatcherOn.readyCallback(); - expect(cdkDeployMock).toBeCalledWith(expect.objectContaining({ hotswap: HotswapMode.HOTSWAP_ONLY })); + expect(cdkDeployMock).toHaveBeenCalledWith(expect.objectContaining({ hotswap: HotswapMode.HOTSWAP_ONLY })); }); test('respects HotswapMode.FALL_BACK', async () => { @@ -1109,7 +1109,7 @@ describe('watch', () => { }); fakeChokidarWatcherOn.readyCallback(); - expect(cdkDeployMock).toBeCalledWith(expect.objectContaining({ hotswap: HotswapMode.FALL_BACK })); + expect(cdkDeployMock).toHaveBeenCalledWith(expect.objectContaining({ hotswap: HotswapMode.FALL_BACK })); }); test('respects HotswapMode.FULL_DEPLOYMENT', async () => { @@ -1124,7 +1124,7 @@ describe('watch', () => { }); fakeChokidarWatcherOn.readyCallback(); - expect(cdkDeployMock).toBeCalledWith(expect.objectContaining({ hotswap: HotswapMode.FULL_DEPLOYMENT })); + expect(cdkDeployMock).toHaveBeenCalledWith(expect.objectContaining({ hotswap: HotswapMode.FULL_DEPLOYMENT })); }); describe('with file change events', () => { diff --git a/packages/aws-cdk/test/util.ts b/packages/aws-cdk/test/util.ts index 97b38ee00678c..5a26dcdda5983 100644 --- a/packages/aws-cdk/test/util.ts +++ b/packages/aws-cdk/test/util.ts @@ -5,6 +5,7 @@ import { type CloudAssembly, CloudAssemblyBuilder, type CloudFormationStackArtif import { MockSdkProvider } from './util/mock-sdk'; import { CloudExecutable } from '../lib/api/cxapp/cloud-executable'; import { Configuration } from '../lib/settings'; +import { cxapiAssemblyWithForcedVersion } from './api/assembly-versions'; export const DEFAULT_FAKE_TEMPLATE = { No: 'Resources' }; @@ -136,7 +137,8 @@ export function testAssembly(assembly: TestAssembly): CloudAssembly { }); } - return builder.buildAssembly(); + const asm = builder.buildAssembly(); + return cxapiAssemblyWithForcedVersion(asm, '30.0.0'); } /**