diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts index 3e88e64cfc7dc..3bc37117162d6 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts @@ -345,7 +345,6 @@ function includeDownstreamStacks( } while (madeProgress); if (added.length > 0) { - // @todo remove here or use iohost info('Including depending stacks: %s', chalk.bold(added.join(', '))); } } @@ -376,7 +375,6 @@ function includeUpstreamStacks( } if (added.length > 0) { - // @todo remove here or use iohost info('Including dependency stacks: %s', chalk.bold(added.join(', '))); } } diff --git a/packages/aws-cdk/test/api/cloud-assembly.test.ts b/packages/aws-cdk/test/api/cloud-assembly.test.ts index ce66be6a9a0a0..574b401b9d30c 100644 --- a/packages/aws-cdk/test/api/cloud-assembly.test.ts +++ b/packages/aws-cdk/test/api/cloud-assembly.test.ts @@ -4,33 +4,6 @@ import { DefaultSelection } from '../../lib/api/cxapp/cloud-assembly'; import { MockCloudExecutable } from '../util'; import { cliAssemblyWithForcedVersion } from './assembly-versions'; -test('do not throw when selecting stack without errors', async () => { - // GIVEN - const cxasm = await testCloudAssembly(); - - // WHEN - const selected = await cxasm.selectStacks( { patterns: ['withouterrorsNODEPATH'] }, { - defaultBehavior: DefaultSelection.AllStacks, - }); - await selected.validateMetadata(); - - // THEN - expect(selected.firstStack.template.resource).toBe('noerrorresource'); -}); - -test('do throw when selecting stack with errors', async () => { - // GIVEN - const cxasm = await testCloudAssembly(); - - // WHEN - const selected = await cxasm.selectStacks({ patterns: ['witherrors'] }, { - defaultBehavior: DefaultSelection.AllStacks, - }); - - // THEN - await expect(async () => selected.validateMetadata()).rejects.toThrow(/Found errors/); -}); - test('select all top level stacks in the presence of nested assemblies', async () => { // GIVEN const cxasm = await testNestedCloudAssembly(); @@ -186,6 +159,95 @@ test('select behavior with no stacks and default ignore stacks options (false)', .rejects.toThrow('This app contains no stacks'); }); +describe('StackCollection', () => { + test('returns hierarchicalIds', async () => { + // GIVEN + const cxasm = await testNestedCloudAssembly(); + + // WHEN + const x = await cxasm.selectStacks({ allTopLevel: true, patterns: [] }, { defaultBehavior: DefaultSelection.AllStacks }); + + // THEN + expect(x.stackCount).toBe(2); + expect(x.hierarchicalIds).toEqual(['witherrors', 'deeply/hidden/withouterrors']); + }); + + describe('validateMetadata', () => { + test('do not throw when selecting stack without errors', async () => { + // GIVEN + const cxasm = await testCloudAssembly(); + + // WHEN + const selected = await cxasm.selectStacks( { patterns: ['withouterrorsNODEPATH'] }, { + defaultBehavior: DefaultSelection.AllStacks, + }); + await selected.validateMetadata(); + + // THEN + expect(selected.stackCount).toBe(1); + expect(selected.firstStack.template.resource).toBe('noerrorresource'); + }); + + test('do not throw when selecting stack with warnings', async () => { + // GIVEN + const cxasm = await testCloudAssembly(); + + // WHEN + const selected = await cxasm.selectStacks( { patterns: ['withwarns'] }, { + defaultBehavior: DefaultSelection.AllStacks, + }); + await selected.validateMetadata(); + + // THEN + expect(selected.stackCount).toBe(1); + expect(selected.firstStack.template.resource).toBe('warnresource'); + }); + + test('do not throw when selecting stack with errors but errors are ignored', async () => { + // GIVEN + const cxasm = await testCloudAssembly(); + + // WHEN + const selected = await cxasm.selectStacks({ patterns: ['witherrors'] }, { + defaultBehavior: DefaultSelection.AllStacks, + }); + await selected.validateMetadata('none'); + + // THEN + expect(selected.stackCount).toBe(1); + expect(selected.firstStack.template.resource).toBe('errorresource'); + }); + + test('do throw when selecting stack with errors', async () => { + // GIVEN + const cxasm = await testCloudAssembly(); + + // WHEN + const selected = await cxasm.selectStacks({ patterns: ['witherrors'] }, { + defaultBehavior: DefaultSelection.AllStacks, + }); + + // THEN + expect(selected.stackCount).toBe(1); + await expect(async () => selected.validateMetadata()).rejects.toThrow(/Found errors/); + }); + + test('do throw when selecting stack with warnings and we are on strict mode', async () => { + // GIVEN + const cxasm = await testCloudAssembly(); + + // WHEN + const selected = await cxasm.selectStacks( { patterns: ['withwarns'] }, { + defaultBehavior: DefaultSelection.AllStacks, + }); + + // THEN + expect(selected.stackCount).toBe(1); + await expect(async () => selected.validateMetadata('warn')).rejects.toThrow(/Found warnings/); + }); + }); +}); + async function testCloudAssembly({ env }: { env?: string; versionReporting?: boolean } = {}) { const cloudExec = new MockCloudExecutable({ stacks: [{ @@ -206,6 +268,19 @@ async function testCloudAssembly({ env }: { env?: string; versionReporting?: boo }, ], }, + }, + { + stackName: 'withwarns', + env, + template: { resource: 'warnresource' }, + metadata: { + '/resource': [ + { + type: cxschema.ArtifactMetadataEntryType.WARN, + data: 'this is a warning', + }, + ], + }, }], }); diff --git a/packages/aws-cdk/test/serialize.test.ts b/packages/aws-cdk/test/serialize.test.ts index c30e3caec2715..e465f1c8f8630 100644 --- a/packages/aws-cdk/test/serialize.test.ts +++ b/packages/aws-cdk/test/serialize.test.ts @@ -1,5 +1,5 @@ /* eslint-disable import/order */ -import { toYAML } from '../lib/serialize'; +import { toYAML, obscureTemplate } from '../lib/serialize'; describe(toYAML, () => { test('does not wrap lines', () => { @@ -7,3 +7,30 @@ describe(toYAML, () => { expect(toYAML({ longString })).toEqual(`longString: ${longString}\n`); }); }); + +describe(obscureTemplate, () => { + test('removes CheckBootstrapVersion rule only', () => { + const template = { + Rules: { + CheckBootstrapVersion: { Assertions: [{ AssertDescription: 'bootstrap' }] }, + MyOtherRule: { Assertions: [{ AssertDescription: 'other' }] }, + }, + }; + + const obscured = obscureTemplate(template); + expect(obscured).not.toHaveProperty('Rules.CheckBootstrapVersion'); + expect(obscured).toHaveProperty('Rules.MyOtherRule.Assertions.0.AssertDescription', 'other'); + }); + + test('removes all rules when CheckBootstrapVersion is the only rule', () => { + const template = { + Rules: { + CheckBootstrapVersion: { Assertions: [{ AssertDescription: 'bootstrap' }] }, + }, + }; + + const obscured = obscureTemplate(template); + expect(obscured).not.toHaveProperty('Rules.CheckBootstrapVersion'); + expect(obscured).not.toHaveProperty('Rules'); + }); +}); diff --git a/packages/aws-cdk/test/toolkit-error.test.ts b/packages/aws-cdk/test/toolkit-error.test.ts index 1aef772e186a5..5f2ff259300f1 100644 --- a/packages/aws-cdk/test/toolkit-error.test.ts +++ b/packages/aws-cdk/test/toolkit-error.test.ts @@ -1,17 +1,30 @@ -import { AuthenticationError, ToolkitError } from '../lib/toolkit/error'; +import { AssemblyError, AuthenticationError, ToolkitError } from '../lib/toolkit/error'; describe('toolkit error', () => { let toolkitError = new ToolkitError('Test toolkit error'); let authError = new AuthenticationError('Test authentication error'); + let assemblyError = new AssemblyError('Test authentication error'); + test('types are correctly assigned', async () => { expect(toolkitError.type).toBe('toolkit'); expect(authError.type).toBe('authentication'); + expect(assemblyError.type).toBe('assembly'); }); - test('isToolkitError and isAuthenticationError functions work', () => { + test('isToolkitError works', () => { expect(ToolkitError.isToolkitError(toolkitError)).toBe(true); expect(ToolkitError.isToolkitError(authError)).toBe(true); + expect(ToolkitError.isToolkitError(assemblyError)).toBe(true); + }); + + test('isAuthenticationError works', () => { expect(ToolkitError.isAuthenticationError(toolkitError)).toBe(false); expect(ToolkitError.isAuthenticationError(authError)).toBe(true); }); + + test('isAssemblyError works', () => { + expect(ToolkitError.isAssemblyError(assemblyError)).toBe(true); + expect(ToolkitError.isAssemblyError(toolkitError)).toBe(false); + expect(ToolkitError.isAssemblyError(authError)).toBe(false); + }); }); diff --git a/packages/aws-cdk/test/toolkit/cli-io-host.test.ts b/packages/aws-cdk/test/toolkit/cli-io-host.test.ts index 910f2ad19df81..210a9a310a95e 100644 --- a/packages/aws-cdk/test/toolkit/cli-io-host.test.ts +++ b/packages/aws-cdk/test/toolkit/cli-io-host.test.ts @@ -239,4 +239,21 @@ describe('CliIoHost', () => { })).rejects.toThrow('Write failed'); }); }); + + describe('requestResponse', () => { + test('logs messages and returns default', async () => { + CliIoHost.isTTY = true; + const response = await CliIoHost.getIoHost().requestResponse({ + time: new Date(), + level: 'info', + action: 'synth', + code: 'CDK_TOOLKIT_I0001', + message: 'test message', + defaultResponse: 'default response', + }); + + expect(mockStderr).toHaveBeenCalledWith(chalk.white('test message') + '\n'); + expect(response).toBe('default response'); + }); + }); });