From d0d6fc520491351b44cac78aa90284c82a9499b2 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 10:29:33 +0000 Subject: [PATCH 01/23] feat(assertions): support for parameters (#18469) Add the ability to match parameters in the template. Closes #16720 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../assertions/lib/private/parameters.ts | 30 ++++ .../assertions/lib/private/template.ts | 10 +- packages/@aws-cdk/assertions/lib/template.ts | 25 +++ .../@aws-cdk/assertions/test/template.test.ts | 152 +++++++++++++++++- 4 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 packages/@aws-cdk/assertions/lib/private/parameters.ts diff --git a/packages/@aws-cdk/assertions/lib/private/parameters.ts b/packages/@aws-cdk/assertions/lib/private/parameters.ts new file mode 100644 index 0000000000000..b708460caf399 --- /dev/null +++ b/packages/@aws-cdk/assertions/lib/private/parameters.ts @@ -0,0 +1,30 @@ +import { filterLogicalId, formatFailure, matchSection } from './section'; +import { Template } from './template'; + +export function findParameters(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { + const section: { [key: string] : {} } = template.Parameters; + const result = matchSection(filterLogicalId(section, logicalId), props); + + if (!result.match) { + return {}; + } + + return result.matches; +} + +export function hasParameter(template: Template, logicalId: string, props: any): string | void { + const section: { [key: string] : {} } = template.Parameters; + const result = matchSection(filterLogicalId(section, logicalId), props); + if (result.match) { + return; + } + + if (result.closestResult === undefined) { + return 'No parameters found in the template'; + } + + return [ + `Template has ${result.analyzedCount} parameters, but none match as expected.`, + formatFailure(result.closestResult), + ].join('\n'); +} diff --git a/packages/@aws-cdk/assertions/lib/private/template.ts b/packages/@aws-cdk/assertions/lib/private/template.ts index 3b44368138435..72dbeb8b64661 100644 --- a/packages/@aws-cdk/assertions/lib/private/template.ts +++ b/packages/@aws-cdk/assertions/lib/private/template.ts @@ -3,7 +3,8 @@ export type Template = { Resources: { [logicalId: string]: Resource }, Outputs: { [logicalId: string]: Output }, - Mappings: { [logicalId: string]: Mapping } + Mappings: { [logicalId: string]: Mapping }, + Parameters: { [logicalId: string]: Parameter } } export type Resource = { @@ -13,4 +14,9 @@ export type Resource = { export type Output = { [key: string]: any }; -export type Mapping = { [key: string]: any }; \ No newline at end of file +export type Mapping = { [key: string]: any }; + +export type Parameter = { + Type: string; + [key: string]: any; +} \ 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 dfc830cf8d822..631c9f7137dc4 100644 --- a/packages/@aws-cdk/assertions/lib/template.ts +++ b/packages/@aws-cdk/assertions/lib/template.ts @@ -5,6 +5,7 @@ import { Match } from './match'; import { Matcher } from './matcher'; import { findMappings, hasMapping } from './private/mappings'; import { findOutputs, hasOutput } from './private/outputs'; +import { findParameters, hasParameter } from './private/parameters'; import { countResources, findResources, hasResource, hasResourceProperties } from './private/resources'; import { Template as TemplateType } from './private/template'; @@ -108,6 +109,30 @@ export class Template { return findResources(this.template, type, props); } + /** + * Assert that a Parameter with the given properties exists in the CloudFormation template. + * By default, performs partial matching on the parameter, via the `Match.objectLike()`. + * To configure different behavior, use other matchers in the `Match` class. + * @param logicalId the name of the parameter. Provide `'*'` to match all parameters in the template. + * @param props the parameter as should be expected in the template. + */ + public hasParameter(logicalId: string, props: any): void { + const matchError = hasParameter(this.template, logicalId, props); + if (matchError) { + throw new Error(matchError); + } + } + + /** + * Get the set of matching Parameters that match the given properties in the CloudFormation template. + * @param logicalId the name of the parameter. Provide `'*'` to match all parameters in the template. + * @param props by default, matches all Parameters 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 findParameters(logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { + return findParameters(this.template, logicalId, props); + } + /** * 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()`. diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index f5068cede6265..dd8377892f405 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -1,4 +1,4 @@ -import { App, CfnMapping, CfnOutput, CfnResource, NestedStack, Stack } from '@aws-cdk/core'; +import { App, CfnMapping, CfnOutput, CfnParameter, CfnResource, NestedStack, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Capture, Match, Template } from '../lib'; @@ -708,6 +708,156 @@ describe('Template', () => { }); }); + describe('findParameters', () => { + test('matching', () => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findParameters('*', { Type: 'String' }); + expect(result).toEqual({ + p1: { + Description: 'string parameter', + Type: 'String', + }, + }); + }); + + test('not matching', () => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findParameters('*', { Type: 'Number' }); + expect(Object.keys(result).length).toEqual(0); + }); + + test('matching with specific parameter name', () => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findParameters('p1', { Type: 'String' }); + expect(result).toEqual({ + p1: { + Description: 'string parameter', + Type: 'String', + }, + }); + }); + + test('not matching specific parameter name', () => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findParameters('p3', { Type: 'String' }); + expect(Object.keys(result).length).toEqual(0); + }); + }); + + describe('hasParameter', () => { + test('matching', () => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + expect(() => inspect.findParameters('p3', { Type: 'String' })).not.toThrow(); + }); + + test('not matching', (done) => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasParameter('*', { Type: 'CommaDelimitedList' }), + [ + /2 parameters/, + /Expected CommaDelimitedList but received String/, + ], + done, + ); + done(); + }); + + test('matching specific parameter name', () => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + expect(() => inspect.findParameters('p1', { Type: 'String' })).not.toThrow(); + }); + + test('not matching specific parameter name', (done) => { + const stack = new Stack(); + new CfnParameter(stack, 'p1', { + type: 'String', + description: 'string parameter', + }); + new CfnParameter(stack, 'p2', { + type: 'Number', + description: 'number parameter', + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasParameter('p2', { Type: 'CommaDelimitedList' }), + [ + /1 parameter/, + /Expected CommaDelimitedList but received Number/, + ], + done, + ); + done(); + }); + }); + describe('findMappings', () => { test('matching', () => { const stack = new Stack(); From c9f675c0a28e3fcf22a7caa445c1afb1a0afb355 Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Tue, 18 Jan 2022 03:17:56 -0800 Subject: [PATCH 02/23] docs(cfnspec): update CloudFormation documentation (#18479) Co-authored-by: AWS CDK Team Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json index 9237148f89e19..5b6f0ce4d8f0c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json @@ -11448,6 +11448,7 @@ "AWS::EC2::Instance": { "attributes": { "AvailabilityZone": "The Availability Zone where the specified instance is launched. For example: `us-east-1b` .\n\nYou can retrieve a list of all Availability Zones for a Region by using the [Fn::GetAZs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getavailabilityzones.html) intrinsic function.", + "PrivateDnsName": "The private DNS name of the specified instance. For example: `ip-10-24-34-0.ec2.internal` .", "PrivateIp": "The private IP address of the specified instance. For example: `10.24.34.0` .", "PublicDnsName": "The public DNS name of the specified instance. For example: `ec2-107-20-50-45.compute-1.amazonaws.com` .", "PublicIp": "The public IP address of the specified instance. For example: `192.0.2.0` .", From 38e1fe42d8b30d6afaf4a3ccc90dd15d6a5d8255 Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Tue, 18 Jan 2022 04:05:41 -0800 Subject: [PATCH 03/23] feat(cfnspec): cloudformation spec v53.0.0 (#18480) Co-authored-by: AWS CDK Team Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/@aws-cdk/cfnspec/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 80f81e58e20e6..9d2b6815ee159 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,4 +1,10 @@ +## Unapplied changes + +* AWS::ECS is at 51.0.0 +* AWS::SageMaker is at 51.0.0 + + ## Unapplied changes * AWS::ECS is at 51.0.0 From 91f3539f4aa8383adcb2273790ddb469fb1274a6 Mon Sep 17 00:00:00 2001 From: Michael Kaiser Date: Tue, 18 Jan 2022 07:56:33 -0600 Subject: [PATCH 04/23] fix(secretsmanager): Secret requires KMS key for some same-account access (#17812) Fix for #15450 Previous code did not check if the account IDs were the different. This checks if CDK is able to resolve the account ids and they are different then fail otherwise let the user create a secret. FYI first PR. Let me know if there is something that I missed. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-secretsmanager/lib/secret.ts | 6 ++- .../aws-secretsmanager/test/secret.test.ts | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index cc51f4b009d26..81e8fa2f4ca81 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { ArnFormat, FeatureFlags, Fn, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core'; +import { ArnFormat, FeatureFlags, Fn, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token, TokenComparison } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { IConstruct, Construct } from 'constructs'; import { ResourcePolicy } from './policy'; @@ -306,8 +306,10 @@ abstract class SecretBase extends Resource implements ISecret { ); } + const crossAccount = Token.compareStrings(Stack.of(this).account, grantee.grantPrincipal.principalAccount || ''); + // Throw if secret is not imported and it's shared cross account and no KMS key is provided - if (this instanceof Secret && result.resourceStatement && !this.encryptionKey) { + if (this instanceof Secret && result.resourceStatement && (!this.encryptionKey && crossAccount === TokenComparison.DIFFERENT)) { throw new Error('KMS Key must be provided for cross account access to Secret'); } diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts index 66ec71c497474..0068a8d46652e 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts @@ -267,6 +267,46 @@ describe('secretStringBeta1', () => { }); test('grantRead', () => { + // GIVEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + const role = new iam.Role(stack, 'Role', { assumedBy: new iam.AccountRootPrincipal() }); + + // WHEN + secret.grantRead(role); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + Action: [ + 'secretsmanager:GetSecretValue', + 'secretsmanager:DescribeSecret', + ], + Effect: 'Allow', + Resource: { Ref: 'SecretA720EF05' }, + }], + }, + }); +}); + +test('Error when grantRead with different role and no KMS', () => { + // GIVEN + const testStack = new cdk.Stack(app, 'TestStack', { + env: { + account: '123456789012', + }, + }); + const secret = new secretsmanager.Secret(testStack, 'Secret'); + const role = iam.Role.fromRoleArn(testStack, 'RoleFromArn', 'arn:aws:iam::111111111111:role/SomeRole'); + + // THEN + expect(() => { + secret.grantRead(role); + }).toThrowError('KMS Key must be provided for cross account access to Secret'); +}); + +test('grantRead with KMS Key', () => { // GIVEN const key = new kms.Key(stack, 'KMS'); const secret = new secretsmanager.Secret(stack, 'Secret', { encryptionKey: key }); From 2a80e4b113bac0716f5aa1d4806e425759da1743 Mon Sep 17 00:00:00 2001 From: Jericho Tolentino <68654047+jericht@users.noreply.github.com> Date: Tue, 18 Jan 2022 08:43:42 -0600 Subject: [PATCH 05/23] fix(ec2): launch template names in imdsv2 not unique across stacks (under feature flag) (#17766) Fixes https://github.com/aws/aws-cdk/issues/17656 ### Notes Changes the name for the `LaunchTemplate` created in the aspect that enforces IMDSv2 on EC2 instances to a unique name. Introduces a new feature flag (`@aws-cdk/aws-ec2:uniqueImdsv2TemplateName`) to change the launch template name. ### Testing Added a unit test ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/aspects/require-imdsv2-aspect.ts | 11 ++-- .../aspects/require-imdsv2-aspect.test.ts | 53 +++++++++++++++++++ packages/@aws-cdk/cx-api/lib/features.ts | 13 +++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/aspects/require-imdsv2-aspect.ts b/packages/@aws-cdk/aws-ec2/lib/aspects/require-imdsv2-aspect.ts index f1a5270f1fb08..abad030c160a8 100644 --- a/packages/@aws-cdk/aws-ec2/lib/aspects/require-imdsv2-aspect.ts +++ b/packages/@aws-cdk/aws-ec2/lib/aspects/require-imdsv2-aspect.ts @@ -1,4 +1,6 @@ import * as cdk from '@aws-cdk/core'; +import { FeatureFlags } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { CfnLaunchTemplate } from '../ec2.generated'; import { Instance } from '../instance'; import { LaunchTemplate } from '../launch-template'; @@ -83,17 +85,20 @@ export class InstanceRequireImdsv2Aspect extends RequireImdsv2Aspect { return; } - const name = `${node.node.id}LaunchTemplate`; const launchTemplate = new CfnLaunchTemplate(node, 'LaunchTemplate', { launchTemplateData: { metadataOptions: { httpTokens: 'required', }, }, - launchTemplateName: name, }); + if (FeatureFlags.of(node).isEnabled(cxapi.EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME)) { + launchTemplate.launchTemplateName = cdk.Names.uniqueId(launchTemplate); + } else { + launchTemplate.launchTemplateName = `${node.node.id}LaunchTemplate`; + } node.instance.launchTemplate = { - launchTemplateName: name, + launchTemplateName: launchTemplate.launchTemplateName, version: launchTemplate.getAtt('LatestVersionNumber').toString(), }; } diff --git a/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts b/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts index ade2eaeab1f1d..189244bc251f5 100644 --- a/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/aspects/require-imdsv2-aspect.test.ts @@ -4,7 +4,9 @@ import { haveResourceLike, } from '@aws-cdk/assert-internal'; import '@aws-cdk/assert-internal/jest'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { CfnLaunchTemplate, Instance, @@ -135,6 +137,57 @@ describe('RequireImdsv2Aspect', () => { trace: undefined, }); }); + + testFutureBehavior('launch template name is unique with feature flag', { [cxapi.EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: true }, cdk.App, (app2) => { + // GIVEN + const otherStack = new cdk.Stack(app2, 'OtherStack'); + const otherVpc = new Vpc(otherStack, 'OtherVpc'); + const otherInstance = new Instance(otherStack, 'OtherInstance', { + vpc: otherVpc, + instanceType: new InstanceType('t2.micro'), + machineImage: MachineImage.latestAmazonLinux(), + }); + const imdsv2Stack = new cdk.Stack(app2, 'RequireImdsv2Stack'); + const imdsv2Vpc = new Vpc(imdsv2Stack, 'Vpc'); + const instance = new Instance(imdsv2Stack, 'Instance', { + vpc: imdsv2Vpc, + instanceType: new InstanceType('t2.micro'), + machineImage: MachineImage.latestAmazonLinux(), + }); + const aspect = new InstanceRequireImdsv2Aspect(); + + // WHEN + cdk.Aspects.of(imdsv2Stack).add(aspect); + cdk.Aspects.of(otherStack).add(aspect); + app2.synth(); + + // THEN + const launchTemplate = instance.node.tryFindChild('LaunchTemplate') as LaunchTemplate; + const otherLaunchTemplate = otherInstance.node.tryFindChild('LaunchTemplate') as LaunchTemplate; + expect(launchTemplate).toBeDefined(); + expect(otherLaunchTemplate).toBeDefined(); + expect(launchTemplate.launchTemplateName !== otherLaunchTemplate.launchTemplateName); + }); + + testLegacyBehavior('launch template name uses legacy id without feature flag', cdk.App, (app2) => { + // GIVEN + const imdsv2Stack = new cdk.Stack(app2, 'RequireImdsv2Stack'); + const imdsv2Vpc = new Vpc(imdsv2Stack, 'Vpc'); + const instance = new Instance(imdsv2Stack, 'Instance', { + vpc: imdsv2Vpc, + instanceType: new InstanceType('t2.micro'), + machineImage: MachineImage.latestAmazonLinux(), + }); + const aspect = new InstanceRequireImdsv2Aspect(); + + // WHEN + cdk.Aspects.of(imdsv2Stack).add(aspect); + app2.synth(); + + // THEN + const launchTemplate = instance.node.tryFindChild('LaunchTemplate') as LaunchTemplate; + expect(launchTemplate.launchTemplateName).toEqual(`${instance.node.id}LaunchTemplate`); + }); }); describe('LaunchTemplateRequireImdsv2Aspect', () => { diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 71ed4856ec85a..f4ced76f60d3a 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -178,6 +178,17 @@ export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; */ export const ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER = '@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver'; +/** + * Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names. + * + * Previously, the generated Launch Template names were only unique within a stack because they were based only on the + * `Instance` construct ID. If another stack that has an `Instance` with the same construct ID is deployed in the same + * account and region, the deployments would always fail as the generated Launch Template names were the same. + * + * The new implementation addresses this issue by generating the Launch Template name with the `Names.uniqueId` method. + */ +export const EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME = '@aws-cdk/aws-ec2:uniqueImdsv2TemplateName'; + /** * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default @@ -206,6 +217,7 @@ export const FUTURE_FLAGS: { [key: string]: boolean } = { [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: true, + [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: true, // We will advertise this flag when the feature is complete // [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', @@ -245,6 +257,7 @@ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { [LAMBDA_RECOGNIZE_VERSION_PROPS]: false, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: false, [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: false, + [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: false, }; export function futureFlagDefault(flag: string): boolean | undefined { From 717bb047ef9513a7792f8cea6919c74125fc5fdb Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 15:30:39 +0000 Subject: [PATCH 06/23] chore(s3-assets): migrated tests to `assertions` (#18483) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-s3-assets/package.json | 2 +- .../@aws-cdk/aws-s3-assets/test/asset.test.ts | 37 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 489749cfee25e..80996d4ebc255 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -77,7 +77,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts index 7a335ab3b7bb2..f04218f95929d 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts +++ b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts @@ -1,12 +1,11 @@ -import { ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; import { Asset } from '../lib/asset'; const SAMPLE_ASSET_DIR = path.join(__dirname, 'sample-asset-directory'); @@ -79,7 +78,7 @@ test('"file" assets', () => { expect(entry).toBeTruthy(); // synthesize first so "prepare" is called - const template = SynthUtils.synthesize(stack).template; + const template = Template.fromStack(stack); expect(stack.resolve(entry!.data)).toEqual({ path: 'asset.78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197.txt', @@ -92,8 +91,12 @@ test('"file" assets', () => { }); // verify that now the template contains parameters for this asset - expect(template.Parameters.AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A.Type).toBe('String'); - expect(template.Parameters.AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3VersionKey9482DC35.Type).toBe('String'); + expect(template.findParameters('AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A') + .AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3Bucket2C60F94A.Type) + .toBe('String'); + expect(template.findParameters('AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3VersionKey9482DC35') + .AssetParameters78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197S3VersionKey9482DC35.Type) + .toBe('String'); }); test('"readers" or "grantRead" can be used to grant read permissions on the asset to a principal', () => { @@ -108,7 +111,7 @@ test('"readers" or "grantRead" can be used to grant read permissions on the asse asset.grantRead(group); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -200,13 +203,13 @@ test('addResourceMetadata can be used to add CFN metadata to resources', () => { asset.addResourceMetadata(resource, 'PropName'); // THEN - expect(stack).toHaveResource('My::Resource::Type', { + Template.fromStack(stack).hasResource('My::Resource::Type', { Metadata: { 'aws:asset:path': 'asset.6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2', 'aws:asset:is-bundled': false, 'aws:asset:property': 'PropName', }, - }, ResourcePart.CompleteDefinition); + }); }); test('asset metadata is only emitted if ASSET_RESOURCE_METADATA_ENABLED_CONTEXT is defined', () => { @@ -220,13 +223,13 @@ test('asset metadata is only emitted if ASSET_RESOURCE_METADATA_ENABLED_CONTEXT asset.addResourceMetadata(resource, 'PropName'); // THEN - expect(stack).not.toHaveResource('My::Resource::Type', { + Template.fromStack(stack).hasResource('My::Resource::Type', Match.not({ Metadata: { 'aws:asset:path': SAMPLE_ASSET_DIR, 'aws:asset:is-bundled': false, 'aws:asset:property': 'PropName', }, - }, ResourcePart.CompleteDefinition); + })); }); test('nested assemblies share assets: legacy synth edition', () => { @@ -350,8 +353,8 @@ describe('staging', () => { // WHEN asset.addResourceMetadata(resource, 'PropName'); - const template = SynthUtils.synthesize(stack).template; - expect(template.Resources.MyResource.Metadata).toEqual({ + const template = Template.fromStack(stack); + expect(template.findResources('My::Resource::Type').MyResource.Metadata).toEqual({ 'aws:asset:path': 'asset.6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2', 'aws:asset:is-bundled': false, 'aws:asset:property': 'PropName', @@ -377,8 +380,8 @@ describe('staging', () => { // WHEN asset.addResourceMetadata(resource, 'PropName'); - const template = SynthUtils.synthesize(stack).template; - expect(template.Resources.MyResource.Metadata).toEqual({ + const template = Template.fromStack(stack); + expect(template.findResources('My::Resource::Type').MyResource.Metadata).toEqual({ 'aws:asset:path': SAMPLE_ASSET_DIR, 'aws:asset:is-bundled': false, 'aws:asset:property': 'PropName', From a295dc6f85bd42d64dfa96ba1cc2dcaab3d5c8fb Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 16:18:54 +0000 Subject: [PATCH 07/23] chore(kinesis): migrated tests to `assertions` (#18482) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-kinesis/package.json | 2 +- .../@aws-cdk/aws-kinesis/test/stream.test.ts | 75 +++++++++---------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 37495af6cf1cd..0b1aea08d72df 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -79,7 +79,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts index 8e4fa385133dd..e1fce397cce4c 100644 --- a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts +++ b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { arrayWith } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; @@ -16,7 +15,7 @@ describe('Kinesis data streams', () => { new Stream(stack, 'MyStream'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -72,7 +71,7 @@ describe('Kinesis data streams', () => { new Stream(stack, 'MyStream'); new Stream(stack, 'MyOtherStream'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -161,7 +160,7 @@ describe('Kinesis data streams', () => { shardCount: 2, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -218,7 +217,7 @@ describe('Kinesis data streams', () => { retentionPeriod: Duration.hours(168), }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -292,7 +291,7 @@ describe('Kinesis data streams', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -335,7 +334,7 @@ describe('Kinesis data streams', () => { }); // THEN - expect(stack).toHaveResource('AWS::Kinesis::Stream', { + Template.fromStack(stack).hasResourceProperties('AWS::Kinesis::Stream', { ShardCount: 1, StreamModeDetails: { StreamMode: StreamMode.PROVISIONED, @@ -357,11 +356,11 @@ describe('Kinesis data streams', () => { encryption: StreamEncryption.KMS, }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { Description: 'Created by Default/MyStream', }); - expect(stack).toHaveResource('AWS::Kinesis::Stream', { + Template.fromStack(stack).hasResourceProperties('AWS::Kinesis::Stream', { StreamEncryption: { EncryptionType: 'KMS', KeyId: stack.resolve(stream.encryptionKey?.keyArn), @@ -381,11 +380,11 @@ describe('Kinesis data streams', () => { encryptionKey: explicitKey, }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { Description: 'Explicit Key', }); - expect(stack).toHaveResource('AWS::Kinesis::Stream', { + Template.fromStack(stack).hasResourceProperties('AWS::Kinesis::Stream', { ShardCount: 1, StreamModeDetails: { StreamMode: StreamMode.PROVISIONED, @@ -405,7 +404,7 @@ describe('Kinesis data streams', () => { streamMode: StreamMode.PROVISIONED, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -462,7 +461,7 @@ describe('Kinesis data streams', () => { streamMode: StreamMode.ON_DEMAND, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -531,17 +530,17 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantRead(user); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: 'kms:Decrypt', Effect: 'Allow', Resource: stack.resolve(stream.encryptionKey?.keyArn), - }), + }]), }, }); - expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + Template.fromStack(stack).hasResourceProperties('AWS::Kinesis::Stream', { StreamEncryption: { KeyId: stack.resolve(stream.encryptionKey?.keyArn), }, @@ -559,7 +558,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantRead(user); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStreamKey76F3300E: { Type: 'AWS::KMS::Key', @@ -693,17 +692,17 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantWrite(user); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: ['kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], Effect: 'Allow', Resource: stack.resolve(stream.encryptionKey?.keyArn), - }), + }]), }, }); - expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + Template.fromStack(stack).hasResourceProperties('AWS::Kinesis::Stream', { StreamEncryption: { KeyId: stack.resolve(stream.encryptionKey?.keyArn), }, @@ -721,7 +720,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantWrite(user); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStreamKey76F3300E: { Type: 'AWS::KMS::Key', @@ -847,17 +846,17 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantReadWrite(user); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: ['kms:Decrypt', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], Effect: 'Allow', Resource: stack.resolve(stream.encryptionKey?.keyArn), - }), + }]), }, }); - expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + Template.fromStack(stack).hasResourceProperties('AWS::Kinesis::Stream', { StreamEncryption: { KeyId: stack.resolve(stream.encryptionKey?.keyArn), }, @@ -875,7 +874,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantReadWrite(user); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStreamKey76F3300E: { Type: 'AWS::KMS::Key', @@ -1009,7 +1008,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantRead(user); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -1100,7 +1099,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantWrite(user); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -1183,7 +1182,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantReadWrite(user); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -1276,7 +1275,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grant(user, 'kinesis:DescribeStream'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -1361,7 +1360,7 @@ describe('Kinesis data streams', () => { const user = new iam.User(stackB, 'UserWhoNeedsAccess'); streamFromStackA.grantRead(user); - expect(stackA).toMatchTemplate({ + Template.fromStack(stackA).templateMatches({ Resources: { MyStream5C050E93: { Type: 'AWS::Kinesis::Stream', @@ -1446,15 +1445,15 @@ describe('Kinesis data streams', () => { const user = new iam.User(stackB, 'UserWhoNeedsAccess'); streamFromStackA.grantRead(user); - expect(stackB).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stackB).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: 'kms:Decrypt', Effect: 'Allow', Resource: { 'Fn::ImportValue': 'stackA:ExportsOutputFnGetAttMyStreamKey76F3300EArn190947B4', }, - }), + }]), }, }); }); @@ -1473,7 +1472,7 @@ describe('Kinesis data streams', () => { retentionPeriod: Duration.hours(parameter.valueAsNumber), }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Parameters: { myretentionperiod: { Type: 'Number', From d8c11fe1f5cd554accf8d0c1fec9d4f0c3a0ce06 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 17:05:22 +0000 Subject: [PATCH 08/23] chore(ses): migrated tests to `assertions` (#18481) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ses/package.json | 2 +- .../@aws-cdk/aws-ses/test/receipt-filter.test.ts | 6 +++--- .../@aws-cdk/aws-ses/test/receipt-rule-set.test.ts | 14 +++++++------- .../@aws-cdk/aws-ses/test/receipt-rule.test.ts | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 134bc98d95365..64ad0fc5f67ce 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -79,7 +79,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses/test/receipt-filter.test.ts b/packages/@aws-cdk/aws-ses/test/receipt-filter.test.ts index 69e966555d0a9..74e6dc8742340 100644 --- a/packages/@aws-cdk/aws-ses/test/receipt-filter.test.ts +++ b/packages/@aws-cdk/aws-ses/test/receipt-filter.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; import { AllowListReceiptFilter, ReceiptFilter, ReceiptFilterPolicy } from '../lib'; @@ -17,7 +17,7 @@ describe('receipt filter', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'FilterC907D6DA': { 'Type': 'AWS::SES::ReceiptFilter', @@ -50,7 +50,7 @@ describe('receipt filter', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'AllowListBlockAll094C9B97': { 'Type': 'AWS::SES::ReceiptFilter', diff --git a/packages/@aws-cdk/aws-ses/test/receipt-rule-set.test.ts b/packages/@aws-cdk/aws-ses/test/receipt-rule-set.test.ts index a80886c442144..0386b71f39425 100644 --- a/packages/@aws-cdk/aws-ses/test/receipt-rule-set.test.ts +++ b/packages/@aws-cdk/aws-ses/test/receipt-rule-set.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; import { ReceiptRuleSet } from '../lib'; @@ -15,7 +15,7 @@ describe('receipt rule set', () => { }); // THEN - expect(stack).toHaveResource('AWS::SES::ReceiptRuleSet', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRuleSet', { RuleSetName: 'MyRuleSet', }); @@ -32,7 +32,7 @@ describe('receipt rule set', () => { }); // THEN - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { Rule: { Actions: [ { @@ -52,7 +52,7 @@ describe('receipt rule set', () => { }, }); - expect(stack).toHaveResource('AWS::Lambda::Function'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 1); }); @@ -73,7 +73,7 @@ describe('receipt rule set', () => { }); // THEN - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { Rule: { Enabled: true, Recipients: [ @@ -87,7 +87,7 @@ describe('receipt rule set', () => { }, }); - expect(stack).toHaveResource('AWS::Lambda::Function'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 1); }); @@ -102,7 +102,7 @@ describe('receipt rule set', () => { receiptRuleSet.addRule('MyRule'); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'ImportedRuleSetMyRule53EE2F7F': { 'Type': 'AWS::SES::ReceiptRule', diff --git a/packages/@aws-cdk/aws-ses/test/receipt-rule.test.ts b/packages/@aws-cdk/aws-ses/test/receipt-rule.test.ts index 4cb86efe88b72..d8a3805cee858 100644 --- a/packages/@aws-cdk/aws-ses/test/receipt-rule.test.ts +++ b/packages/@aws-cdk/aws-ses/test/receipt-rule.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; import { ReceiptRule, ReceiptRuleSet, TlsPolicy } from '../lib'; @@ -26,7 +26,7 @@ describe('receipt rule', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'RuleSetE30C6C48': { 'Type': 'AWS::SES::ReceiptRuleSet', @@ -82,7 +82,7 @@ describe('receipt rule', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'RuleSetE30C6C48': { 'Type': 'AWS::SES::ReceiptRuleSet', @@ -124,7 +124,7 @@ describe('receipt rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { 'Rule': { 'Actions': [ { @@ -159,7 +159,7 @@ describe('receipt rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { 'Rule': { 'Actions': [ { From 438511dfb6dd6df107621e56009311fe331e2d24 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 17:53:07 +0000 Subject: [PATCH 09/23] chore(ses-actions): migrated tests to `assertions` (#18472) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-ses-actions/package.json | 2 +- .../aws-ses-actions/test/actions.test.ts | 29 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index 1c41d8f7333b0..2d42ecb26c71b 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -65,7 +65,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts b/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts index 4a425fd51f76b..845f99c963aa7 100644 --- a/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts +++ b/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts @@ -1,5 +1,4 @@ -import { arrayWith, ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; @@ -25,7 +24,7 @@ test('add header action', () => { value: 'value', })); - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { Rule: { Actions: [ { @@ -62,7 +61,7 @@ test('add bounce action', () => { topic, })); - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { Rule: { Actions: [ { @@ -95,7 +94,7 @@ test('add lambda action', () => { topic, })); - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResource('AWS::SES::ReceiptRule', { Properties: { Rule: { Actions: [ @@ -123,9 +122,9 @@ test('add lambda action', () => { DependsOn: [ 'FunctionAllowSes1829904A', ], - }, ResourcePart.CompleteDefinition); + }); - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -151,7 +150,7 @@ test('add s3 action', () => { topic, })); - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResource('AWS::SES::ReceiptRule', { Properties: { Rule: { Actions: [ @@ -182,9 +181,9 @@ test('add s3 action', () => { DependsOn: [ 'BucketPolicyE9A3008A', ], - }, ResourcePart.CompleteDefinition); + }); - expect(stack).toHaveResource('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { Bucket: { Ref: 'Bucket83908E77', }, @@ -223,9 +222,9 @@ test('add s3 action', () => { }, }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: [ 'kms:Encrypt', 'kms:GenerateDataKey', @@ -246,7 +245,7 @@ test('add s3 action', () => { Service: 'ses.amazonaws.com', }, Resource: '*', - }), + }]), }, }); }); @@ -257,7 +256,7 @@ test('add sns action', () => { topic, })); - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { Rule: { Actions: [ { @@ -279,7 +278,7 @@ test('add stop action', () => { topic, })); - expect(stack).toHaveResource('AWS::SES::ReceiptRule', { + Template.fromStack(stack).hasResourceProperties('AWS::SES::ReceiptRule', { Rule: { Actions: [ { From d735ce4bc9049b68b830641d68c97f4be565968d Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 18:38:57 +0000 Subject: [PATCH 10/23] chore(assets): migrated tests to `assertions` (#18471) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assets/package.json | 2 +- packages/@aws-cdk/assets/test/compat.test.ts | 1 - packages/@aws-cdk/assets/test/staging.test.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index d0ce86e435218..7bac0d2b66d81 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -69,7 +69,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/assets/test/compat.test.ts b/packages/@aws-cdk/assets/test/compat.test.ts index 25afe6dd9411b..dfb3c3afd2daa 100644 --- a/packages/@aws-cdk/assets/test/compat.test.ts +++ b/packages/@aws-cdk/assets/test/compat.test.ts @@ -1,5 +1,4 @@ import { SymlinkFollowMode } from '@aws-cdk/core'; -import '@aws-cdk/assert-internal/jest'; import { FollowMode } from '../lib'; import { toSymlinkFollow } from '../lib/compat'; diff --git a/packages/@aws-cdk/assets/test/staging.test.ts b/packages/@aws-cdk/assets/test/staging.test.ts index bd924e434207b..8893c6451f2c1 100644 --- a/packages/@aws-cdk/assets/test/staging.test.ts +++ b/packages/@aws-cdk/assets/test/staging.test.ts @@ -3,7 +3,6 @@ import * as path from 'path'; import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; import { App, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import '@aws-cdk/assert-internal/jest'; import { Staging } from '../lib'; describeDeprecated('staging', () => { From 15a19364c4aea7e6d12d1401b458ee09816d8a33 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 19:25:06 +0000 Subject: [PATCH 11/23] chore(s3-deployment): migrated tests to `assertions` (#18467) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-s3-deployment/package.json | 2 +- .../test/bucket-deployment.test.ts | 65 +++++++++---------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index aa967f81e56c4..70adaaac2ff88 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -85,7 +85,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts index 38023cc0154e6..9507cdb5dace7 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts @@ -1,6 +1,5 @@ import * as path from 'path'; -import { MatchStyle, objectLike } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; @@ -27,7 +26,7 @@ test('deploy from local directory asset', () => { }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { ServiceToken: { 'Fn::GetAtt': [ 'CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536', @@ -89,7 +88,7 @@ test('deploy with configured log retention', () => { }); // THEN - expect(stack).toHaveResourceLike('Custom::LogRetention', { RetentionInDays: 7 }); + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { RetentionInDays: 7 }); }); test('deploy from local directory assets', () => { @@ -107,7 +106,7 @@ test('deploy from local directory assets', () => { }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { ServiceToken: { 'Fn::GetAtt': [ 'CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536', @@ -235,7 +234,7 @@ test('deploy from a local .zip file when efs is enabled', () => { }); //THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { MOUNT_PATH: '/mnt/lambda', @@ -315,7 +314,7 @@ testDeprecated('honors passed asset options', () => { }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { ServiceToken: { 'Fn::GetAtt': [ 'CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536', @@ -377,7 +376,7 @@ test('retainOnDelete can be used to retain files when resource is deleted', () = }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { RetainOnDelete: true, }); }); @@ -398,7 +397,7 @@ test('user metadata is correctly transformed', () => { }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { UserMetadata: { a: '1', b: '2' }, }); }); @@ -427,7 +426,7 @@ test('system metadata is correctly transformed', () => { }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { SystemMetadata: { 'content-type': 'text/html', 'content-language': 'en', @@ -472,7 +471,7 @@ test.each(Object.entries(accessControlMap) as [s3.BucketAccessControl, string][] }); // THEN - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { SystemMetadata: { acl: systemMetadataKeyword, }, @@ -537,7 +536,7 @@ test('distribution can be used to provide a CloudFront distribution for invalida distributionPaths: ['/images/*'], }); - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { DistributionId: { Ref: 'DistributionCFDistribution882A7313', }, @@ -567,7 +566,7 @@ test('invalidation can happen without distributionPaths provided', () => { distribution, }); - expect(stack).toHaveResource('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { DistributionId: { Ref: 'DistributionCFDistribution882A7313', }, @@ -626,7 +625,7 @@ testFutureBehavior('lambda execution role gets permissions to read from the sour }); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -735,9 +734,9 @@ test('memoryLimit can be used to specify the memory limit for the deployment res // we expect to find only two handlers, one for each configuration - expect(stack).toCountResources('AWS::Lambda::Function', 2); - expect(stack).toHaveResource('AWS::Lambda::Function', { MemorySize: 256 }); - expect(stack).toHaveResource('AWS::Lambda::Function', { MemorySize: 1024 }); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 2); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { MemorySize: 256 }); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { MemorySize: 1024 }); }); test('deployment allows custom role to be supplied', () => { @@ -757,9 +756,9 @@ test('deployment allows custom role to be supplied', () => { }); // THEN - expect(stack).toCountResources('AWS::IAM::Role', 1); - expect(stack).toCountResources('AWS::Lambda::Function', 1); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 1); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 1); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Role: { 'Fn::GetAtt': [ 'Role1ABCC5F0', @@ -782,7 +781,7 @@ test('deploy without deleting missing files from destination', () => { prune: false, }); - expect(stack).toHaveResourceLike('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { Prune: false, }); }); @@ -799,7 +798,7 @@ test('deploy with excluded files from destination', () => { exclude: ['sample.js'], }); - expect(stack).toHaveResourceLike('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { Exclude: ['sample.js'], }); }); @@ -817,7 +816,7 @@ test('deploy with included files from destination', () => { include: ['sample.js'], }); - expect(stack).toHaveResourceLike('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { Include: ['sample.js'], }); }); @@ -836,7 +835,7 @@ test('deploy with excluded and included files from destination', () => { include: ['sample/include.json'], }); - expect(stack).toHaveResourceLike('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { Exclude: ['sample/*'], Include: ['sample/include.json'], }); @@ -856,7 +855,7 @@ test('deploy with multiple exclude and include filters', () => { include: ['sample/include.json', 'another/include.json'], }); - expect(stack).toHaveResourceLike('Custom::CDKBucketDeployment', { + Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', { Exclude: ['sample/*', 'another/*'], Include: ['sample/include.json', 'another/include.json'], }); @@ -877,7 +876,7 @@ test('deployment allows vpc to be implicitly supplied to lambda', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { @@ -922,7 +921,7 @@ test('deployment allows vpc and subnets to be implicitly supplied to lambda', () }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { @@ -957,13 +956,13 @@ test('resource id includes memory and vpc', () => { }); // THEN - expect(stack).toMatchTemplate({ - Resources: objectLike({ - DeployWithVpc2CustomResource256MiBc8a39596cb8641929fcf6a288bc9db5ab7b0f656ad3C5F6E78: objectLike({ + Template.fromStack(stack).templateMatches({ + Resources: Match.objectLike({ + DeployWithVpc2CustomResource256MiBc8a39596cb8641929fcf6a288bc9db5ab7b0f656ad3C5F6E78: Match.objectLike({ Type: 'Custom::CDKBucketDeployment', }), }), - }, MatchStyle.SUPERSET); + }); }); test('bucket includes custom resource owner tag', () => { @@ -983,7 +982,7 @@ test('bucket includes custom resource owner tag', () => { }); // THEN - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { Tags: [{ Key: 'aws-cdk:cr-owned:/a/b/c:971e1fa8', Value: 'true', @@ -1040,7 +1039,7 @@ test('bucket has multiple deployments', () => { }); // THEN - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { Tags: [ { Key: 'aws-cdk:cr-owned:/a/b/c:6da0a4ab', From 93bc333cb8fbfc5703b7a05eb04e35b30c20f049 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 18 Jan 2022 20:14:43 +0000 Subject: [PATCH 12/23] chore(s3-notifications): migrated tests to `assertions` (#18465) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-s3-notifications/package.json | 2 +- .../test/lambda/lambda.test.ts | 44 +++++++++---------- .../test/notifications.test.ts | 40 ++++++++--------- .../aws-s3-notifications/test/queue.test.ts | 19 ++++---- .../aws-s3-notifications/test/sns.test.ts | 4 +- 5 files changed, 55 insertions(+), 54 deletions(-) diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index 3723da0f32e79..f40467d02c99d 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts index 4d80618ad8ff3..d6e563a4438ca 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts @@ -1,6 +1,4 @@ -// import { SynthUtils } from '@aws-cdk/assert-internal'; -import { ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import { Stack, App } from '@aws-cdk/core'; @@ -29,20 +27,20 @@ test('add notifications to multiple functions', () => { bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination2, { prefix: 'v2/' }); // expecting notification configuration to have both events - expect(stack).toHaveResourceLike('Custom::S3BucketNotifications', { - NotificationConfiguration: { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { + NotificationConfiguration: Match.objectLike({ LambdaFunctionConfigurations: [ - { Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v1/' }] } } }, - { Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v2/' }] } } }, + Match.objectLike({ Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v1/' }] } } }), + Match.objectLike({ Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v2/' }] } } }), ], - }, + }), }); // expecting one permission for each function - expect(stack).toCountResources('AWS::Lambda::Permission', 2); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 2); // make sure each permission points to the correct function - expect(stack).toHaveResourceLike('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { FunctionName: { 'Fn::GetAtt': [ 'MyFunction12A744C2E', @@ -56,7 +54,7 @@ test('add notifications to multiple functions', () => { ], }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { FunctionName: { 'Fn::GetAtt': [ 'MyFunction2F2A964CA', @@ -89,7 +87,7 @@ test('lambda in a different stack as notification target', () => { bucket.addObjectCreatedNotification(new s3n.LambdaDestination(lambdaFunction)); // permission should be in the bucket stack - expect(bucketStack).toHaveResourceLike('AWS::Lambda::Permission', { + Template.fromStack(bucketStack).hasResourceProperties('AWS::Lambda::Permission', { FunctionName: { 'Fn::ImportValue': 'stack1:ExportsOutputFnGetAttlambdaFunction940E68ADArn6B2878AF', }, @@ -115,7 +113,7 @@ test('imported lambda in a different account as notification target', () => { bucket.addObjectCreatedNotification(new s3n.LambdaDestination(lambdaFunction)); // no permissions created - expect(stack).not.toHaveResourceLike('AWS::Lambda::Permission'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 0); }); test('lambda as notification target', () => { @@ -132,7 +130,7 @@ test('lambda as notification target', () => { bucketA.addObjectCreatedNotification(new s3n.LambdaDestination(fn), { suffix: '.png' }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': ['MyFunction3BAA72D1', 'Arn'] }, Principal: 's3.amazonaws.com', @@ -140,7 +138,7 @@ test('lambda as notification target', () => { SourceArn: { 'Fn::GetAtt': ['MyBucketF68F3FF0', 'Arn'] }, }); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { NotificationConfiguration: { LambdaFunctionConfigurations: [ { @@ -167,7 +165,7 @@ test('lambda as notification target specified by function arn', () => { bucketA.addObjectCreatedNotification(new s3n.LambdaDestination(fn), { suffix: '.png' }); // THEN - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { NotificationConfiguration: { LambdaFunctionConfigurations: [ { @@ -199,9 +197,9 @@ test('permissions are added as a dependency to the notifications resource when u bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination, { prefix: 'v1/' }); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResource('Custom::S3BucketNotifications', { DependsOn: ['MyBucketAllowBucketNotificationsToSingletonLambdauuid28C96883'], - }, ResourcePart.CompleteDefinition); + }); }); test('add multiple event notifications using a singleton function', () => { @@ -220,13 +218,13 @@ test('add multiple event notifications using a singleton function', () => { bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination, { prefix: 'v1/' }); bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination, { prefix: 'v2/' }); - expect(stack).toHaveResourceLike('Custom::S3BucketNotifications', { - NotificationConfiguration: { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { + NotificationConfiguration: Match.objectLike({ LambdaFunctionConfigurations: [ - { Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v1/' }] } } }, - { Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v2/' }] } } }, + Match.objectLike({ Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v1/' }] } } }), + Match.objectLike({ Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v2/' }] } } }), ], - }, + }), }); }); diff --git a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts index 2bfe968f99279..ee4cbc9c5c5d0 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts @@ -1,5 +1,4 @@ -import { SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; @@ -13,7 +12,7 @@ test('bucket without notifications', () => { new s3.Bucket(stack, 'MyBucket'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyBucketF68F3FF0': { 'Type': 'AWS::S3::Bucket', @@ -33,7 +32,7 @@ test('notifications can be added to imported buckets', () => { bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SnsDestination(topic)); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { ServiceToken: { 'Fn::GetAtt': ['BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691', 'Arn'] }, BucketName: 'mybucket', Managed: false, @@ -61,9 +60,9 @@ test('when notification are added, a custom resource is provisioned + a lambda h bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SnsDestination(topic)); - expect(stack).toHaveResource('AWS::S3::Bucket'); - expect(stack).toHaveResource('AWS::Lambda::Function', { Description: 'AWS CloudFormation handler for "Custom::S3BucketNotifications" resources (@aws-cdk/aws-s3)' }); - expect(stack).toHaveResource('Custom::S3BucketNotifications'); + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Description: 'AWS CloudFormation handler for "Custom::S3BucketNotifications" resources (@aws-cdk/aws-s3)' }); + Template.fromStack(stack).resourceCountIs('Custom::S3BucketNotifications', 1); }); test('when notification are added, you can tag the lambda', () => { @@ -76,12 +75,12 @@ test('when notification are added, you can tag the lambda', () => { bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SnsDestination(topic)); - expect(stack).toHaveResource('AWS::S3::Bucket'); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Tags: [{ Key: 'Lambda', Value: 'AreTagged' }], Description: 'AWS CloudFormation handler for "Custom::S3BucketNotifications" resources (@aws-cdk/aws-s3)', }); - expect(stack).toHaveResource('Custom::S3BucketNotifications'); + Template.fromStack(stack).resourceCountIs('Custom::S3BucketNotifications', 1); }); test('bucketNotificationTarget is not called during synthesis', () => { @@ -95,7 +94,7 @@ test('bucketNotificationTarget is not called during synthesis', () => { bucket.addObjectCreatedNotification(new s3n.SnsDestination(topic)); - expect(stack).toHaveResourceLike('AWS::SNS::TopicPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { 'Topics': [ { 'Ref': 'TopicBFC7AF6E', @@ -122,6 +121,7 @@ test('bucketNotificationTarget is not called during synthesis', () => { 'Resource': { 'Ref': 'TopicBFC7AF6E', }, + 'Sid': '0', }, ], 'Version': '2012-10-17', @@ -159,7 +159,7 @@ test('subscription types', () => { bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaTarget); bucket.addObjectRemovedNotification(topicTarget, { prefix: 'prefix' }); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { 'ServiceToken': { 'Fn::GetAtt': [ 'BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691', @@ -227,7 +227,7 @@ test('multiple subscriptions of the same type', () => { }), }); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { 'ServiceToken': { 'Fn::GetAtt': [ 'BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691', @@ -268,7 +268,7 @@ test('prefix/suffix filters', () => { bucket.addEventNotification(s3.EventType.OBJECT_REMOVED_DELETE, { bind: _ => bucketNotificationTarget }, { prefix: 'images/', suffix: '.jpg' }); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { 'ServiceToken': { 'Fn::GetAtt': [ 'BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691', @@ -320,7 +320,7 @@ test('a notification destination can specify a set of dependencies that must be bucket.addObjectCreatedNotification(dest); - expect(SynthUtils.synthesize(stack).template.Resources.BucketNotifications8F2E257D).toEqual({ + expect(Template.fromStack(stack).findResources('Custom::S3BucketNotifications').BucketNotifications8F2E257D).toEqual({ Type: 'Custom::S3BucketNotifications', Properties: { ServiceToken: { 'Fn::GetAtt': ['BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691', 'Arn'] }, @@ -344,7 +344,7 @@ describe('CloudWatch Events', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.s3', @@ -387,7 +387,7 @@ describe('CloudWatch Events', () => { paths: ['my/path.zip'], }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.s3', @@ -429,7 +429,7 @@ describe('CloudWatch Events', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.s3', @@ -457,7 +457,7 @@ describe('CloudWatch Events', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.s3', @@ -485,7 +485,7 @@ describe('CloudWatch Events', () => { paths: ['my/path.zip'], }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.s3', diff --git a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts index 22c2edac592c8..b1ae15e895a7c 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts @@ -1,5 +1,4 @@ -import { arrayWith, SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; import { Stack } from '@aws-cdk/core'; @@ -13,7 +12,7 @@ test('queues can be used as destinations', () => { bucket.addObjectRemovedNotification(new notif.SqsDestination(queue)); - expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -44,7 +43,7 @@ test('queues can be used as destinations', () => { ], }); - expect(stack).toHaveResource('Custom::S3BucketNotifications', { + Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { BucketName: { Ref: 'Bucket83908E77', }, @@ -67,7 +66,11 @@ test('queues can be used as destinations', () => { // make sure the queue policy is added as a dependency to the bucket // notifications resource so it will be created first. - expect(SynthUtils.synthesize(stack).template.Resources.BucketNotifications8F2E257D.DependsOn).toEqual(['QueuePolicy25439813', 'Queue4A7E3555']); + + const resources = Template.fromStack(stack).findResources('Custom::S3BucketNotifications'); + + expect(resources.BucketNotifications8F2E257D.DependsOn) + .toEqual(['QueuePolicy25439813', 'Queue4A7E3555']); }); test('if the queue is encrypted with a custom kms key, the key resource policy is updated to allow s3 to read messages', () => { @@ -77,9 +80,9 @@ test('if the queue is encrypted with a custom kms key, the key resource policy i bucket.addObjectCreatedNotification(new notif.SqsDestination(queue)); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: [ 'kms:GenerateDataKey*', 'kms:Decrypt', @@ -89,7 +92,7 @@ test('if the queue is encrypted with a custom kms key, the key resource policy i Service: 's3.amazonaws.com', }, Resource: '*', - }), + }]), }, }); }); diff --git a/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts index 2c91becaae188..8a1d607113059 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; @@ -16,7 +16,7 @@ test('asBucketNotificationDestination adds bucket permissions only once for each // another bucket will be added to the topic policy new notif.SnsDestination(topic).bind(bucket2, bucket2); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { Bucket83908E77: { Type: 'AWS::S3::Bucket', From dcf6870df177f20ee238eed03d4ebe4fa52c8277 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizen3031593@users.noreply.github.com> Date: Tue, 18 Jan 2022 16:02:15 -0500 Subject: [PATCH 13/23] chore(stepfunctions): fix readme example (#18442) Makes this example work for v2, and `cdk synth` successfully. Reference: #18316. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-stepfunctions/README.md | 10 +++++++--- .../aws-stepfunctions/rosetta/default.ts-fixture | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions/README.md b/packages/@aws-cdk/aws-stepfunctions/README.md index e74367df84676..eae413c7c3574 100644 --- a/packages/@aws-cdk/aws-stepfunctions/README.md +++ b/packages/@aws-cdk/aws-stepfunctions/README.md @@ -485,9 +485,9 @@ The class `StateMachineFragment` contains some helper functions (like machine as a subclass of this, it will be convenient to use: ```ts nofixture -import { Construct, Stack } from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; import * as sfn from '@aws-cdk/aws-stepfunctions'; -import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; interface MyJobProps { jobFlavor: string; @@ -515,10 +515,14 @@ class MyStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); // Do 3 different variants of MyJob in parallel - new sfn.Parallel(this, 'All jobs') + const parallel = new sfn.Parallel(this, 'All jobs') .branch(new MyJob(this, 'Quick', { jobFlavor: 'quick' }).prefixStates()) .branch(new MyJob(this, 'Medium', { jobFlavor: 'medium' }).prefixStates()) .branch(new MyJob(this, 'Slow', { jobFlavor: 'slow' }).prefixStates()); + + new sfn.StateMachine(this, 'MyStateMachine', { + definition: parallel, + }); } } ``` diff --git a/packages/@aws-cdk/aws-stepfunctions/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-stepfunctions/rosetta/default.ts-fixture index 91085b6c8933c..01f59d49ec36d 100644 --- a/packages/@aws-cdk/aws-stepfunctions/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-stepfunctions/rosetta/default.ts-fixture @@ -1,10 +1,10 @@ // Fixture with packages imported, but nothing else import { Construct } from 'constructs'; import { App, CfnOutput, Duration, Stack } from '@aws-cdk/core'; -import sfn = require('@aws-cdk/aws-stepfunctions'); -import tasks = require('@aws-cdk/aws-stepfunctions-tasks'); -import cloudwatch = require('@aws-cdk/aws-cloudwatch'); -import iam = require('@aws-cdk/aws-iam'); +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as iam from '@aws-cdk/aws-iam'; class Fixture extends Stack { constructor(scope: Construct, id: string) { From 2415a802a4fb59c4c00cf014f736a46b2acd718b Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 18 Jan 2022 22:50:22 +0100 Subject: [PATCH 14/23] chore: prevent empty zip uploads (#18487) Due to something we haven't completely figured out yet, our asset packaging sometimes produces empty zip files, leading to an error like this uploading code Lambda: ``` Uploaded file must be a non-empty zip ``` Do the following to address this: * If any empty zip files already ended up in S3, do not regard this as a cache hit. Rebuild the asset and upload it again. We do this by checking the item's size: this may be overly pessimistic, but if it is we're probably not wasting a lot of time rebuilding and uploading a tiny file. * If a fresh asset build is producing an empty zip file, loudly complain and ask the user to come to our bug tracker, so we can figure out where these spurious issues are coming from. Relates to #18459. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../cdk-assets/lib/private/handlers/files.ts | 51 +++++++++- packages/cdk-assets/test/fake-listener.ts | 1 + packages/cdk-assets/test/files.test.ts | 98 +++++++++++-------- 3 files changed, 104 insertions(+), 46 deletions(-) diff --git a/packages/cdk-assets/lib/private/handlers/files.ts b/packages/cdk-assets/lib/private/handlers/files.ts index 7433d7d9be517..cf77eda43dddc 100644 --- a/packages/cdk-assets/lib/private/handlers/files.ts +++ b/packages/cdk-assets/lib/private/handlers/files.ts @@ -10,6 +10,13 @@ import { pathExists } from '../fs-extra'; import { replaceAwsPlaceholders } from '../placeholders'; import { shell } from '../shell'; +/** + * The size of an empty zip file is 22 bytes + * + * Ref: https://en.wikipedia.org/wiki/ZIP_(file_format) + */ +const EMPTY_ZIP_FILE_SIZE = 22; + export class FileAssetHandler implements IAssetHandler { private readonly fileCacheRoot: string; @@ -74,6 +81,34 @@ export class FileAssetHandler implements IAssetHandler { const publishFile = this.asset.source.executable ? await this.externalPackageFile(this.asset.source.executable) : await this.packageFile(this.asset.source); + // Add a validation to catch the cases where we're accidentally producing an empty ZIP file (or worse, + // an empty file) + if (publishFile.contentType === 'application/zip') { + const fileSize = (await fs.stat(publishFile.packagedPath)).size; + if (fileSize <= EMPTY_ZIP_FILE_SIZE) { + const message = [ + '🚨 WARNING: EMPTY ZIP FILE 🚨', + '', + 'Zipping this asset produced an empty zip file. We do not know the root cause for this yet, and we need your help tracking it down.', + '', + 'Please visit https://github.com/aws/aws-cdk/issues/18459 and tell us:', + 'Your OS version, Nodejs version, CLI version, package manager, what the asset is supposed to contain, whether', + 'or not this error is reproducible, what files are in your cdk.out directory, if you recently changed anything,', + 'and anything else you think might be relevant.', + '', + 'The deployment will continue, but it may fail. You can try removing the cdk.out directory and running the command', + 'again; let us know if that resolves it.', + '', + 'If you meant to produce an empty asset file on purpose, you can add an empty dotfile to the asset for now', + 'to disable this notice.', + ]; + + for (const line of message) { + this.host.emitMessage(EventType.FAIL, line); + } + } + } + this.host.emitMessage(EventType.UPLOAD, `Upload ${s3Url}`); const params = Object.assign({}, { @@ -101,11 +136,11 @@ export class FileAssetHandler implements IAssetHandler { const packagedPath = path.join(this.fileCacheRoot, `${this.asset.id.assetId}.zip`); if (await pathExists(packagedPath)) { - this.host.emitMessage(EventType.CACHED, `From cache ${path}`); + this.host.emitMessage(EventType.CACHED, `From cache ${packagedPath}`); return { packagedPath, contentType }; } - this.host.emitMessage(EventType.BUILD, `Zip ${fullPath} -> ${path}`); + this.host.emitMessage(EventType.BUILD, `Zip ${fullPath} -> ${packagedPath}`); await zipDirectory(fullPath, packagedPath); return { packagedPath, contentType }; } else { @@ -149,9 +184,19 @@ async function objectExists(s3: AWS.S3, bucket: string, key: string) { * prefix, and limiting results to 1. Since the list operation returns keys ordered by binary * UTF-8 representation, the key we are looking for is guaranteed to always be the first match * returned if it exists. + * + * If the file is too small, we discount it as a cache hit. There is an issue + * somewhere that sometimes produces empty zip files, and we would otherwise + * never retry building those assets without users having to manually clear + * their bucket, which is a bad experience. */ const response = await s3.listObjectsV2({ Bucket: bucket, Prefix: key, MaxKeys: 1 }).promise(); - return response.Contents != null && response.Contents.some(object => object.Key === key); + return ( + response.Contents != null && + response.Contents.some( + (object) => object.Key === key && (object.Size == null || object.Size > EMPTY_ZIP_FILE_SIZE), + ) + ); } diff --git a/packages/cdk-assets/test/fake-listener.ts b/packages/cdk-assets/test/fake-listener.ts index 46b7f31a3ecc7..7aef7fbe9d9f6 100644 --- a/packages/cdk-assets/test/fake-listener.ts +++ b/packages/cdk-assets/test/fake-listener.ts @@ -1,6 +1,7 @@ import { IPublishProgressListener, EventType, IPublishProgress } from '../lib/progress'; export class FakeListener implements IPublishProgressListener { + public readonly types = new Array(); public readonly messages = new Array(); constructor(private readonly doAbort = false) { diff --git a/packages/cdk-assets/test/files.test.ts b/packages/cdk-assets/test/files.test.ts index 7616482d43944..9ef52ef8a21a8 100644 --- a/packages/cdk-assets/test/files.test.ts +++ b/packages/cdk-assets/test/files.test.ts @@ -2,13 +2,20 @@ jest.mock('child_process'); import { Manifest } from '@aws-cdk/cloud-assembly-schema'; import * as mockfs from 'mock-fs'; -import { AssetManifest, AssetPublishing } from '../lib'; +import { AssetPublishing, AssetManifest } from '../lib'; import { FakeListener } from './fake-listener'; import { mockAws, mockedApiFailure, mockedApiResult, mockUpload } from './mock-aws'; import { mockSpawn } from './mock-child_process'; const ABS_PATH = '/simple/cdk.out/some_external_file'; +const DEFAULT_DESTINATION = { + region: 'us-north-50', + assumeRoleArn: 'arn:aws:role', + bucketName: 'some_bucket', + objectKey: 'some_key', +}; + let aws: ReturnType; beforeEach(() => { jest.resetAllMocks(); @@ -21,19 +28,12 @@ beforeEach(() => { source: { path: 'some_file', }, - destinations: { - theDestination: { - region: 'us-north-50', - assumeRoleArn: 'arn:aws:role', - bucketName: 'some_bucket', - objectKey: 'some_key', - }, - }, + destinations: { theDestination: DEFAULT_DESTINATION }, }, }, }), '/simple/cdk.out/some_file': 'FILE_CONTENTS', - [ABS_PATH]: 'FILE_CONTENTS', + [ABS_PATH]: 'ZIP_FILE_THAT_IS_DEFINITELY_NOT_EMPTY', '/abs/cdk.out/assets.json': JSON.stringify({ version: Manifest.version(), files: { @@ -41,14 +41,7 @@ beforeEach(() => { source: { path: '/simple/cdk.out/some_file', }, - destinations: { - theDestination: { - region: 'us-north-50', - assumeRoleArn: 'arn:aws:role', - bucketName: 'some_other_bucket', - objectKey: 'some_key', - }, - }, + destinations: { theDestination: { ...DEFAULT_DESTINATION, bucketName: 'some_other_bucket' } }, }, }, }), @@ -59,14 +52,7 @@ beforeEach(() => { source: { executable: ['sometool'], }, - destinations: { - theDestination: { - region: 'us-north-50', - assumeRoleArn: 'arn:aws:role', - bucketName: 'some_external_bucket', - objectKey: 'some_key', - }, - }, + destinations: { theDestination: { ...DEFAULT_DESTINATION, bucketName: 'some_external_bucket' } }, }, }, }), @@ -77,32 +63,31 @@ beforeEach(() => { source: { path: 'plain_text.txt', }, - destinations: { - theDestination: { - region: 'us-north-50', - assumeRoleArn: 'arn:aws:role', - bucketName: 'some_bucket', - objectKey: 'some_key.txt', - }, - }, + destinations: { theDestination: { ...DEFAULT_DESTINATION, objectKey: 'some_key.txt' } }, }, theImageAsset: { source: { path: 'image.png', }, - destinations: { - theDestination: { - region: 'us-north-50', - assumeRoleArn: 'arn:aws:role', - bucketName: 'some_bucket', - objectKey: 'some_key.png', - }, - }, + destinations: { theDestination: { ...DEFAULT_DESTINATION, objectKey: 'some_key.png' } }, }, }, }), '/types/cdk.out/plain_text.txt': 'FILE_CONTENTS', '/types/cdk.out/image.png': 'FILE_CONTENTS', + '/emptyzip/cdk.out/assets.json': JSON.stringify({ + version: Manifest.version(), + files: { + theTextAsset: { + source: { + path: 'empty_dir', + packaging: 'zip', + }, + destinations: { theDestination: DEFAULT_DESTINATION }, + }, + }, + }), + '/emptyzip/cdk.out/empty_dir': { }, // Empty directory }); aws = mockAws(); @@ -114,6 +99,7 @@ afterEach(() => { test('pass destination properties to AWS client', async () => { const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws, throwOnError: false }); + aws.mockS3.listObjectsV2 = mockedApiResult({}); await pub.publish(); @@ -127,6 +113,7 @@ test('Do nothing if file already exists', async () => { const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key' }] }); + aws.mockS3.upload = mockUpload(); await pub.publish(); expect(aws.mockS3.listObjectsV2).toHaveBeenCalledWith(expect.objectContaining({ @@ -134,8 +121,21 @@ test('Do nothing if file already exists', async () => { Prefix: 'some_key', MaxKeys: 1, })); + expect(aws.mockS3.upload).not.toHaveBeenCalled(); +}); + +test('tiny file does not count as cache hit', async () => { + const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); + + aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key', Size: 5 }] }); + aws.mockS3.upload = mockUpload(); + + await pub.publish(); + + expect(aws.mockS3.upload).toHaveBeenCalled(); }); + test('upload file if new (list returns other key)', async () => { const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); @@ -310,6 +310,18 @@ test('correctly identify asset path if path is absolute', async () => { expect(true).toBeTruthy(); // No exception, satisfy linter }); +test('empty directory prints failures', async () => { + const progressListener = new FakeListener(); + const pub = new AssetPublishing(AssetManifest.fromPath('/emptyzip/cdk.out'), { aws, progressListener }); + + aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: undefined }); + aws.mockS3.upload = mockUpload(); // Should not be hit + + await pub.publish(); + + expect(progressListener.messages).toContainEqual(expect.stringContaining('EMPTY ZIP FILE')); +}); + describe('external assets', () => { let pub: AssetPublishing; beforeEach(() => { @@ -330,7 +342,7 @@ describe('external assets', () => { test('upload external asset correctly', async () => { aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: undefined }); - aws.mockS3.upload = mockUpload('FILE_CONTENTS'); + aws.mockS3.upload = mockUpload('ZIP_FILE_THAT_IS_DEFINITELY_NOT_EMPTY'); const expectAllSpawns = mockSpawn({ commandLine: ['sometool'], stdout: ABS_PATH }); await pub.publish(); From da5a305875f0b82b896861be3fcb12fddaa0cc7b Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Tue, 18 Jan 2022 17:38:14 -0500 Subject: [PATCH 15/23] fix(cli): warning to upgrade to bootstrap version >= undefined (#18489) When we try to assume the lookup role and fail, we print out a warning telling the user to upgrade to the required bootstrap stack version. In cases where the user is not using the default stack synthesizer (legacy, custom, etc.) the cli might not have information on the lookup role. In those cases where we don't have the necessary information on the ARN of the lookup role or the required bootstrap version, we will not print any warnings. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/api/cloudformation-deployments.ts | 12 +++-- packages/aws-cdk/test/cdk-toolkit.test.ts | 44 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk/lib/api/cloudformation-deployments.ts b/packages/aws-cdk/lib/api/cloudformation-deployments.ts index 72c48bb109ee7..a4438ff0ca8f7 100644 --- a/packages/aws-cdk/lib/api/cloudformation-deployments.ts +++ b/packages/aws-cdk/lib/api/cloudformation-deployments.ts @@ -96,14 +96,20 @@ export async function prepareSdkWithLookupRoleFor( if (version < stack.lookupRole.requiresBootstrapStackVersion) { throw new Error(`Bootstrap stack version '${stack.lookupRole.requiresBootstrapStackVersion}' is required, found version '${version}'.`); } - } else if (!stackSdk.didAssumeRole) { + // we may not have assumed the lookup role because one was not provided + // if that is the case then don't print the upgrade warning + } else if (!stackSdk.didAssumeRole && stack.lookupRole?.requiresBootstrapStackVersion) { warning(upgradeMessage); } return { ...stackSdk, resolvedEnvironment }; } catch (e) { debug(e); - warning(warningMessage); - warning(upgradeMessage); + // only print out the warnings if the lookupRole exists AND there is a required + // bootstrap version, otherwise the warnings will print `undefined` + if (stack.lookupRole && stack.lookupRole.requiresBootstrapStackVersion) { + warning(warningMessage); + warning(upgradeMessage); + } throw (e); } } diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 7b8f96d5d948c..c7ee3b87130fc 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -127,6 +127,13 @@ describe('readCurrentTemplate', () => { }, }, }, + { + stackName: 'Test-Stack-A', + template, + properties: { + assumeRoleArn: 'bloop:${AWS::Region}:${AWS::AccountId}', + }, + }, ], }); mockForEnvironment = jest.fn().mockImplementation(() => { return { sdk: mockCloudExecutable.sdkProvider.sdk, didAssumeRole: true }; }); @@ -145,6 +152,11 @@ describe('readCurrentTemplate', () => { StackStatus: 'CREATE_COMPLETE', CreationTime: new Date(), }, + { + StackName: 'Test-Stack-A', + StackStatus: 'CREATE_COMPLETE', + CreationTime: new Date(), + }, ], }; }, @@ -329,6 +341,38 @@ describe('readCurrentTemplate', () => { assumeRoleArn: 'bloop:here:123456789012', }); }); + + test('do not print warnings if lookup role not provided in stack artifact', async () => { + // GIVEN + mockCloudExecutable.sdkProvider.stubSSM({ + getParameter() { + return {}; + }, + }); + const cdkToolkit = new CdkToolkit({ + cloudExecutable: mockCloudExecutable, + configuration: mockCloudExecutable.configuration, + sdkProvider: mockCloudExecutable.sdkProvider, + cloudFormation: new CloudFormationDeployments({ sdkProvider: mockCloudExecutable.sdkProvider }), + }); + + // WHEN + await cdkToolkit.deploy({ + selector: { patterns: ['Test-Stack-A'] }, + }); + + // THEN + expect(flatten(stderrMock.mock.calls)).not.toEqual(expect.arrayContaining([ + expect.stringMatching(/Could not assume/), + expect.stringMatching(/please upgrade to bootstrap version/), + ])); + expect(mockCloudExecutable.sdkProvider.sdk.ssm).not.toHaveBeenCalled(); + expect(mockForEnvironment.mock.calls.length).toEqual(2); + expect(mockForEnvironment.mock.calls[0][2]).toEqual({ + assumeRoleArn: undefined, + assumeRoleExternalId: undefined, + }); + }); }); describe('deploy', () => { From 03d388d4f052e2d47a719378753b8ccbda3ba6ef Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 19 Jan 2022 00:27:13 +0100 Subject: [PATCH 16/23] chore(fsx): migrate tests to `assertions` (#18490) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-fsx/package.json | 2 +- .../aws-fsx/test/lustre-file-system.test.ts | 60 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index fb7cd9f8ef29d..0b0c1f0426004 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -81,7 +81,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts index ad4c4462d8c58..6f581475dbe3d 100644 --- a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts +++ b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts @@ -1,5 +1,5 @@ import { strictEqual } from 'assert'; -import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { ISubnet, Port, SecurityGroup, Subnet, Vpc } from '@aws-cdk/aws-ec2'; import { Key } from '@aws-cdk/aws-kms'; import { Aws, Stack, Token } from '@aws-cdk/core'; @@ -35,15 +35,15 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem')); - expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroup')); + Template.fromStack(stack).hasResource('AWS::FSx::FileSystem', {}); + Template.fromStack(stack).hasResource('AWS::EC2::SecurityGroup', {}); strictEqual( fileSystem.dnsName, `${fileSystem.fileSystemId}.fsx.${stack.region}.${Aws.URL_SUFFIX}`); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResource('AWS::FSx::FileSystem', { DeletionPolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); + }); }); test('file system is created correctly when security group is provided', () => { @@ -63,8 +63,8 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem')); - expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroup')); + Template.fromStack(stack).hasResource('AWS::FSx::FileSystem', {}); + Template.fromStack(stack).hasResource('AWS::EC2::SecurityGroup', {}); }); test('encrypted file system is created correctly with custom KMS', () => { @@ -88,11 +88,11 @@ describe('FSx for Lustre File System', () => { * in generated CDK, hence hardcoding the MD5 hash here for assertion. Assumption is that the path of the Key wont * change in this UT. Checked the unique id by generating the cloud formation stack. */ - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { KmsKeyId: { Ref: 'customKeyFSDDB87C6D', }, - })); + }); }); test('file system is created correctly when weekly maintenance time is provided', () => { @@ -118,13 +118,13 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: 'SCRATCH_2', WeeklyMaintenanceStartTime: '7:12:34', }, - })); - expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroup')); + }); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', {}); }); describe('when validating props', () => { @@ -145,13 +145,13 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.SCRATCH_2, ExportPath: exportPath, ImportPath: importPath, }, - })); + }); }); test('export and import paths are Tokens', () => { @@ -172,13 +172,13 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.SCRATCH_2, ExportPath: exportPathResolved, ImportPath: importPathResolved, }, - })); + }); }); test('only export path is Token', () => { @@ -299,12 +299,12 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.SCRATCH_2, ImportedFileChunkSize: size, }, - })); + }); }); test.each([ @@ -342,12 +342,12 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.SCRATCH_2, ImportPath: importPath, }, - })); + }); }); test('import path is Token', () => { @@ -364,12 +364,12 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.SCRATCH_2, ImportPath: importPathResolved, }, - })); + }); }); test('invalid import path format', () => { @@ -428,12 +428,12 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.PERSISTENT_1, PerUnitStorageThroughput: throughput, }, - })); + }); }); test('invalid perUnitStorageThroughput', () => { @@ -489,12 +489,12 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: deploymentType, }, StorageCapacity: value, - })); + }); }); test.each([ @@ -529,12 +529,12 @@ describe('FSx for Lustre File System', () => { vpcSubnet, }); - expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + Template.fromStack(stack).hasResourceProperties('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: LustreDeploymentType.SCRATCH_1, }, StorageCapacity: validValue, - })); + }); }); test.each([1, 3601])('invalid value of %d for storage capacity with SCRATCH_1', (invalidValue: number) => { @@ -566,8 +566,8 @@ describe('FSx for Lustre File System', () => { fs.connections.allowToAnyIpv4(Port.tcp(443)); - expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: 'sg-123456789', - })); + }); }); }); \ No newline at end of file From 3f87b4d9bcaa54e76abed7deed4d462f15412ed4 Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Tue, 18 Jan 2022 19:15:01 -0500 Subject: [PATCH 17/23] chore(lambda-nodejs): migrate tests to `assertions` (#18497) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-lambda-nodejs/package.json | 2 +- .../aws-lambda-nodejs/test/function.test.ts | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index 60915214f9a76..a9a64704b6be9 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts index 01b90d89dd6dd..f197bb34b60da 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts @@ -1,7 +1,6 @@ -import '@aws-cdk/assert-internal/jest'; import * as fs from 'fs'; import * as path from 'path'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Template, Match } from '@aws-cdk/assertions'; import { Vpc } from '@aws-cdk/aws-ec2'; import { CodeConfig, Runtime } from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; @@ -40,7 +39,7 @@ test('NodejsFunction with .ts handler', () => { entry: expect.stringContaining('function.test.handler1.ts'), // Automatically finds .ts handler file })); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'index.handler', Runtime: 'nodejs14.x', }); @@ -155,7 +154,7 @@ test('configures connection reuse for aws sdk', () => { // WHEN new NodejsFunction(stack, 'handler1'); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1', @@ -170,8 +169,8 @@ test('can opt-out of connection reuse for aws sdk', () => { awsSdkConnectionReuse: false, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { - Environment: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Environment: Match.absent(), }); }); @@ -183,7 +182,7 @@ test('NodejsFunction in a VPC', () => { new NodejsFunction(stack, 'handler1', { vpc }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { From 8c5d125ab438e228c7e96e5462a8b99dfe01c606 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 19 Jan 2022 02:03:44 +0100 Subject: [PATCH 18/23] chore(cloudformation): migrate tests to `assertions` (#18498) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-cloudformation/package.json | 2 +- .../aws-cloudformation/test/deps.test.ts | 39 ++++++----- .../test/nested-stack.test.ts | 66 +++++++++---------- .../aws-cloudformation/test/resource.test.ts | 15 ++--- 4 files changed, 60 insertions(+), 62 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index c00a412462faa..5a7014994d6c5 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -69,7 +69,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts b/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts index 0354c7e9e4fa8..1e814b754eece 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts @@ -1,7 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { testDeprecated, describeDeprecated } from '@aws-cdk/cdk-build-tools'; import { App, CfnResource, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; @@ -39,8 +38,8 @@ describe('resource dependencies', () => { // THEN: the dependency needs to transfer from the resource within the // nested stack to the nested stack resource itself so the nested stack // will only be deployed the dependent resource - expect(parent).toHaveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInParent'] }, ResourcePart.CompleteDefinition); - expect(nested).toMatchTemplate({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource + Template.fromStack(parent).hasResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInParent'] }); + Template.fromStack(nested).templateMatches({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource })); // eslint-disable-next-line jest/valid-describe @@ -57,8 +56,8 @@ describe('resource dependencies', () => { // THEN: the dependency needs to transfer from the resource within the // nested stack to the *parent* nested stack - expect(grantparent).toHaveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInGrandparent'] }, ResourcePart.CompleteDefinition); - expect(nested).toMatchTemplate({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource + Template.fromStack(grantparent).hasResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInGrandparent'] }); + Template.fromStack(nested).templateMatches({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource })); // eslint-disable-next-line jest/valid-describe @@ -73,9 +72,9 @@ describe('resource dependencies', () => { addDep(resourceInParent, resourceInNested); // THEN: resource in parent needs to depend on the nested stack - expect(parent).toHaveResource('PARENT', { + Template.fromStack(parent).hasResource('PARENT', { DependsOn: [parent.resolve(nested.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + }); })); // eslint-disable-next-line jest/valid-describe @@ -91,9 +90,9 @@ describe('resource dependencies', () => { addDep(resourceInGrandparent, resourceInNested); // THEN: resource in grantparent needs to depend on the top-level nested stack - expect(grandparent).toHaveResource('GRANDPARENT', { + Template.fromStack(grandparent).hasResource('GRANDPARENT', { DependsOn: [grandparent.resolve(parent.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + }); })); // eslint-disable-next-line jest/valid-describe @@ -154,13 +153,13 @@ describe('resource dependencies', () => { addDep(resourceInNested1, resourceInNested2); // THEN: dependency transfered to nested stack resources - expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResource('AWS::CloudFormation::Stack', { DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + }); - expect(stack).not.toHaveResource('AWS::CloudFormation::Stack', { + expect(Template.fromStack(stack).findResources('AWS::CloudFormation::Stack', { DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + })).toEqual({}); })); }); @@ -226,9 +225,9 @@ describe('stack dependencies', () => { nested1.addDependency(nested2); // THEN - expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResource('AWS::CloudFormation::Stack', { DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + }); }); testDeprecated('nested stack depends on a deeply nested stack', () => { @@ -242,9 +241,9 @@ describe('stack dependencies', () => { nested1.addDependency(nested21); // THEN: transfered to a resource dep between the resources in the common stack - expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResource('AWS::CloudFormation::Stack', { DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + }); }); testDeprecated('deeply nested stack depends on a parent nested stack', () => { @@ -258,9 +257,9 @@ describe('stack dependencies', () => { nested21.addDependency(nested1); // THEN: transfered to a resource dep between the resources in the common stack - expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResource('AWS::CloudFormation::Stack', { DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition); + }); }); testDeprecated('top-level stack depends on a nested stack within a sibling', () => { diff --git a/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts index 07a43586971bd..a625012eba58a 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts @@ -1,7 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import * as sns from '@aws-cdk/aws-sns'; import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; @@ -122,7 +121,7 @@ describeDeprecated('NestedStack', () => { }); // the parent template includes the parameters and the nested stack resource which points to the s3 url - expect(parent).toMatchTemplate({ + Template.fromStack(parent).templateMatches({ Resources: { nestedstackNestedStacknestedstackNestedStackResource71CDD241: { Type: 'AWS::CloudFormation::Stack', @@ -276,7 +275,7 @@ describeDeprecated('NestedStack', () => { app.synth(); // nested template should use a parameter to reference the resource from the parent stack - expect(nested).toMatchTemplate({ + Template.fromStack(nested).templateMatches({ Resources: { resource: @@ -303,7 +302,7 @@ describeDeprecated('NestedStack', () => { }); // parent template should pass in the value through the parameter - expect(parentStack).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(parentStack).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { referencetoparentparentresourceD56EA8F7Ref: { Ref: 'parentresource', @@ -347,7 +346,7 @@ describeDeprecated('NestedStack', () => { app.synth(); // nested template should use a parameter to reference the resource from the parent stack - expect(nested).toMatchTemplate({ + Template.fromStack(nested).templateMatches({ Resources: { resource: { Type: 'AWS::Child::Resource' }, }, @@ -357,7 +356,7 @@ describeDeprecated('NestedStack', () => { }); // parent template should pass in the value through the parameter - expect(parentStack).toHaveResource('AWS::Parent::Resource', { + Template.fromStack(parentStack).hasResourceProperties('AWS::Parent::Resource', { RefToResourceInNestedStack: { 'Fn::GetAtt': [ 'nestedNestedStacknestedNestedStackResource3DD143BF', @@ -387,7 +386,7 @@ describeDeprecated('NestedStack', () => { const assembly = app.synth(); // producing stack should have an export - expect(stack2).toMatchTemplate({ + Template.fromStack(stack2).templateMatches({ Resources: { ResourceInStack2: { Type: 'MyResource' }, }, @@ -400,7 +399,7 @@ describeDeprecated('NestedStack', () => { }); // nested stack uses Fn::ImportValue like normal - expect(nestedUnderStack1).toMatchTemplate({ + Template.fromStack(nestedUnderStack1).templateMatches({ Resources: { ResourceInNestedStack1: { Type: 'Nested::Resource', @@ -464,7 +463,7 @@ describeDeprecated('NestedStack', () => { const assembly = app.synth(); // nested stack should output this value as if it was referenced by the parent (without the export) - expect(nestedUnderStack1).toMatchTemplate({ + Template.fromStack(nestedUnderStack1).templateMatches({ Resources: { ResourceInNestedStack: { Type: 'MyResource', @@ -491,7 +490,7 @@ describeDeprecated('NestedStack', () => { }); // consuming stack should use ImportValue to import the value from the parent stack - expect(stack2).toMatchTemplate({ + Template.fromStack(stack2).templateMatches({ Resources: { ResourceInStack2: { Type: 'JustResource', @@ -532,7 +531,7 @@ describeDeprecated('NestedStack', () => { app.synth(); // producing nested stack - expect(nested1).toMatchTemplate({ + Template.fromStack(nested1).templateMatches({ Resources: { Resource1: { Type: 'Resource1', @@ -548,7 +547,7 @@ describeDeprecated('NestedStack', () => { }); // consuming nested stack - expect(nested2).toMatchTemplate({ + Template.fromStack(nested2).templateMatches({ Resources: { Resource2: { Type: 'Resource2', @@ -567,7 +566,7 @@ describeDeprecated('NestedStack', () => { }); // parent - expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(parent).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { 'Fn::GetAtt': [ @@ -591,7 +590,7 @@ describeDeprecated('NestedStack', () => { }); // THEN - expect(nested).toHaveResource('Nested::Resource', { + Template.fromStack(nested).hasResourceProperties('Nested::Resource', { MyStackId: { Ref: 'AWS::StackId' }, }); }); @@ -608,7 +607,7 @@ describeDeprecated('NestedStack', () => { }); // THEN - expect(parent).toHaveResource('Parent::Resource', { + Template.fromStack(parent).hasResourceProperties('Parent::Resource', { NestedStackId: { Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD' }, }); }); @@ -625,7 +624,7 @@ describeDeprecated('NestedStack', () => { }); // THEN - expect(nested).toHaveResource('Nested::Resource', { + Template.fromStack(nested).hasResourceProperties('Nested::Resource', { MyStackName: { Ref: 'AWS::StackName' }, }); }); @@ -642,7 +641,7 @@ describeDeprecated('NestedStack', () => { }); // THEN - expect(parent).toHaveResource('Parent::Resource', { + Template.fromStack(parent).hasResourceProperties('Parent::Resource', { NestedStackName: { 'Fn::Select': [ 1, @@ -689,7 +688,7 @@ describeDeprecated('NestedStack', () => { const assembly = app.synth(); // nested2 is a "leaf", so it's just the resource - expect(nested2).toMatchTemplate({ + Template.fromStack(nested2).templateMatches({ Resources: { Resource2: { Type: 'Resource::2' }, }, @@ -701,8 +700,9 @@ describeDeprecated('NestedStack', () => { const hashSuffix = 'E28F0693'; // nested1 wires the nested2 template through parameters, so we expect those - expect(nested1).toHaveResource('Resource::1'); - const nested2Template = SynthUtils.toCloudFormation(nested1); + const nested1Template = Template.fromStack(nested1); + nested1Template.resourceCountIs('Resource::1', 1); + const nested2Template = nested1Template.toJSON(); expect(nested2Template.Parameters).toEqual({ referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Type: 'String' }, referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Type: 'String' }, @@ -710,7 +710,7 @@ describeDeprecated('NestedStack', () => { // parent stack should have two sets of parameters. one for the first nested stack and the second // for the second nested stack, passed in as parameters to the first - const template = SynthUtils.toCloudFormation(parent); + const template = Template.fromStack(parent).toJSON(); expect(template.Parameters).toEqual({ AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, @@ -721,7 +721,7 @@ describeDeprecated('NestedStack', () => { }); // proxy asset params to nested stack - expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(parent).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6' }, referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA' }, @@ -780,7 +780,7 @@ describeDeprecated('NestedStack', () => { // THEN const assembly = app.synth(); - const template = SynthUtils.toCloudFormation(parent); + const template = Template.fromStack(parent).toJSON(); // two sets of asset parameters: one for the nested stack itself and one as a proxy for the asset within the stack expect(template.Parameters).toEqual({ @@ -793,7 +793,7 @@ describeDeprecated('NestedStack', () => { }); // asset proxy parameters are passed to the nested stack - expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(parent).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3Bucket82C55B96Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637' }, referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyA43C3CC6Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2' }, @@ -887,7 +887,7 @@ describeDeprecated('NestedStack', () => { }); // THEN - expect(nested).toMatchTemplate({ + Template.fromStack(nested).templateMatches({ Resources: { resourceinnested: { Type: 'CONSUMED', @@ -905,7 +905,7 @@ describeDeprecated('NestedStack', () => { }, }); - expect(parent).toHaveResource('CONSUMER', { + Template.fromStack(parent).hasResourceProperties('CONSUMER', { ConsumedAttribute: { 'Fn::GetAtt': [ 'nestedNestedStacknestedNestedStackResource3DD143BF', @@ -984,7 +984,7 @@ describeDeprecated('NestedStack', () => { }); // THEN - expect(top).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(top).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3Bucket5DA5D2E7Ref: { Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3BucketDD4D96B5', @@ -998,7 +998,7 @@ describeDeprecated('NestedStack', () => { }, }); - expect(nested1).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(nested1).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { referencetostacktoplevelBB16BF13Ref: { Ref: 'referencetostacktoplevelBB16BF13Ref', @@ -1006,7 +1006,7 @@ describeDeprecated('NestedStack', () => { }, }); - expect(nested2).toMatchTemplate({ + Template.fromStack(nested2).templateMatches({ Resources: { refToTopLevel: { Type: 'BottomLevel', @@ -1048,7 +1048,7 @@ describeDeprecated('NestedStack', () => { const paramName = 'referencetoGrandparentResourceInGrandparent010E997ARef'; // child (bottom) references through a parameter. - expect(bottom).toMatchTemplate({ + Template.fromStack(bottom).templateMatches({ Resources: { ResourceInChild: { Type: 'ResourceInChild', @@ -1063,14 +1063,14 @@ describeDeprecated('NestedStack', () => { }); // the parent (middle) sets the value of this parameter to be a reference to another parameter - expect(middle).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(middle).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { [paramName]: { Ref: paramName }, }, }); // grandparent (top) assigns the actual value to the parameter - expect(top).toHaveResource('AWS::CloudFormation::Stack', { + Template.fromStack(top).hasResourceProperties('AWS::CloudFormation::Stack', { Parameters: { [paramName]: { Ref: 'ResourceInGrandparent' }, diff --git a/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts b/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts index c6cefdc714675..e2f6eae16f3b3 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts @@ -1,5 +1,4 @@ -import { ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; import { describeDeprecated, testDeprecated } from '@aws-cdk/cdk-build-tools'; @@ -23,7 +22,7 @@ describeDeprecated('custom resources honor removalPolicy', () => { new TestCustomResource(stack, 'Custom'); // THEN - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition); + Template.fromStack(stack).hasResource('AWS::CloudFormation::CustomResource', {}); expect(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length).toEqual(0); }); @@ -36,7 +35,7 @@ describeDeprecated('custom resources honor removalPolicy', () => { new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.DESTROY }); // THEN - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition); + Template.fromStack(stack).hasResource('AWS::CloudFormation::CustomResource', {}); expect(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length).toEqual(0); }); @@ -49,10 +48,10 @@ describeDeprecated('custom resources honor removalPolicy', () => { new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.RETAIN }); // THEN - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + Template.fromStack(stack).hasResource('AWS::CloudFormation::CustomResource', { DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition); + }); }); }); @@ -66,7 +65,7 @@ testDeprecated('custom resource is added twice, lambda is added once', () => { new TestCustomResource(stack, 'Custom2'); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C': { 'Type': 'AWS::IAM::Role', @@ -149,7 +148,7 @@ testDeprecated('custom resources can specify a resource type that starts with Cu resourceType: 'Custom::MyCustomResourceType', provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), }); - expect(stack).toHaveResource('Custom::MyCustomResourceType'); + Template.fromStack(stack).hasResourceProperties('Custom::MyCustomResourceType', {}); }); describeDeprecated('fails if custom resource type is invalid', () => { From 71ee5f60316e3afdbfce827a601462dadf20284d Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 19 Jan 2022 02:52:36 +0100 Subject: [PATCH 19/23] chore(logs-destinations): migrate tests to `assertions` (#18500) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-logs-destinations/package.json | 2 +- .../aws-logs-destinations/test/kinesis.test.ts | 14 +++++++------- .../aws-logs-destinations/test/lambda.test.ts | 16 ++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index e8c1455b1920e..ceb9c5c120499 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -64,7 +64,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts b/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts index 42c87261d60b2..4325993406ccd 100644 --- a/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts +++ b/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as kinesis from '@aws-cdk/aws-kinesis'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; @@ -18,13 +18,13 @@ test('stream can be subscription destination', () => { }); // THEN: subscription target is Stream - expect(stack).toHaveResource('AWS::Logs::SubscriptionFilter', { + Template.fromStack(stack).hasResourceProperties('AWS::Logs::SubscriptionFilter', { DestinationArn: { 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] }, RoleArn: { 'Fn::GetAtt': ['SubscriptionCloudWatchLogsCanPutRecords9C1223EC', 'Arn'] }, }); // THEN: we have a role to write to the Stream - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -44,7 +44,7 @@ test('stream can be subscription destination', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -88,13 +88,13 @@ test('stream can be subscription destination twice, without duplicating permissi }); // THEN: subscription target is Stream - expect(stack).toHaveResource('AWS::Logs::SubscriptionFilter', { + Template.fromStack(stack).hasResourceProperties('AWS::Logs::SubscriptionFilter', { DestinationArn: { 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] }, RoleArn: { 'Fn::GetAtt': ['SubscriptionCloudWatchLogsCanPutRecords9C1223EC', 'Arn'] }, }); // THEN: we have a role to write to the Stream - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -114,7 +114,7 @@ test('stream can be subscription destination twice, without duplicating permissi }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ diff --git a/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts b/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts index b1f0048716a74..f5a80285c8146 100644 --- a/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts +++ b/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; @@ -28,12 +28,12 @@ test('lambda can be used as metric subscription destination', () => { }); // THEN: subscription target is Lambda - expect(stack).toHaveResource('AWS::Logs::SubscriptionFilter', { + Template.fromStack(stack).hasResourceProperties('AWS::Logs::SubscriptionFilter', { DestinationArn: { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, }); // THEN: Lambda has permissions to be invoked by CWL - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, Principal: 'logs.amazonaws.com', @@ -55,14 +55,14 @@ test('can have multiple subscriptions use the same Lambda', () => { }); // THEN: Lambda has permissions to be invoked by CWL from both Source Arns - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, SourceArn: { 'Fn::GetAtt': ['LogGroupF5B46931', 'Arn'] }, Principal: 'logs.amazonaws.com', }); - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, SourceArn: { 'Fn::GetAtt': ['LG224A94C8F', 'Arn'] }, @@ -79,14 +79,14 @@ test('lambda permissions are not added when addPermissions is false', () => { }); // THEN: subscription target is Lambda - expect(stack).toHaveResource('AWS::Logs::SubscriptionFilter', { + Template.fromStack(stack).hasResourceProperties('AWS::Logs::SubscriptionFilter', { DestinationArn: { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, }); // THEN: Lambda does not have permissions to be invoked by CWL - expect(stack).not.toHaveResource('AWS::Lambda::Permission', { + expect(Template.fromStack(stack).findResources('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, Principal: 'logs.amazonaws.com', - }); + })).toEqual({}); }); \ No newline at end of file From 802a031245619715fb405d04a02056cf699e0fc2 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 19 Jan 2022 03:41:14 +0100 Subject: [PATCH 20/23] chore(lambda-layer-awscli): migrate tests to `assertions` (#18499) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/lambda-layer-awscli/package.json | 2 +- .../@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 759a1c35ec1d9..cf5a3d857f5b3 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts b/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts index 2a5c4b7d80043..561bb87a14ac7 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts +++ b/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts @@ -1,6 +1,6 @@ import { Stack } from '@aws-cdk/core'; import { AwsCliLayer } from '../lib'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; test('synthesized to a layer version', () => { //GIVEN @@ -10,7 +10,7 @@ test('synthesized to a layer version', () => { new AwsCliLayer(stack, 'MyLayer'); // THEN - expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', { Description: '/opt/awscli/aws', }); }); From c6609cf89c9fcd0443e9032a04a73ae568419ab8 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 19 Jan 2022 04:30:18 +0100 Subject: [PATCH 21/23] chore(custom-resources): migrate tests to `assertions` (#18501) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/custom-resources/package.json | 2 +- .../aws-custom-resource.test.ts | 40 ++++++++--------- .../test/provider-framework/provider.test.ts | 43 +++++++++---------- .../waiter-state-machine.test.ts | 8 ++-- 4 files changed, 46 insertions(+), 47 deletions(-) diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index a16653f20c6bf..cb6707b8b1611 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -79,7 +79,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts index f072c0f926875..c3df398f6f5dd 100644 --- a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts +++ b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; @@ -33,7 +33,7 @@ test('aws sdk js custom resource with onCreate and onDelete', () => { }); // THEN - expect(stack).toHaveResource('Custom::LogRetentionPolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::LogRetentionPolicy', { 'Create': JSON.stringify({ 'service': 'CloudWatchLogs', 'action': 'putRetentionPolicy', @@ -55,7 +55,7 @@ test('aws sdk js custom resource with onCreate and onDelete', () => { 'InstallLatestAwsSdk': true, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -95,7 +95,7 @@ test('onCreate defaults to onUpdate', () => { }); // THEN - expect(stack).toHaveResource('Custom::S3PutObject', { + Template.fromStack(stack).hasResourceProperties('Custom::S3PutObject', { 'Create': JSON.stringify({ 'service': 's3', 'action': 'putObject', @@ -148,7 +148,7 @@ test('with custom policyStatements', () => { }); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -207,7 +207,7 @@ test('booleans are encoded in the stringified parameters object', () => { }); // THEN - expect(stack).toHaveResource('Custom::ServiceAction', { + Template.fromStack(stack).hasResourceProperties('Custom::ServiceAction', { 'Create': JSON.stringify({ 'service': 'service', 'action': 'action', @@ -263,7 +263,7 @@ test('encodes physical resource id reference', () => { }); // THEN - expect(stack).toHaveResource('Custom::ServiceAction', { + Template.fromStack(stack).hasResourceProperties('Custom::ServiceAction', { 'Create': JSON.stringify({ 'service': 'service', 'action': 'action', @@ -296,7 +296,7 @@ test('timeout defaults to 2 minutes', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Timeout: 120, }); }); @@ -317,7 +317,7 @@ test('can specify timeout', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Timeout: 900, }); }); @@ -340,7 +340,7 @@ test('implements IGrantable', () => { // WHEN role.grantPassRole(customResource.grantPrincipal); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -376,11 +376,11 @@ test('can use existing role', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Role: 'arn:aws:iam::123456789012:role/CoolRole', }); - expect(stack).not.toHaveResource('AWS::IAM::Role'); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); }); test('getData', () => { @@ -524,7 +524,7 @@ test('getDataString', () => { }); // THEN - expect(stack).toHaveResource('Custom::AWS', { + Template.fromStack(stack).hasResourceProperties('Custom::AWS', { Create: { 'Fn::Join': [ '', @@ -559,7 +559,7 @@ test('can specify log retention', () => { }); // THEN - expect(stack).toHaveResource('Custom::LogRetention', { + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { LogGroupName: { 'Fn::Join': [ '', @@ -591,7 +591,7 @@ test('disable AWS SDK installation', () => { }); // THEN - expect(stack).toHaveResource('Custom::AWS', { + Template.fromStack(stack).hasResourceProperties('Custom::AWS', { 'InstallLatestAwsSdk': false, }); }); @@ -612,7 +612,7 @@ test('can specify function name', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'my-cool-function', }); }); @@ -640,7 +640,7 @@ test('separate policies per custom resource', () => { }); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -652,7 +652,7 @@ test('separate policies per custom resource', () => { Version: '2012-10-17', }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -690,7 +690,7 @@ test('tokens can be used as dictionary keys', () => { }); // THEN - expect(stack).toHaveResource('Custom::AWS', { + Template.fromStack(stack).hasResourceProperties('Custom::AWS', { Create: { 'Fn::Join': [ '', @@ -730,7 +730,7 @@ test('assumedRoleArn adds statement for sts:assumeRole', () => { // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts index 724c76425a1ee..ac09be73e0f89 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts @@ -1,4 +1,5 @@ import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -7,8 +8,6 @@ import { Duration, Stack } from '@aws-cdk/core'; import * as cr from '../../lib'; import * as util from '../../lib/provider-framework/util'; -import '@aws-cdk/assert-internal/jest'; - test('security groups are applied to all framework functions', () => { // GIVEN @@ -34,7 +33,7 @@ test('security groups are applied to all framework functions', () => { securityGroups: [securityGroup], }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onEvent', VpcConfig: { SecurityGroupIds: [ @@ -48,7 +47,7 @@ test('security groups are applied to all framework functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.isComplete', VpcConfig: { SecurityGroupIds: [ @@ -62,7 +61,7 @@ test('security groups are applied to all framework functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onTimeout', VpcConfig: { SecurityGroupIds: [ @@ -101,7 +100,7 @@ test('vpc is applied to all framework functions', () => { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onEvent', VpcConfig: { SubnetIds: [ @@ -111,7 +110,7 @@ test('vpc is applied to all framework functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.isComplete', VpcConfig: { SubnetIds: [ @@ -121,7 +120,7 @@ test('vpc is applied to all framework functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onTimeout', VpcConfig: { SubnetIds: [ @@ -149,23 +148,23 @@ test('minimal setup', () => { // THEN // framework "onEvent" handler - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onEvent', Environment: { Variables: { USER_ON_EVENT_FUNCTION_ARN: { 'Fn::GetAtt': ['MyHandler6B74D312', 'Arn'] } } }, Timeout: 900, }); // user "onEvent" handler - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'index.onEvent', }); // no framework "is complete" handler or state machine - expect(stack).not.toHaveResource('AWS::StepFunctions::StateMachine'); - expect(stack).not.toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).resourceCountIs('AWS::StepFunctions::StateMachine', 0); + expect(Template.fromStack(stack).findResources('AWS::Lambda::Function', { Handler: 'framework.isComplete', Timeout: 900, - }); + })).toEqual({}); }); test('if isComplete is specified, the isComplete framework handler is also included', () => { @@ -193,7 +192,7 @@ test('if isComplete is specified, the isComplete framework handler is also inclu }, }; - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onEvent', Timeout: 900, Environment: { @@ -204,19 +203,19 @@ test('if isComplete is specified, the isComplete framework handler is also inclu }, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.isComplete', Timeout: 900, Environment: expectedEnv, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'framework.onTimeout', Timeout: 900, Environment: expectedEnv, }); - expect(stack).toHaveResource('AWS::StepFunctions::StateMachine', { + Template.fromStack(stack).hasResourceProperties('AWS::StepFunctions::StateMachine', { DefinitionString: { 'Fn::Join': [ '', @@ -310,7 +309,7 @@ describe('log retention', () => { }); // THEN - expect(stack).toHaveResource('Custom::LogRetention', { + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { LogGroupName: { 'Fn::Join': [ '', @@ -340,7 +339,7 @@ describe('log retention', () => { }); // THEN - expect(stack).not.toHaveResource('Custom::LogRetention'); + Template.fromStack(stack).resourceCountIs('Custom::LogRetention', 0); }); }); @@ -363,7 +362,7 @@ describe('role', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Role: { 'Fn::GetAtt': [ 'MyRoleF48FFE04', @@ -387,7 +386,7 @@ describe('role', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Role: { 'Fn::GetAtt': [ 'MyProviderframeworkonEventServiceRole8761E48D', @@ -415,7 +414,7 @@ describe('name', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: providerFunctionName, }); }); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts index f9b683417dc94..7548f4e151041 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Code, Function as lambdaFn, Runtime } from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; import { Node } from 'constructs'; @@ -35,7 +35,7 @@ describe('state machine', () => { // THEN const roleId = 'statemachineRole52044F93'; - expect(stack).toHaveResourceLike('AWS::StepFunctions::StateMachine', { + Template.fromStack(stack).hasResourceProperties('AWS::StepFunctions::StateMachine', { DefinitionString: { 'Fn::Join': [ '', @@ -54,7 +54,7 @@ describe('state machine', () => { 'Fn::GetAtt': [roleId, 'Arn'], }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -77,7 +77,7 @@ describe('state machine', () => { Version: '2012-10-17', }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { From 0e757a59d5449cf30bae98369bd47a9fec27e391 Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Tue, 18 Jan 2022 23:18:10 -0500 Subject: [PATCH 22/23] chore(apprunner): migrate tests to `assertions` (#18502) Looks like tests were already migrated, just needed to remove the unused assert-internal import ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-apprunner/test/service.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@aws-cdk/aws-apprunner/test/service.test.ts b/packages/@aws-cdk/aws-apprunner/test/service.test.ts index 412ff09cd14e9..2d5285d06f7fa 100644 --- a/packages/@aws-cdk/aws-apprunner/test/service.test.ts +++ b/packages/@aws-cdk/aws-apprunner/test/service.test.ts @@ -1,5 +1,4 @@ import * as path from 'path'; -import '@aws-cdk/assert-internal/jest'; import { Template } from '@aws-cdk/assertions'; import * as ecr from '@aws-cdk/aws-ecr'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; From 4e4f7d2c3bd236e033df247071b57e6f5ad3fec3 Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Wed, 19 Jan 2022 00:08:33 -0500 Subject: [PATCH 23/23] chore(signer): migrate tests to `assertions` (#18504) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-signer/package.json | 2 +- .../@aws-cdk/aws-signer/test/signing-profile.test.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index 93cb08670772c..064c381b6a88a 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -74,7 +74,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts b/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts index 49ada5da2f596..44db183b565a5 100644 --- a/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts +++ b/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as signer from '../lib'; @@ -14,7 +14,7 @@ describe('signing profile', () => { const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; new signer.SigningProfile( stack, 'SigningProfile', { platform } ); - expect(stack).toHaveResource('AWS::Signer::SigningProfile', { + Template.fromStack(stack).hasResourceProperties('AWS::Signer::SigningProfile', { PlatformId: platform.platformId, SignatureValidityPeriod: { Type: 'MONTHS', @@ -30,7 +30,7 @@ describe('signing profile', () => { signatureValidity: cdk.Duration.days( 7 ), } ); - expect(stack).toHaveResource('AWS::Signer::SigningProfile', { + Template.fromStack(stack).hasResourceProperties('AWS::Signer::SigningProfile', { PlatformId: platform.platformId, SignatureValidityPeriod: { Type: 'DAYS', @@ -47,7 +47,7 @@ describe('signing profile', () => { cdk.Tags.of(signing).add('tag2', 'value2'); cdk.Tags.of(signing).add('tag3', ''); - expect(stack).toHaveResource('AWS::Signer::SigningProfile', { + Template.fromStack(stack).hasResourceProperties('AWS::Signer::SigningProfile', { PlatformId: platform.platformId, SignatureValidityPeriod: { Type: 'MONTHS', @@ -109,7 +109,7 @@ describe('signing profile', () => { ], ], }); - expect(stack).toMatchTemplate({}); + Template.fromStack(stack).templateMatches({}); }); } ); });