UNPKG

@aws-cdk-testing/cli-integ

Version:

Integration tests for the AWS CDK CLI

659 lines 107 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = require("fs"); const os = require("os"); const path = require("path"); const aws_1 = require("../helpers/aws"); const cdk_1 = require("../helpers/cdk"); const test_helpers_1 = require("../helpers/test-helpers"); jest.setTimeout(600 * 1000); test_helpers_1.integTest('VPC Lookup', cdk_1.withDefaultFixture(async (fixture) => { fixture.log('Making sure we are clean before starting.'); await fixture.cdkDestroy('define-vpc', { modEnv: { ENABLE_VPC_TESTING: 'DEFINE' } }); fixture.log('Setting up: creating a VPC with known tags'); await fixture.cdkDeploy('define-vpc', { modEnv: { ENABLE_VPC_TESTING: 'DEFINE' } }); fixture.log('Setup complete!'); fixture.log('Verifying we can now import that VPC'); await fixture.cdkDeploy('import-vpc', { modEnv: { ENABLE_VPC_TESTING: 'IMPORT' } }); })); test_helpers_1.integTest('Two ways of shoing the version', cdk_1.withDefaultFixture(async (fixture) => { const version1 = await fixture.cdk(['version'], { verbose: false }); const version2 = await fixture.cdk(['--version'], { verbose: false }); expect(version1).toEqual(version2); })); test_helpers_1.integTest('Termination protection', cdk_1.withDefaultFixture(async (fixture) => { const stackName = 'termination-protection'; await fixture.cdkDeploy(stackName); // Try a destroy that should fail await expect(fixture.cdkDestroy(stackName)).rejects.toThrow('exited with error'); // Can update termination protection even though the change set doesn't contain changes await fixture.cdkDeploy(stackName, { modEnv: { TERMINATION_PROTECTION: 'FALSE' } }); await fixture.cdkDestroy(stackName); })); test_helpers_1.integTest('cdk synth', cdk_1.withDefaultFixture(async (fixture) => { await fixture.cdk(['synth', fixture.fullStackName('test-1')]); const template1 = await readTemplate(fixture, 'test-1'); expect(template1).toEqual({ Resources: { topic69831491: { Type: 'AWS::SNS::Topic', Metadata: { 'aws:cdk:path': `${fixture.stackNamePrefix}-test-1/topic/Resource`, }, }, }, }); await fixture.cdk(['synth', fixture.fullStackName('test-2')], { verbose: false }); const template2 = await readTemplate(fixture, 'test-2'); expect(template2).toEqual({ Resources: { topic152D84A37: { Type: 'AWS::SNS::Topic', Metadata: { 'aws:cdk:path': `${fixture.stackNamePrefix}-test-2/topic1/Resource`, }, }, topic2A4FB547F: { Type: 'AWS::SNS::Topic', Metadata: { 'aws:cdk:path': `${fixture.stackNamePrefix}-test-2/topic2/Resource`, }, }, }, }); })); test_helpers_1.integTest('ssm parameter provider error', cdk_1.withDefaultFixture(async (fixture) => { await expect(fixture.cdk(['synth', fixture.fullStackName('missing-ssm-parameter'), '-c', 'test:ssm-parameter-name=/does/not/exist'], { allowErrExit: true, })).resolves.toContain('SSM parameter not available in account'); })); test_helpers_1.integTest('automatic ordering', cdk_1.withDefaultFixture(async (fixture) => { // Deploy the consuming stack which will include the producing stack await fixture.cdkDeploy('order-consuming'); // Destroy the providing stack which will include the consuming stack await fixture.cdkDestroy('order-providing'); })); test_helpers_1.integTest('context setting', cdk_1.withDefaultFixture(async (fixture) => { await fs_1.promises.writeFile(path.join(fixture.integTestDir, 'cdk.context.json'), JSON.stringify({ contextkey: 'this is the context value', })); try { await expect(fixture.cdk(['context'])).resolves.toContain('this is the context value'); // Test that deleting the contextkey works await fixture.cdk(['context', '--reset', 'contextkey']); await expect(fixture.cdk(['context'])).resolves.not.toContain('this is the context value'); // Test that forced delete of the context key does not throw await fixture.cdk(['context', '-f', '--reset', 'contextkey']); } finally { await fs_1.promises.unlink(path.join(fixture.integTestDir, 'cdk.context.json')); } })); test_helpers_1.integTest('context in stage propagates to top', cdk_1.withDefaultFixture(async (fixture) => { await expect(fixture.cdkSynth({ // This will make it error to prove that the context bubbles up, and also that we can fail on command options: ['--no-lookups'], modEnv: { INTEG_STACK_SET: 'stage-using-context', }, allowErrExit: true, })).resolves.toContain('Context lookups have been disabled'); })); test_helpers_1.integTest('deploy', cdk_1.withDefaultFixture(async (fixture) => { var _a; const stackArn = await fixture.cdkDeploy('test-2', { captureStderr: false }); // verify the number of resources in the stack const response = await fixture.aws.cloudFormation('describeStackResources', { StackName: stackArn, }); expect((_a = response.StackResources) === null || _a === void 0 ? void 0 : _a.length).toEqual(2); })); test_helpers_1.integTest('deploy all', cdk_1.withDefaultFixture(async (fixture) => { const arns = await fixture.cdkDeploy('test-*', { captureStderr: false }); // verify that we only deployed a single stack (there's a single ARN in the output) expect(arns.split('\n').length).toEqual(2); })); test_helpers_1.integTest('nested stack with parameters', cdk_1.withDefaultFixture(async (fixture) => { var _a; // STACK_NAME_PREFIX is used in MyTopicParam to allow multiple instances // of this test to run in parallel, othewise they will attempt to create the same SNS topic. const stackArn = await fixture.cdkDeploy('with-nested-stack-using-parameters', { options: ['--parameters', `MyTopicParam=${fixture.stackNamePrefix}ThereIsNoSpoon`], captureStderr: false, }); // verify that we only deployed a single stack (there's a single ARN in the output) expect(stackArn.split('\n').length).toEqual(1); // verify the number of resources in the stack const response = await fixture.aws.cloudFormation('describeStackResources', { StackName: stackArn, }); expect((_a = response.StackResources) === null || _a === void 0 ? void 0 : _a.length).toEqual(1); })); test_helpers_1.integTest('deploy without execute a named change set', cdk_1.withDefaultFixture(async (fixture) => { var _a; const changeSetName = 'custom-change-set-name'; const stackArn = await fixture.cdkDeploy('test-2', { options: ['--no-execute', '--change-set-name', changeSetName], captureStderr: false, }); // verify that we only deployed a single stack (there's a single ARN in the output) expect(stackArn.split('\n').length).toEqual(1); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].StackStatus).toEqual('REVIEW_IN_PROGRESS'); //verify a change set was created with the provided name const changeSetResponse = await fixture.aws.cloudFormation('listChangeSets', { StackName: stackArn, }); const changeSets = changeSetResponse.Summaries || []; expect(changeSets.length).toEqual(1); expect(changeSets[0].ChangeSetName).toEqual(changeSetName); expect(changeSets[0].Status).toEqual('CREATE_COMPLETE'); })); test_helpers_1.integTest('security related changes without a CLI are expected to fail', cdk_1.withDefaultFixture(async (fixture) => { // redirect /dev/null to stdin, which means there will not be tty attached // since this stack includes security-related changes, the deployment should // immediately fail because we can't confirm the changes const stackName = 'iam-test'; await expect(fixture.cdkDeploy(stackName, { options: ['<', '/dev/null'], neverRequireApproval: false, })).rejects.toThrow('exited with error'); // Ensure stack was not deployed await expect(fixture.aws.cloudFormation('describeStacks', { StackName: fixture.fullStackName(stackName), })).rejects.toThrow('does not exist'); })); test_helpers_1.integTest('deploy wildcard with outputs', cdk_1.withDefaultFixture(async (fixture) => { const outputsFile = path.join(fixture.integTestDir, 'outputs', 'outputs.json'); await fs_1.promises.mkdir(path.dirname(outputsFile), { recursive: true }); await fixture.cdkDeploy(['outputs-test-*'], { options: ['--outputs-file', outputsFile], }); const outputs = JSON.parse((await fs_1.promises.readFile(outputsFile, { encoding: 'utf-8' })).toString()); expect(outputs).toEqual({ [`${fixture.stackNamePrefix}-outputs-test-1`]: { TopicName: `${fixture.stackNamePrefix}-outputs-test-1MyTopic`, }, [`${fixture.stackNamePrefix}-outputs-test-2`]: { TopicName: `${fixture.stackNamePrefix}-outputs-test-2MyOtherTopic`, }, }); })); test_helpers_1.integTest('deploy with parameters', cdk_1.withDefaultFixture(async (fixture) => { var _a; const stackArn = await fixture.cdkDeploy('param-test-1', { options: [ '--parameters', `TopicNameParam=${fixture.stackNamePrefix}bazinga`, ], captureStderr: false, }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].Parameters).toEqual([ { ParameterKey: 'TopicNameParam', ParameterValue: `${fixture.stackNamePrefix}bazinga`, }, ]); })); test_helpers_1.integTest('update to stack in ROLLBACK_COMPLETE state will delete stack and create a new one', cdk_1.withDefaultFixture(async (fixture) => { var _a, _b, _c, _d; // GIVEN await expect(fixture.cdkDeploy('param-test-1', { options: [ '--parameters', `TopicNameParam=${fixture.stackNamePrefix}@aww`, ], captureStderr: false, })).rejects.toThrow('exited with error'); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: fixture.fullStackName('param-test-1'), }); const stackArn = (_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].StackId; expect((_b = response.Stacks) === null || _b === void 0 ? void 0 : _b[0].StackStatus).toEqual('ROLLBACK_COMPLETE'); // WHEN const newStackArn = await fixture.cdkDeploy('param-test-1', { options: [ '--parameters', `TopicNameParam=${fixture.stackNamePrefix}allgood`, ], captureStderr: false, }); const newStackResponse = await fixture.aws.cloudFormation('describeStacks', { StackName: newStackArn, }); // THEN expect(stackArn).not.toEqual(newStackArn); // new stack was created expect((_c = newStackResponse.Stacks) === null || _c === void 0 ? void 0 : _c[0].StackStatus).toEqual('CREATE_COMPLETE'); expect((_d = newStackResponse.Stacks) === null || _d === void 0 ? void 0 : _d[0].Parameters).toEqual([ { ParameterKey: 'TopicNameParam', ParameterValue: `${fixture.stackNamePrefix}allgood`, }, ]); })); test_helpers_1.integTest('stack in UPDATE_ROLLBACK_COMPLETE state can be updated', cdk_1.withDefaultFixture(async (fixture) => { var _a, _b, _c, _d; // GIVEN const stackArn = await fixture.cdkDeploy('param-test-1', { options: [ '--parameters', `TopicNameParam=${fixture.stackNamePrefix}nice`, ], captureStderr: false, }); let response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].StackStatus).toEqual('CREATE_COMPLETE'); // bad parameter name with @ will put stack into UPDATE_ROLLBACK_COMPLETE await expect(fixture.cdkDeploy('param-test-1', { options: [ '--parameters', `TopicNameParam=${fixture.stackNamePrefix}@aww`, ], captureStderr: false, })).rejects.toThrow('exited with error'); ; response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); expect((_b = response.Stacks) === null || _b === void 0 ? void 0 : _b[0].StackStatus).toEqual('UPDATE_ROLLBACK_COMPLETE'); // WHEN await fixture.cdkDeploy('param-test-1', { options: [ '--parameters', `TopicNameParam=${fixture.stackNamePrefix}allgood`, ], captureStderr: false, }); response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); // THEN expect((_c = response.Stacks) === null || _c === void 0 ? void 0 : _c[0].StackStatus).toEqual('UPDATE_COMPLETE'); expect((_d = response.Stacks) === null || _d === void 0 ? void 0 : _d[0].Parameters).toEqual([ { ParameterKey: 'TopicNameParam', ParameterValue: `${fixture.stackNamePrefix}allgood`, }, ]); })); test_helpers_1.integTest('deploy with wildcard and parameters', cdk_1.withDefaultFixture(async (fixture) => { await fixture.cdkDeploy('param-test-*', { options: [ '--parameters', `${fixture.stackNamePrefix}-param-test-1:TopicNameParam=${fixture.stackNamePrefix}bazinga`, '--parameters', `${fixture.stackNamePrefix}-param-test-2:OtherTopicNameParam=${fixture.stackNamePrefix}ThatsMySpot`, '--parameters', `${fixture.stackNamePrefix}-param-test-3:DisplayNameParam=${fixture.stackNamePrefix}HeyThere`, '--parameters', `${fixture.stackNamePrefix}-param-test-3:OtherDisplayNameParam=${fixture.stackNamePrefix}AnotherOne`, ], }); })); test_helpers_1.integTest('deploy with parameters multi', cdk_1.withDefaultFixture(async (fixture) => { var _a; const paramVal1 = `${fixture.stackNamePrefix}bazinga`; const paramVal2 = `${fixture.stackNamePrefix}=jagshemash`; const stackArn = await fixture.cdkDeploy('param-test-3', { options: [ '--parameters', `DisplayNameParam=${paramVal1}`, '--parameters', `OtherDisplayNameParam=${paramVal2}`, ], captureStderr: false, }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].Parameters).toEqual([ { ParameterKey: 'DisplayNameParam', ParameterValue: paramVal1, }, { ParameterKey: 'OtherDisplayNameParam', ParameterValue: paramVal2, }, ]); })); test_helpers_1.integTest('deploy with notification ARN', cdk_1.withDefaultFixture(async (fixture) => { var _a; const topicName = `${fixture.stackNamePrefix}-test-topic`; const response = await fixture.aws.sns('createTopic', { Name: topicName }); const topicArn = response.TopicArn; try { await fixture.cdkDeploy('test-2', { options: ['--notification-arns', topicArn], }); // verify that the stack we deployed has our notification ARN const describeResponse = await fixture.aws.cloudFormation('describeStacks', { StackName: fixture.fullStackName('test-2'), }); expect((_a = describeResponse.Stacks) === null || _a === void 0 ? void 0 : _a[0].NotificationARNs).toEqual([topicArn]); } finally { await fixture.aws.sns('deleteTopic', { TopicArn: topicArn, }); } })); test_helpers_1.integTest('deploy with role', cdk_1.withDefaultFixture(async (fixture) => { const roleName = `${fixture.stackNamePrefix}-test-role`; await deleteRole(); const createResponse = await fixture.aws.iam('createRole', { RoleName: roleName, AssumeRolePolicyDocument: JSON.stringify({ Version: '2012-10-17', Statement: [{ Action: 'sts:AssumeRole', Principal: { Service: 'cloudformation.amazonaws.com' }, Effect: 'Allow', }, { Action: 'sts:AssumeRole', Principal: { AWS: (await fixture.aws.sts('getCallerIdentity', {})).Arn }, Effect: 'Allow', }], }), }); const roleArn = createResponse.Role.Arn; try { await fixture.aws.iam('putRolePolicy', { RoleName: roleName, PolicyName: 'DefaultPolicy', PolicyDocument: JSON.stringify({ Version: '2012-10-17', Statement: [{ Action: '*', Resource: '*', Effect: 'Allow', }], }), }); await aws_1.retry(fixture.output, 'Trying to assume fresh role', aws_1.retry.forSeconds(300), async () => { await fixture.aws.sts('assumeRole', { RoleArn: roleArn, RoleSessionName: 'testing', }); }); // In principle, the role has replicated from 'us-east-1' to wherever we're testing. // Give it a little more sleep to make sure CloudFormation is not hitting a box // that doesn't have it yet. await aws_1.sleep(5000); await fixture.cdkDeploy('test-2', { options: ['--role-arn', roleArn], }); // Immediately delete the stack again before we delete the role. // // Since roles are sticky, if we delete the role before the stack, subsequent DeleteStack // operations will fail when CloudFormation tries to assume the role that's already gone. await fixture.cdkDestroy('test-2'); } finally { await deleteRole(); } async function deleteRole() { try { for (const policyName of (await fixture.aws.iam('listRolePolicies', { RoleName: roleName })).PolicyNames) { await fixture.aws.iam('deleteRolePolicy', { RoleName: roleName, PolicyName: policyName, }); } await fixture.aws.iam('deleteRole', { RoleName: roleName }); } catch (e) { if (e.message.indexOf('cannot be found') > -1) { return; } throw e; } } })); test_helpers_1.integTest('cdk diff', cdk_1.withDefaultFixture(async (fixture) => { const diff1 = await fixture.cdk(['diff', fixture.fullStackName('test-1')]); expect(diff1).toContain('AWS::SNS::Topic'); const diff2 = await fixture.cdk(['diff', fixture.fullStackName('test-2')]); expect(diff2).toContain('AWS::SNS::Topic'); // We can make it fail by passing --fail await expect(fixture.cdk(['diff', '--fail', fixture.fullStackName('test-1')])) .rejects.toThrow('exited with error'); })); test_helpers_1.integTest('cdk diff --fail on multiple stacks exits with error if any of the stacks contains a diff', cdk_1.withDefaultFixture(async (fixture) => { // GIVEN const diff1 = await fixture.cdk(['diff', fixture.fullStackName('test-1')]); expect(diff1).toContain('AWS::SNS::Topic'); await fixture.cdkDeploy('test-2'); const diff2 = await fixture.cdk(['diff', fixture.fullStackName('test-2')]); expect(diff2).toContain('There were no differences'); // WHEN / THEN await expect(fixture.cdk(['diff', '--fail', fixture.fullStackName('test-1'), fixture.fullStackName('test-2')])).rejects.toThrow('exited with error'); })); test_helpers_1.integTest('cdk diff --fail with multiple stack exits with if any of the stacks contains a diff', cdk_1.withDefaultFixture(async (fixture) => { // GIVEN await fixture.cdkDeploy('test-1'); const diff1 = await fixture.cdk(['diff', fixture.fullStackName('test-1')]); expect(diff1).toContain('There were no differences'); const diff2 = await fixture.cdk(['diff', fixture.fullStackName('test-2')]); expect(diff2).toContain('AWS::SNS::Topic'); // WHEN / THEN await expect(fixture.cdk(['diff', '--fail', fixture.fullStackName('test-1'), fixture.fullStackName('test-2')])).rejects.toThrow('exited with error'); })); test_helpers_1.integTest('cdk diff --security-only --fail exits when security changes are present', cdk_1.withDefaultFixture(async (fixture) => { const stackName = 'iam-test'; await expect(fixture.cdk(['diff', '--security-only', '--fail', fixture.fullStackName(stackName)])).rejects.toThrow('exited with error'); })); test_helpers_1.integTest('deploy stack with docker asset', cdk_1.withDefaultFixture(async (fixture) => { await fixture.cdkDeploy('docker'); })); test_helpers_1.integTest('deploy and test stack with lambda asset', cdk_1.withDefaultFixture(async (fixture) => { var _a, _b; const stackArn = await fixture.cdkDeploy('lambda', { captureStderr: false }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn, }); const lambdaArn = (_b = (_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].Outputs) === null || _b === void 0 ? void 0 : _b[0].OutputValue; if (lambdaArn === undefined) { throw new Error('Stack did not have expected Lambda ARN output'); } const output = await fixture.aws.lambda('invoke', { FunctionName: lambdaArn, }); expect(JSON.stringify(output.Payload)).toContain('dear asset'); })); test_helpers_1.integTest('cdk ls', cdk_1.withDefaultFixture(async (fixture) => { const listing = await fixture.cdk(['ls'], { captureStderr: false }); const expectedStacks = [ 'conditional-resource', 'docker', 'docker-with-custom-file', 'failed', 'iam-test', 'lambda', 'missing-ssm-parameter', 'order-providing', 'outputs-test-1', 'outputs-test-2', 'param-test-1', 'param-test-2', 'param-test-3', 'termination-protection', 'test-1', 'test-2', 'with-nested-stack', 'with-nested-stack-using-parameters', 'order-consuming', ]; for (const stack of expectedStacks) { expect(listing).toContain(fixture.fullStackName(stack)); } })); test_helpers_1.integTest('synthing a stage with errors leads to failure', cdk_1.withDefaultFixture(async (fixture) => { const output = await fixture.cdk(['synth'], { allowErrExit: true, modEnv: { INTEG_STACK_SET: 'stage-with-errors', }, }); expect(output).toContain('This is an error'); })); test_helpers_1.integTest('synthing a stage with errors can be suppressed', cdk_1.withDefaultFixture(async (fixture) => { await fixture.cdk(['synth', '--no-validation'], { modEnv: { INTEG_STACK_SET: 'stage-with-errors', }, }); })); test_helpers_1.integTest('deploy stack without resource', cdk_1.withDefaultFixture(async (fixture) => { // Deploy the stack without resources await fixture.cdkDeploy('conditional-resource', { modEnv: { NO_RESOURCE: 'TRUE' } }); // This should have succeeded but not deployed the stack. await expect(fixture.aws.cloudFormation('describeStacks', { StackName: fixture.fullStackName('conditional-resource') })) .rejects.toThrow('conditional-resource does not exist'); // Deploy the stack with resources await fixture.cdkDeploy('conditional-resource'); // Then again WITHOUT resources (this should destroy the stack) await fixture.cdkDeploy('conditional-resource', { modEnv: { NO_RESOURCE: 'TRUE' } }); await expect(fixture.aws.cloudFormation('describeStacks', { StackName: fixture.fullStackName('conditional-resource') })) .rejects.toThrow('conditional-resource does not exist'); })); test_helpers_1.integTest('IAM diff', cdk_1.withDefaultFixture(async (fixture) => { const output = await fixture.cdk(['diff', fixture.fullStackName('iam-test')]); // Roughly check for a table like this: // // ┌───┬─────────────────┬────────┬────────────────┬────────────────────────────-──┬───────────┐ // │ │ Resource │ Effect │ Action │ Principal │ Condition │ // ├───┼─────────────────┼────────┼────────────────┼───────────────────────────────┼───────────┤ // │ + │ ${SomeRole.Arn} │ Allow │ sts:AssumeRole │ Service:ec2.amazonaws.com │ │ // └───┴─────────────────┴────────┴────────────────┴───────────────────────────────┴───────────┘ expect(output).toContain('${SomeRole.Arn}'); expect(output).toContain('sts:AssumeRole'); expect(output).toContain('ec2.amazonaws.com'); })); test_helpers_1.integTest('fast deploy', cdk_1.withDefaultFixture(async (fixture) => { // we are using a stack with a nested stack because CFN will always attempt to // update a nested stack, which will allow us to verify that updates are actually // skipped unless --force is specified. const stackArn = await fixture.cdkDeploy('with-nested-stack', { captureStderr: false }); const changeSet1 = await getLatestChangeSet(); // Deploy the same stack again, there should be no new change set created await fixture.cdkDeploy('with-nested-stack'); const changeSet2 = await getLatestChangeSet(); expect(changeSet2.ChangeSetId).toEqual(changeSet1.ChangeSetId); // Deploy the stack again with --force, now we should create a changeset await fixture.cdkDeploy('with-nested-stack', { options: ['--force'] }); const changeSet3 = await getLatestChangeSet(); expect(changeSet3.ChangeSetId).not.toEqual(changeSet2.ChangeSetId); // Deploy the stack again with tags, expected to create a new changeset // even though the resources didn't change. await fixture.cdkDeploy('with-nested-stack', { options: ['--tags', 'key=value'] }); const changeSet4 = await getLatestChangeSet(); expect(changeSet4.ChangeSetId).not.toEqual(changeSet3.ChangeSetId); async function getLatestChangeSet() { var _a, _b, _c; const response = await fixture.aws.cloudFormation('describeStacks', { StackName: stackArn }); if (!((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0])) { throw new Error('Did not get a ChangeSet at all'); } fixture.log(`Found Change Set ${(_b = response.Stacks) === null || _b === void 0 ? void 0 : _b[0].ChangeSetId}`); return (_c = response.Stacks) === null || _c === void 0 ? void 0 : _c[0]; } })); test_helpers_1.integTest('failed deploy does not hang', cdk_1.withDefaultFixture(async (fixture) => { // this will hang if we introduce https://github.com/aws/aws-cdk/issues/6403 again. await expect(fixture.cdkDeploy('failed')).rejects.toThrow('exited with error'); })); test_helpers_1.integTest('can still load old assemblies', cdk_1.withDefaultFixture(async (fixture) => { const cxAsmDir = path.join(os.tmpdir(), 'cdk-integ-cx'); const testAssembliesDirectory = path.join(__dirname, 'cloud-assemblies'); for (const asmdir of await listChildDirs(testAssembliesDirectory)) { fixture.log(`ASSEMBLY ${asmdir}`); await cdk_1.cloneDirectory(asmdir, cxAsmDir); // Some files in the asm directory that have a .js extension are // actually treated as templates. Evaluate them using NodeJS. const templates = await listChildren(cxAsmDir, fullPath => Promise.resolve(fullPath.endsWith('.js'))); for (const template of templates) { const targetName = template.replace(/.js$/, ''); await cdk_1.shell([process.execPath, template, '>', targetName], { cwd: cxAsmDir, output: fixture.output, modEnv: { TEST_ACCOUNT: await fixture.aws.account(), TEST_REGION: fixture.aws.region, }, }); } // Use this directory as a Cloud Assembly const output = await fixture.cdk([ '--app', cxAsmDir, '-v', 'synth', ]); // Assert that there was no providerError in CDK's stderr // Because we rely on the app/framework to actually error in case the // provider fails, we inspect the logs here. expect(output).not.toContain('$providerError'); } })); test_helpers_1.integTest('generating and loading assembly', cdk_1.withDefaultFixture(async (fixture) => { const asmOutputDir = `${fixture.integTestDir}-cdk-integ-asm`; await fixture.shell(['rm', '-rf', asmOutputDir]); // Synthesize a Cloud Assembly tothe default directory (cdk.out) and a specific directory. await fixture.cdk(['synth']); await fixture.cdk(['synth', '--output', asmOutputDir]); // cdk.out in the current directory and the indicated --output should be the same await fixture.shell(['diff', 'cdk.out', asmOutputDir]); // Check that we can 'ls' the synthesized asm. // Change to some random directory to make sure we're not accidentally loading cdk.json const list = await fixture.cdk(['--app', asmOutputDir, 'ls'], { cwd: os.tmpdir() }); // Same stacks we know are in the app expect(list).toContain(`${fixture.stackNamePrefix}-lambda`); expect(list).toContain(`${fixture.stackNamePrefix}-test-1`); expect(list).toContain(`${fixture.stackNamePrefix}-test-2`); // Check that we can use '.' and just synth ,the generated asm const stackTemplate = await fixture.cdk(['--app', '.', 'synth', fixture.fullStackName('test-2')], { cwd: asmOutputDir, }); expect(stackTemplate).toContain('topic152D84A37'); // Deploy a Lambda from the copied asm await fixture.cdkDeploy('lambda', { options: ['-a', '.'], cwd: asmOutputDir }); // Remove (rename) the original custom docker file that was used during synth. // this verifies that the assemly has a copy of it and that the manifest uses // relative paths to reference to it. const customDockerFile = path.join(fixture.integTestDir, 'docker', 'Dockerfile.Custom'); await fs_1.promises.rename(customDockerFile, `${customDockerFile}~`); try { // deploy a docker image with custom file without synth (uses assets) await fixture.cdkDeploy('docker-with-custom-file', { options: ['-a', '.'], cwd: asmOutputDir }); } finally { // Rename back to restore fixture to original state await fs_1.promises.rename(`${customDockerFile}~`, customDockerFile); } })); test_helpers_1.integTest('templates on disk contain metadata resource, also in nested assemblies', cdk_1.withDefaultFixture(async (fixture) => { // Synth first, and switch on version reporting because cdk.json is disabling it await fixture.cdk(['synth', '--version-reporting=true']); // Load template from disk from root assembly const templateContents = await fixture.shell(['cat', 'cdk.out/*-lambda.template.json']); expect(JSON.parse(templateContents).Resources.CDKMetadata).toBeTruthy(); // Load template from nested assembly const nestedTemplateContents = await fixture.shell(['cat', 'cdk.out/assembly-*-stage/*-stage-StackInStage.template.json']); expect(JSON.parse(nestedTemplateContents).Resources.CDKMetadata).toBeTruthy(); })); async function listChildren(parent, pred) { const ret = new Array(); for (const child of await fs_1.promises.readdir(parent, { encoding: 'utf-8' })) { const fullPath = path.join(parent, child.toString()); if (await pred(fullPath)) { ret.push(fullPath); } } return ret; } async function listChildDirs(parent) { return listChildren(parent, async (fullPath) => (await fs_1.promises.stat(fullPath)).isDirectory()); } async function readTemplate(fixture, stackName) { const fullStackName = fixture.fullStackName(stackName); const templatePath = path.join(fixture.integTestDir, 'cdk.out', `${fullStackName}.template.json`); return JSON.parse((await fs_1.promises.readFile(templatePath, { encoding: 'utf-8' })).toString()); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmludGVndGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNsaS5pbnRlZ3Rlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQkFBb0M7QUFDcEMseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3Qix3Q0FBOEM7QUFDOUMsd0NBQXdGO0FBQ3hGLDBEQUFvRDtBQUVwRCxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQztBQUU1Qix3QkFBUyxDQUFDLFlBQVksRUFBRSx3QkFBa0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7SUFDM0QsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO0lBQ3pELE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUUsRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFckYsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO0lBQzFELE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUUsRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEYsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBRS9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0NBQXNDLENBQUMsQ0FBQztJQUNwRCxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsWUFBWSxFQUFFLEVBQUUsTUFBTSxFQUFFLEVBQUUsa0JBQWtCLEVBQUUsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3RGLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFSix3QkFBUyxDQUFDLGdDQUFnQyxFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtJQUMvRSxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFH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