From ce7a4c442cb6b432cfbff9cba14ab0901b6c520c Mon Sep 17 00:00:00 2001 From: Kendra Neil <53584728+TheRealAmazonKendra@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:58:49 -0700 Subject: [PATCH 1/2] chore(migrate): add integ tests with app deployment --- .../cli-integ/lib/with-cdk-app.ts | 61 +++++++++++++++++++ .../resources/templates/sqs-template.json | 36 +++++++++++ .../tests/cli-integ-tests/cli.integtest.ts | 19 +++++- 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk-testing/cli-integ/resources/templates/sqs-template.json diff --git a/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts b/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts index a37edcb206dd4..85ce8bb99aef6 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts @@ -84,6 +84,50 @@ export function withCdkApp( }; } +export function withCdkMigrateApp(language: string, block: (context: TestFixture) => Promise) { + return async (context: A) => { + const stackName = `cdk-migrate-${language}-integ-${context.randomString}`; + const integTestDir = path.join(os.tmpdir(), `cdk-migrate-${language}-integ-${context.randomString}`); + + context.output.write(` Stack name: ${stackName}\n`); + context.output.write(` Test directory: ${integTestDir}\n`); + + const awsClients = await AwsClients.default(context.output); + fs.mkdirSync(integTestDir); + const fixture = new TestFixture( + integTestDir, + stackName, + context.output, + awsClients, + context.randomString, + ); + + await fixture.cdkMigrate(language, stackName); + + const testFixture = new TestFixture( + path.join(integTestDir, stackName), + stackName, + context.output, + awsClients, + context.randomString, + ); + + let success = true; + try { + await block(testFixture); + } catch (e) { + success = false; + throw e; + } finally { + if (process.env.INTEG_NO_CLEAN) { + context.log(`Left test directory in '${integTestDir}' ($INTEG_NO_CLEAN)`); + } else { + await fixture.dispose(success); + } + } + }; +} + export function withMonolithicCfnIncludeCdkApp(block: (context: TestFixture) => Promise) { return async (context: A) => { const uberPackage = process.env.UBERPACKAGE; @@ -141,6 +185,10 @@ export function withDefaultFixture(block: (context: TestFixture) => Promise Promise) { + return withAws(withTimeout(DEFAULT_TEST_TIMEOUT_S, withCdkMigrateApp(language, block))); +} + export interface DisableBootstrapContext { /** * Whether to disable creating the default bootstrap @@ -379,6 +427,19 @@ export class TestFixture extends ShellHelper { }); } + public async cdkMigrate(language: string, stackName: string, inputPath?: string, options?: CdkCliOptions) { + return this.cdk([ + 'migrate', + '--language', + language, + '--stack-name', + stackName, + '--from-path', + inputPath ?? path.join(__dirname, '..', 'resources', 'templates', 'sqs-template.json').toString(), + ...(options?.options ?? []), + ], options); + } + public async cdk(args: string[], options: CdkCliOptions = {}) { const verbose = options.verbose ?? true; diff --git a/packages/@aws-cdk-testing/cli-integ/resources/templates/sqs-template.json b/packages/@aws-cdk-testing/cli-integ/resources/templates/sqs-template.json new file mode 100644 index 0000000000000..57c9ef5d12a3d --- /dev/null +++ b/packages/@aws-cdk-testing/cli-integ/resources/templates/sqs-template.json @@ -0,0 +1,36 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "AWS CloudFormation Sample Template SQS_With_CloudWatch_Alarms: Sample template showing how to create an SQS queue with AWS CloudWatch alarms on queue depth.", + "Resources": { + "MyQueue": { + "Type": "AWS::SQS::Queue", + "Properties": {} + } + }, + "Outputs": { + "QueueURL": { + "Description": "URL of newly created SQS Queue", + "Value": { + "Ref": "MyQueue" + } + }, + "QueueARN": { + "Description": "ARN of newly created SQS Queue", + "Value": { + "Fn::GetAtt": [ + "MyQueue", + "Arn" + ] + } + }, + "QueueName": { + "Description": "Name newly created SQS Queue", + "Value": { + "Fn::GetAtt": [ + "MyQueue", + "QueueName" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index b5b55ba5a6a75..6363b3f12f689 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -1,7 +1,7 @@ import { promises as fs, existsSync } from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { integTest, cloneDirectory, shell, withDefaultFixture, retry, sleep, randomInteger, withSamIntegrationFixture, RESOURCES_DIR } from '../../lib'; +import { integTest, cloneDirectory, shell, withDefaultFixture, retry, sleep, randomInteger, withSamIntegrationFixture, RESOURCES_DIR, withCDKMigrateFixture } from '../../lib'; jest.setTimeout(2 * 60 * 60_000); // Includes the time to acquire locks, worst-case single-threaded runtime @@ -571,6 +571,23 @@ integTest('deploy with role', withDefaultFixture(async (fixture) => { } })); +// TODO add go back in when template synths properly +['typescript', 'python', 'csharp', 'java'].forEach(language => { + integTest(`cdk migrate ${language}`, withCDKMigrateFixture(language, async (fixture) => { + if (language === 'python') { + await fixture.shell(['pip', 'install', '-r', 'requirements.txt']); + } + + const stackArn = await fixture.cdkDeploy(fixture.stackNamePrefix, { neverRequireApproval: true, verbose: true, captureStderr: false }); + const response = await fixture.aws.cloudFormation('describeStacks', { + StackName: stackArn, + }); + + expect(response.Stacks?.[0].StackStatus).toEqual('CREATE_COMPLETE'); + await fixture.cdkDestroy(fixture.stackNamePrefix); + })); +}); + integTest('cdk diff', withDefaultFixture(async (fixture) => { const diff1 = await fixture.cdk(['diff', fixture.fullStackName('test-1')]); expect(diff1).toContain('AWS::SNS::Topic'); From 9f0448f9e649046ca3a767d4084fb2e2d0b4d6be Mon Sep 17 00:00:00 2001 From: Kendra Neil <53584728+TheRealAmazonKendra@users.noreply.github.com> Date: Wed, 11 Oct 2023 21:46:46 -0700 Subject: [PATCH 2/2] leave name of stack alone --- packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts | 4 ++-- .../cli-integ/tests/cli-integ-tests/cli.integtest.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts b/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts index 85ce8bb99aef6..8124088e00634 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts @@ -318,7 +318,7 @@ export class TestFixture extends ShellHelper { this.output.write(`${s}\n`); } - public async cdkDeploy(stackNames: string | string[], options: CdkCliOptions = {}) { + public async cdkDeploy(stackNames: string | string[], options: CdkCliOptions = {}, skipStackRename?: boolean) { stackNames = typeof stackNames === 'string' ? [stackNames] : stackNames; const neverRequireApproval = options.neverRequireApproval ?? true; @@ -328,7 +328,7 @@ export class TestFixture extends ShellHelper { ...(options.options ?? []), // use events because bar renders bad in tests '--progress', 'events', - ...this.fullStackName(stackNames)], options); + ...(skipStackRename ? stackNames : this.fullStackName(stackNames))], options); } public async cdkSynth(options: CdkCliOptions = {}) { diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index 6363b3f12f689..93b25eed0c6b6 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -578,7 +578,7 @@ integTest('deploy with role', withDefaultFixture(async (fixture) => { await fixture.shell(['pip', 'install', '-r', 'requirements.txt']); } - const stackArn = await fixture.cdkDeploy(fixture.stackNamePrefix, { neverRequireApproval: true, verbose: true, captureStderr: false }); + const stackArn = await fixture.cdkDeploy(fixture.stackNamePrefix, { neverRequireApproval: true, verbose: true, captureStderr: false }, true); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, });