From 46ea434e4dd3aa1f2d6d35217315c0464781d914 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Wed, 1 Sep 2021 13:53:21 -0400 Subject: [PATCH 1/9] initial implementation of adding outputname to hasoutput --- .../assertions/lib/private/outputs.ts | 15 ++++-- packages/@aws-cdk/assertions/lib/template.ts | 5 +- .../@aws-cdk/assertions/test/template.test.ts | 50 +++++++++++++++++-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/outputs.ts b/packages/@aws-cdk/assertions/lib/private/outputs.ts index 46e5a6cb1d52b..0b328ffda7fcb 100644 --- a/packages/@aws-cdk/assertions/lib/private/outputs.ts +++ b/packages/@aws-cdk/assertions/lib/private/outputs.ts @@ -12,20 +12,25 @@ export function findOutputs(inspector: StackInspector, props: any = {}): { [key: return result.matches; } -export function hasOutput(inspector: StackInspector, props: any): string | void { +export function hasOutput(inspector: StackInspector, outputName: string, props: any): string | void { const section: { [key: string]: {} } = inspector.value.Outputs; - const result = matchSection(section, props); - + const result = matchSection(filterName(section, outputName), props); if (result.match) { return; } if (result.closestResult === undefined) { - return 'No outputs found in the template'; + return `No outputs named ${outputName} found in the template.`; } return [ - `Template has ${result.analyzedCount} outputs, but none match as expected.`, + `Template has ${result.analyzedCount} outputs named ${outputName}, but none match as expected.`, formatFailure(result.closestResult), ].join('\n'); +} + +function filterName(section: { [key: string]: {} }, outputName: string): { [key: string]: {} } { + return Object.entries(section ?? {}) + .filter(([k, _]) => k === outputName) + .reduce((agg, [k, v]) => { return { ...agg, [k]: v }; }, {}); } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/template.ts b/packages/@aws-cdk/assertions/lib/template.ts index 848c46bcc295a..2f9f84c54cabb 100644 --- a/packages/@aws-cdk/assertions/lib/template.ts +++ b/packages/@aws-cdk/assertions/lib/template.ts @@ -109,10 +109,11 @@ export class Template { * Assert that an Output with the given properties exists in the CloudFormation template. * By default, performs partial matching on the resource, via the `Match.objectLike()`. * To configure different behavour, use other matchers in the `Match` class. + * @param outputName the name of the output. * @param props the output as should be expected in the template. */ - public hasOutput(props: any): void { - const matchError = hasOutput(this.inspector, props); + public hasOutput(outputName: string, props: any): void { + const matchError = hasOutput(this.inspector, outputName, props); if (matchError) { throw new Error(matchError); } diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index 50fb60a1a27f7..fc3c34deecd57 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -342,7 +342,7 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - expect(() => inspect.hasOutput({ Value: 'Bar' })).not.toThrow(); + expect(() => inspect.hasOutput('Foo', { Value: 'Bar' })).not.toThrow(); }); test('not matching', (done) => { @@ -357,18 +357,62 @@ describe('Template', () => { const inspect = Template.fromStack(stack); expectToThrow( - () => inspect.hasOutput({ + () => inspect.hasOutput('Foo', { Value: 'Bar', Export: { Name: 'ExportBaz' }, }), [ - /2 outputs/, + /1 outputs named Foo/, /Expected ExportBaz but received ExportBar/, ], done, ); done(); }); + + test('outputName not matching', (done) => { + const stack = new Stack(); + new CfnOutput(stack, 'Foo', { + value: 'Bar', + }); + new CfnOutput(stack, 'Fred', { + value: 'Baz', + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasOutput('Fred', { + Value: 'Bar', + }), + [ + /1 outputs named Fred/, + /Expected Bar but received Baz/, + ], + done, + ); + done(); + }); + }); + + test('name not matching', (done) => { + const stack = new Stack(); + new CfnOutput(stack, 'Foo', { + value: 'Bar', + exportName: 'ExportBar', + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasOutput('Fred', { + Value: 'Bar', + Export: { Name: 'ExportBar' }, + }), + [ + /No outputs named Fred found in the template./, + ], + done, + ); + done(); }); describe('findOutputs', () => { From 0dc220fd1849702253643f23396dbc05740074f4 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Tue, 7 Sep 2021 16:45:46 -0400 Subject: [PATCH 2/9] outputName for has/find outputs and mapping --- .../assertions/lib/private/mappings.ts | 10 +- .../assertions/lib/private/outputs.ts | 14 +- .../assertions/lib/private/section.ts | 9 ++ packages/@aws-cdk/assertions/lib/template.ts | 17 ++- .../@aws-cdk/assertions/test/template.test.ts | 135 ++++++++++++++++-- 5 files changed, 155 insertions(+), 30 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/mappings.ts b/packages/@aws-cdk/assertions/lib/private/mappings.ts index 0def435cc0e1d..be83027e9276b 100644 --- a/packages/@aws-cdk/assertions/lib/private/mappings.ts +++ b/packages/@aws-cdk/assertions/lib/private/mappings.ts @@ -1,9 +1,9 @@ import { StackInspector } from '../vendored/assert'; -import { formatFailure, matchSection } from './section'; +import { filterLogicalId, formatFailure, matchSection } from './section'; -export function findMappings(inspector: StackInspector, props: any = {}): { [key: string]: any }[] { +export function findMappings(inspector: StackInspector, outputName: string, props: any = {}): { [key: string]: any }[] { const section: { [key: string] : {} } = inspector.value.Mappings; - const result = matchSection(section, props); + const result = matchSection(filterLogicalId(section,outputName), props); if (!result.match) { return []; @@ -12,9 +12,9 @@ export function findMappings(inspector: StackInspector, props: any = {}): { [key return result.matches; } -export function hasMapping(inspector: StackInspector, props: any): string | void { +export function hasMapping(inspector: StackInspector, outputName: string, props: any): string | void { const section: { [key: string]: {} } = inspector.value.Mappings; - const result = matchSection(section, props); + const result = matchSection(filterLogicalId(section, outputName), props); if (result.match) { return; diff --git a/packages/@aws-cdk/assertions/lib/private/outputs.ts b/packages/@aws-cdk/assertions/lib/private/outputs.ts index 0b328ffda7fcb..8d97353cf56d1 100644 --- a/packages/@aws-cdk/assertions/lib/private/outputs.ts +++ b/packages/@aws-cdk/assertions/lib/private/outputs.ts @@ -1,9 +1,9 @@ import { StackInspector } from '../vendored/assert'; -import { formatFailure, matchSection } from './section'; +import { filterLogicalId, formatFailure, matchSection } from './section'; -export function findOutputs(inspector: StackInspector, props: any = {}): { [key: string]: any }[] { +export function findOutputs(inspector: StackInspector, outputName: string, props: any = {}): { [key: string]: any }[] { const section: { [key: string] : {} } = inspector.value.Outputs; - const result = matchSection(section, props); + const result = matchSection(filterLogicalId(section, outputName), props); if (!result.match) { return []; @@ -14,7 +14,7 @@ export function findOutputs(inspector: StackInspector, props: any = {}): { [key: export function hasOutput(inspector: StackInspector, outputName: string, props: any): string | void { const section: { [key: string]: {} } = inspector.value.Outputs; - const result = matchSection(filterName(section, outputName), props); + const result = matchSection(filterLogicalId(section, outputName), props); if (result.match) { return; } @@ -28,9 +28,3 @@ export function hasOutput(inspector: StackInspector, outputName: string, props: formatFailure(result.closestResult), ].join('\n'); } - -function filterName(section: { [key: string]: {} }, outputName: string): { [key: string]: {} } { - return Object.entries(section ?? {}) - .filter(([k, _]) => k === outputName) - .reduce((agg, [k, v]) => { return { ...agg, [k]: v }; }, {}); -} \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index d8f0123de20d6..c7e1d93ecc0f7 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -55,4 +55,13 @@ export function formatFailure(closestResult: MatchResult): string { function leftPad(x: string, indent: number = 2): string { const pad = ' '.repeat(indent); return pad + x.split('\n').join(`\n${pad}`); +} + +export function filterLogicalId(section: { [key: string]: {} }, outputName: string): { [key: string]: {} } { + // default signal for all outputs is '*' + if (outputName === '*') return section; + + return Object.entries(section ?? {}) + .filter(([k, _]) => k === outputName) + .reduce((agg, [k, v]) => { return { ...agg, [k]: v }; }, {}); } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/template.ts b/packages/@aws-cdk/assertions/lib/template.ts index 2f9f84c54cabb..f67d7e64f3018 100644 --- a/packages/@aws-cdk/assertions/lib/template.ts +++ b/packages/@aws-cdk/assertions/lib/template.ts @@ -109,7 +109,7 @@ export class Template { * Assert that an Output with the given properties exists in the CloudFormation template. * By default, performs partial matching on the resource, via the `Match.objectLike()`. * To configure different behavour, use other matchers in the `Match` class. - * @param outputName the name of the output. + * @param outputName the name of the output. Provide '*' to match all Output names in the template. * @param props the output as should be expected in the template. */ public hasOutput(outputName: string, props: any): void { @@ -121,22 +121,24 @@ export class Template { /** * Get the set of matching Outputs that match the given properties in the CloudFormation template. + * @param outputName the name of the output. Provide '*' to match all Output names in the template. * @param props by default, matches all Outputs in the template. * When a literal object is provided, performs a partial match via `Match.objectLike()`. * Use the `Match` APIs to configure a different behaviour. */ - public findOutputs(props: any = {}): { [key: string]: any }[] { - return findOutputs(this.inspector, props); + public findOutputs(outputName: string, props: any = {}): { [key: string]: any }[] { + return findOutputs(this.inspector, outputName, props); } /** * Assert that a Mapping with the given properties exists in the CloudFormation template. * By default, performs partial matching on the resource, via the `Match.objectLike()`. * To configure different behavour, use other matchers in the `Match` class. + * @param outputName the name of the output. Provide '*' to match all Output names in the template. * @param props the output as should be expected in the template. */ - public hasMapping(props: any): void { - const matchError = hasMapping(this.inspector, props); + public hasMapping(outputName: string, props: any): void { + const matchError = hasMapping(this.inspector, outputName, props); if (matchError) { throw new Error(matchError); } @@ -144,12 +146,13 @@ export class Template { /** * Get the set of matching Mappings that match the given properties in the CloudFormation template. + * @param outputName the name of the output. Provide '*' to match all Output names in the template. * @param props by default, matches all Mappings in the template. * When a literal object is provided, performs a partial match via `Match.objectLike()`. * Use the `Match` APIs to configure a different behaviour. */ - public findMappings(props: any = {}): { [key: string]: any }[] { - return findMappings(this.inspector, props); + public findMappings(outputName: string, props: any = {}): { [key: string]: any }[] { + return findMappings(this.inspector, outputName, props); } /** diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index fc3c34deecd57..6d255eac0c0b7 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -370,7 +370,7 @@ describe('Template', () => { done(); }); - test('outputName not matching', (done) => { + test('value not matching with outputName', (done) => { const stack = new Stack(); new CfnOutput(stack, 'Foo', { value: 'Bar', @@ -394,7 +394,7 @@ describe('Template', () => { }); }); - test('name not matching', (done) => { + test('outputName not matching', (done) => { const stack = new Stack(); new CfnOutput(stack, 'Foo', { value: 'Bar', @@ -432,7 +432,7 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - const result = inspect.findOutputs({ Value: 'Fred' }); + const result = inspect.findOutputs('*', { Value: 'Fred' }); expect(result).toEqual([ { Value: 'Fred', Description: 'FooFred' }, { Value: 'Fred', Description: 'BarFred' }, @@ -446,7 +446,37 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - const result = inspect.findOutputs({ Value: 'Waldo' }); + const result = inspect.findOutputs('*', { Value: 'Waldo' }); + expect(result.length).toEqual(0); + }); + + test('matching specific output', () => { + const stack = new Stack(); + new CfnOutput(stack, 'Foo', { + value: 'Fred', + }); + new CfnOutput(stack, 'Baz', { + value: 'Waldo', + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findOutputs('Foo', { Value: 'Fred'}); + expect(result).toEqual([ + { Value: 'Fred' }, + ]); + }); + + test('not matching specific output', () => { + const stack = new Stack(); + new CfnOutput(stack, 'Foo', { + value: 'Fred', + }); + new CfnOutput(stack, 'Baz', { + value: 'Waldo', + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findOutputs('Foo', { Value: 'Waldo'}); expect(result.length).toEqual(0); }); }); @@ -467,7 +497,7 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - expect(() => inspect.hasMapping({ Foo: { Bar: 'Lightning' } })).not.toThrow(); + expect(() => inspect.hasMapping('*', { Foo: { Bar: 'Lightning' } })).not.toThrow(); }); test('not matching', (done) => { @@ -486,7 +516,7 @@ describe('Template', () => { const inspect = Template.fromStack(stack); expectToThrow( - () => inspect.hasMapping({ + () => inspect.hasMapping('*',{ Foo: { Bar: 'Qux' }, }), [ @@ -497,6 +527,52 @@ describe('Template', () => { ); done(); }); + + test('matching specific outputName', () => { + const stack = new Stack(); + new CfnMapping(stack, 'Foo', { + mapping: { + Foo: { Bar: 'Lightning', Fred: 'Waldo' }, + Baz: { Bar: 'Qux' }, + }, + }); + new CfnMapping(stack, 'Fred', { + mapping: { + Foo: { Bar: 'Lightning' }, + }, + }); + + const inspect = Template.fromStack(stack); + expect(() => inspect.hasMapping('Foo', { Baz: { Bar: 'Qux' } })).not.toThrow(); + }); + + test('not matching specific outputName', (done) => { + const stack = new Stack(); + new CfnMapping(stack, 'Foo', { + mapping: { + Foo: { Bar: 'Fred', Baz: 'Waldo' }, + Qux: { Bar: 'Fred' }, + }, + }); + new CfnMapping(stack, 'Fred', { + mapping: { + Foo: { Baz: 'Baz' }, + }, + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasMapping('Fred',{ + Foo: { Baz: 'Fred' }, + }), + [ + /1 mappings/, + /Expected Fred but received Baz/, + ], + done, + ); + done(); + }); }); describe('findMappings', () => { @@ -515,7 +591,7 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - const result = inspect.findMappings({ Foo: { Bar: 'Lightning' } }); + const result = inspect.findMappings('*', { Foo: { Bar: 'Lightning' } }); expect(result).toEqual([ { Foo: { Bar: 'Lightning', Fred: 'Waldo' }, @@ -534,7 +610,50 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - const result = inspect.findMappings({ Foo: { Bar: 'Waldo' } }); + const result = inspect.findMappings('*', { Foo: { Bar: 'Waldo' } }); + expect(result.length).toEqual(0); + }); + + test('matching with specific outputName', () => { + const stack = new Stack(); + new CfnMapping(stack, 'Foo', { + mapping: { + Foo: { Bar: 'Lightning', Fred: 'Waldo' }, + Baz: { Bar: 'Qux' }, + }, + }); + new CfnMapping(stack, 'Fred', { + mapping: { + Foo: { Bar: 'Lightning' }, + }, + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findMappings('Foo', { Foo: { Bar: 'Lightning' } }); + expect(result).toEqual([ + { + Foo: { Bar: 'Lightning', Fred: 'Waldo' }, + Baz: { Bar: 'Qux' }, + }, + ]); + }); + + test('not matching', () => { + const stack = new Stack(); + new CfnMapping(stack, 'Foo', { + mapping: { + Foo: { Bar: 'Lightning', Fred: 'Waldo' }, + Baz: { Bar: 'Qux' }, + }, + }); + new CfnMapping(stack, 'Fred', { + mapping: { + Foo: { Bar: 'Lightning' }, + }, + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findMappings('Fred', { Baz: { Bar: 'Qux' } }); expect(result.length).toEqual(0); }); }); From a86aea8d26de3900ea1bb3119fa9161de22f533a Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Tue, 7 Sep 2021 16:47:36 -0400 Subject: [PATCH 3/9] linter --- packages/@aws-cdk/assertions/lib/private/mappings.ts | 2 +- packages/@aws-cdk/assertions/test/template.test.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/mappings.ts b/packages/@aws-cdk/assertions/lib/private/mappings.ts index be83027e9276b..0c5b3d459faeb 100644 --- a/packages/@aws-cdk/assertions/lib/private/mappings.ts +++ b/packages/@aws-cdk/assertions/lib/private/mappings.ts @@ -3,7 +3,7 @@ import { filterLogicalId, formatFailure, matchSection } from './section'; export function findMappings(inspector: StackInspector, outputName: string, props: any = {}): { [key: string]: any }[] { const section: { [key: string] : {} } = inspector.value.Mappings; - const result = matchSection(filterLogicalId(section,outputName), props); + const result = matchSection(filterLogicalId(section, outputName), props); if (!result.match) { return []; diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index 6d255eac0c0b7..ca5c5c5ea1e58 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -460,7 +460,7 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - const result = inspect.findOutputs('Foo', { Value: 'Fred'}); + const result = inspect.findOutputs('Foo', { Value: 'Fred' }); expect(result).toEqual([ { Value: 'Fred' }, ]); @@ -476,7 +476,7 @@ describe('Template', () => { }); const inspect = Template.fromStack(stack); - const result = inspect.findOutputs('Foo', { Value: 'Waldo'}); + const result = inspect.findOutputs('Foo', { Value: 'Waldo' }); expect(result.length).toEqual(0); }); }); @@ -516,7 +516,7 @@ describe('Template', () => { const inspect = Template.fromStack(stack); expectToThrow( - () => inspect.hasMapping('*',{ + () => inspect.hasMapping('*', { Foo: { Bar: 'Qux' }, }), [ @@ -562,7 +562,7 @@ describe('Template', () => { const inspect = Template.fromStack(stack); expectToThrow( - () => inspect.hasMapping('Fred',{ + () => inspect.hasMapping('Fred', { Foo: { Baz: 'Fred' }, }), [ From 8f9b74e10df6ab8e779bb03d8af644547e72ba36 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Tue, 7 Sep 2021 17:00:36 -0400 Subject: [PATCH 4/9] fix neptune tests --- packages/@aws-cdk/aws-neptune/test/instance.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-neptune/test/instance.test.ts b/packages/@aws-cdk/aws-neptune/test/instance.test.ts index 38a6981ab2a78..ed83e1506496a 100644 --- a/packages/@aws-cdk/aws-neptune/test/instance.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/instance.test.ts @@ -43,7 +43,7 @@ describe('DatabaseInstance', () => { }); // THEN - Template.fromStack(stack).hasOutput({ + Template.fromStack(stack).hasOutput(exportName, { Export: { Name: exportName }, Value: { 'Fn::Join': [ @@ -78,7 +78,7 @@ describe('DatabaseInstance', () => { }); // THEN - Template.fromStack(stack).hasOutput({ + Template.fromStack(stack).hasOutput('EndpointOutput', { Export: { Name: endpointExportName }, Value: `${instanceEndpointAddress}:${port}`, }); From 59691719500895e555b884bd216c1bd10a770ad3 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Tue, 7 Sep 2021 17:13:37 -0400 Subject: [PATCH 5/9] fix firehose tests --- .../@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts b/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts index 7c36a29e379b5..f716e56a8f326 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts @@ -491,7 +491,7 @@ describe('delivery stream', () => { destinations: [mockS3Destination], }); - Template.fromStack(stack).hasMapping({ + Template.fromStack(stack).hasMapping('*', { 'af-south-1': { FirehoseCidrBlock: '13.244.121.224/27', }, From 9b3d40ecc8af1529589bcb2e3912accfef08f3fa Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Wed, 8 Sep 2021 11:26:41 -0400 Subject: [PATCH 6/9] change param name from outputName to logicalId --- .../assertions/lib/private/mappings.ts | 8 +++---- .../assertions/lib/private/outputs.ts | 12 +++++----- .../assertions/lib/private/section.ts | 8 +++---- packages/@aws-cdk/assertions/lib/template.ts | 24 +++++++++---------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/mappings.ts b/packages/@aws-cdk/assertions/lib/private/mappings.ts index 0c5b3d459faeb..266e322bb1139 100644 --- a/packages/@aws-cdk/assertions/lib/private/mappings.ts +++ b/packages/@aws-cdk/assertions/lib/private/mappings.ts @@ -1,9 +1,9 @@ import { StackInspector } from '../vendored/assert'; import { filterLogicalId, formatFailure, matchSection } from './section'; -export function findMappings(inspector: StackInspector, outputName: string, props: any = {}): { [key: string]: any }[] { +export function findMappings(inspector: StackInspector, logicalId: string, props: any = {}): { [key: string]: any }[] { const section: { [key: string] : {} } = inspector.value.Mappings; - const result = matchSection(filterLogicalId(section, outputName), props); + const result = matchSection(filterLogicalId(section, logicalId), props); if (!result.match) { return []; @@ -12,9 +12,9 @@ export function findMappings(inspector: StackInspector, outputName: string, prop return result.matches; } -export function hasMapping(inspector: StackInspector, outputName: string, props: any): string | void { +export function hasMapping(inspector: StackInspector, logicalId: string, props: any): string | void { const section: { [key: string]: {} } = inspector.value.Mappings; - const result = matchSection(filterLogicalId(section, outputName), props); + const result = matchSection(filterLogicalId(section, logicalId), props); if (result.match) { return; diff --git a/packages/@aws-cdk/assertions/lib/private/outputs.ts b/packages/@aws-cdk/assertions/lib/private/outputs.ts index 8d97353cf56d1..870e00555b254 100644 --- a/packages/@aws-cdk/assertions/lib/private/outputs.ts +++ b/packages/@aws-cdk/assertions/lib/private/outputs.ts @@ -1,9 +1,9 @@ import { StackInspector } from '../vendored/assert'; import { filterLogicalId, formatFailure, matchSection } from './section'; -export function findOutputs(inspector: StackInspector, outputName: string, props: any = {}): { [key: string]: any }[] { +export function findOutputs(inspector: StackInspector, logicalId: string, props: any = {}): { [key: string]: any }[] { const section: { [key: string] : {} } = inspector.value.Outputs; - const result = matchSection(filterLogicalId(section, outputName), props); + const result = matchSection(filterLogicalId(section, logicalId), props); if (!result.match) { return []; @@ -12,19 +12,19 @@ export function findOutputs(inspector: StackInspector, outputName: string, props return result.matches; } -export function hasOutput(inspector: StackInspector, outputName: string, props: any): string | void { +export function hasOutput(inspector: StackInspector, logicalId: string, props: any): string | void { const section: { [key: string]: {} } = inspector.value.Outputs; - const result = matchSection(filterLogicalId(section, outputName), props); + const result = matchSection(filterLogicalId(section, logicalId), props); if (result.match) { return; } if (result.closestResult === undefined) { - return `No outputs named ${outputName} found in the template.`; + return `No outputs named ${logicalId} found in the template.`; } return [ - `Template has ${result.analyzedCount} outputs named ${outputName}, but none match as expected.`, + `Template has ${result.analyzedCount} outputs named ${logicalId}, but none match as expected.`, formatFailure(result.closestResult), ].join('\n'); } diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index c7e1d93ecc0f7..59ad55241e581 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -57,11 +57,11 @@ function leftPad(x: string, indent: number = 2): string { return pad + x.split('\n').join(`\n${pad}`); } -export function filterLogicalId(section: { [key: string]: {} }, outputName: string): { [key: string]: {} } { - // default signal for all outputs is '*' - if (outputName === '*') return section; +export function filterLogicalId(section: { [key: string]: {} }, logicalId: string): { [key: string]: {} } { + // default signal for all logicalIds is '*' + if (logicalId === '*') return section; return Object.entries(section ?? {}) - .filter(([k, _]) => k === outputName) + .filter(([k, _]) => k === logicalId) .reduce((agg, [k, v]) => { return { ...agg, [k]: v }; }, {}); } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/template.ts b/packages/@aws-cdk/assertions/lib/template.ts index f67d7e64f3018..d642e74962080 100644 --- a/packages/@aws-cdk/assertions/lib/template.ts +++ b/packages/@aws-cdk/assertions/lib/template.ts @@ -109,11 +109,11 @@ export class Template { * Assert that an Output with the given properties exists in the CloudFormation template. * By default, performs partial matching on the resource, via the `Match.objectLike()`. * To configure different behavour, use other matchers in the `Match` class. - * @param outputName the name of the output. Provide '*' to match all Output names in the template. + * @param logicalId the name of the output. Provide `'*'` to match all outputs in the template. * @param props the output as should be expected in the template. */ - public hasOutput(outputName: string, props: any): void { - const matchError = hasOutput(this.inspector, outputName, props); + public hasOutput(logicalId: string, props: any): void { + const matchError = hasOutput(this.inspector, logicalId, props); if (matchError) { throw new Error(matchError); } @@ -121,24 +121,24 @@ export class Template { /** * Get the set of matching Outputs that match the given properties in the CloudFormation template. - * @param outputName the name of the output. Provide '*' to match all Output names in the template. + * @param logicalId the name of the output. Provide `'*'` to match all outputs in the template. * @param props by default, matches all Outputs in the template. * When a literal object is provided, performs a partial match via `Match.objectLike()`. * Use the `Match` APIs to configure a different behaviour. */ - public findOutputs(outputName: string, props: any = {}): { [key: string]: any }[] { - return findOutputs(this.inspector, outputName, props); + public findOutputs(logicalId: string, props: any = {}): { [key: string]: any }[] { + return findOutputs(this.inspector, logicalId, props); } /** * Assert that a Mapping with the given properties exists in the CloudFormation template. * By default, performs partial matching on the resource, via the `Match.objectLike()`. * To configure different behavour, use other matchers in the `Match` class. - * @param outputName the name of the output. Provide '*' to match all Output names in the template. + * @param logicalId the name of the mapping. Provide `'*'` to match all mappings in the template. * @param props the output as should be expected in the template. */ - public hasMapping(outputName: string, props: any): void { - const matchError = hasMapping(this.inspector, outputName, props); + public hasMapping(logicalId: string, props: any): void { + const matchError = hasMapping(this.inspector, logicalId, props); if (matchError) { throw new Error(matchError); } @@ -146,13 +146,13 @@ export class Template { /** * Get the set of matching Mappings that match the given properties in the CloudFormation template. - * @param outputName the name of the output. Provide '*' to match all Output names in the template. + * @param logicalId the name of the mapping. Provide `'*'` to match all mappings in the template. * @param props by default, matches all Mappings in the template. * When a literal object is provided, performs a partial match via `Match.objectLike()`. * Use the `Match` APIs to configure a different behaviour. */ - public findMappings(outputName: string, props: any = {}): { [key: string]: any }[] { - return findMappings(this.inspector, outputName, props); + public findMappings(logicalId: string, props: any = {}): { [key: string]: any }[] { + return findMappings(this.inspector, logicalId, props); } /** From 36d1f102b6c48bbd3882c3c07444d6d7a5ba07d3 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Wed, 8 Sep 2021 11:43:16 -0400 Subject: [PATCH 7/9] update readme --- packages/@aws-cdk/assertions/README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index d651ab72c1bc3..7b84a9ec8ad12 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -107,16 +107,27 @@ By default, the `hasResource()` and `hasResourceProperties()` APIs perform deep partial object matching. This behavior can be configured using matchers. See subsequent section on [special matchers](#special-matchers). -## Other Sections +## Output and Mapping Matching -Similar to the `hasResource()` and `findResources()`, we have equivalent methods -to check and find other sections of the CloudFormation resources. +The module allows you to assert that an output or matching has specific properties. The following code asserts that a resource contains an output with a `logicalId` of `Foo` and the specified properties - -* Outputs - `hasOutput()` and `findOutputs()` -* Mapping - `hasMapping()` and `findMappings()` +```ts +assert.hasOutput('Foo', { + Value: 'Bar', + Export: { Name: 'ExportBaz' }, +}); +``` + +Alternatively, if you want to match the value to all outputs, you can use the `'*'` special case as the `logicalId`. + +```ts +assert.hasOutput('*', { + Value: 'Bar', + Export: { Name: 'ExportBaz' }, +}); +``` -All of the defaults and behaviour documented for `hasResource()` and -`findResources()` apply to these methods. +`findOutputs()` will return a list of outputs that match the `logicalId` and `props`, and you can use the `'*'` special case as well. `hasMapping()` and `findMappings()` follow a similar pattern to output matching. ## Special Matchers From a209bd3bb4a4d5e5f64524641205e3d591d37d13 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Wed, 8 Sep 2021 11:44:52 -0400 Subject: [PATCH 8/9] better structure --- packages/@aws-cdk/assertions/README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index 7b84a9ec8ad12..d47f3a4323683 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -109,7 +109,9 @@ See subsequent section on [special matchers](#special-matchers). ## Output and Mapping Matching -The module allows you to assert that an output or matching has specific properties. The following code asserts that a resource contains an output with a `logicalId` of `Foo` and the specified properties - +The module allows you to assert that an output or matching has specific properties. +The following code asserts that a resource contains an output with a `logicalId` of +`Foo` and the specified properties - ```ts assert.hasOutput('Foo', { @@ -118,7 +120,8 @@ assert.hasOutput('Foo', { }); ``` -Alternatively, if you want to match the value to all outputs, you can use the `'*'` special case as the `logicalId`. +Alternatively, if you want to match the value to all outputs, you can use the `'*'` +special case as the `logicalId`. ```ts assert.hasOutput('*', { @@ -127,7 +130,9 @@ assert.hasOutput('*', { }); ``` -`findOutputs()` will return a list of outputs that match the `logicalId` and `props`, and you can use the `'*'` special case as well. `hasMapping()` and `findMappings()` follow a similar pattern to output matching. +`findOutputs()` will return a list of outputs that match the `logicalId` and `props`, +and you can use the `'*'` special case as well. `hasMapping()` and `findMappings()` +follow a similar pattern to output matching. ## Special Matchers From 5c670cdfc0b661ef8d25831fd15641eec090b153 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Wed, 8 Sep 2021 12:47:26 -0400 Subject: [PATCH 9/9] readme CR suggestions --- packages/@aws-cdk/assertions/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index d47f3a4323683..706d467eb3e59 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -107,11 +107,11 @@ By default, the `hasResource()` and `hasResourceProperties()` APIs perform deep partial object matching. This behavior can be configured using matchers. See subsequent section on [special matchers](#special-matchers). -## Output and Mapping Matching +## Output and Mapping sections -The module allows you to assert that an output or matching has specific properties. -The following code asserts that a resource contains an output with a `logicalId` of -`Foo` and the specified properties - +The module allows you to assert that the CloudFormation template contains an Output +that matches specific properties. The following code asserts that a template contains +an Output with a `logicalId` of `Foo` and the specified properties - ```ts assert.hasOutput('Foo', { @@ -120,8 +120,7 @@ assert.hasOutput('Foo', { }); ``` -Alternatively, if you want to match the value to all outputs, you can use the `'*'` -special case as the `logicalId`. +If you want to match against all Outputs in the template, use `*` as the `logicalId`. ```ts assert.hasOutput('*', { @@ -131,8 +130,9 @@ assert.hasOutput('*', { ``` `findOutputs()` will return a list of outputs that match the `logicalId` and `props`, -and you can use the `'*'` special case as well. `hasMapping()` and `findMappings()` -follow a similar pattern to output matching. +and you can use the `'*'` special case as well. + +The APIs `hasMapping()` and `findMappings()` provide similar functionalities. ## Special Matchers