diff --git a/CHANGELOG.md b/CHANGELOG.md index dea1caa9163d9..dc314e3354418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,61 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.140.0](https://github.com/aws/aws-cdk/compare/v1.139.0...v1.140.0) (2022-01-20) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **apigatewayv2:** `HttpIntegrationType.LAMBDA_PROXY` has been renamed to `HttpIntegrationType.AWS_PROXY` +* **iot:** the class `FirehoseStreamAction` has been renamed to `FirehosePutRecordAction` + +### Features + +* **apigatewayv2:** HttpRouteIntegration supports AWS services integrations ([#18154](https://github.com/aws/aws-cdk/issues/18154)) ([a8094c7](https://github.com/aws/aws-cdk/commit/a8094c7d9970557077f560ccd24882216094ee3c)), closes [#16287](https://github.com/aws/aws-cdk/issues/16287) +* **apigatewayv2:** support for mock integration type ([#18129](https://github.com/aws/aws-cdk/issues/18129)) ([7779c14](https://github.com/aws/aws-cdk/commit/7779c147c7445d9e8ccafa9b732521c9021a6234)), closes [#15008](https://github.com/aws/aws-cdk/issues/15008) +* **apigatewayv2:** websocket api: api keys ([#16636](https://github.com/aws/aws-cdk/issues/16636)) ([24f8f74](https://github.com/aws/aws-cdk/commit/24f8f74ebec023f5e3f5bd2bdfc89575a53b38f3)) +* **assertions:** `stringLikeRegexp()` matcher ([#18491](https://github.com/aws/aws-cdk/issues/18491)) ([b49b002](https://github.com/aws/aws-cdk/commit/b49b002e40f5b901935f52827f417bb3851badc2)) +* **assertions:** support for parameters ([#18469](https://github.com/aws/aws-cdk/issues/18469)) ([d0d6fc5](https://github.com/aws/aws-cdk/commit/d0d6fc520491351b44cac78aa90284c82a9499b2)), closes [#16720](https://github.com/aws/aws-cdk/issues/16720) +* **aws-neptune:** add autoMinorVersionUpgrade to cluster props ([#18394](https://github.com/aws/aws-cdk/issues/18394)) ([8b5320a](https://github.com/aws/aws-cdk/commit/8b5320ac5e5c320db46bc74f33b3841977dd3a5d)), closes [#17545](https://github.com/aws/aws-cdk/issues/17545) +* **aws-s3:** support number of newer versions to retain in lifecycle policy ([#18225](https://github.com/aws/aws-cdk/issues/18225)) ([e1731b1](https://github.com/aws/aws-cdk/commit/e1731b11c9417a9a4d6cf0f2089c62a721e8d074)), closes [#17996](https://github.com/aws/aws-cdk/issues/17996) [#17996](https://github.com/aws/aws-cdk/issues/17996) +* **cfnspec:** cloudformation spec v53.0.0 ([#18468](https://github.com/aws/aws-cdk/issues/18468)) ([50637e0](https://github.com/aws/aws-cdk/commit/50637e08590c2051d9a1e446ee7ded47e85d02b3)) +* **cfnspec:** cloudformation spec v53.0.0 ([#18480](https://github.com/aws/aws-cdk/issues/18480)) ([38e1fe4](https://github.com/aws/aws-cdk/commit/38e1fe42d8b30d6afaf4a3ccc90dd15d6a5d8255)) +* **cfnspec:** cloudformation spec v53.0.0 ([#18524](https://github.com/aws/aws-cdk/issues/18524)) ([517d517](https://github.com/aws/aws-cdk/commit/517d517a0bb3f7f6e98538dca736086b86b206c8)) +* **cfnspec:** cloudformation spec v53.0.0 ([#18551](https://github.com/aws/aws-cdk/issues/18551)) ([926310b](https://github.com/aws/aws-cdk/commit/926310bace65a763972d56c0df5730cdc44f8f82)) +* **cli:** support hotswapping Lambda functions that use Docker images ([#18319](https://github.com/aws/aws-cdk/issues/18319)) ([6b553b7](https://github.com/aws/aws-cdk/commit/6b553b7f84e5cde8a1fc533af95ad440c020e834)), closes [#18302](https://github.com/aws/aws-cdk/issues/18302) [#18408](https://github.com/aws/aws-cdk/issues/18408) +* **cli:** support hotswapping Lambda functions with inline code ([#18408](https://github.com/aws/aws-cdk/issues/18408)) ([d0b8512](https://github.com/aws/aws-cdk/commit/d0b8512449759bf74bb53aabbb6d5224b5f8c5ae)), closes [#18319](https://github.com/aws/aws-cdk/issues/18319) +* **cli:** watch streams resources' CloudWatch logs to the terminal ([#18159](https://github.com/aws/aws-cdk/issues/18159)) ([a9038ae](https://github.com/aws/aws-cdk/commit/a9038ae9c7d9b15b89ae24cfa24aefa6012674bc)), closes [#18122](https://github.com/aws/aws-cdk/issues/18122) +* **cognito:** identity pools ([#16190](https://github.com/aws/aws-cdk/issues/16190)) ([59fe395](https://github.com/aws/aws-cdk/commit/59fe395a5adcd35bd59c6d9c74f4a2606aec88b0)) +* **ec2:** add Hpc6a instances ([#18445](https://github.com/aws/aws-cdk/issues/18445)) ([c7f39ca](https://github.com/aws/aws-cdk/commit/c7f39ca97874c1d8d5286ab347a97fc458547830)) +* **ec2:** add support for al2022 and amzn2 with kernel 5.x ([#18117](https://github.com/aws/aws-cdk/issues/18117)) ([6b73d1d](https://github.com/aws/aws-cdk/commit/6b73d1d3d0ac05042c1e43a64068938138fe8421)) +* **ec2:** create Peers via security group ids ([#18248](https://github.com/aws/aws-cdk/issues/18248)) ([9d1b2c7](https://github.com/aws/aws-cdk/commit/9d1b2c7b1f0147089f912c32a61d7ba86edb543c)), closes [#7111](https://github.com/aws/aws-cdk/issues/7111) +* **ecs-service-extensions:** Enable default logging to CloudWatch for extensions (under feature flag) ([#17817](https://github.com/aws/aws-cdk/issues/17817)) ([06666f4](https://github.com/aws/aws-cdk/commit/06666f4727b9745d001bc20f027b535538bb8250)) +* **iot:** add Action to put record to Kinesis Data stream ([#18321](https://github.com/aws/aws-cdk/issues/18321)) ([1480213](https://github.com/aws/aws-cdk/commit/1480213a032549ab7319e0c3a66e02e9b6a9c4ab)), closes [#17703](https://github.com/aws/aws-cdk/issues/17703) +* **lambda-nodejs:** ES modules ([#18346](https://github.com/aws/aws-cdk/issues/18346)) ([e23b63f](https://github.com/aws/aws-cdk/commit/e23b63fc106c4781e3dd39a16d4a3e3c81bdd874)), closes [#13274](https://github.com/aws/aws-cdk/issues/13274) +* **opensearch:** added opensearch 1.1 to engineversion ([#18432](https://github.com/aws/aws-cdk/issues/18432)) ([e01a57a](https://github.com/aws/aws-cdk/commit/e01a57aa3085a8282123afbc3583b1b78a075c9a)), closes [#18431](https://github.com/aws/aws-cdk/issues/18431) + + +### Bug Fixes + +* **apigateway:** `enabled` property of `ApiKeyProps` is ignored ([#18407](https://github.com/aws/aws-cdk/issues/18407)) ([c31f9b4](https://github.com/aws/aws-cdk/commit/c31f9b44165f872f8dd51605e00f4801ed611d4d)) +* **applicationautoscaling:** typo in `DYANMODB_WRITE_CAPACITY_UTILIZATION` ([#18085](https://github.com/aws/aws-cdk/issues/18085)) ([626e6aa](https://github.com/aws/aws-cdk/commit/626e6aa1a27feffe7ce60a46a6fdcf26f317eaef)), closes [#17209](https://github.com/aws/aws-cdk/issues/17209) +* **assertions:** object partiality is dropped passing through arrays ([#18525](https://github.com/aws/aws-cdk/issues/18525)) ([eb29e6f](https://github.com/aws/aws-cdk/commit/eb29e6ff0308eb320ec772cc35cdbf781168198e)) +* **cli:** `cdk watch` constantly prints 'messages suppressed' ([#18486](https://github.com/aws/aws-cdk/issues/18486)) ([9b266f4](https://github.com/aws/aws-cdk/commit/9b266f49643d058709771892f908f1c2ae248f95)), closes [#18451](https://github.com/aws/aws-cdk/issues/18451) +* **cli:** warning to upgrade to bootstrap version >= undefined ([#18489](https://github.com/aws/aws-cdk/issues/18489)) ([da5a305](https://github.com/aws/aws-cdk/commit/da5a305875f0b82b896861be3fcb12fddaa0cc7b)) +* **ec2:** interface endpoints do not work with `Vpc.fromLookup()` ([#18554](https://github.com/aws/aws-cdk/issues/18554)) ([f55cd2b](https://github.com/aws/aws-cdk/commit/f55cd2bd86405cc61d3eb24c2b827c2cd133363d)), closes [#17600](https://github.com/aws/aws-cdk/issues/17600) +* **ec2:** launch template names in imdsv2 not unique across stacks (under feature flag) ([#17766](https://github.com/aws/aws-cdk/issues/17766)) ([2a80e4b](https://github.com/aws/aws-cdk/commit/2a80e4b113bac0716f5aa1d4806e425759da1743)) +* **ecs:** respect LogGroup's region for aws-log-driver ([#18212](https://github.com/aws/aws-cdk/issues/18212)) ([b6e3e51](https://github.com/aws/aws-cdk/commit/b6e3e517ac42b7951bc4ca4c1fd62422e3b49092)), closes [#17747](https://github.com/aws/aws-cdk/issues/17747) +* **elbv2:** BaseLoadBalancer.vpc is not optional ([#18474](https://github.com/aws/aws-cdk/issues/18474)) ([f511c17](https://github.com/aws/aws-cdk/commit/f511c17aac8ca4d3fa94ace051d9946dc23f40a3)), closes [aws/jsii#3342](https://github.com/aws/jsii/issues/3342) +* **iot:** `FirehoseStreamAction` is now called `FirehosePutRecordAction` ([#18356](https://github.com/aws/aws-cdk/issues/18356)) ([c016a9f](https://github.com/aws/aws-cdk/commit/c016a9fcf51f2415e6e0fcca2255da384c8abbc1)), closes [/github.com/aws/aws-cdk/pull/18321#discussion_r781620195](https://github.com/aws//github.com/aws/aws-cdk/pull/18321/issues/discussion_r781620195) +* **pipelines:** "Maximum schema version supported" error ([#18404](https://github.com/aws/aws-cdk/issues/18404)) ([a684ff4](https://github.com/aws/aws-cdk/commit/a684ff47d56038a94c82cdbad9588da939963351)), closes [#18370](https://github.com/aws/aws-cdk/issues/18370) +* **pipelines:** graphnode dependencies can have duplicates ([#18450](https://github.com/aws/aws-cdk/issues/18450)) ([2b0b5ea](https://github.com/aws/aws-cdk/commit/2b0b5ea5db7ce8103a641c1267b1c213453ac145)) +* **secretsmanager:** Secret requires KMS key for some same-account access ([#17812](https://github.com/aws/aws-cdk/issues/17812)) ([91f3539](https://github.com/aws/aws-cdk/commit/91f3539f4aa8383adcb2273790ddb469fb1274a6)), closes [#15450](https://github.com/aws/aws-cdk/issues/15450) + + +### Reverts + +* **s3:** add EventBridge bucket notifications ([#18150](https://github.com/aws/aws-cdk/issues/18150)) ([#18507](https://github.com/aws/aws-cdk/issues/18507)) ([2041278](https://github.com/aws/aws-cdk/commit/204127862d5fb1d2e6dd573a1621254e52eca4aa)) + ## [1.139.0](https://github.com/aws/aws-cdk/compare/v1.138.2...v1.139.0) (2022-01-11) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 36045a4661c51..0110332a70379 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,7 +46,7 @@ let us know if it's not up-to-date (even better, submit a PR with your correcti The following steps describe how to set up the AWS CDK repository on your local machine. The alternative is to use [Gitpod](https://www.gitpod.io/), a Cloud IDE for your development. -See [Gitpod section](#gitpod) on how to set up the CDK repo on Gitpod. +See [Gitpod section](#gitpod-alternative) on how to set up the CDK repo on Gitpod. ### Setup diff --git a/package.json b/package.json index be3d9e61e48c4..b99f8690e2171 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@yarnpkg/lockfile": "^1.1.0", - "cdk-generate-synthetic-examples": "^0.1.2", + "cdk-generate-synthetic-examples": "^0.1.3", "conventional-changelog-cli": "^2.2.2", "fs-extra": "^9.1.0", "graceful-fs": "^4.2.9", diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index cb1e48d089632..7f57bf73f19d3 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -60,7 +60,7 @@ "constructs": "^3.3.69" }, "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-s3": "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/app-delivery/test/pipeline-deploy-stack-action.test.ts b/packages/@aws-cdk/app-delivery/test/pipeline-deploy-stack-action.test.ts index b0c8e4f941a04..ccd9c230fe284 100644 --- a/packages/@aws-cdk/app-delivery/test/pipeline-deploy-stack-action.test.ts +++ b/packages/@aws-cdk/app-delivery/test/pipeline-deploy-stack-action.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { isSuperObject } from '@aws-cdk/assert-internal'; +import { Match, Matcher, Template } from '@aws-cdk/assertions'; import * as cfn from '@aws-cdk/aws-cloudformation'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; @@ -135,56 +134,43 @@ describeDeprecated('pipeline deploy stack action', () => { capabilities: [cfn.CloudFormationCapabilities.ANONYMOUS_IAM, cfn.CloudFormationCapabilities.AUTO_EXPAND], adminPermissions: false, })); - expect(pipelineStack).toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'TestStack', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_NAMED_IAM', - }, + + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', hasPipelineActionConfiguration({ + StackName: 'TestStack', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_NAMED_IAM', })); - expect(pipelineStack).toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'AnonymousIAM', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_IAM', - }, + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', hasPipelineActionConfiguration({ + StackName: 'AnonymousIAM', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_IAM', })); - expect(pipelineStack).not.toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'NoCapStack', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_NAMED_IAM', - }, + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.not(hasPipelineActionConfiguration({ + StackName: 'NoCapStack', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_NAMED_IAM', + }))); + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.not(hasPipelineActionConfiguration({ + StackName: 'NoCapStack', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_IAM', + }))); + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', hasPipelineActionConfiguration({ + StackName: 'NoCapStack', + ActionMode: 'CHANGE_SET_REPLACE', })); - expect(pipelineStack).not.toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'NoCapStack', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_IAM', - }, + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', hasPipelineActionConfiguration({ + StackName: 'AutoExpand', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_AUTO_EXPAND', })); - expect(pipelineStack).toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'NoCapStack', - ActionMode: 'CHANGE_SET_REPLACE', - }, + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', hasPipelineActionConfiguration({ + StackName: 'AnonymousIAMAndAutoExpand', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND', })); - expect(pipelineStack).toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'AutoExpand', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_AUTO_EXPAND', - }, - })); - expect(pipelineStack).toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'AnonymousIAMAndAutoExpand', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND', - }, - })); - }); + test('users can use admin permissions', () => { const pipelineStack = getTestStack(); const selfUpdatingStack = createSelfUpdatingStack(pipelineStack); @@ -196,7 +182,7 @@ describeDeprecated('pipeline deploy stack action', () => { input: selfUpdatingStack.synthesizedApp, adminPermissions: true, })); - expect(pipelineStack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -251,15 +237,13 @@ describeDeprecated('pipeline deploy stack action', () => { ], }, }); - expect(pipelineStack).toHaveResource('AWS::CodePipeline::Pipeline', hasPipelineAction({ - Configuration: { - StackName: 'TestStack', - ActionMode: 'CHANGE_SET_REPLACE', - Capabilities: 'CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND', - }, + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', hasPipelineActionConfiguration({ + StackName: 'TestStack', + ActionMode: 'CHANGE_SET_REPLACE', + Capabilities: 'CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND', })); - }); + test('users can supply a role for deploy action', () => { const pipelineStack = getTestStack(); const selfUpdatingStack = createSelfUpdatingStack(pipelineStack); @@ -313,7 +297,7 @@ describeDeprecated('pipeline deploy stack action', () => { })); // THEN // - expect(pipelineStack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -391,7 +375,7 @@ describeDeprecated('pipeline deploy stack action', () => { const app = new cdk.App(); const deployedStack = new cdk.Stack(app, 'DeployedStack'); - for (let i = 0 ; i < assetCount ; i++) { + for (let i = 0; i < assetCount; i++) { deployedStack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, {}); } @@ -406,7 +390,6 @@ describeDeprecated('pipeline deploy stack action', () => { }, ), ); - }); test('allows overriding the ChangeSet and Execute action names', () => { @@ -425,25 +408,21 @@ describeDeprecated('pipeline deploy stack action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - Stages: [ - {}, - {}, - { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + Stages: Match.arrayWith([ + Match.objectLike({ Name: 'Deploy', - Actions: [ - { + Actions: Match.arrayWith([ + Match.objectLike({ Name: 'Prepare', - }, - { + }), + Match.objectLike({ Name: 'Deploy', - }, - ], - }, - ], + }), + ]), + }), + ]), }); - - }); }); @@ -481,7 +460,7 @@ function createSelfUpdatingStack(pipelineStack: cdk.Stack): SelfUpdatingPipeline }); // simple source - const bucket = s3.Bucket.fromBucketArn( pipeline, 'PatternBucket', 'arn:aws:s3:::totally-fake-bucket'); + const bucket = s3.Bucket.fromBucketArn(pipeline, 'PatternBucket', 'arn:aws:s3:::totally-fake-bucket'); const sourceOutput = new codepipeline.Artifact('SourceOutput'); const sourceAction = new cpactions.S3SourceAction({ actionName: 'S3Source', @@ -509,15 +488,16 @@ function createSelfUpdatingStack(pipelineStack: cdk.Stack): SelfUpdatingPipeline return { synthesizedApp: buildOutput, pipeline }; } -function hasPipelineAction(expectedAction: any): (props: any) => boolean { - return (props: any) => { - for (const stage of props.Stages) { - for (const action of stage.Actions) { - if (isSuperObject(action, expectedAction, [], true)) { - return true; - } - } - } - return false; - }; -} +function hasPipelineActionConfiguration(expectedActionConfiguration: any): Matcher { + return Match.objectLike({ + Stages: Match.arrayWith([ + Match.objectLike({ + Actions: Match.arrayWith([ + Match.objectLike({ + Configuration: expectedActionConfiguration, + }), + ]), + }), + ]), + }); +} \ No newline at end of file diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json index fc4bf503aeae3..99b32de7a66c9 100644 --- a/packages/@aws-cdk/assert-internal/package.json +++ b/packages/@aws-cdk/assert-internal/package.json @@ -28,7 +28,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.4.0", "jest": "^27.4.7", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index ef707331605ac..1a66fcf3a6d99 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -41,7 +41,7 @@ "aws-cdk-migration": "0.0.0", "constructs": "^3.3.69", "jest": "^27.3.1", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0", diff --git a/packages/@aws-cdk/assertions/NOTICE b/packages/@aws-cdk/assertions/NOTICE index 7904e6da91128..1ed908383e334 100644 --- a/packages/@aws-cdk/assertions/NOTICE +++ b/packages/@aws-cdk/assertions/NOTICE @@ -85,4 +85,4 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------- \ No newline at end of file +---------------- diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index 55b8d3520d550..3d1275d2b4a3e 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -139,7 +139,7 @@ expect(result.Foo).toEqual({ Value: 'Fred', Description: 'FooFred' }); expect(result.Bar).toEqual({ Value: 'Fred', Description: 'BarFred' }); ``` -The APIs `hasMapping()` and `findMappings()` provide similar functionalities. +The APIs `hasMapping()`, `findMappings()`, `hasCondition()`, and `hasCondtions()` provide similar functionalities. ## Special Matchers @@ -299,6 +299,35 @@ target array. Out of order will be recorded as a match failure. Alternatively, the `Match.arrayEquals()` API can be used to assert that the target is exactly equal to the pattern array. +### String Matchers + +The `Match.stringLikeRegexp()` API can be used to assert that the target matches the +provided regular expression. + +```ts +// Given a template - +// { +// "Resources": { +// "MyBar": { +// "Type": "Foo::Bar", +// "Properties": { +// "Template": "const includeHeaders = true;" +// } +// } +// } +// } + +// The following will NOT throw an assertion error +template.hasResourceProperties('Foo::Bar', { + Template: Match.stringLikeRegexp('includeHeaders = (true|false)'), +}); + +// The following will throw an assertion error +template.hasResourceProperties('Foo::Bar', { + Template: Match.stringLikeRegexp('includeHeaders = null'), +}); +``` + ### Not Matcher The not matcher inverts the search pattern and matches all patterns in the path that does diff --git a/packages/@aws-cdk/assertions/lib/match.ts b/packages/@aws-cdk/assertions/lib/match.ts index 453174f969195..dd03bba1950a2 100644 --- a/packages/@aws-cdk/assertions/lib/match.ts +++ b/packages/@aws-cdk/assertions/lib/match.ts @@ -79,6 +79,13 @@ export abstract class Match { public static anyValue(): Matcher { return new AnyMatch('anyValue'); } + + /** + * Matches targets according to a regular expression + */ + public static stringLikeRegexp(pattern: string): Matcher { + return new StringLikeRegexpMatch('stringLikeRegexp', pattern); + } } /** @@ -390,3 +397,37 @@ class AnyMatch extends Matcher { return result; } } + +class StringLikeRegexpMatch extends Matcher { + constructor( + public readonly name: string, + private readonly pattern: string) { + + super(); + } + + test(actual: any): MatchResult { + const result = new MatchResult(actual); + + const regex = new RegExp(this.pattern, 'gm'); + + if (typeof actual !== 'string') { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'`, + }); + } + + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'`, + }); + } + + return result; + } + +} diff --git a/packages/@aws-cdk/assertions/lib/private/conditions.ts b/packages/@aws-cdk/assertions/lib/private/conditions.ts new file mode 100644 index 0000000000000..e7c4665dee219 --- /dev/null +++ b/packages/@aws-cdk/assertions/lib/private/conditions.ts @@ -0,0 +1,30 @@ +import { filterLogicalId, formatFailure, matchSection } from './section'; +import { Template } from './template'; + +export function findConditions(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { + const section: { [key: string] : {} } = template.Conditions; + const result = matchSection(filterLogicalId(section, logicalId), props); + + if (!result.match) { + return {}; + } + + return result.matches; +} + +export function hasCondition(template: Template, logicalId: string, props: any): string | void { + const section: { [key: string] : {} } = template.Conditions; + const result = matchSection(filterLogicalId(section, logicalId), props); + if (result.match) { + return; + } + + if (result.closestResult === undefined) { + return 'No conditions found in the template'; + } + + return [ + `Template has ${result.analyzedCount} conditions, 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 72dbeb8b64661..fc5d0cb6b1e01 100644 --- a/packages/@aws-cdk/assertions/lib/private/template.ts +++ b/packages/@aws-cdk/assertions/lib/private/template.ts @@ -4,7 +4,8 @@ export type Template = { Resources: { [logicalId: string]: Resource }, Outputs: { [logicalId: string]: Output }, Mappings: { [logicalId: string]: Mapping }, - Parameters: { [logicalId: string]: Parameter } + Parameters: { [logicalId: string]: Parameter }, + Conditions: { [logicalId: string]: Condition }, } export type Resource = { @@ -19,4 +20,6 @@ export type Mapping = { [key: string]: any }; export type Parameter = { Type: string; [key: string]: any; -} \ No newline at end of file +} + +export type Condition = { [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 631c9f7137dc4..8875a91d0ac9c 100644 --- a/packages/@aws-cdk/assertions/lib/template.ts +++ b/packages/@aws-cdk/assertions/lib/template.ts @@ -3,6 +3,7 @@ import { Stack, Stage } from '@aws-cdk/core'; import * as fs from 'fs-extra'; import { Match } from './match'; import { Matcher } from './matcher'; +import { findConditions, hasCondition } from './private/conditions'; import { findMappings, hasMapping } from './private/mappings'; import { findOutputs, hasOutput } from './private/outputs'; import { findParameters, hasParameter } from './private/parameters'; @@ -183,6 +184,31 @@ export class Template { return findMappings(this.template, logicalId, props); } + /** + * Assert that a Condition with the given properties exists in the CloudFormation template. + * By default, performs partial matching on the resource, via the `Match.objectLike()`. + * To configure different behavour, use other matchers in the `Match` class. + * @param logicalId the name of the mapping. Provide `'*'` to match all conditions in the template. + * @param props the output as should be expected in the template. + */ + public hasCondition(logicalId: string, props: any): void { + const matchError = hasCondition(this.template, logicalId, props); + if (matchError) { + throw new Error(matchError); + } + } + + /** + * Get the set of matching Conditions that match the given properties in the CloudFormation template. + * @param logicalId the name of the condition. Provide `'*'` to match all conditions in the template. + * @param props by default, matches all Conditions 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 findConditions(logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { + return findConditions(this.template, logicalId, props); + } + /** * Assert that the CloudFormation template matches the given value * @param expected the expected CloudFormation template as key-value pairs. @@ -205,6 +231,7 @@ function toTemplate(stack: Stack): any { if (!Stage.isStage(root)) { throw new Error('unexpected: all stacks must be part of a Stage or an App'); } + const assembly = root.synth(); if (stack.nestedStackParent) { // if this is a nested stack (it has a parent), then just read the template as a string diff --git a/packages/@aws-cdk/assertions/package.json b/packages/@aws-cdk/assertions/package.json index 1073d76e836e2..31bcf0b7d0067 100644 --- a/packages/@aws-cdk/assertions/package.json +++ b/packages/@aws-cdk/assertions/package.json @@ -68,7 +68,7 @@ "@types/jest": "^27.4.0", "constructs": "^3.3.69", "jest": "^27.4.7", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/assertions/test/match.test.ts b/packages/@aws-cdk/assertions/test/match.test.ts index 7dda38e269c10..92c3646e044a7 100644 --- a/packages/@aws-cdk/assertions/test/match.test.ts +++ b/packages/@aws-cdk/assertions/test/match.test.ts @@ -401,6 +401,22 @@ describe('Matchers', () => { expectPass(matcher, {}); }); }); + + describe('stringLikeRegexp', () => { + let matcher: Matcher; + + test('simple', () => { + matcher = Match.stringLikeRegexp('.*includeHeaders = true.*'); + expectFailure(matcher, 'const includeHeaders = false;', [/did not match pattern/]); + expectPass(matcher, 'const includeHeaders = true;'); + }); + + test('nested in object', () => { + matcher = Match.objectLike({ foo: Match.stringLikeRegexp('.*includeHeaders = true.*') }); + expectFailure(matcher, { foo: 'const includeHeaders = false;' }, [/did not match pattern/]); + expectPass(matcher, { foo: 'const includeHeaders = true;' }); + }); + }); }); function expectPass(matcher: Matcher, target: any): void { diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index dd8377892f405..92bdb405ab9ce 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, CfnParameter, CfnResource, NestedStack, Stack } from '@aws-cdk/core'; +import { App, CfnCondition, CfnMapping, CfnOutput, CfnParameter, CfnResource, Fn, NestedStack, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Capture, Match, Template } from '../lib'; @@ -940,6 +940,150 @@ describe('Template', () => { expect(Object.keys(result).length).toEqual(0); }); }); + + describe('hasCondition', () => { + test('matching', () => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + const inspect = Template.fromStack(stack); + expect(() => inspect.hasCondition('*', { 'Fn::Equals': ['Bar', 'Baz'] })).not.toThrow(); + }); + + test('not matching', (done) => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + new CfnCondition(stack, 'Qux', { + expression: Fn.conditionNot(Fn.conditionEquals('Quux', 'Quuz')), + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasCondition('*', { + 'Fn::Equals': ['Baz', 'Bar'], + }), + [ + /2 conditions/, + /Missing key/, + ], + done, + ); + done(); + }); + + test('matching specific outputName', () => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + const inspect = Template.fromStack(stack); + expect(() => inspect.hasCondition('Foo', { 'Fn::Equals': ['Bar', 'Baz'] })).not.toThrow(); + }); + + test('not matching specific outputName', (done) => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Baz', 'Bar'), + }); + + const inspect = Template.fromStack(stack); + expectToThrow( + () => inspect.hasCondition('Foo', { + 'Fn::Equals': ['Bar', 'Baz'], + }), + [ + /1 conditions/, + /Expected Baz but received Bar/, + ], + done, + ); + done(); + }); + }); + + describe('findConditions', () => { + test('matching', () => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + new CfnCondition(stack, 'Qux', { + expression: Fn.conditionNot(Fn.conditionEquals('Quux', 'Quuz')), + }); + + const inspect = Template.fromStack(stack); + const firstCondition = inspect.findConditions('Foo'); + expect(firstCondition).toEqual({ + Foo: { + 'Fn::Equals': [ + 'Bar', + 'Baz', + ], + }, + }); + + const secondCondition = inspect.findConditions('Qux'); + expect(secondCondition).toEqual({ + Qux: { + 'Fn::Not': [ + { + 'Fn::Equals': [ + 'Quux', + 'Quuz', + ], + }, + ], + }, + }); + }); + + test('not matching', () => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findMappings('Bar'); + expect(Object.keys(result).length).toEqual(0); + }); + + test('matching with specific outputName', () => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findConditions('Foo', { 'Fn::Equals': ['Bar', 'Baz'] }); + expect(result).toEqual({ + Foo: { + 'Fn::Equals': [ + 'Bar', + 'Baz', + ], + }, + }); + }); + + test('not matching specific output name', () => { + const stack = new Stack(); + new CfnCondition(stack, 'Foo', { + expression: Fn.conditionEquals('Bar', 'Baz'), + }); + + const inspect = Template.fromStack(stack); + const result = inspect.findConditions('Foo', { 'Fn::Equals': ['Bar', 'Qux'] }); + expect(Object.keys(result).length).toEqual(0); + }); + }); }); function expectToThrow(fn: () => void, msgs: (RegExp | string)[], done: jest.DoneCallback): void { diff --git a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts index a354c8a4b3196..f7be4f954d7e8 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; -import { Duration, Lazy, Names, Stack } from '@aws-cdk/core'; +import { Arn, ArnFormat, Duration, Lazy, Names, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnAuthorizer } from '../apigateway.generated'; import { Authorizer, IAuthorizer } from '../authorizer'; @@ -254,5 +254,6 @@ export class RequestAuthorizer extends LambdaAuthorizer { * constructs the authorizerURIArn. */ function lambdaAuthorizerArn(handler: lambda.IFunction) { - return `arn:${Stack.of(handler).partition}:apigateway:${Stack.of(handler).region}:lambda:path/2015-03-31/functions/${handler.functionArn}/invocations`; + const { region, partition } = Arn.split( handler.functionArn, ArnFormat.COLON_RESOURCE_NAME); + return `arn:${partition}:apigateway:${region}:lambda:path/2015-03-31/functions/${handler.functionArn}/invocations`; } diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.lit.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.lit.expected.json index 9768e9692a548..981f02ebed888 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.lit.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.lit.expected.json @@ -253,11 +253,37 @@ [ "arn:", { - "Ref": "AWS::Partition" + "Fn::Select": [ + 1, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + } + ] + } + ] }, ":apigateway:", { - "Ref": "AWS::Region" + "Fn::Select": [ + 3, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + } + ] + } + ] }, ":lambda:path/2015-03-31/functions/", { diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json index b3d35baa2e42c..eda922f948d66 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json @@ -122,11 +122,37 @@ [ "arn:", { - "Ref": "AWS::Partition" + "Fn::Select": [ + 1, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + } + ] + } + ] }, ":apigateway:", { - "Ref": "AWS::Region" + "Fn::Select": [ + 3, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + } + ] + } + ] }, ":lambda:path/2015-03-31/functions/", { diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.lit.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.lit.expected.json index f36705d28f193..237a238eefcaa 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.lit.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.lit.expected.json @@ -253,11 +253,37 @@ [ "arn:", { - "Ref": "AWS::Partition" + "Fn::Select": [ + 1, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + } + ] + } + ] }, ":apigateway:", { - "Ref": "AWS::Region" + "Fn::Select": [ + 3, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "MyAuthorizerFunction70F1223E", + "Arn" + ] + } + ] + } + ] }, ":lambda:path/2015-03-31/functions/", { diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts b/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts index fdaa20af10cd3..6728e0204ed37 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts @@ -35,11 +35,31 @@ describe('lambda authorizer', () => { [ 'arn:', { - Ref: 'AWS::Partition', + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':apigateway:', { - Ref: 'AWS::Region', + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':lambda:path/2015-03-31/functions/', { @@ -89,11 +109,31 @@ describe('lambda authorizer', () => { [ 'arn:', { - Ref: 'AWS::Partition', + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':apigateway:', { - Ref: 'AWS::Region', + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':lambda:path/2015-03-31/functions/', { @@ -167,11 +207,31 @@ describe('lambda authorizer', () => { [ 'arn:', { - Ref: 'AWS::Partition', + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':apigateway:', { - Ref: 'AWS::Region', + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':lambda:path/2015-03-31/functions/', { @@ -218,11 +278,31 @@ describe('lambda authorizer', () => { [ 'arn:', { - Ref: 'AWS::Partition', + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':apigateway:', { - Ref: 'AWS::Region', + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':lambda:path/2015-03-31/functions/', { @@ -269,11 +349,31 @@ describe('lambda authorizer', () => { [ 'arn:', { - Ref: 'AWS::Partition', + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':apigateway:', { - Ref: 'AWS::Region', + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':lambda:path/2015-03-31/functions/', { @@ -341,11 +441,31 @@ describe('lambda authorizer', () => { [ 'arn:', { - Ref: 'AWS::Partition', + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':apigateway:', { - Ref: 'AWS::Region', + 'Fn::Select': [ + 3, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + ], + }, + ], }, ':lambda:path/2015-03-31/functions/', { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index ffe4d53a30896..e1f2183ab9e43 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index 7936a9364e84c..e2a885f180327 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -84,7 +84,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-appmesh/test/gateway-route.test.ts b/packages/@aws-cdk/aws-appmesh/test/gateway-route.test.ts index 6ae344e7ff297..63516490d37a8 100644 --- a/packages/@aws-cdk/aws-appmesh/test/gateway-route.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/gateway-route.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as appmesh from '../lib'; @@ -50,9 +49,9 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', - MeshOwner: ABSENT, + MeshOwner: Match.absent(), Spec: { HttpRoute: { Action: { @@ -70,7 +69,7 @@ describe('gateway route', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http2-route', Spec: { Http2Route: { @@ -89,7 +88,7 @@ describe('gateway route', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-grpc-route', Spec: { GrpcRoute: { @@ -163,11 +162,9 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { MeshOwner: meshEnv.account, }); - - }); }); @@ -214,7 +211,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -229,7 +226,7 @@ describe('gateway route', () => { }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-grpc-route', Spec: { GrpcRoute: { @@ -243,8 +240,6 @@ describe('gateway route', () => { }, }, }); - - }); }); @@ -279,10 +274,8 @@ describe('gateway route', () => { }), gatewayRouteName: 'gateway-http2-route', }); - - // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http2-route', Spec: { Http2Route: { @@ -296,8 +289,6 @@ describe('gateway route', () => { }, }, }); - - }); }); @@ -355,7 +346,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -370,7 +361,7 @@ describe('gateway route', () => { }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http2-route', Spec: { Http2Route: { @@ -385,18 +376,16 @@ describe('gateway route', () => { }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http2-route-1', Spec: { Http2Route: { Action: { - Rewrite: ABSENT, + Rewrite: Match.absent(), }, }, }, }); - - }); test("should throw an error if the prefix match does not start and end with '/'", () => { @@ -429,8 +418,6 @@ describe('gateway route', () => { gatewayRouteName: 'gateway-http-route', }); }).toThrow(/Prefix path for the match must start with \'\/\', got: test\//); - - expect(() => { virtualGateway.addGatewayRoute('gateway-http2-route', { routeSpec: appmesh.GatewayRouteSpec.http2({ @@ -442,8 +429,6 @@ describe('gateway route', () => { gatewayRouteName: 'gateway-http2-route', }); }).toThrow(/When prefix path for the rewrite is specified, prefix path for the match must end with \'\/\', got: \/test/); - - }); test("should throw an error if the custom prefix does not start and end with '/'", () => { @@ -488,8 +473,6 @@ describe('gateway route', () => { gatewayRouteName: 'gateway-http2-route', }); }).toThrow(/Prefix path for the rewrite must start and end with \'\/\', got: \/rewrittenUri/); - - }); }); @@ -535,7 +518,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -545,13 +528,13 @@ describe('gateway route', () => { }, }, Action: { - Rewrite: ABSENT, + Rewrite: Match.absent(), }, }, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-grpc-route', Spec: { GrpcRoute: { @@ -563,8 +546,6 @@ describe('gateway route', () => { }, }, }); - - }); }); @@ -610,7 +591,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-grpc-route', Spec: { GrpcRoute: { @@ -681,8 +662,6 @@ describe('gateway route', () => { }, }, }); - - }); test('should throw an error if the array length is invalid', () => { @@ -742,8 +721,6 @@ describe('gateway route', () => { gatewayRouteName: 'gateway-grpc-route', }); }).toThrow(/Number of metadata provided for matching must be between 1 and 10/); - - }); }); @@ -790,7 +767,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -861,8 +838,6 @@ describe('gateway route', () => { }, }, }); - - }); }); @@ -898,7 +873,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -908,8 +883,6 @@ describe('gateway route', () => { }, }, }); - - }); }); @@ -956,7 +929,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -966,13 +939,13 @@ describe('gateway route', () => { }, }, Action: { - Rewrite: ABSENT, + Rewrite: Match.absent(), }, }, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http2-route', Spec: { Http2Route: { @@ -984,8 +957,6 @@ describe('gateway route', () => { }, }, }); - - }); test('should throw an error if empty string is passed', () => { @@ -1019,8 +990,6 @@ describe('gateway route', () => { gatewayRouteName: 'gateway-http-route', }); }).toThrow(/Exact Path for the rewrite cannot be empty. Unlike startsWith\(\) method, no automatic rewrite on whole path match/); - - }); }); @@ -1058,7 +1027,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -1075,8 +1044,6 @@ describe('gateway route', () => { }, }, }); - - }); }); }); @@ -1112,7 +1079,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'gateway-http-route', Spec: { HttpRoute: { @@ -1157,7 +1124,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { Spec: { Priority: 100, }, @@ -1197,7 +1164,7 @@ describe('gateway route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { Spec: { Priority: 500, }, diff --git a/packages/@aws-cdk/aws-appmesh/test/health-check.test.ts b/packages/@aws-cdk/aws-appmesh/test/health-check.test.ts index 7abb6ed92f249..ebc78039d8cc4 100644 --- a/packages/@aws-cdk/aws-appmesh/test/health-check.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/health-check.test.ts @@ -1,5 +1,4 @@ import * as cdk from '@aws-cdk/core'; - import * as appmesh from '../lib'; let idCounter = 0; @@ -29,8 +28,6 @@ describe('health check', () => { expect(() => toThrow(max)).not.toThrow(); expect(() => toThrow(min - 1)).toThrow(/interval must be between 5 seconds and 300 seconds/); expect(() => toThrow(max + 1)).toThrow(/interval must be between 5 seconds and 300 seconds/); - - }); test('timeout', () => { // GIVEN @@ -48,8 +45,6 @@ describe('health check', () => { expect(() => toThrow(max)).not.toThrow(); expect(() => toThrow(min - 1)).toThrow(/timeout must be between 2 seconds and 60 seconds/); expect(() => toThrow(max + 1)).toThrow(/timeout must be between 2 seconds and 60 seconds/); - - }); test('healthyThreshold', () => { // GIVEN @@ -67,8 +62,6 @@ describe('health check', () => { expect(() => toThrow(max)).not.toThrow(); expect(() => toThrow(min - 1)).toThrow(/healthyThreshold must be between 2 and 10/); expect(() => toThrow(max + 1)).toThrow(/healthyThreshold must be between 2 and 10/); - - }); test('unhealthyThreshold', () => { // GIVEN @@ -86,7 +79,5 @@ describe('health check', () => { expect(() => toThrow(max)).not.toThrow(); expect(() => toThrow(min - 1)).toThrow(/unhealthyThreshold must be between 2 and 10/); expect(() => toThrow(max + 1)).toThrow(/unhealthyThreshold must be between 2 and 10/); - - }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts b/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts index 294701e0d550a..e8f7588e59f4f 100644 --- a/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts @@ -1,8 +1,7 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; - import * as appmesh from '../lib'; describe('mesh', () => { @@ -16,13 +15,11 @@ describe('mesh', () => { new appmesh.Mesh(stack, 'mesh', { meshName: 'test-mesh' }); // THEN - expect(stack). - toHaveResource('AWS::AppMesh::Mesh', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Mesh', { Spec: { }, }); - - }); }); @@ -38,16 +35,14 @@ describe('mesh', () => { }); // THEN - expect(stack). - toHaveResource('AWS::AppMesh::Mesh', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Mesh', { Spec: { EgressFilter: { Type: 'ALLOW_ALL', }, }, }); - - }); }); }); @@ -66,8 +61,8 @@ describe('mesh', () => { mesh.addVirtualRouter('router'); // THEN - expect(stack). - toHaveResource('AWS::AppMesh::VirtualRouter', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualRouter', { Spec: { Listeners: [ { @@ -79,8 +74,6 @@ describe('mesh', () => { ], }, }); - - }); }); }); @@ -105,7 +98,7 @@ describe('mesh', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { ServiceDiscovery: { AWSCloudMap: { @@ -115,8 +108,6 @@ describe('mesh', () => { }, }, }); - - }); test('VirtualService can use CloudMap service with instanceAttributes', () => { @@ -142,7 +133,7 @@ describe('mesh', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { ServiceDiscovery: { AWSCloudMap: { @@ -158,8 +149,6 @@ describe('mesh', () => { }, }, }); - - }); describe('When adding a VirtualNode to a mesh', () => { @@ -178,8 +167,8 @@ describe('mesh', () => { }); // THEN - expect(stack). - toHaveResource('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualNode', { MeshName: { 'Fn::GetAtt': ['meshACDFE68E', 'MeshName'], }, @@ -192,8 +181,6 @@ describe('mesh', () => { }, }, }); - - }); }); describe('with added listeners', () => { @@ -214,8 +201,8 @@ describe('mesh', () => { }); // THEN - expect(stack). - toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualNode', { MeshName: { 'Fn::GetAtt': ['meshACDFE68E', 'MeshName'], }, @@ -230,8 +217,6 @@ describe('mesh', () => { ], }, }); - - }); }); describe('with added listeners with healthchecks', () => { @@ -259,14 +244,14 @@ describe('mesh', () => { }); // THEN - expect(stack). - toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualNode', { MeshName: { 'Fn::GetAtt': ['meshACDFE68E', 'MeshName'], }, Spec: { Listeners: [ - { + Match.objectLike({ HealthCheck: { HealthyThreshold: 3, IntervalMillis: 5000, @@ -276,12 +261,10 @@ describe('mesh', () => { TimeoutMillis: 2000, UnhealthyThreshold: 2, }, - }, + }), ], }, }); - - }); }); describe('with backends', () => { @@ -308,8 +291,8 @@ describe('mesh', () => { }); // THEN - expect(stack). - toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Backends: [ { @@ -320,8 +303,6 @@ describe('mesh', () => { ], }, }); - - }); }); }); @@ -336,13 +317,11 @@ describe('mesh', () => { }); // THEN - expect(stack2). - toHaveResourceLike('AWS::AppMesh::VirtualService', { + Template.fromStack(stack2). + hasResourceProperties('AWS::AppMesh::VirtualService', { MeshName: 'abc', Spec: {}, VirtualServiceName: 'test.domain.local', }); - - }); }); diff --git a/packages/@aws-cdk/aws-appmesh/test/route.test.ts b/packages/@aws-cdk/aws-appmesh/test/route.test.ts index e39b20585a03c..130a46f058f63 100644 --- a/packages/@aws-cdk/aws-appmesh/test/route.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/route.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as appmesh from '../lib'; @@ -80,7 +79,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { Action: { @@ -111,11 +110,11 @@ describe('route', () => { }, }, }, - MeshOwner: ABSENT, + MeshOwner: Match.absent(), RouteName: 'test-http-route', }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Http2Route: { Action: { @@ -149,7 +148,7 @@ describe('route', () => { RouteName: 'test-http2-route', }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { TcpRoute: { Action: { @@ -176,7 +175,7 @@ describe('route', () => { RouteName: 'test-tcp-route', }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { GrpcRoute: { Action: { @@ -209,8 +208,6 @@ describe('route', () => { }, RouteName: 'test-grpc-route', }); - - }); test('should have expected features', () => { @@ -247,7 +244,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { Action: { @@ -311,7 +308,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { RetryPolicy: { @@ -326,11 +323,9 @@ describe('route', () => { }, }, }); - - }); - test('http retry events are ABSENT when specified as an empty array', () => { + test('http retry events are Match.absent() when specified as an empty array', () => { // GIVEN const stack = new cdk.Stack(); const mesh = new appmesh.Mesh(stack, 'mesh', { @@ -370,28 +365,26 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { RetryPolicy: { - HttpRetryEvents: ABSENT, + HttpRetryEvents: Match.absent(), TcpRetryEvents: ['connection-error'], }, }, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { RetryPolicy: { HttpRetryEvents: ['client-error'], - TcpRetryEvents: ABSENT, + TcpRetryEvents: Match.absent(), }, }, }, }); - - }); test('errors when http retry policy has no events', () => { @@ -420,8 +413,6 @@ describe('route', () => { }), }); }).toThrow(/specify one value for at least/i); - - }); test('should allow grpc retries', () => { @@ -454,7 +445,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { GrpcRoute: { RetryPolicy: { @@ -470,11 +461,9 @@ describe('route', () => { }, }, }); - - }); - test('grpc retry events are ABSENT when specified as an empty array', () => { + test('grpc retry events are Match.absent() when specified as an empty array', () => { // GIVEN const stack = new cdk.Stack(); const mesh = new appmesh.Mesh(stack, 'mesh', { @@ -518,30 +507,28 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { GrpcRoute: { RetryPolicy: { - GrpcRetryEvents: ABSENT, - HttpRetryEvents: ABSENT, + GrpcRetryEvents: Match.absent(), + HttpRetryEvents: Match.absent(), TcpRetryEvents: ['connection-error'], }, }, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { GrpcRoute: { RetryPolicy: { GrpcRetryEvents: ['cancelled'], - HttpRetryEvents: ABSENT, - TcpRetryEvents: ABSENT, + HttpRetryEvents: Match.absent(), + TcpRetryEvents: Match.absent(), }, }, }, }); - - }); test('errors when grpc retry policy has no events', () => { @@ -571,8 +558,6 @@ describe('route', () => { }), }); }).toThrow(/specify one value for at least/i); - - }); describe('with shared service mesh', () => { @@ -605,11 +590,9 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { MeshOwner: meshEnv.account, }); - - }); }); }); @@ -653,7 +636,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Http2Route: { Match: { @@ -724,8 +707,6 @@ describe('route', () => { }, }, }); - - }); test('should match routes based on method', () => { @@ -756,7 +737,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Http2Route: { Match: { @@ -766,8 +747,6 @@ describe('route', () => { }, }, }); - - }); test('should match routes based on scheme', () => { @@ -798,7 +777,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Http2Route: { Match: { @@ -808,8 +787,6 @@ describe('route', () => { }, }, }); - - }); test('should match routes based on metadata', () => { @@ -852,7 +829,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { GrpcRoute: { Match: { @@ -922,8 +899,6 @@ describe('route', () => { }, }, }); - - }); test('should match routes based on path', () => { @@ -966,7 +941,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { Match: { @@ -978,7 +953,7 @@ describe('route', () => { }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Http2Route: { Match: { @@ -989,8 +964,6 @@ describe('route', () => { }, }, }); - - }); test('should match routes based query parameter', () => { @@ -1022,7 +995,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { HttpRoute: { Match: { @@ -1038,8 +1011,6 @@ describe('route', () => { }, }, }); - - }); test('should match routes based method name', () => { @@ -1073,7 +1044,7 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { GrpcRoute: { Match: { @@ -1083,8 +1054,6 @@ describe('route', () => { }, }, }); - - }); test('should throw an error with invalid number of headers', () => { @@ -1141,8 +1110,6 @@ describe('route', () => { }), }); }).toThrow(/Number of headers provided for matching must be between 1 and 10, got: 11/); - - }); test('should throw an error with invalid number of query parameters', () => { @@ -1199,8 +1166,6 @@ describe('route', () => { }), }); }).toThrow(/Number of query parameters provided for matching must be between 1 and 10, got: 11/); - - }); test('should throw an error with invalid number of metadata', () => { @@ -1260,8 +1225,6 @@ describe('route', () => { }), }); }).toThrow(/Number of metadata provided for matching must be between 1 and 10, got: 11/); - - }); test('should throw an error if no gRPC match type is defined', () => { @@ -1292,8 +1255,6 @@ describe('route', () => { }), }); }).toThrow(/At least one gRPC route match property must be provided/); - - }); test('should throw an error if method name is specified without service name', () => { @@ -1326,8 +1287,6 @@ describe('route', () => { }), }); }).toThrow(/If you specify a method name, you must also specify a service name/); - - }); test('should allow route priority', () => { @@ -1376,32 +1335,30 @@ describe('route', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Priority: 0, Http2Route: {}, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Priority: 10, HttpRoute: {}, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Priority: 20, GrpcRoute: {}, }, }); - expect(stack).toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::Route', { Spec: { Priority: 30, TcpRoute: {}, }, }); - - }); test('Can import Routes using an ARN', () => { @@ -1443,7 +1400,5 @@ describe('route', () => { // THEN expect(route.routeName).toEqual(routeName); expect(route.virtualRouter.mesh.meshName).toEqual(meshName); - - }); }); diff --git a/packages/@aws-cdk/aws-appmesh/test/virtual-gateway.test.ts b/packages/@aws-cdk/aws-appmesh/test/virtual-gateway.test.ts index 17a78b7d361d6..eadfebec29493 100644 --- a/packages/@aws-cdk/aws-appmesh/test/virtual-gateway.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/virtual-gateway.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; @@ -39,7 +38,7 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ { @@ -53,7 +52,7 @@ describe('virtual gateway', () => { VirtualGatewayName: 'testGateway', }); - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ { @@ -74,10 +73,10 @@ describe('virtual gateway', () => { ], }, VirtualGatewayName: 'httpGateway', - MeshOwner: ABSENT, + MeshOwner: Match.absent(), }); - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ { @@ -99,7 +98,6 @@ describe('virtual gateway', () => { }, VirtualGatewayName: 'http2Gateway', }); - }); test('should have expected features', () => { @@ -122,7 +120,7 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ { @@ -150,7 +148,6 @@ describe('virtual gateway', () => { }, VirtualGatewayName: 'test-gateway', }); - }); test('with an http listener with a TLS certificate from ACM', () => { @@ -179,10 +176,10 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -193,12 +190,10 @@ describe('virtual gateway', () => { }, }, }, - }, + }), ], }, }); - - }); test('with an grpc listener with a TLS certificate from file', () => { @@ -223,10 +218,10 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -236,12 +231,10 @@ describe('virtual gateway', () => { }, }, }, - }, + }), ], }, }); - - }); test('with an http2 listener with a TLS certificate from SDS', () => { @@ -265,10 +258,10 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -277,12 +270,10 @@ describe('virtual gateway', () => { }, }, }, - }, + }), ], }, }); - - }); describe('with an grpc listener with a TLS validation from file', () => { @@ -310,10 +301,10 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -330,12 +321,10 @@ describe('virtual gateway', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -365,10 +354,10 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -384,12 +373,10 @@ describe('virtual gateway', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -415,10 +402,10 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.PERMISSIVE, Certificate: { @@ -428,12 +415,10 @@ describe('virtual gateway', () => { }, }, }, - }, + }), ], }, }); - - }); describe('with shared service mesh', () => { @@ -455,11 +440,9 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { MeshOwner: meshEnv.account, }); - - }); }); }); @@ -491,7 +474,7 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'test-gateway-route', Spec: { HttpRoute: { @@ -510,7 +493,6 @@ describe('virtual gateway', () => { }, }, }); - }); }); @@ -542,13 +524,12 @@ describe('virtual gateway', () => { }), }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'test-gateway-route', }); - expect(stack).toHaveResourceLike('AWS::AppMesh::GatewayRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::GatewayRoute', { GatewayRouteName: 'test-gateway-route-2', }); - }); }); @@ -575,7 +556,7 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { VirtualGatewayName: 'virtual-gateway', Spec: { BackendDefaults: { @@ -593,8 +574,6 @@ describe('virtual gateway', () => { }, }, }); - - }); describe("with client's TLS certificate from SDS", () => { @@ -621,7 +600,7 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { VirtualGatewayName: 'virtual-gateway', Spec: { BackendDefaults: { @@ -649,8 +628,6 @@ describe('virtual gateway', () => { }, }, }); - - }); }); }); @@ -679,23 +656,21 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { VirtualGatewayName: 'virtual-gateway', Spec: { Listeners: [ - { + Match.objectLike({ ConnectionPool: { HTTP: { MaxConnections: 100, MaxPendingRequests: 10, }, }, - }, + }), ], }, }); - - }); test('Can add an grpc connection pool to listener', () => { @@ -721,22 +696,20 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { VirtualGatewayName: 'virtual-gateway', Spec: { Listeners: [ - { + Match.objectLike({ ConnectionPool: { GRPC: { MaxRequests: 10, }, }, - }, + }), ], }, }); - - }); test('Can add an http2 connection pool to listener', () => { @@ -762,22 +735,20 @@ describe('virtual gateway', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualGateway', { VirtualGatewayName: 'virtual-gateway', Spec: { Listeners: [ - { + Match.objectLike({ ConnectionPool: { HTTP2: { MaxRequests: 10, }, }, - }, + }), ], }, }); - - }); test('Can import VirtualGateways using an ARN', () => { @@ -796,7 +767,6 @@ describe('virtual gateway', () => { // THEN expect(virtualGateway.mesh.meshName).toEqual(meshName); expect(virtualGateway.virtualGatewayName).toEqual(virtualGatewayName); - }); test('Can import VirtualGateways using attributes', () => { @@ -816,8 +786,6 @@ describe('virtual gateway', () => { // THEN expect(virtualGateway.mesh.meshName).toEqual(meshName); expect(virtualGateway.virtualGatewayName).toEqual(virtualGatewayName); - - }); test('Can grant an identity StreamAggregatedResources for a given VirtualGateway', () => { @@ -835,7 +803,7 @@ describe('virtual gateway', () => { gateway.grantStreamAggregatedResources(user); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -848,7 +816,5 @@ describe('virtual gateway', () => { ], }, }); - - }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts b/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts index 842c061f68a15..f419f7ac41733 100644 --- a/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acmpca from '@aws-cdk/aws-acmpca'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as iam from '@aws-cdk/aws-iam'; @@ -36,7 +35,7 @@ describe('virtual node', () => { node.addBackend(appmesh.Backend.virtualService(service2)); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Backends: [ { @@ -51,7 +50,7 @@ describe('virtual node', () => { }, ], }, - MeshOwner: ABSENT, + MeshOwner: Match.absent(), }); }); }); @@ -75,7 +74,7 @@ describe('virtual node', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ { @@ -87,8 +86,6 @@ describe('virtual node', () => { ], }, }); - - }); }); @@ -115,7 +112,7 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ { @@ -139,8 +136,6 @@ describe('virtual node', () => { ], }, }); - - }); }); @@ -165,10 +160,10 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ HealthCheck: { HealthyThreshold: 2, IntervalMillis: 5000, @@ -189,12 +184,10 @@ describe('virtual node', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -222,10 +215,10 @@ describe('virtual node', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ HealthCheck: { HealthyThreshold: 2, IntervalMillis: 5000, @@ -246,12 +239,10 @@ describe('virtual node', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -281,7 +272,7 @@ describe('virtual node', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ { @@ -305,8 +296,6 @@ describe('virtual node', () => { ], }, }); - - }); }); @@ -336,7 +325,7 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { BackendDefaults: { ClientPolicy: { @@ -354,8 +343,6 @@ describe('virtual node', () => { }, }, }); - - }); }); @@ -384,7 +371,7 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { BackendDefaults: { ClientPolicy: { @@ -412,8 +399,6 @@ describe('virtual node', () => { }, }, }); - - }); }); @@ -447,7 +432,7 @@ describe('virtual node', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Backends: [ { @@ -494,7 +479,7 @@ describe('virtual node', () => { node.addBackend(appmesh.Backend.virtualService(myVirtualService)); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Backends: [ { @@ -528,7 +513,7 @@ describe('virtual node', () => { node.addBackend(appmesh.Backend.virtualService(myVirtualService)); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Backends: [ { @@ -570,10 +555,10 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -584,12 +569,10 @@ describe('virtual node', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -616,10 +599,10 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -629,12 +612,10 @@ describe('virtual node', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -660,10 +641,10 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.STRICT, Certificate: { @@ -672,12 +653,10 @@ describe('virtual node', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -704,10 +683,10 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ TLS: { Mode: appmesh.TlsMode.PERMISSIVE, Certificate: { @@ -717,12 +696,10 @@ describe('virtual node', () => { }, }, }, - }, + }), ], }, }); - - }); }); @@ -750,22 +727,20 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ ConnectionPool: { HTTP: { MaxConnections: 100, MaxPendingRequests: 10, }, }, - }, + }), ], }, }); - - }); test('Can add an tcp connection pool to listener', () => { @@ -791,21 +766,19 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { - Listeners: [ - { + Listeners: Match.arrayWith([ + Match.objectLike({ ConnectionPool: { TCP: { MaxConnections: 100, }, }, - }, - ], + }), + ]), }, }); - - }); test('Can add an grpc connection pool to listener', () => { @@ -831,21 +804,19 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { - Listeners: [ - { + Listeners: Match.arrayWith([ + Match.objectLike({ ConnectionPool: { GRPC: { MaxRequests: 10, }, }, - }, - ], + }), + ]), }, }); - - }); test('Can add an http2 connection pool to listener', () => { @@ -871,21 +842,19 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { Listeners: [ - { + Match.objectLike({ ConnectionPool: { HTTP2: { MaxRequests: 10, }, }, - }, + }), ], }, }); - - }); }); @@ -903,8 +872,6 @@ describe('virtual node', () => { // THEN expect(virtualNode.mesh.meshName).toEqual(meshName); expect(virtualNode.virtualNodeName).toEqual(virtualNodeName); - - }); test('Can import Virtual Nodes using attributes', () => { @@ -920,8 +887,6 @@ describe('virtual node', () => { // THEN expect(virtualNode.mesh.meshName).toEqual(meshName); expect(virtualNode.virtualNodeName).toEqual(virtualNodeName); - - }); test('Can grant an identity StreamAggregatedResources for a given VirtualNode', () => { @@ -947,7 +912,7 @@ describe('virtual node', () => { node.grantStreamAggregatedResources(user); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -960,8 +925,6 @@ describe('virtual node', () => { ], }, }); - - }); describe('When creating a VirtualNode', () => { @@ -984,11 +947,9 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { MeshOwner: meshEnv.account, }); - - }); }); @@ -1008,7 +969,7 @@ describe('virtual node', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualNode', { Spec: { ServiceDiscovery: { DNS: { @@ -1018,8 +979,6 @@ describe('virtual node', () => { }, }, }); - - }); }); @@ -1053,11 +1012,7 @@ describe('virtual node', () => { expect(() => { node.addListener(appmesh.VirtualNodeListener.http()); }).toThrow(/Service discovery information is required for a VirtualNode with a listener/); - - }); }); }); }); - - diff --git a/packages/@aws-cdk/aws-appmesh/test/virtual-router.test.ts b/packages/@aws-cdk/aws-appmesh/test/virtual-router.test.ts index 7342aa8f052bd..24df84fd051ad 100644 --- a/packages/@aws-cdk/aws-appmesh/test/virtual-router.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/virtual-router.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as appmesh from '../lib'; @@ -11,10 +10,11 @@ describe('virtual router', () => { const mesh = new appmesh.Mesh(stack, 'mesh', { meshName: 'test-mesh', }); + // WHEN mesh.addVirtualRouter('http-router-listener'); - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualRouter', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualRouter', { VirtualRouterName: 'meshhttprouterlistenerF57BCB2F', Spec: { Listeners: [ @@ -27,14 +27,15 @@ describe('virtual router', () => { ], }, }); - }); + test('should have protocol variant listeners', () => { // GIVEN const stack = new cdk.Stack(); const mesh = new appmesh.Mesh(stack, 'mesh', { meshName: 'test-mesh', }); + // WHEN mesh.addVirtualRouter('http-router-listener', { listeners: [ @@ -67,7 +68,7 @@ describe('virtual router', () => { // THEN const expectedPorts = [appmesh.Protocol.HTTP, appmesh.Protocol.HTTP2, appmesh.Protocol.GRPC, appmesh.Protocol.TCP]; expectedPorts.forEach(protocol => { - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualRouter', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualRouter', { VirtualRouterName: `${protocol}-router-listener`, Spec: { Listeners: [ @@ -79,11 +80,9 @@ describe('virtual router', () => { }, ], }, - MeshOwner: ABSENT, + MeshOwner: Match.absent(), }); }); - - }); describe('with shared service mesh', () => { @@ -105,11 +104,9 @@ describe('virtual router', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualRouter', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualRouter', { MeshOwner: meshEnv.account, }); - - }); }); }); @@ -154,8 +151,8 @@ describe('virtual router', () => { }); // THEN - expect(stack). - toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Route', { RouteName: 'route-1', Spec: { HttpRoute: { @@ -178,8 +175,6 @@ describe('virtual router', () => { 'Fn::GetAtt': ['meshrouter81B8087E', 'VirtualRouterName'], }, }); - - }); }); describe('When adding routes to a VirtualRouter with existing routes', () => { @@ -268,8 +263,8 @@ describe('virtual router', () => { }); // THEN - expect(stack). - toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Route', { RouteName: 'route-1', Spec: { HttpRoute: { @@ -290,8 +285,8 @@ describe('virtual router', () => { }, }); - expect(stack). - toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Route', { RouteName: 'route-2', Spec: { HttpRoute: { @@ -312,8 +307,8 @@ describe('virtual router', () => { }, }); - expect(stack). - toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Route', { RouteName: 'route-3', Spec: { HttpRoute: { @@ -333,8 +328,6 @@ describe('virtual router', () => { }, }, }); - - }); }); describe('When adding a TCP route to existing VirtualRouter', () => { @@ -374,8 +367,8 @@ describe('virtual router', () => { }); // THEN - expect(stack). - toHaveResourceLike('AWS::AppMesh::Route', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::Route', { RouteName: 'route-tcp-1', Spec: { TcpRoute: { @@ -395,8 +388,6 @@ describe('virtual router', () => { 'Fn::GetAtt': ['meshrouter81B8087E', 'VirtualRouterName'], }, }); - - }); }); @@ -414,8 +405,6 @@ describe('virtual router', () => { // THEN expect(virtualRouter.mesh.meshName).toEqual(meshName); expect(virtualRouter.virtualRouterName).toEqual(virtualRouterName); - - }); test('Can import Virtual Routers using attributes', () => { // GIVEN @@ -433,7 +422,5 @@ describe('virtual router', () => { // THEN expect(virtualRouter1.mesh.meshName).toEqual(meshName); expect(virtualRouter1.virtualRouterName).toEqual(virtualRouterName); - - }); }); diff --git a/packages/@aws-cdk/aws-appmesh/test/virtual-service.test.ts b/packages/@aws-cdk/aws-appmesh/test/virtual-service.test.ts index d74ad01920ef0..2cec646ed7377 100644 --- a/packages/@aws-cdk/aws-appmesh/test/virtual-service.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/virtual-service.test.ts @@ -1,7 +1,5 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; - import * as appmesh from '../lib'; describe('virtual service', () => { @@ -17,8 +15,6 @@ describe('virtual service', () => { // THEN expect(virtualRouter.mesh.meshName).toEqual(meshName); expect(virtualRouter.virtualRouterName).toEqual(virtualServiceName); - - }); test('Can import Virtual Services using attributes', () => { @@ -36,8 +32,6 @@ describe('virtual service', () => { // THEN expect(virtualService.mesh.meshName).toEqual(meshName); expect(virtualService.virtualServiceName).toEqual(virtualServiceName); - - }); describe('When adding a VirtualService to a mesh', () => { @@ -63,8 +57,8 @@ describe('virtual service', () => { }); // THEN - expect(stack). - toHaveResource('AWS::AppMesh::VirtualService', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualService', { Spec: { Provider: { VirtualRouter: { @@ -74,10 +68,8 @@ describe('virtual service', () => { }, }, }, - MeshOwner: ABSENT, + MeshOwner: Match.absent(), }); - - }); }); @@ -104,8 +96,8 @@ describe('virtual service', () => { }); // THEN - expect(stack). - toHaveResource('AWS::AppMesh::VirtualService', { + Template.fromStack(stack). + hasResourceProperties('AWS::AppMesh::VirtualService', { Spec: { Provider: { VirtualNode: { @@ -116,8 +108,6 @@ describe('virtual service', () => { }, }, }); - - }); }); }); @@ -149,11 +139,9 @@ describe('virtual service', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualService', { + Template.fromStack(stack).hasResourceProperties('AWS::AppMesh::VirtualService', { MeshOwner: meshEnv.account, }); - - }); }); }); diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json index db0b2433d6583..5766802aa1e3e 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -29,7 +29,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/sinon": "^9.0.11", "@aws-cdk/cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", @@ -44,6 +44,6 @@ "lambda-tester": "^3.6.0", "sinon": "^9.2.4", "nock": "^13.2.2", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 78fec9d65cd49..86685caaf49ff 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/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/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts index 8edcdf95b8158..4b49f423f0a1a 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as route53 from '@aws-cdk/aws-route53'; import { Duration, Lazy, Stack } from '@aws-cdk/core'; import { Certificate, CertificateValidation } from '../lib'; @@ -10,7 +10,7 @@ test('apex domain selection by default', () => { domainName: 'test.example.com', }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', DomainValidationOptions: [{ DomainName: 'test.example.com', @@ -48,7 +48,7 @@ test('validation domain can be overridden', () => { }), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainValidationOptions: [{ DomainName: 'test.example.com', ValidationDomain: 'test.example.com', @@ -75,7 +75,7 @@ test('can configure validation method', () => { validation: CertificateValidation.fromDns(), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', ValidationMethod: 'DNS', }); @@ -103,7 +103,7 @@ test('validationdomains can be given for a Token', () => { }), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'my.example.com', DomainValidationOptions: [{ DomainName: 'my.example.com', @@ -123,7 +123,7 @@ test('CertificateValidation.fromEmail', () => { }), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', SubjectAlternativeNames: ['extra.example.com'], DomainValidationOptions: [ @@ -151,7 +151,7 @@ describe('CertificateValidation.fromDns', () => { validation: CertificateValidation.fromDns(), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', SubjectAlternativeNames: ['extra.example.com'], ValidationMethod: 'DNS', @@ -170,7 +170,7 @@ describe('CertificateValidation.fromDns', () => { validation: CertificateValidation.fromDns(exampleCom), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', DomainValidationOptions: [ { @@ -198,7 +198,7 @@ describe('CertificateValidation.fromDns', () => { }); //Wildcard domain names are de-duped. - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', DomainValidationOptions: [ { @@ -226,7 +226,7 @@ describe('CertificateValidation.fromDns', () => { }); //Wildcard domain names are de-duped. - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', DomainValidationOptions: [ { @@ -275,7 +275,7 @@ test('CertificateValidation.fromDnsMultiZone', () => { }), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', DomainValidationOptions: [ { diff --git a/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts index aadce823b74a0..935f8680415b4 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { SynthUtils } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import { HostedZone, PublicHostedZone } from '@aws-cdk/aws-route53'; import { App, Stack, Token, Tags } from '@aws-cdk/core'; @@ -17,7 +16,7 @@ test('creates CloudFormation Custom Resource', () => { hostedZone: exampleDotComZone, }); - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::CustomResource', { DomainName: 'test.example.com', ServiceToken: { 'Fn::GetAtt': [ @@ -29,12 +28,12 @@ test('creates CloudFormation Custom Resource', () => { Ref: 'ExampleDotCom4D1B83AA', }, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: 'index.certificateRequestHandler', Runtime: 'nodejs12.x', Timeout: 900, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyName: 'CertificateCertificateRequestorFunctionServiceRoleDefaultPolicy3C8845BC', Roles: [ { @@ -92,7 +91,7 @@ test('adds validation error on domain mismatch', () => { }); expect(() => { - SynthUtils.synthesize(stack); + Template.fromStack(stack); }).toThrow(/DNS zone hello.com is not authoritative for certificate domain name example.com/); }); @@ -108,7 +107,7 @@ test('does not try to validate unresolved tokens', () => { hostedZone: helloDotComZone, }); - SynthUtils.synthesize(stack); // does not throw + Template.fromStack(stack); // does not throw }); test('test root certificate', () => { @@ -123,7 +122,7 @@ test('test root certificate', () => { hostedZone: exampleDotComZone, }); - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::CustomResource', { ServiceToken: { 'Fn::GetAtt': [ 'CertCertificateRequestorFunction98FDF273', @@ -150,7 +149,7 @@ test('test tags are passed to customresource', () => { hostedZone: exampleDotComZone, }); - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::CustomResource', { ServiceToken: { 'Fn::GetAtt': [ 'CertCertificateRequestorFunction98FDF273', @@ -185,7 +184,7 @@ test('works with imported zone', () => { }); // THEN - expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::CustomResource', { ServiceToken: { 'Fn::GetAtt': [ 'CertCertificateRequestorFunction98FDF273', @@ -217,7 +216,7 @@ test('works with imported role', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Role: 'arn:aws:iam::account-id:role/role-name', }); }); diff --git a/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts index e43a4ca005691..fe9008f15e135 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as acmpca from '@aws-cdk/aws-acmpca'; import { Duration, Lazy, Stack } from '@aws-cdk/core'; import { PrivateCertificate } from '../lib'; @@ -12,7 +12,7 @@ test('private certificate authority', () => { 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', }); @@ -28,7 +28,7 @@ test('private certificate authority with subjectAlternativeNames', () => { 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', SubjectAlternativeNames: ['extra.example.com'], CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', @@ -45,7 +45,7 @@ test('private certificate authority with multiple subjectAlternativeNames', () = 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', SubjectAlternativeNames: ['*.test.example.com', '*.foo.test.example.com', 'bar.test.example.com'], CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', @@ -73,7 +73,7 @@ test('private certificate authority with tokens', () => { certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', certificateAuthority), }); - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'test.example.com', SubjectAlternativeNames: ['extra.example.com'], CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', diff --git a/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts index a4bdb2e05e1e0..5c1ccf5315499 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import { PublicHostedZone } from '@aws-cdk/aws-route53'; import { App, Aws, Stack } from '@aws-cdk/core'; import { Certificate, DnsValidatedCertificate } from '../lib'; diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index ea34b27c4a74d..2abb1900c7cfd 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/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/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts b/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts index a5d2b443ed486..9918dba29a1a1 100644 --- a/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts +++ b/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts @@ -1,5 +1,4 @@ -import { ABSENT } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; @@ -21,7 +20,7 @@ describe('SlackChannelConfiguration', () => { slackChannelConfigurationName: 'Test', }); - expect(stack).toHaveResourceLike('AWS::Chatbot::SlackChannelConfiguration', { + Template.fromStack(stack).hasResourceProperties('AWS::Chatbot::SlackChannelConfiguration', { ConfigurationName: 'Test', IamRoleArn: { 'Fn::GetAtt': [ @@ -33,7 +32,7 @@ describe('SlackChannelConfiguration', () => { SlackWorkspaceId: 'ABC123', }); - expect(stack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -57,7 +56,7 @@ describe('SlackChannelConfiguration', () => { loggingLevel: chatbot.LoggingLevel.ERROR, }); - expect(stack).toHaveResourceLike('AWS::Chatbot::SlackChannelConfiguration', { + Template.fromStack(stack).hasResourceProperties('AWS::Chatbot::SlackChannelConfiguration', { ConfigurationName: 'Test', IamRoleArn: { 'Fn::GetAtt': [ @@ -81,7 +80,7 @@ describe('SlackChannelConfiguration', () => { notificationTopics: [topic], }); - expect(stack).toHaveResourceLike('AWS::Chatbot::SlackChannelConfiguration', { + Template.fromStack(stack).hasResourceProperties('AWS::Chatbot::SlackChannelConfiguration', { ConfigurationName: 'Test', IamRoleArn: { 'Fn::GetAtt': [ @@ -109,7 +108,7 @@ describe('SlackChannelConfiguration', () => { const topic = new sns.Topic(stack, 'MyTopic'); slackChannel.addNotificationTopic(topic); - expect(stack).toHaveResourceLike('AWS::Chatbot::SlackChannelConfiguration', { + Template.fromStack(stack).hasResourceProperties('AWS::Chatbot::SlackChannelConfiguration', { ConfigurationName: 'Test', SnsTopicArns: [ { @@ -129,7 +128,7 @@ describe('SlackChannelConfiguration', () => { role: role, }); - expect(stack).toCountResources('AWS::IAM::Role', 0); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); }); test('created with new role and extra iam policies', () => { @@ -147,7 +146,7 @@ describe('SlackChannelConfiguration', () => { resources: ['arn:aws:s3:::abc/xyz/123.txt'], })); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -169,7 +168,7 @@ describe('SlackChannelConfiguration', () => { logRetention: logs.RetentionDays.ONE_MONTH, }); - expect(stack).toHaveResourceLike('Custom::LogRetention', { + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { LogGroupName: '/aws/chatbot/ConfigurationName', RetentionInDays: 30, LogGroupRegion: 'us-east-1', @@ -199,7 +198,7 @@ describe('SlackChannelConfiguration', () => { }, metricName: 'MetricName', })); - expect(stack).toHaveResourceLike('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { Namespace: 'AWS/Chatbot', MetricName: 'MetricName', Dimensions: [ @@ -228,10 +227,10 @@ describe('SlackChannelConfiguration', () => { region: 'us-east-1', metricName: 'MetricName', })); - expect(stack).toHaveResourceLike('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { Namespace: 'AWS/Chatbot', MetricName: 'MetricName', - Dimensions: ABSENT, + Dimensions: Match.absent(), ComparisonOperator: 'GreaterThanThreshold', EvaluationPeriods: 1, Threshold: 0, @@ -249,8 +248,8 @@ describe('SlackChannelConfiguration', () => { resources: ['arn:aws:s3:::abc/xyz/123.txt'], })); - expect(stack).toCountResources('AWS::IAM::Role', 0); - expect(stack).toCountResources('AWS::IAM::Policy', 0); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Policy', 0); }); test('should throw error if ARN invalid', () => { diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 5a7014994d6c5..f9d68e24b15a3 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "jest": "^27.4.7" }, diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index 132c0705f1ae6..a7fd2e966e6fd 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/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/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-cloudfront-origins/test/http-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts index dc8c6c702fce3..c64a04bf26ced 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import { App, Duration, Stack } from '@aws-cdk/core'; import { HttpOrigin } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts index 8a21feb22f30e..899fe27ce2e39 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { App, Duration, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts index d8f8bb10fabb2..8289c9c2794e3 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import { Stack } from '@aws-cdk/core'; @@ -29,7 +29,7 @@ describe('Origin Groups', () => { const primaryOriginId = 'DistributionOrigin13547B94F'; const failoverOriginId = 'DistributionOrigin2C85CC43B'; const originGroupId = 'DistributionOriginGroup1A1A31B49'; - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { TargetOriginId: originGroupId, diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts index 9f817d1d7e986..5d2d27a1bce0e 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, Stack } from '@aws-cdk/core'; @@ -77,16 +77,17 @@ describe('With bucket', () => { const origin = new S3Origin(bucket, { originAccessIdentity }); new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin } }); - expect(stack).toHaveResourceLike('AWS::CloudFront::CloudFrontOriginAccessIdentity', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CloudFrontOriginAccessIdentity', { CloudFrontOriginAccessIdentityConfig: { Comment: 'Identity for bucket provided by test', }, }); - expect(stack).toHaveResourceLike('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Statement: [{ Action: 's3:GetObject', + Effect: 'Allow', Principal: { CanonicalUser: { 'Fn::GetAtt': ['OriginAccessIdentityDF1E3CAC', 'S3CanonicalUserId'] }, }, @@ -104,15 +105,16 @@ describe('With bucket', () => { const origin = new S3Origin(bucket); new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin } }); - expect(stack).toHaveResourceLike('AWS::CloudFront::CloudFrontOriginAccessIdentity', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CloudFrontOriginAccessIdentity', { CloudFrontOriginAccessIdentityConfig: { Comment: 'Identity for StackDistOrigin15754CE84', }, }); - expect(stack).toHaveResourceLike('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Statement: [{ Action: 's3:GetObject', + Effect: 'Allow', Principal: { CanonicalUser: { 'Fn::GetAtt': ['DistOrigin1S3Origin87D64058', 'S3CanonicalUserId'] }, }, @@ -133,20 +135,20 @@ describe('With bucket', () => { const origin = new S3Origin(bucket); new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin } }); - expect(stack).toHaveResource('AWS::CloudFront::Distribution'); - expect(bucketStack).toHaveResource('AWS::S3::Bucket'); - expect(bucketStack).toHaveResourceLike('AWS::CloudFront::CloudFrontOriginAccessIdentity', { + Template.fromStack(stack).resourceCountIs('AWS::CloudFront::Distribution', 1); + Template.fromStack(bucketStack).resourceCountIs('AWS::S3::Bucket', 1); + Template.fromStack(bucketStack).hasResourceProperties('AWS::CloudFront::CloudFrontOriginAccessIdentity', { CloudFrontOriginAccessIdentityConfig: { Comment: 'Identity for StackDistOrigin15754CE84', }, }); - expect(bucketStack).toHaveResourceLike('AWS::S3::BucketPolicy', { + Template.fromStack(bucketStack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { - Statement: [{ + Statement: [Match.objectLike({ Principal: { CanonicalUser: { 'Fn::GetAtt': ['StackDistOrigin15754CE84S3Origin25582A25', 'S3CanonicalUserId'] }, }, - }], + })], }, }); }); diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index e95400301f33b..b803454912cec 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/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-cloudfront/test/cache-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts index 84996aadccb79..47e9b0ee46fb9 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { App, Aws, Duration, Stack } from '@aws-cdk/core'; import { CachePolicy, CacheCookieBehavior, CacheHeaderBehavior, CacheQueryStringBehavior } from '../lib'; @@ -22,7 +22,7 @@ describe('CachePolicy', () => { test('minimal example', () => { new CachePolicy(stack, 'CachePolicy'); - expect(stack).toHaveResource('AWS::CloudFront::CachePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CachePolicy', { CachePolicyConfig: { Name: 'StackCachePolicy0D6FCBC0-testregion', MinTTL: 0, @@ -59,7 +59,7 @@ describe('CachePolicy', () => { enableAcceptEncodingBrotli: true, }); - expect(stack).toHaveResource('AWS::CloudFront::CachePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CachePolicy', { CachePolicyConfig: { Name: 'MyPolicy', Comment: 'A default policy', @@ -106,7 +106,7 @@ describe('CachePolicy', () => { test('default TTLs', () => { new CachePolicy(stack, 'CachePolicy', { cachePolicyName: 'MyPolicy' }); - expect(stack).toHaveResourceLike('AWS::CloudFront::CachePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CachePolicy', { CachePolicyConfig: { MinTTL: 0, DefaultTTL: 86400, @@ -121,7 +121,7 @@ describe('CachePolicy', () => { minTtl: Duration.days(2), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::CachePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CachePolicy', { CachePolicyConfig: { MinTTL: 172800, DefaultTTL: 172800, @@ -136,7 +136,7 @@ describe('CachePolicy', () => { defaultTtl: Duration.days(400), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::CachePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CachePolicy', { CachePolicyConfig: { MinTTL: 0, DefaultTTL: 34560000, diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 470be56acf0d5..01b70136258e0 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -1,11 +1,10 @@ -import { ABSENT, objectLike } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { App, Duration, Stack } from '@aws-cdk/core'; import { CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 } from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { CfnDistribution, Distribution, @@ -35,7 +34,7 @@ test('minimal example renders correctly', () => { const origin = defaultOrigin(); new Distribution(stack, 'MyDist', { defaultBehavior: { origin } }); - expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6', @@ -79,7 +78,7 @@ test('exhaustive example of props renders correctly', () => { webAclId: '473e64fd-f30b-4765-81a0-62ad96dd167a', }); - expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Aliases: ['example.com'], DefaultCacheBehavior: { @@ -130,7 +129,7 @@ test('ensure comment prop is not greater than max lenght', () => { ellipsis so a user would know there was more to read and everything beyond this point should not show up`, }); - expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6', @@ -180,7 +179,7 @@ describe('multiple behaviors', () => { }, }); - expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6', @@ -219,7 +218,7 @@ describe('multiple behaviors', () => { }, }); - expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6', @@ -266,7 +265,7 @@ describe('multiple behaviors', () => { }); dist.addBehavior('api/2*', origin); - expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6', @@ -359,7 +358,7 @@ describe('certificates', () => { certificate, }); - expect(customStack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(customStack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Aliases: ['example.com', 'www.example.com'], ViewerCertificate: { @@ -386,7 +385,7 @@ describe('certificates', () => { certificate, }); - expect(customStack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(customStack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Aliases: ['example.com', 'www.example.com'], ViewerCertificate: { @@ -409,7 +408,7 @@ describe('certificates', () => { certificate: certificate, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { ViewerCertificate: { AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012', @@ -457,7 +456,7 @@ describe('custom error responses', () => { }], }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { CustomErrorResponses: [ { @@ -486,9 +485,9 @@ describe('logging', () => { const origin = defaultOrigin(); new Distribution(stack, 'MyDist', { defaultBehavior: { origin } }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { - Logging: ABSENT, + Logging: Match.absent(), }, }); }); @@ -512,7 +511,7 @@ describe('logging', () => { enableLogging: true, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Logging: { Bucket: { 'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName'] }, @@ -529,7 +528,7 @@ describe('logging', () => { logBucket: loggingBucket, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Logging: { Bucket: { 'Fn::GetAtt': ['MyLoggingBucket4382CD04', 'RegionalDomainName'] }, @@ -547,7 +546,7 @@ describe('logging', () => { logIncludesCookies: true, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Logging: { Bucket: { 'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName'] }, @@ -587,7 +586,7 @@ describe('with Lambda@Edge functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { LambdaFunctionAssociations: [ @@ -617,7 +616,7 @@ describe('with Lambda@Edge functions', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -656,10 +655,10 @@ describe('with Lambda@Edge functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { CacheBehaviors: [ - { + Match.objectLike({ PathPattern: 'images/*', LambdaFunctionAssociations: [ { @@ -669,7 +668,7 @@ describe('with Lambda@Edge functions', () => { }, }, ], - }, + }), ], }, }); @@ -711,8 +710,8 @@ describe('with Lambda@Edge functions', () => { }, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { - Environment: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Environment: Match.absent(), Code: { ZipFile: 'whateverwithenv', }, @@ -764,7 +763,7 @@ describe('with Lambda@Edge functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { LambdaFunctionAssociations: [ @@ -798,7 +797,7 @@ describe('with CloudFront functions', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { FunctionAssociations: [ @@ -826,7 +825,7 @@ test('price class is included if provided', () => { priceClass: PriceClass.PRICE_CLASS_200, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { PriceClass: 'PriceClass_200', }, @@ -840,7 +839,7 @@ test('escape hatches are supported', () => { const cfnDist = dist.node.defaultChild as CfnDistribution; cfnDist.addPropertyOverride('DistributionConfig.DefaultCacheBehavior.ForwardedValues.Headers', ['*']); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { DefaultCacheBehavior: { ForwardedValues: { @@ -859,9 +858,9 @@ describe('origin IDs', () => { defaultBehavior: { origin: defaultOrigin() }, }); - expect(nestedStack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(nestedStack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { - Origins: [objectLike({ + Origins: [Match.objectLike({ Id: 'ngerThanTheOneHundredAndTwentyEightCharacterLimitAReallyAwesomeDistributionWithAMemorableNameThatIWillNeverForgetOrigin1D38031F9', })], }, @@ -875,10 +874,10 @@ describe('origin IDs', () => { defaultBehavior: { origin: defaultOriginGroup() }, }); - expect(nestedStack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(nestedStack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { OriginGroups: { - Items: [objectLike({ + Items: [Match.objectLike({ Id: 'hanTheOneHundredAndTwentyEightCharacterLimitAReallyAwesomeDistributionWithAMemorableNameThatIWillNeverForgetOriginGroup1B5CE3FE6', })], }, diff --git a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts index 55d6f3689103c..5b4a73f965930 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -20,7 +20,7 @@ describe('stacks', () => { test('creates a custom resource and supporting resources in main stack', () => { new cloudfront.experimental.EdgeFunction(stack, 'MyFn', defaultEdgeFunctionProps()); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [{ Action: 'sts:AssumeRole', @@ -46,13 +46,13 @@ describe('stacks', () => { }, }], }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: '__entrypoint__.handler', Role: { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderRole71CD6825', 'Arn'], }, }); - expect(stack).toHaveResource('Custom::CrossRegionStringParameterReader', { + Template.fromStack(stack).hasResourceProperties('Custom::CrossRegionStringParameterReader', { ServiceToken: { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderHandler65B5F33A', 'Arn'], }, @@ -66,7 +66,7 @@ describe('stacks', () => { const fnStack = getFnStack(); - expect(fnStack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(fnStack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -86,16 +86,16 @@ describe('stacks', () => { { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }, ], }); - expect(fnStack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(fnStack).hasResourceProperties('AWS::Lambda::Function', { Code: { ZipFile: 'foo' }, Handler: 'index.handler', Role: { 'Fn::GetAtt': ['MyFnServiceRoleF3016589', 'Arn'] }, Runtime: 'nodejs12.x', }); - expect(fnStack).toHaveResource('AWS::Lambda::Version', { + Template.fromStack(fnStack).hasResourceProperties('AWS::Lambda::Version', { FunctionName: { Ref: 'MyFn6F8F742F' }, }); - expect(fnStack).toHaveResource('AWS::SSM::Parameter', { + Template.fromStack(fnStack).hasResourceProperties('AWS::SSM::Parameter', { Type: 'String', Value: { Ref: 'MyFnCurrentVersion309B29FC29686ce94039b6e08d1645be854b3ac9' }, Name: '/cdk/EdgeFunctionArn/testregion/Stack/MyFn', @@ -128,7 +128,7 @@ describe('stacks', () => { }); new cloudfront.experimental.EdgeFunction(stack, 'MyFn', defaultEdgeFunctionProps()); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -148,13 +148,13 @@ describe('stacks', () => { { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }, ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { ZipFile: 'foo' }, Handler: 'index.handler', Role: { 'Fn::GetAtt': ['MyFnServiceRole3F9D41E1', 'Arn'] }, Runtime: 'nodejs12.x', }); - expect(stack).toHaveResource('AWS::Lambda::Version', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Version', { FunctionName: { Ref: 'MyFn223608AD' }, }); }); @@ -164,7 +164,7 @@ describe('stacks', () => { new cloudfront.experimental.EdgeFunction(stack, 'MyFn2', defaultEdgeFunctionProps()); const fnStack = getFnStack(); - expect(fnStack).toCountResources('AWS::Lambda::Function', 2); + Template.fromStack(fnStack).resourceCountIs('AWS::Lambda::Function', 2); }); test('can set the stack id for each function', () => { @@ -174,9 +174,9 @@ describe('stacks', () => { new cloudfront.experimental.EdgeFunction(stack, 'MyFn2', defaultEdgeFunctionProps(fn2StackId)); const fn1Stack = app.node.findChild(fn1StackId) as cdk.Stack; - expect(fn1Stack).toCountResources('AWS::Lambda::Function', 1); + Template.fromStack(fn1Stack).resourceCountIs('AWS::Lambda::Function', 1); const fn2Stack = app.node.findChild(fn2StackId) as cdk.Stack; - expect(fn2Stack).toCountResources('AWS::Lambda::Function', 1); + Template.fromStack(fn2Stack).resourceCountIs('AWS::Lambda::Function', 1); }); test('cross-region stack supports defining functions within stages', () => { @@ -188,15 +188,13 @@ describe('stacks', () => { new cloudfront.experimental.EdgeFunction(stack, 'MyFn', defaultEdgeFunctionProps()); - // Because 'expect(stack)' doesn't work correctly for stacks in nested assemblies - const stackArtifact = stage.synth().getStackArtifact(stack.artifactId); - expect(stackArtifact).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Handler: '__entrypoint__.handler', Role: { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderRole71CD6825', 'Arn'], }, }); - expect(stackArtifact).toHaveResource('Custom::CrossRegionStringParameterReader', { + Template.fromStack(stack).hasResourceProperties('Custom::CrossRegionStringParameterReader', { ServiceToken: { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderHandler65B5F33A', 'Arn'], }, @@ -220,10 +218,10 @@ describe('stacks', () => { const secondFnStack = app.node.findChild(`edge-lambda-stack-${secondStack.node.addr}`) as cdk.Stack; // Two SSM parameters - expect(firstFnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Template.fromStack(firstFnStack).hasResourceProperties('AWS::SSM::Parameter', { Name: '/cdk/EdgeFunctionArn/testregion/FirstStack/MyFn', }); - expect(secondFnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Template.fromStack(secondFnStack).hasResourceProperties('AWS::SSM::Parameter', { Name: '/cdk/EdgeFunctionArn/testregion/SecondStack/MyFn', }); }); @@ -235,7 +233,7 @@ test('addAlias() creates alias in function stack', () => { fn.addAlias('MyCurrentAlias'); const fnStack = getFnStack(); - expect(fnStack).toHaveResourceLike('AWS::Lambda::Alias', { + Template.fromStack(fnStack).hasResourceProperties('AWS::Lambda::Alias', { Name: 'MyCurrentAlias', }); }); @@ -247,8 +245,8 @@ test('mutliple aliases with the same name can be added to the same stack', () => fn2.addAlias('live'); const fnStack = getFnStack(); - expect(fnStack).toCountResources('AWS::Lambda::Function', 2); - expect(fnStack).toCountResources('AWS::Lambda::Alias', 2); + Template.fromStack(fnStack).resourceCountIs('AWS::Lambda::Function', 2); + Template.fromStack(fnStack).resourceCountIs('AWS::Lambda::Alias', 2); }); test('addPermission() creates permissions in function stack', () => { @@ -260,7 +258,7 @@ test('addPermission() creates permissions in function stack', () => { }); const fnStack = getFnStack(); - expect(fnStack).toHaveResourceLike('AWS::Lambda::Permission', { + Template.fromStack(fnStack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', Principal: '123456789012', }); @@ -303,7 +301,7 @@ test('SSM parameter name is sanitized to remove disallowed characters', () => { const fnStack = getFnStack(); - expect(fnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Template.fromStack(fnStack).hasResourceProperties('AWS::SSM::Parameter', { Name: '/cdk/EdgeFunctionArn/testregion/Stack/My_Bad_Fn_Name-With.Bonus', }); }); diff --git a/packages/@aws-cdk/aws-cloudfront/test/function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/function.test.ts index c2466a71c8ff2..12e3d1d525433 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/function.test.ts @@ -1,6 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert-internal/jest'; -import { expect as expectStack } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { App, Stack } from '@aws-cdk/core'; import { Function, FunctionCode } from '../lib'; @@ -15,7 +14,7 @@ describe('CloudFront Function', () => { code: FunctionCode.fromInline('code'), }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { CF2D7241DD7: { Type: 'AWS::CloudFront::Function', @@ -40,7 +39,7 @@ describe('CloudFront Function', () => { code: FunctionCode.fromInline('code'), }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { CF2D7241DD7: { Type: 'AWS::CloudFront::Function', @@ -89,7 +88,7 @@ describe('CloudFront Function', () => { functionName: 'FunctionName', }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { CF2D7241DD7: { Type: 'AWS::CloudFront::Function', @@ -116,7 +115,7 @@ describe('CloudFront Function', () => { code: FunctionCode.fromFile({ filePath: path.join(__dirname, 'function-code.js') }), }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { CF2D7241DD7: { Type: 'AWS::CloudFront::Function', @@ -133,4 +132,4 @@ describe('CloudFront Function', () => { }, }); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts b/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts index c9fb509d29d1d..5ba9ff2fbd25c 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import { GeoRestriction } from '../lib'; describe.each([ diff --git a/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts b/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts index f27f2ad7e0e42..6a1dfbdd90a5d 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { expect as expectStack } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { App, Stack } from '@aws-cdk/core'; import { KeyGroup, PublicKey } from '../lib'; @@ -49,7 +48,7 @@ describe('KeyGroup', () => { ], }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { MyPublicKey78071F3D: { Type: 'AWS::CloudFront::PublicKey', @@ -91,7 +90,7 @@ describe('KeyGroup', () => { ], }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { MyPublicKey78071F3D: { Type: 'AWS::CloudFront::PublicKey', @@ -140,7 +139,7 @@ describe('KeyGroup', () => { ], }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { BingoKeyCBEC786C: { Type: 'AWS::CloudFront::PublicKey', @@ -184,4 +183,4 @@ describe('KeyGroup', () => { }, }); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts b/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts index e9e04fa6e3003..ad579cca681b0 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/oai.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 { OriginAccessIdentity } from '../lib'; @@ -8,7 +8,7 @@ describe('Origin Access Identity', () => { new OriginAccessIdentity(stack, 'OAI'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( { Resources: { OAIE1EFC67F: { @@ -31,7 +31,7 @@ describe('Origin Access Identity', () => { comment: 'test comment', }); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( { Resources: { OAIE1EFC67F: { @@ -54,7 +54,7 @@ describe('Origin Access Identity', () => { comment: 'This is a really long comment. Auto-generated comments based on ids of origins might sometimes be this long or even longer and that will break', }); - expect(stack).toHaveResourceLike('AWS::CloudFront::CloudFrontOriginAccessIdentity', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::CloudFrontOriginAccessIdentity', { CloudFrontOriginAccessIdentityConfig: { Comment: 'This is a really long comment. Auto-generated comments based on ids of origins might sometimes be this long or even longer and t', }, diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts index 891fd10eaff37..8d6ffa55f7db1 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { CloudFrontWebDistribution, FailoverStatusCode } from '../lib'; @@ -28,85 +28,82 @@ describe('origin group', () => { ], }); - expect(stack) - .toHaveResourceLike('AWS::CloudFront::Distribution', { - DistributionConfig: { - OriginGroups: { - Items: [ - { - FailoverCriteria: { - StatusCodes: { - Items: [ - 500, - 502, - 503, - 504, - ], - Quantity: 4, - }, - }, - Id: 'OriginGroup1', - Members: { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + OriginGroups: { + Items: [ + { + FailoverCriteria: { + StatusCodes: { Items: [ - { - OriginId: 'origin1', - }, - { - OriginId: 'originSecondary1', - }, + 500, + 502, + 503, + 504, ], - Quantity: 2, + Quantity: 4, }, }, - ], - Quantity: 1, - }, - Origins: [ - { - CustomOriginConfig: { - HTTPPort: 80, - HTTPSPort: 443, - OriginKeepaliveTimeout: 5, - OriginProtocolPolicy: 'https-only', - OriginReadTimeout: 30, - OriginSSLProtocols: [ - 'TLSv1.2', + Id: 'OriginGroup1', + Members: { + Items: [ + { + OriginId: 'origin1', + }, + { + OriginId: 'originSecondary1', + }, ], + Quantity: 2, }, - DomainName: 'myoriginfallback.com', - Id: 'originSecondary1', - OriginCustomHeaders: [ - { - HeaderName: 'X-Custom-Header', - HeaderValue: 'somevalue', - }, + }, + ], + Quantity: 1, + }, + Origins: [ + Match.objectLike({ + CustomOriginConfig: { + HTTPPort: 80, + HTTPSPort: 443, + OriginKeepaliveTimeout: 5, + OriginProtocolPolicy: 'https-only', + OriginReadTimeout: 30, + OriginSSLProtocols: [ + 'TLSv1.2', ], }, - { - CustomOriginConfig: { - HTTPPort: 80, - HTTPSPort: 443, - OriginKeepaliveTimeout: 5, - OriginProtocolPolicy: 'https-only', - OriginReadTimeout: 30, - OriginSSLProtocols: [ - 'TLSv1.2', - ], + DomainName: 'myoriginfallback.com', + Id: 'originSecondary1', + OriginCustomHeaders: [ + { + HeaderName: 'X-Custom-Header', + HeaderValue: 'somevalue', }, - DomainName: 'myorigin.com', - Id: 'origin1', - OriginCustomHeaders: [ - { - HeaderName: 'X-Custom-Header', - HeaderValue: 'somevalue', - }, + ], + }), + Match.objectLike({ + CustomOriginConfig: { + HTTPPort: 80, + HTTPSPort: 443, + OriginKeepaliveTimeout: 5, + OriginProtocolPolicy: 'https-only', + OriginReadTimeout: 30, + OriginSSLProtocols: [ + 'TLSv1.2', ], }, - ], - }, - }); - - + DomainName: 'myorigin.com', + Id: 'origin1', + OriginCustomHeaders: [ + { + HeaderName: 'X-Custom-Header', + HeaderValue: 'somevalue', + }, + ], + }), + ], + }, + }); }); test('Distribution with s3 origin failover', () => { @@ -139,92 +136,91 @@ describe('origin group', () => { ], }); - expect(stack) - .toHaveResourceLike('AWS::CloudFront::Distribution', { - DistributionConfig: { - OriginGroups: { - Items: [ - { - FailoverCriteria: { - StatusCodes: { - Items: [ - 500, - ], - Quantity: 1, - }, - }, - Id: 'OriginGroup1', - Members: { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + OriginGroups: { + Items: [ + { + FailoverCriteria: { + StatusCodes: { Items: [ - { - OriginId: 'origin1', - }, - { - OriginId: 'originSecondary1', - }, + 500, ], - Quantity: 2, + Quantity: 1, }, }, - ], - Quantity: 1, - }, - Origins: [ - { - DomainName: { - 'Fn::Join': [ - '', - [ - 'myoriginbucketfallback.s3.', - { - Ref: 'AWS::Region', - }, - '.', - { - Ref: 'AWS::URLSuffix', - }, - ], + Id: 'OriginGroup1', + Members: { + Items: [ + { + OriginId: 'origin1', + }, + { + OriginId: 'originSecondary1', + }, ], + Quantity: 2, }, - Id: 'originSecondary1', - OriginCustomHeaders: [ - { - HeaderName: 'myHeader2', - HeaderValue: '21', - }, - ], - OriginPath: '/somwhere', - S3OriginConfig: {}, }, - { - DomainName: { - 'Fn::Join': [ - '', - [ - 'myoriginbucket.s3.', - { - Ref: 'AWS::Region', - }, - '.', - { - Ref: 'AWS::URLSuffix', - }, - ], + ], + Quantity: 1, + }, + Origins: [ + Match.objectLike({ + DomainName: { + 'Fn::Join': [ + '', + [ + 'myoriginbucketfallback.s3.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, ], + ], + }, + Id: 'originSecondary1', + OriginCustomHeaders: [ + { + HeaderName: 'myHeader2', + HeaderValue: '21', }, - Id: 'origin1', - OriginCustomHeaders: [ - { - HeaderName: 'myHeader', - HeaderValue: '42', - }, + ], + OriginPath: '/somwhere', + S3OriginConfig: {}, + }), + Match.objectLike({ + DomainName: { + 'Fn::Join': [ + '', + [ + 'myoriginbucket.s3.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + ], ], - OriginPath: '/', - S3OriginConfig: {}, }, - ], - }, - }); + Id: 'origin1', + OriginCustomHeaders: [ + { + HeaderName: 'myHeader', + HeaderValue: '42', + }, + ], + OriginPath: '/', + S3OriginConfig: {}, + }), + ], + }, + }); }); diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts index b2b04af43f18a..bda5a09058e67 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { App, Aws, Stack } from '@aws-cdk/core'; import { OriginRequestPolicy, OriginRequestCookieBehavior, OriginRequestHeaderBehavior, OriginRequestQueryStringBehavior } from '../lib'; @@ -22,7 +22,7 @@ describe('OriginRequestPolicy', () => { test('minimal example', () => { new OriginRequestPolicy(stack, 'OriginRequestPolicy'); - expect(stack).toHaveResource('AWS::CloudFront::OriginRequestPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::OriginRequestPolicy', { OriginRequestPolicyConfig: { Name: 'StackOriginRequestPolicy6B17D9ED', CookiesConfig: { @@ -47,7 +47,7 @@ describe('OriginRequestPolicy', () => { queryStringBehavior: OriginRequestQueryStringBehavior.allowList('username'), }); - expect(stack).toHaveResource('AWS::CloudFront::OriginRequestPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::OriginRequestPolicy', { OriginRequestPolicyConfig: { Name: 'MyPolicy', Comment: 'A default policy', diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts index e6a59ff6179d6..418bac1f3d275 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import { App, Stack, Duration } from '@aws-cdk/core'; import { TestOrigin } from './test-origin'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts b/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts index 326b33490271e..842f42e494157 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; import { AllowedMethods, CachedMethods, CachePolicy, KeyGroup, LambdaEdgeEventType, OriginRequestPolicy, PublicKey, ViewerProtocolPolicy } from '../../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts b/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts index 5fbd8da23ddc8..75ae100ab9bfd 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { expect as expectStack } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { App, Stack } from '@aws-cdk/core'; import { PublicKey } from '../lib'; @@ -35,7 +34,7 @@ describe('PublicKey', () => { encodedKey: publicKey, }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { MyPublicKey78071F3D: { Type: 'AWS::CloudFront::PublicKey', @@ -58,7 +57,7 @@ describe('PublicKey', () => { comment: 'Key expiring on 1/1/1984', }); - expectStack(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { MyPublicKey78071F3D: { Type: 'AWS::CloudFront::PublicKey', @@ -82,4 +81,4 @@ describe('PublicKey', () => { comment: 'Key expiring on 1/1/1984', })).toThrow(/Public key must be in PEM format [(]with the BEGIN\/END PUBLIC KEY lines[)]; got (.*?)/); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts index 926b17d85a219..7160fd8c3d6c1 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { App, Duration, Stack } from '@aws-cdk/core'; import { HeadersFrameOption, HeadersReferrerPolicy, ResponseHeadersPolicy } from '../lib'; @@ -30,7 +30,7 @@ describe('ResponseHeadersPolicy', () => { test('minimal example', () => { new ResponseHeadersPolicy(stack, 'ResponseHeadersPolicy'); - expect(stack).toHaveResource('AWS::CloudFront::ResponseHeadersPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::ResponseHeadersPolicy', { ResponseHeadersPolicyConfig: { Name: 'StackResponseHeadersPolicy7B76F936', }, @@ -66,7 +66,7 @@ describe('ResponseHeadersPolicy', () => { }, }); - expect(stack).toHaveResource('AWS::CloudFront::ResponseHeadersPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::ResponseHeadersPolicy', { ResponseHeadersPolicyConfig: { Comment: 'A default policy', CorsConfig: { diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index df1d401ae7de0..ef7487bac0076 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as certificatemanager from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; @@ -58,7 +57,7 @@ describe('web distribution', () => { ], }); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( { 'Resources': { 'AnAmazingWebsiteProbablyCFDistribution47E3983B': { @@ -149,7 +148,7 @@ describe('web distribution', () => { ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -227,7 +226,7 @@ describe('web distribution', () => { ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -290,7 +289,7 @@ describe('web distribution', () => { const sourceBucket = new s3.Bucket(stack, 'Bucket'); new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { - comment: `Adding a comment longer than 128 characters should be trimmed and + comment: `Adding a comment longer than 128 characters should be trimmed and added the ellipsis so a user would know there was more to read and everything beyond this point should not show up`, originConfigs: [ { @@ -306,7 +305,7 @@ added the ellipsis so a user would know there was more to read and everything be ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { Bucket83908E77: { Type: 'AWS::S3::Bucket', @@ -344,8 +343,8 @@ added the ellipsis so a user would know there was more to read and everything be }, Compress: true, }, - Comment: `Adding a comment longer than 128 characters should be trimmed and -added the ellipsis so a user would know there was more to ...`, + Comment: `Adding a comment longer than 128 characters should be trimmed and +added the ellipsis so a user would know there was more to r...`, Enabled: true, IPV6Enabled: true, HttpVersion: 'http2', @@ -369,7 +368,7 @@ added the ellipsis so a user would know there was more to ...`, }], }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Origins: [ { @@ -392,10 +391,11 @@ added the ellipsis so a user would know there was more to ...`, }, }); - expect(stack).toHaveResourceLike('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Statement: [{ Action: 's3:GetObject', + Effect: 'Allow', Principal: { CanonicalUser: { 'Fn::GetAtt': ['OAIE1EFC67F', 'S3CanonicalUserId'] }, }, @@ -441,7 +441,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -548,7 +548,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -630,7 +630,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -729,7 +729,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -812,7 +812,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'DefaultCacheBehavior': { 'FunctionAssociations': [ @@ -863,7 +863,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'DefaultCacheBehavior': { 'LambdaFunctionAssociations': [ @@ -913,8 +913,8 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { - Environment: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Environment: Match.absent(), }); @@ -1027,7 +1027,7 @@ added the ellipsis so a user would know there was more to ...`, aliasConfiguration: { acmCertRef: 'another_acm_ref', names: ['ftp.example.com'] }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': ['www.example.com'], 'ViewerCertificate': { @@ -1037,7 +1037,7 @@ added the ellipsis so a user would know there was more to ...`, }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': ['ftp.example.com'], 'ViewerCertificate': { @@ -1067,7 +1067,7 @@ added the ellipsis so a user would know there was more to ...`, viewerCertificate: ViewerCertificate.fromAcmCertificate(certificate), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': [], 'ViewerCertificate': { @@ -1097,7 +1097,7 @@ added the ellipsis so a user would know there was more to ...`, viewerCertificate: ViewerCertificate.fromAcmCertificate(certificate), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': [], 'ViewerCertificate': { @@ -1129,7 +1129,7 @@ added the ellipsis so a user would know there was more to ...`, }), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': ['example.com', 'www.example.com'], 'ViewerCertificate': { @@ -1158,7 +1158,7 @@ added the ellipsis so a user would know there was more to ...`, viewerCertificate: ViewerCertificate.fromIamCertificate('test'), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': [], 'ViewerCertificate': { @@ -1186,7 +1186,7 @@ added the ellipsis so a user would know there was more to ...`, }), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': ['example.com'], 'ViewerCertificate': { @@ -1213,7 +1213,7 @@ added the ellipsis so a user would know there was more to ...`, viewerCertificate: ViewerCertificate.fromCloudFrontDefaultCertificate(), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': [], 'ViewerCertificate': { @@ -1236,7 +1236,7 @@ added the ellipsis so a user would know there was more to ...`, viewerCertificate: ViewerCertificate.fromCloudFrontDefaultCertificate('example.com', 'www.example.com'), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': ['example.com', 'www.example.com'], 'ViewerCertificate': { @@ -1302,7 +1302,7 @@ added the ellipsis so a user would know there was more to ...`, viewerCertificate: ViewerCertificate.fromAcmCertificate(certificate), }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { 'DistributionConfig': { 'Aliases': [], 'ViewerCertificate': { @@ -1349,7 +1349,7 @@ added the ellipsis so a user would know there was more to ...`, }); // THEN - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { 'Statement': [ { @@ -1399,7 +1399,7 @@ added the ellipsis so a user would know there was more to ...`, ], }); - expect(stack).not.toHaveResourceLike('AWS::IAM::Role'); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); }); @@ -1417,7 +1417,7 @@ added the ellipsis so a user would know there was more to ...`, geoRestriction: GeoRestriction.allowlist('US', 'UK'), }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', @@ -1493,7 +1493,7 @@ added the ellipsis so a user would know there was more to ...`, geoRestriction: GeoRestriction.denylist('US'), }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Bucket83908E77': { 'Type': 'AWS::S3::Bucket', diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 97a1498ed89cf..08a59bffab0d5 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/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/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-cloudwatch-actions/test/appscaling.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts index f355290aaa553..066df92d34b45 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; @@ -27,7 +27,7 @@ test('can use topic as alarm action', () => { alarm.addAlarmAction(new actions.ApplicationScalingAction(action)); // THEN - expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { AlarmActions: [ { Ref: 'Action62AD07C0' }, ], diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts index 1d6dd47793796..ed4c4ba66bc85 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; import * as actions from '../lib'; @@ -22,7 +22,7 @@ test('can use instance reboot as alarm action', () => { alarm.addAlarmAction(new actions.Ec2Action(actions.Ec2InstanceAction.REBOOT)); // THEN - expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { AlarmActions: [ { 'Fn::Join': [ diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts index 61561cd412e15..d3b16268e03bf 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -29,7 +29,7 @@ test('can use topic as alarm action', () => { alarm.addAlarmAction(new actions.AutoScalingAction(action)); // THEN - expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { AlarmActions: [ { Ref: 'Action62AD07C0' }, ], diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts index 3cdc6e71ae9c2..ba379902b653f 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as sns from '@aws-cdk/aws-sns'; import { Stack } from '@aws-cdk/core'; @@ -18,7 +18,7 @@ test('can use topic as alarm action', () => { alarm.addAlarmAction(new actions.SnsAction(topic)); // THEN - expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { AlarmActions: [ { Ref: 'TopicBFC7AF6E' }, ], diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index f5b3925eac5a2..2374b358d9194 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -84,7 +84,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-sns": "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-codecommit/test/codecommit.test.ts b/packages/@aws-cdk/aws-codecommit/test/codecommit.test.ts index 3dca30532e1ad..623f66eb4675a 100644 --- a/packages/@aws-cdk/aws-codecommit/test/codecommit.test.ts +++ b/packages/@aws-cdk/aws-codecommit/test/codecommit.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert-internal/jest'; import { join, resolve } from 'path'; +import { Template } from '@aws-cdk/assertions'; import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { Asset } from '@aws-cdk/aws-s3-assets'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; @@ -19,7 +19,7 @@ describe('codecommit', () => { new Repository(stack, 'MyRepository', props).notify(snsArn); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyRepository4C4BD5FC: { Type: 'AWS::CodeCommit::Repository', @@ -258,7 +258,7 @@ describe('codecommit', () => { repository.grantPullPush(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/aws-codecommit/test/notification-rule.test.ts b/packages/@aws-cdk/aws-codecommit/test/notification-rule.test.ts index 721ce01d4c490..ae65a5f4f2ef8 100644 --- a/packages/@aws-cdk/aws-codecommit/test/notification-rule.test.ts +++ b/packages/@aws-cdk/aws-codecommit/test/notification-rule.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; import * as codecommit from '../lib'; @@ -16,7 +16,7 @@ describe('notification rule', () => { repository.notifyOnPullRequestMerged('NotifyOnPullRequestMerged', target); - expect(stack).toHaveResource('AWS::CodeStarNotifications::NotificationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeStarNotifications::NotificationRule', { Name: 'MyCodecommitRepositoryNotifyOnPullRequestCreatedBB14EA32', DetailType: 'FULL', EventTypeIds: [ @@ -38,7 +38,7 @@ describe('notification rule', () => { ], }); - expect(stack).toHaveResource('AWS::CodeStarNotifications::NotificationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeStarNotifications::NotificationRule', { Name: 'MyCodecommitRepositoryNotifyOnPullRequestMerged34A7EDF1', DetailType: 'FULL', EventTypeIds: [ diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 4afc41c582025..b3b06d2306188 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts index 4e3fd6045a251..959a7413a4d9e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { describeDeprecated } from '@aws-cdk/cdk-build-tools'; @@ -17,7 +16,7 @@ describeDeprecated('BitBucket source Action', () => { codeBuildCloneOutput: false, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -58,7 +57,7 @@ describeDeprecated('BitBucket source Action', () => { codeBuildCloneOutput: true, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -88,10 +87,10 @@ describeDeprecated('BitBucket source Action', () => { createBitBucketAndCodeBuildPipeline(stack, { codeBuildCloneOutput: true, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { - 'Statement': arrayWith( - objectLike({ + 'Statement': Match.arrayWith([ + Match.objectLike({ 'Action': 's3:PutObjectAcl', 'Effect': 'Allow', 'Resource': { @@ -109,7 +108,7 @@ describeDeprecated('BitBucket source Action', () => { ], }, }), - ), + ]), }, }); @@ -121,7 +120,7 @@ describeDeprecated('BitBucket source Action', () => { triggerOnPush: false, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts index e7f46a685ed55..5ed83cd1f6711 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; @@ -78,7 +78,7 @@ describe('CloudFormation Pipeline Actions', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStore': { 'Location': { 'Ref': 'MagicPipelineArtifactsBucket212FE7BF', @@ -212,7 +212,7 @@ describe('CloudFormation Pipeline Actions', () => { const roleId = 'PipelineDeployCreateUpdateRole515CB7D4'; // THEN: Action in Pipeline has named IAM capabilities - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -235,7 +235,7 @@ describe('CloudFormation Pipeline Actions', () => { }); // THEN: Role is created with full permissions - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -281,7 +281,7 @@ describe('CloudFormation Pipeline Actions', () => { })); // THEN: Action has output artifacts - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -313,7 +313,7 @@ describe('CloudFormation Pipeline Actions', () => { })); // THEN: Action has output artifacts - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -349,7 +349,7 @@ describe('CloudFormation Pipeline Actions', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -397,7 +397,7 @@ describe('CloudFormation Pipeline Actions', () => { stackName: 'magicStack', })); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', /* don't care about the rest */ @@ -444,7 +444,7 @@ describe('CloudFormation Pipeline Actions', () => { const roleId = 'PipelineDeployCreateUpdateRole515CB7D4'; // THEN: Action in Pipeline has named IAM capabilities - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -488,7 +488,7 @@ describe('CloudFormation Pipeline Actions', () => { const roleId = 'PipelineDeployCreateUpdateRole515CB7D4'; // THEN: Action in Pipeline has named IAM and AUTOEXPAND capabilities - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -531,7 +531,7 @@ describe('CloudFormation Pipeline Actions', () => { const roleId = 'PipelineDeployCreateUpdateRole515CB7D4'; // THEN: Action in Pipeline has no capabilities - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -572,7 +572,7 @@ describe('CloudFormation Pipeline Actions', () => { })); // THEN: Action in Pipeline has named IAM and AUTOEXPAND capabilities - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source' /* don't care about the rest */ }, { @@ -636,7 +636,7 @@ describe('CloudFormation Pipeline Actions', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -663,8 +663,8 @@ describe('CloudFormation Pipeline Actions', () => { }); // the pipeline's BucketPolicy should trust both CFN roles - expect(pipelineStack).toHaveResourceLike('AWS::S3::BucketPolicy', { - 'PolicyDocument': { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::S3::BucketPolicy', { + 'PolicyDocument': Match.objectLike({ 'Statement': [ { 'Action': 's3:*', @@ -675,9 +675,7 @@ describe('CloudFormation Pipeline Actions', () => { 'Principal': { 'AWS': '*', }, - 'Resource': [ - - ], + 'Resource': Match.anyValue(), }, { 'Action': [ @@ -692,6 +690,7 @@ describe('CloudFormation Pipeline Actions', () => { ':iam::123456789012:role/pipelinestack-support-123fndeploymentrole4668d9b5a30ce3dc4508']], }, }, + 'Resource': Match.anyValue(), }, { 'Action': [ @@ -706,16 +705,17 @@ describe('CloudFormation Pipeline Actions', () => { ':iam::123456789012:role/pipelinestack-support-123loycfnactionrole56af64af3590f311bc50']], }, }, + 'Resource': Match.anyValue(), }, ], - }, + }), }); const otherStack = app.node.findChild('cross-account-support-stack-123456789012') as cdk.Stack; - expect(otherStack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(otherStack).hasResourceProperties('AWS::IAM::Role', { 'RoleName': 'pipelinestack-support-123loycfnactionrole56af64af3590f311bc50', }); - expect(otherStack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(otherStack).hasResourceProperties('AWS::IAM::Role', { 'RoleName': 'pipelinestack-support-123fndeploymentrole4668d9b5a30ce3dc4508', }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts index 3d9594a9ddfbd..9b1dc140f6068 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as notifications from '@aws-cdk/aws-codestarnotifications'; import * as events from '@aws-cdk/aws-events'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts index c8ddc211a813d..fdd470bf19640 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; @@ -101,7 +101,7 @@ describe('CodeBuild Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -176,7 +176,7 @@ describe('CodeBuild Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -235,7 +235,7 @@ describe('CodeBuild Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -291,7 +291,7 @@ describe('CodeBuild Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts index 648c113ce2155..101b35c77d581 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT, arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; @@ -18,7 +17,7 @@ describe('CodeCommit Source Action', () => { minimalPipeline(stack, undefined); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Actions': [ @@ -33,7 +32,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).toCountResources('AWS::Events::Rule', 1); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 1); }); @@ -67,7 +66,7 @@ describe('CodeCommit Source Action', () => { }); // THEN - creates a Rule in the source stack targeting the pipeline stack's event bus using a generated role - expect(sourceStack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(sourceStack).hasResourceProperties('AWS::Events::Rule', { EventPattern: { source: ['aws.codecommit'], resources: [ @@ -75,7 +74,7 @@ describe('CodeCommit Source Action', () => { ], }, Targets: [{ - RoleARN: ABSENT, + RoleARN: Match.absent(), Arn: { 'Fn::Join': ['', [ 'arn:', @@ -87,7 +86,7 @@ describe('CodeCommit Source Action', () => { }); // THEN - creates a Rule in the pipeline stack using the role to start the pipeline - expect(targetStack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(targetStack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.codecommit', @@ -128,7 +127,7 @@ describe('CodeCommit Source Action', () => { minimalPipeline(stack, cpactions.CodeCommitTrigger.EVENTS); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Actions': [ @@ -143,7 +142,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).toCountResources('AWS::Events::Rule', 1); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 1); }); @@ -153,7 +152,7 @@ describe('CodeCommit Source Action', () => { minimalPipeline(stack, cpactions.CodeCommitTrigger.POLL); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Actions': [ @@ -168,7 +167,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).not.toHaveResourceLike('AWS::Events::Rule'); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); }); @@ -178,7 +177,7 @@ describe('CodeCommit Source Action', () => { minimalPipeline(stack, cpactions.CodeCommitTrigger.NONE); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Actions': [ @@ -193,7 +192,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).not.toHaveResourceLike('AWS::Events::Rule'); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); }); @@ -291,7 +290,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -345,7 +344,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { EventPattern: { detail: { referenceName: ['my-branch'], @@ -389,7 +388,7 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -410,17 +409,17 @@ describe('CodeCommit Source Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { - 'Statement': arrayWith( - objectLike({ + 'Statement': Match.arrayWith([ + Match.objectLike({ 'Action': [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents', ], }), - objectLike({ + Match.objectLike({ 'Action': 'codecommit:GitPull', 'Effect': 'Allow', 'Resource': { @@ -430,14 +429,14 @@ describe('CodeCommit Source Action', () => { ], }, }), - ), + ]), }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { - 'Statement': arrayWith( - objectLike({ + 'Statement': Match.arrayWith([ + Match.objectLike({ 'Action': [ 'codecommit:GetBranch', 'codecommit:GetCommit', @@ -454,7 +453,7 @@ describe('CodeCommit Source Action', () => { ], }, }), - ), + ]), }, }); @@ -504,7 +503,7 @@ describe('CodeCommit Source Action', () => { actions: [buildAction], }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: stack.resolve(pipeline.pipelineArn), @@ -552,9 +551,9 @@ describe('CodeCommit Source Action', () => { ], }); - expect(repoStack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(repoStack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ 'Action': 's3:PutObjectAcl', 'Effect': 'Allow', 'Resource': { @@ -564,7 +563,7 @@ describe('CodeCommit Source Action', () => { ':s3:::pipeline-bucket/*', ]], }, - }), + }]), }, }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts index 18a0c714f4d5b..c59465746c25b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as codedeploy from '@aws-cdk/aws-codedeploy'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as cdk from '@aws-cdk/core'; @@ -111,7 +111,7 @@ describe('CodeDeploy ECS Deploy Action', () => { appSpecTemplateInput: new codepipeline.Artifact('AppSpecArtifact'), }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: [ {}, { @@ -162,7 +162,7 @@ describe('CodeDeploy ECS Deploy Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: [ {}, { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts index 312251bd8457a..6eba0f1e62cf8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts @@ -1,8 +1,7 @@ -import '@aws-cdk/assert-internal/jest'; -import { arrayWith, objectLike, SynthUtils } from '@aws-cdk/assert-internal'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; -import { Stack } from '@aws-cdk/core'; +import { App, Stack } from '@aws-cdk/core'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ @@ -16,7 +15,7 @@ describe('CodeStar Connections source Action', () => { codeBuildCloneOutput: false, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -57,7 +56,7 @@ describe('CodeStar Connections source Action', () => { codeBuildCloneOutput: true, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -90,10 +89,10 @@ describe('CodeStar Connections source Action', () => { codeBuildCloneOutput: true, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { - 'Statement': arrayWith( - objectLike({ + 'Statement': Match.arrayWith([ + Match.objectLike({ 'Action': 's3:PutObjectAcl', 'Effect': 'Allow', 'Resource': { @@ -103,7 +102,7 @@ describe('CodeStar Connections source Action', () => { ]], }, }), - ), + ]), }, }); @@ -117,7 +116,7 @@ describe('CodeStar Connections source Action', () => { triggerOnPush: false, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -154,7 +153,7 @@ describe('CodeStar Connections source Action', () => { const stack = new Stack(); createBitBucketAndCodeBuildPipeline(stack); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -180,7 +179,7 @@ describe('CodeStar Connections source Action', () => { variablesNamespace: 'kornicameister', }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -207,7 +206,8 @@ describe('CodeStar Connections source Action', () => { }); test('fail if variable from unused action is referenced', () => { - const stack = new Stack(); + const app = new App(); + const stack = new Stack(app); const pipeline = createBitBucketAndCodeBuildPipeline(stack); const unusedSourceOutput = new codepipeline.Artifact(); @@ -229,12 +229,13 @@ describe('CodeStar Connections source Action', () => { pipeline.stage('Build').addAction(unusedBuildAction); expect(() => { - SynthUtils.synthesize(stack); + App.of(stack)!.synth(); }).toThrow(/Cannot reference variables of action 'UnusedBitBucket', as that action was never added to a pipeline/); }); test('fail if variable from unused action with custom namespace is referenced', () => { - const stack = new Stack(); + const app = new App(); + const stack = new Stack(app); const pipeline = createBitBucketAndCodeBuildPipeline(stack, { variablesNamespace: 'kornicameister', }); @@ -258,7 +259,7 @@ describe('CodeStar Connections source Action', () => { pipeline.stage('Build').addAction(unusedBuildAction); expect(() => { - SynthUtils.synthesize(stack); + App.of(stack)!.synth(); }).toThrow(/Cannot reference variables of action 'UnusedBitBucket', as that action was never added to a pipeline/); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts index 99160cdd4193a..99752272df90f 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT } from '@aws-cdk/assert-internal'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ecr from '@aws-cdk/aws-ecr'; @@ -41,27 +40,27 @@ describe('ecr source action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': [ - { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': Match.arrayWith([ + Match.objectLike({ 'Name': 'Source', - }, - { + }), + Match.objectLike({ 'Name': 'Build', - 'Actions': [ - { + 'Actions': Match.arrayWith([ + Match.objectLike({ 'Name': 'Build', 'Configuration': { 'EnvironmentVariables': '[{"name":"ImageDigest","type":"PLAINTEXT","value":"#{Source_Source_NS.ImageDigest}"}]', }, - }, - ], - }, - ], + }), + ]), + }), + ]), }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'detail': { 'requestParameters': { @@ -105,33 +104,33 @@ describe('ecr source action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', ], 'detail': { 'requestParameters': { - 'imageTag': ABSENT, + 'imageTag': Match.absent(), }, }, }, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': [ - { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': Match.arrayWith([ + Match.objectLike({ 'Name': 'Source', - 'Actions': [ - { + 'Actions': Match.arrayWith([ + Match.objectLike({ 'Name': 'Source', 'Configuration': { - 'ImageTag': ABSENT, + 'ImageTag': Match.absent(), }, - }, - ], - }, - ], + }), + ]), + }), + ]), }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts index 63927d5832ec8..91976ec921e74 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; @@ -172,7 +172,7 @@ describe('ecs deploy action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: [ {}, { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts index 6a1342888042e..b7e970ba59a02 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts @@ -1,8 +1,7 @@ -import '@aws-cdk/assert-internal/jest'; -import { SynthUtils } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; -import { SecretValue, Stack } from '@aws-cdk/core'; +import { App, SecretValue, Stack } from '@aws-cdk/core'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ @@ -42,7 +41,7 @@ describe('Github source action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -96,7 +95,7 @@ describe('Github source action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -116,7 +115,8 @@ describe('Github source action', () => { }); test('fails if a variable from an action without a namespace set that is not part of a pipeline is referenced', () => { - const stack = new Stack(); + const app = new App(); + const stack = new Stack(app); const unusedSourceAction = new cpactions.GitHubSourceAction({ actionName: 'Source2', @@ -155,14 +155,15 @@ describe('Github source action', () => { }); expect(() => { - SynthUtils.synthesize(stack); + App.of(stack)!.synth(); }).toThrow(/Cannot reference variables of action 'Source2', as that action was never added to a pipeline/); }); test('fails if a variable from an action with a namespace set that is not part of a pipeline is referenced', () => { - const stack = new Stack(); + const app = new App(); + const stack = new Stack(app); const unusedSourceAction = new cpactions.GitHubSourceAction({ actionName: 'Source2', @@ -202,7 +203,7 @@ describe('Github source action', () => { }); expect(() => { - SynthUtils.synthesize(stack); + App.of(stack)!.synth(); }).toThrow(/Cannot reference variables of action 'Source2', as that action was never added to a pipeline/); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts index 1acf0b4764cd6..7227ab34f8f1f 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; @@ -21,7 +21,7 @@ describe('', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ {}, { @@ -34,9 +34,7 @@ describe('', () => { ], }, ], - }); - - + })); }); test('properly resolves any Tokens passed in userParameters', () => { @@ -45,8 +43,7 @@ describe('', () => { key: Lazy.string({ produce: () => Aws.REGION }), }, }); - - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ {}, { @@ -70,9 +67,7 @@ describe('', () => { ], }, ], - }); - - + })); }); test('properly resolves any stringified Tokens passed in userParameters', () => { @@ -82,7 +77,7 @@ describe('', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ {}, { @@ -95,9 +90,7 @@ describe('', () => { ], }, ], - }); - - + })); }); test('properly assings userParametersString to UserParameters', () => { @@ -105,7 +98,7 @@ describe('', () => { userParamsString: '**/*.template.json', }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ {}, { @@ -118,7 +111,7 @@ describe('', () => { ], }, ], - }); + })); }); test('throws if both userParameters and userParametersString are supplied', () => { @@ -135,7 +128,7 @@ describe('', () => { lambdaInput: new codepipeline.Artifact(), }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', Match.objectLike({ 'PolicyDocument': { 'Statement': [ { @@ -164,9 +157,7 @@ describe('', () => { }, ], }, - }); - - + })); }); testFutureBehavior("assigns the Action's Role with write permissions to the Bucket if it has only outputs", s3GrantWriteCtx, App, (app) => { @@ -175,8 +166,9 @@ describe('', () => { // no input to the Lambda Action - we want write permissions only in this case }, app); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyName: 'PipelineInvokeLambdaCodePipelineActionRoleDefaultPolicy103F34DA', + 'PolicyDocument': Match.objectLike({ 'Statement': [ { 'Action': 'lambda:ListFunctions', @@ -200,14 +192,13 @@ describe('', () => { 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*', + 'kms:Decrypt', ], 'Effect': 'Allow', }, ], - }, + }), }); - - }); testFutureBehavior("assigns the Action's Role with read-write permissions to the Bucket if it has both inputs and outputs", s3GrantWriteCtx, App, (app) => { @@ -216,8 +207,9 @@ describe('', () => { lambdaOutput: new codepipeline.Artifact(), }, app); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyName: 'PipelineInvokeLambdaCodePipelineActionRoleDefaultPolicy103F34DA', + 'PolicyDocument': Match.objectLike({ 'Statement': [ { 'Action': 'lambda:ListFunctions', @@ -256,14 +248,13 @@ describe('', () => { 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*', + 'kms:Decrypt', ], 'Effect': 'Allow', }, ], - }, + }), }); - - }); test('exposes variables for other actions to consume', () => { @@ -304,7 +295,7 @@ describe('', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ { 'Name': 'Source', @@ -325,9 +316,7 @@ describe('', () => { ], }, ], - }); - - + })); }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts index bf894a5db1c88..6ebfe84b84c8a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as iam from '@aws-cdk/aws-iam'; import * as sns from '@aws-cdk/aws-sns'; @@ -48,7 +48,7 @@ describe('manual approval', () => { manualApprovalAction.grantManualApproval(role); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -154,7 +154,7 @@ describe('manual approval', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts index 1c680e0c7e95d..16a1bc66e4cce 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { SynthUtils } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; @@ -45,7 +44,7 @@ describe('pipeline', () => { ], }); - expect(SynthUtils.toCloudFormation(stack)).not.toEqual({}); + expect(Template.fromStack(stack).toJSON()).not.toEqual({}); expect([]).toEqual(ConstructNode.validate(pipeline.node)); }); @@ -79,7 +78,7 @@ describe('pipeline', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Name': { 'Ref': 'AWS::StackName', }, @@ -118,9 +117,9 @@ describe('pipeline', () => { ], }); - expect(stack).not.toHaveResourceLike('AWS::CodePipeline::Webhook'); + Template.fromStack(stack).resourceCountIs('AWS::CodePipeline::Webhook', 0); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Actions': [ @@ -177,9 +176,9 @@ describe('pipeline', () => { ], }); - expect(stack).not.toHaveResourceLike('AWS::CodePipeline::Webhook'); + Template.fromStack(stack).resourceCountIs('AWS::CodePipeline::Webhook', 0); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Actions': [ @@ -235,9 +234,9 @@ describe('pipeline', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Webhook'); + Template.fromStack(stack).resourceCountIs('AWS::CodePipeline::Webhook', 1); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStore': { 'Location': { 'Ref': 'PArtifactsBucket5E711C12', @@ -338,7 +337,7 @@ describe('pipeline', () => { }, }); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'Description': 'desc', 'EventPattern': { 'detail': { @@ -402,7 +401,7 @@ describe('pipeline', () => { projectName: 'MyProject', }); - expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', { 'Name': 'MyProject', 'Source': { 'Type': 'CODEPIPELINE', @@ -481,7 +480,7 @@ describe('pipeline', () => { actions: [lambdaAction], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStore': { 'Location': { 'Ref': 'PipelineArtifactsBucket22248F97', @@ -532,7 +531,7 @@ describe('pipeline', () => { expect((lambdaAction.actionProperties.outputs || []).length).toEqual(3); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -616,7 +615,7 @@ describe('pipeline', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStores': [ { 'Region': 'us-west-1', @@ -733,9 +732,9 @@ describe('pipeline', () => { ], }); - expect(stack).toCountResources('AWS::S3::Bucket', 1); + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStores': [ { 'Region': pipelineRegion, @@ -786,7 +785,7 @@ describe('pipeline', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStores': [ { 'Region': replicationRegion, @@ -833,7 +832,7 @@ describe('pipeline', () => { ], }); - expect(replicationStack).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromStack(replicationStack).hasResourceProperties('AWS::S3::Bucket', { 'BucketName': 'replicationstackeplicationbucket2464cd5c33b386483b66', }); @@ -895,7 +894,7 @@ describe('pipeline', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -926,7 +925,7 @@ describe('pipeline', () => { ], }); - expect(buildStack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(buildStack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -1038,7 +1037,7 @@ describe('pipeline', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -1122,7 +1121,7 @@ describe('pipeline', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts index 580a4dc688e19..656ea496aa8dd 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, SecretValue, Stack } from '@aws-cdk/core'; @@ -14,7 +14,7 @@ describe('', () => { const stack = new Stack(); minimalPipeline(stack); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -53,7 +53,7 @@ describe('', () => { const stack = new Stack(app); minimalPipeline(stack); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -85,7 +85,7 @@ describe('', () => { accessControl: s3.BucketAccessControl.PUBLIC_READ_WRITE, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -113,7 +113,7 @@ describe('', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -137,7 +137,7 @@ describe('', () => { objectKey: '/a/b/c', }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -169,7 +169,7 @@ describe('', () => { bucket: deployBucket, }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: [ {}, { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts index 65553aee81be5..0fe6b311ad8a3 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; @@ -14,7 +14,7 @@ describe('S3 source Action', () => { minimalPipeline(stack, undefined); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ { 'Actions': [ @@ -26,9 +26,9 @@ describe('S3 source Action', () => { }, {}, ], - }); + })); - expect(stack).not.toHaveResourceLike('AWS::Events::Rule'); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); }); @@ -38,22 +38,22 @@ describe('S3 source Action', () => { minimalPipeline(stack, { trigger: cpactions.S3Trigger.EVENTS }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ { - 'Actions': [ - { + 'Actions': Match.arrayWith([ + Match.objectLike({ 'Configuration': { 'PollForSourceChanges': false, }, - }, - ], + }), + ]), }, {}, ], - }); + })); - expect(stack).toCountResources('AWS::Events::Rule', 1); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 1); }); @@ -63,7 +63,7 @@ describe('S3 source Action', () => { minimalPipeline(stack, { trigger: cpactions.S3Trigger.POLL }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ { 'Actions': [ @@ -76,9 +76,9 @@ describe('S3 source Action', () => { }, {}, ], - }); + })); - expect(stack).not.toHaveResourceLike('AWS::Events::Rule'); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); }); @@ -88,7 +88,7 @@ describe('S3 source Action', () => { minimalPipeline(stack, { trigger: cpactions.S3Trigger.NONE }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ { 'Actions': [ @@ -101,11 +101,9 @@ describe('S3 source Action', () => { }, {}, ], - }); - - expect(stack).not.toHaveResourceLike('AWS::Events::Rule'); - + })); + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); }); test('does not allow passing an empty string for the bucketKey property', () => { @@ -171,8 +169,6 @@ describe('S3 source Action', () => { expect(() => { sourceStage.addAction(duplicateBucketAndPath); }).toThrow(/S3 source action with path 'my\/other\/path' is already present in the pipeline for this source bucket/); - - }); test('allows using a Token bucketKey with trigger = Events, multiple times', () => { @@ -192,9 +188,9 @@ describe('S3 source Action', () => { output: new codepipeline.Artifact(), })); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': [ - { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ + 'Stages': Match.arrayWith([ + Match.objectLike({ 'Actions': [ { 'Configuration': { @@ -207,11 +203,9 @@ describe('S3 source Action', () => { }, }, ], - }, - ], - }); - - + }), + ]), + })); }); test('exposes variables for other actions to consume', () => { @@ -246,7 +240,7 @@ describe('S3 source Action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ 'Stages': [ { 'Name': 'Source', @@ -263,9 +257,7 @@ describe('S3 source Action', () => { ], }, ], - }); - - + })); }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts index cf490f21fc206..0be3e3a610c49 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { Stack } from '@aws-cdk/core'; @@ -19,13 +19,13 @@ describe('ServiceCatalog Deploy Action', () => { productId: 'prod-xxxxxxxxx', })); // THEN - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': [ - { 'Name': 'Source' /* don't care about the rest */ }, - { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': Match.arrayWith([ + Match.objectLike({ 'Name': 'Source' /* don't care about the rest */ }), + Match.objectLike({ 'Name': 'Deploy', - 'Actions': [ - { + 'Actions': Match.arrayWith([ + Match.objectLike({ 'ActionTypeId': { 'Category': 'Deploy', 'Owner': 'AWS', @@ -45,10 +45,10 @@ describe('ServiceCatalog Deploy Action', () => { }, ], 'Name': 'ServiceCatalogTest', - }, - ], - }, - ], + }), + ]), + }), + ]), }); @@ -64,13 +64,13 @@ describe('ServiceCatalog Deploy Action', () => { productId: 'prod-xxxxxxxxx', })); // THEN - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': [ - { 'Name': 'Source' /* don't care about the rest */ }, - { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': Match.arrayWith([ + Match.objectLike({ 'Name': 'Source' /* don't care about the rest */ }), + Match.objectLike({ 'Name': 'Deploy', - 'Actions': [ - { + 'Actions': Match.arrayWith([ + Match.objectLike({ 'ActionTypeId': { 'Category': 'Deploy', 'Owner': 'AWS', @@ -89,10 +89,10 @@ describe('ServiceCatalog Deploy Action', () => { }, ], 'Name': 'ServiceCatalogTest', - }, - ], - }, - ], + }), + ]), + }), + ]), }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts index 0ad5d8b2213a1..0825f8fdfcf35 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template, Match } from '@aws-cdk/assertions'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import * as stepfunction from '@aws-cdk/aws-stepfunctions'; @@ -14,7 +14,7 @@ describe('StepFunctions Invoke Action', () => { minimalPipeline(stack); // then - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', Match.objectLike({ Stages: [ // Must have a source stage { @@ -57,7 +57,7 @@ describe('StepFunctions Invoke Action', () => { ], }, ], - }); + })); }); @@ -67,9 +67,10 @@ describe('StepFunctions Invoke Action', () => { minimalPipeline(stack); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyName: 'MyPipelineInvokeCodePipelineActionRoleDefaultPolicy07A602B1', PolicyDocument: { - Statement: [ + Statement: Match.arrayWith([ { Action: ['states:StartExecution', 'states:DescribeStateMachine'], Resource: { @@ -77,11 +78,11 @@ describe('StepFunctions Invoke Action', () => { }, Effect: 'Allow', }, - ], + ]), }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Role'); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 4); }); @@ -91,7 +92,7 @@ describe('StepFunctions Invoke Action', () => { minimalPipeline(stack); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ {}, @@ -137,7 +138,7 @@ describe('StepFunctions Invoke Action', () => { }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Role'); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 4); }); diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index b0baf652b6866..29d74c51f6628 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -84,7 +84,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-codepipeline/test/action.test.ts b/packages/@aws-cdk/aws-codepipeline/test/action.test.ts index 69a5839385fcd..a8b6529b3e80a 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/action.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 cdk from '@aws-cdk/core'; import * as codepipeline from '../lib'; @@ -10,54 +10,45 @@ import { FakeSourceAction } from './fake-source-action'; describe('action', () => { describe('artifact bounds validation', () => { - test('artifacts count exceed maximum', () => { const result = boundsValidationResult(1, 0, 0); expect(result.length).toEqual(1); expect(result[0]).toMatch(/cannot have more than 0/); - }); test('artifacts count below minimum', () => { const result = boundsValidationResult(1, 2, 2); expect(result.length).toEqual(1); expect(result[0]).toMatch(/must have at least 2/); - }); test('artifacts count within bounds', () => { const result = boundsValidationResult(1, 0, 2); expect(result.length).toEqual(0); - }); }); describe('action type validation', () => { - test('must be source and is source', () => { const result = validations.validateSourceAction(true, codepipeline.ActionCategory.SOURCE, 'test action', 'test stage'); expect(result.length).toEqual(0); - }); test('must be source and is not source', () => { const result = validations.validateSourceAction(true, codepipeline.ActionCategory.DEPLOY, 'test action', 'test stage'); expect(result.length).toEqual(1); expect(result[0]).toMatch(/may only contain Source actions/); - }); test('cannot be source and is source', () => { const result = validations.validateSourceAction(false, codepipeline.ActionCategory.SOURCE, 'test action', 'test stage'); expect(result.length).toEqual(1); expect(result[0]).toMatch(/may only occur in first stage/); - }); test('cannot be source and is not source', () => { const result = validations.validateSourceAction(false, codepipeline.ActionCategory.DEPLOY, 'test action', 'test stage'); expect(result.length).toEqual(0); - }); }); @@ -74,8 +65,6 @@ describe('action', () => { expect(() => { stage.addAction(action); }).toThrow(/Action name must match regular expression:/); - - }); }); @@ -121,11 +110,9 @@ describe('action', () => { }); expect(() => { - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { }); }).toThrow(/Build\/Fake cannot have more than 3 input artifacts/); - - }); test('validates that output Artifacts are within bounds', () => { @@ -166,11 +153,9 @@ describe('action', () => { }); expect(() => { - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { }); }).toThrow(/Source\/Fake cannot have more than 4 output artifacts/); - - }); }); @@ -199,7 +184,7 @@ describe('action', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -234,8 +219,6 @@ describe('action', () => { }, ], }); - - }); test('the same Action can be safely added to 2 different Stages', () => { @@ -270,8 +253,6 @@ describe('action', () => { expect(() => { pipeline.addStage(stage3); }).not.toThrow(/FakeAction/); - - }); describe('input Artifacts', () => { @@ -285,8 +266,6 @@ describe('action', () => { extraInputs: [artifact], }); }).not.toThrow(); - - }); test('can have duplicate names', () => { @@ -300,8 +279,6 @@ describe('action', () => { extraInputs: [artifact2], }); }).not.toThrow(); - - }); }); @@ -317,8 +294,6 @@ describe('action', () => { ], }); }).not.toThrow(); - - }); }); @@ -355,8 +330,6 @@ describe('action', () => { expect(() => { buildStage.addAction(buildAction); }).toThrow(/Role is not supported for actions with an owner different than 'AWS' - got 'ThirdParty' \(Action: 'build' in Stage: 'Build'\)/); - - }); test('actions can be retrieved from stages they have been added to', () => { @@ -399,8 +372,6 @@ describe('action', () => { expect(buildStage.actions.length).toEqual(2); expect(buildStage.actions[0].actionProperties.actionName).toEqual('build1'); expect(buildStage.actions[1].actionProperties.actionName).toEqual('build2'); - - }); }); diff --git a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts index 4570ea850df3a..9e2e62a6aedda 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/artifacts.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 codepipeline from '../lib'; import { FakeBuildAction } from './fake-build-action'; @@ -10,8 +10,6 @@ describe('artifacts', () => { describe('Artifacts in CodePipeline', () => { test('cannot be created with an empty name', () => { expect(() => new codepipeline.Artifact('')).toThrow(/Artifact name must match regular expression/); - - }); test('without a name, when used as an input without being used as an output first - should fail validation', () => { @@ -45,8 +43,6 @@ describe('artifacts', () => { expect(errors.length).toEqual(1); const error = errors[0]; expect(error).toMatch(/Action 'Build' is using an unnamed input Artifact, which is not being produced in this pipeline/); - - }); test('with a name, when used as an input without being used as an output first - should fail validation', () => { @@ -80,8 +76,6 @@ describe('artifacts', () => { expect(errors.length).toEqual(1); const error = errors[0]; expect(error).toMatch(/Action 'Build' is using input Artifact 'named', which is not being produced in this pipeline/); - - }); test('without a name, when used as an output multiple times - should fail validation', () => { @@ -116,8 +110,6 @@ describe('artifacts', () => { expect(errors.length).toEqual(1); const error = errors[0]; expect(error).toMatch(/Both Actions 'Source' and 'Build' are producting Artifact 'Artifact_Source_Source'. Every artifact can only be produced once./); - - }); test("an Action's output can be used as input for an Action in the same Stage with a higher runOrder", () => { @@ -162,9 +154,7 @@ describe('artifacts', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline'); - - + Template.fromStack(stack).resourceCountIs('AWS::CodePipeline::Pipeline', 1); }); test('violation of runOrder constraints is detected and reported', () => { @@ -215,8 +205,6 @@ describe('artifacts', () => { expect(errors.length).toEqual(1); const error = errors[0]; expect(error).toMatch(/Stage 2 Action 2 \('Build'\/'build2'\) is consuming input Artifact 'buildOutput1' before it is being produced at Stage 2 Action 3 \('Build'\/'build1'\)/); - - }); test('without a name, sanitize the auto stage-action derived name', () => { @@ -246,7 +234,7 @@ describe('artifacts', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source.@', @@ -272,8 +260,6 @@ describe('artifacts', () => { }, ], }); - - }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts b/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts index f26de209ecaf9..9e2608dd36f36 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/cross-env.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 s3 from '@aws-cdk/aws-s3'; import { Stack, App, Stage as CdkStage } from '@aws-cdk/core'; @@ -58,8 +58,8 @@ describe.each([ test('creates a bucket but no keys', () => { // THEN - expect(stack).not.toHaveResource('AWS::KMS::Key'); - expect(stack).toHaveResource('AWS::S3::Bucket'); + Template.fromStack(stack).resourceCountIs('AWS::KMS::Key', 0); + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1); }); describe('prevents adding a cross-account action', () => { @@ -128,8 +128,8 @@ describe.each([ const supportStack = asm.getStackByName(`${stack.stackName}-support-eu-west-1`); // THEN - expect(supportStack).not.toHaveResource('AWS::KMS::Key'); - expect(supportStack).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromJSON(supportStack.template).resourceCountIs('AWS::KMS::Key', 0); + Template.fromJSON(supportStack.template).hasResourceProperties('AWS::S3::Bucket', { PublicAccessBlockConfiguration: { BlockPublicAcls: true, BlockPublicPolicy: true, @@ -150,8 +150,8 @@ describe.each([ })); // THEN - expect(stack2).not.toHaveResource('AWS::KMS::Key'); - expect(stack2).toHaveResource('AWS::S3::Bucket'); + Template.fromStack(stack2).resourceCountIs('AWS::KMS::Key', 0); + Template.fromStack(stack2).resourceCountIs('AWS::S3::Bucket', 1); }); }); }); @@ -200,11 +200,11 @@ describe('cross-environment CodePipeline', function () { const asm = app.synth(); const supportStack = asm.getStackByName(`${pipelineStack.stackName}-support-456`); - expect(supportStack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromJSON(supportStack.template).hasResourceProperties('AWS::IAM::Role', { RoleName: 'pipelinestack-support-456dbuildactionrole91c6f1a469fd11d52dfe', }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: [ { Name: 'Source' }, { diff --git a/packages/@aws-cdk/aws-codepipeline/test/general-validation.test.ts b/packages/@aws-cdk/aws-codepipeline/test/general-validation.test.ts index d8186532d7cea..f3024ec163e9b 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/general-validation.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/general-validation.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import { IStage } from '../lib/action'; import { Artifact } from '../lib/artifact'; @@ -30,8 +29,6 @@ describe('general validation', () => { expect(validationBlock).toThrow(); } }); - - }); describe('Stage validation', () => { @@ -39,8 +36,6 @@ describe('general validation', () => { const stage = stageForTesting(); expect((stage as any).validate().length).toEqual(1); - - }); }); @@ -50,8 +45,6 @@ describe('general validation', () => { const pipeline = new Pipeline(stack, 'Pipeline'); expect(cdk.ConstructNode.validate(pipeline.node).length).toEqual(1); - - }); test('should fail if Pipeline has a Source Action in a non-first Stage', () => { @@ -69,8 +62,6 @@ describe('general validation', () => { }); expect(cdk.ConstructNode.validate(pipeline.node).length).toEqual(1); - - }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline/test/notification-rule.test.ts b/packages/@aws-cdk/aws-codepipeline/test/notification-rule.test.ts index 46d32794dc3e1..ac178204dd263 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/notification-rule.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/notification-rule.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 codepipeline from '../lib'; import { FakeBuildAction } from './fake-build-action'; @@ -35,7 +35,7 @@ describe('pipeline with codestar notification integration', () => { pipeline.notifyOnExecutionStateChange('NotifyOnExecutionStateChange', target); - expect(stack).toHaveResourceLike('AWS::CodeStarNotifications::NotificationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeStarNotifications::NotificationRule', { Name: 'PipelineNotifyOnExecutionStateChange9FE60973', DetailType: 'FULL', EventTypeIds: [ @@ -77,7 +77,7 @@ describe('pipeline with codestar notification integration', () => { pipeline.notifyOnAnyStageStateChange('NotifyOnAnyStageStateChange', target); - expect(stack).toHaveResourceLike('AWS::CodeStarNotifications::NotificationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeStarNotifications::NotificationRule', { Name: 'PipelineNotifyOnAnyStageStateChange05355CCD', DetailType: 'FULL', EventTypeIds: [ @@ -118,7 +118,7 @@ describe('pipeline with codestar notification integration', () => { pipeline.notifyOnAnyActionStateChange('NotifyOnAnyActionStateChange', target); - expect(stack).toHaveResourceLike('AWS::CodeStarNotifications::NotificationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeStarNotifications::NotificationRule', { Name: 'PipelineNotifyOnAnyActionStateChange64D5B2AA', DetailType: 'FULL', EventTypeIds: [ @@ -158,7 +158,7 @@ describe('pipeline with codestar notification integration', () => { pipeline.notifyOnAnyManualApprovalStateChange('NotifyOnAnyManualApprovalStateChange', target); - expect(stack).toHaveResourceLike('AWS::CodeStarNotifications::NotificationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeStarNotifications::NotificationRule', { Name: 'PipelineNotifyOnAnyManualApprovalStateChangeE60778F7', DetailType: 'FULL', EventTypeIds: [ diff --git a/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts b/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts index 5af1eea557f3f..dd4f79d040201 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts @@ -1,5 +1,4 @@ -import { expect as ourExpect, ResourcePart, arrayWith, objectLike, haveResourceLike } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; @@ -22,20 +21,36 @@ describe('', () => { const role = new iam.Role(stack, 'Role', { assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'), }); - new codepipeline.Pipeline(stack, 'Pipeline', { + const pipeline = new codepipeline.Pipeline(stack, 'Pipeline', { role, }); - ourExpect(stack, true).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + // Adding 2 stages with actions so pipeline validation will pass + const sourceArtifact = new codepipeline.Artifact(); + pipeline.addStage({ + stageName: 'Source', + actions: [new FakeSourceAction({ + actionName: 'FakeSource', + output: sourceArtifact, + })], + }); + + pipeline.addStage({ + stageName: 'Build', + actions: [new FakeBuildAction({ + actionName: 'FakeBuild', + input: sourceArtifact, + })], + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'RoleArn': { 'Fn::GetAtt': [ 'Role1ABCC5F0', 'Arn', ], }, - })); - - + }); }); test('can be imported by ARN', () => { @@ -46,8 +61,6 @@ describe('', () => { expect(pipeline.pipelineArn).toEqual('arn:aws:codepipeline:us-east-1:123456789012:MyPipeline'); expect(pipeline.pipelineName).toEqual('MyPipeline'); - - }); describe('that is cross-region', () => { @@ -67,8 +80,6 @@ describe('', () => { expect(() => { sourceStage.addAction(sourceAction); }).toThrow(/Source action 'FakeSource' must be in the same region as the pipeline/); - - }); test('allows passing an Alias in place of the KMS Key in the replication Bucket', () => { @@ -113,7 +124,7 @@ describe('', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStores': [ { 'Region': replicationRegion, @@ -142,7 +153,7 @@ describe('', () => { ], }); - expect(replicationStack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(replicationStack).hasResourceProperties('AWS::KMS::Key', { 'KeyPolicy': { 'Statement': [ { @@ -175,8 +186,6 @@ describe('', () => { ], }, }); - - }); test('generates ArtifactStores with the alias ARN as the KeyID', () => { @@ -208,7 +217,7 @@ describe('', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStores': [ { 'Region': replicationRegion, @@ -237,12 +246,10 @@ describe('', () => { ], }); - expect(pipeline.crossRegionSupport[replicationRegion].stack).toHaveResourceLike('AWS::KMS::Alias', { + Template.fromStack(pipeline.crossRegionSupport[replicationRegion].stack).hasResource('AWS::KMS::Alias', { 'DeletionPolicy': 'Delete', 'UpdateReplacePolicy': 'Delete', - }, ResourcePart.CompleteDefinition); - - + }); }); test('allows passing an imported Bucket and Key for the replication Bucket', () => { @@ -280,7 +287,7 @@ describe('', () => { ], }); - expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'ArtifactStores': [ { 'Region': replicationRegion, @@ -298,8 +305,6 @@ describe('', () => { }, ], }); - - }); test('generates the support stack containing the replication Bucket without the need to bootstrap in that environment', () => { @@ -380,18 +385,18 @@ describe('', () => { const supportStackBArtifact = assembly.getStackByName('PipelineStackB-support-eu-south-1'); const supportStackATemplate = supportStackAArtifact.template; - expect(supportStackATemplate).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromJSON(supportStackATemplate).hasResourceProperties('AWS::S3::Bucket', { BucketName: 'pipelinestacka-support-eueplicationbucket8934e91f26961aa6cbfa', }); - expect(supportStackATemplate).toHaveResourceLike('AWS::KMS::Alias', { + Template.fromJSON(supportStackATemplate).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/pport-eutencryptionalias02f1cda3732942f6c529', }); const supportStackBTemplate = supportStackBArtifact.template; - expect(supportStackBTemplate).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromJSON(supportStackBTemplate).hasResourceProperties('AWS::S3::Bucket', { BucketName: 'pipelinestackb-support-eueplicationbucketdf7c0e10245faa377228', }); - expect(supportStackBTemplate).toHaveResourceLike('AWS::KMS::Alias', { + Template.fromJSON(supportStackBTemplate).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/pport-eutencryptionaliasdef3fd3fec63bc54980e', }); }); @@ -419,8 +424,6 @@ describe('', () => { account: cdk.Aws.ACCOUNT_ID, })); }).toThrow(/The 'account' property must be a concrete value \(action: 'FakeBuild'\)/); - - }); test('does not allow an env-agnostic Pipeline Stack if an Action account has been provided', () => { @@ -444,8 +447,6 @@ describe('', () => { account: '123456789012', })); }).toThrow(/Pipeline stack which uses cross-environment actions must have an explicitly set account/); - - }); test('does not allow enabling key rotation if cross account keys have been disabled', () => { @@ -478,7 +479,7 @@ describe('', () => { ], }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { 'EnableKeyRotation': true, }); }); @@ -513,19 +514,18 @@ describe('test with shared setup', () => { pipeline.stage('Build').addAction(new FakeBuildAction({ actionName: 'debug.com', input: sourceArtifact })); // THEN - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - Stages: arrayWith({ + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + Stages: Match.arrayWith([{ Name: 'Build', Actions: [ - objectLike({ Name: 'Gcc' }), - objectLike({ Name: 'debug.com' }), + Match.objectLike({ Name: 'Gcc' }), + Match.objectLike({ Name: 'debug.com' }), ], - }), + }]), }); }); }); - interface ReusePipelineStackProps extends cdk.StackProps { reuseCrossRegionSupportStacks?: boolean; } diff --git a/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts b/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts index d7931a23a531e..ca5882a4c42a6 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/stages.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 codepipeline from '../lib'; import { Stage } from '../lib/private/stage'; @@ -33,14 +33,12 @@ describe('stages', () => { })); // -- - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'FirstStage' }, { 'Name': 'SecondStage' }, ], }); - - }); test('can be inserted after another Stage', () => { @@ -72,15 +70,13 @@ describe('stages', () => { })); // -- - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'FirstStage' }, { 'Name': 'SecondStage' }, { 'Name': 'ThirdStage' }, ], }); - - }); test("attempting to insert a Stage before a Stage that doesn't exist results in an error", () => { @@ -97,8 +93,6 @@ describe('stages', () => { }, }); }).toThrow(/before/i); - - }); test("attempting to insert a Stage after a Stage that doesn't exist results in an error", () => { @@ -115,8 +109,6 @@ describe('stages', () => { }, }); }).toThrow(/after/i); - - }); test('providing more than one placement value results in an error', () => { @@ -135,8 +127,6 @@ describe('stages', () => { // incredibly, an arrow function below causes nodeunit to crap out with: // "TypeError: Function has non-object prototype 'undefined' in instanceof check" }).toThrow(/(rightBefore.*justAfter)|(justAfter.*rightBefore)/); - - }); test('can be retrieved from a pipeline after it has been created', () => { @@ -160,8 +150,6 @@ describe('stages', () => { stageName: 'ThirdStage', }, pipeline)); expect(pipeline.stageCount).toEqual(2); - - }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts b/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts index 537b108df805a..6d70847bec853 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as codepipeline from '../lib'; import { FakeBuildAction } from './fake-build-action'; @@ -38,21 +37,19 @@ describe('variables', () => { })); // -- - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': [ + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': Match.arrayWith([ { 'Name': 'Source', 'Actions': [ - { + Match.objectLike({ 'Name': 'Source', 'Namespace': 'MyNamespace', - }, + }), ], }, - ], + ]), }); - - }); test('allows using the variable in the configuration of a different action', () => { @@ -80,7 +77,7 @@ describe('variables', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -98,8 +95,6 @@ describe('variables', () => { }, ], }); - - }); test('fails when trying add an action using variables with an empty string for the namespace to a pipeline', () => { @@ -116,8 +111,6 @@ describe('variables', () => { expect(() => { sourceStage.addAction(sourceAction); }).toThrow(/Namespace name must match regular expression:/); - - }); test('can use global variables', () => { @@ -144,12 +137,12 @@ describe('variables', () => { ], }); - expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { - 'Stages': arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::CodePipeline::Pipeline', { + 'Stages': Match.arrayWith([ { 'Name': 'Build', 'Actions': [ - objectLike({ + Match.objectLike({ 'Name': 'Build', 'Configuration': { 'CustomConfigKey': '#{codepipeline.PipelineExecutionId}', @@ -157,10 +150,8 @@ describe('variables', () => { }), ], }, - ), + ]), }); - - }); }); }); diff --git a/packages/@aws-cdk/aws-cognito-identitypool/package.json b/packages/@aws-cdk/aws-cognito-identitypool/package.json index e7b9183ce8ba7..db55fece60596 100644 --- a/packages/@aws-cdk/aws-cognito-identitypool/package.json +++ b/packages/@aws-cdk/aws-cognito-identitypool/package.json @@ -74,8 +74,8 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.3", - "jest": "^27.4.5" + "@types/jest": "^27.4.0", + "jest": "^27.4.7" }, "dependencies": { "@aws-cdk/aws-cognito": "0.0.0", diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index 3695f158d2eb1..e0cd4997a725a 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/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-targets": "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-config/test/managed-rules.test.ts b/packages/@aws-cdk/aws-config/test/managed-rules.test.ts index 98dd3fbd34262..ef7e98ff25709 100644 --- a/packages/@aws-cdk/aws-config/test/managed-rules.test.ts +++ b/packages/@aws-cdk/aws-config/test/managed-rules.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; import * as config from '../lib'; @@ -12,7 +12,7 @@ describe('access keys', () => { new config.AccessKeysRotated(stack, 'AccessKeys'); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Source: { Owner: 'AWS', SourceIdentifier: 'ACCESS_KEYS_ROTATED', @@ -30,7 +30,7 @@ describe('access keys', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Source: { Owner: 'AWS', SourceIdentifier: 'ACCESS_KEYS_ROTATED', @@ -51,7 +51,7 @@ describe('cloudformation stack', () => { new config.CloudFormationStackDriftDetectionCheck(stack, 'Drift'); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Source: { Owner: 'AWS', SourceIdentifier: 'CLOUDFORMATION_STACK_DRIFT_DETECTION_CHECK', @@ -71,7 +71,7 @@ describe('cloudformation stack', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -113,7 +113,7 @@ describe('cloudformation stack', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Source: { Owner: 'AWS', SourceIdentifier: 'CLOUDFORMATION_STACK_NOTIFICATION_CHECK', @@ -157,7 +157,7 @@ describe('ec2 instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Source: { Owner: 'AWS', SourceIdentifier: config.ManagedRuleIdentifiers.EC2_INSTANCE_PROFILE_ATTACHED, diff --git a/packages/@aws-cdk/aws-config/test/rule.test.ts b/packages/@aws-cdk/aws-config/test/rule.test.ts index 259727982a330..a6e125b4d89ec 100644 --- a/packages/@aws-cdk/aws-config/test/rule.test.ts +++ b/packages/@aws-cdk/aws-config/test/rule.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as targets from '@aws-cdk/aws-events-targets'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; @@ -22,7 +21,7 @@ describe('rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Source: { Owner: 'AWS', SourceIdentifier: 'AWS_SUPER_COOL', @@ -59,7 +58,7 @@ describe('rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResource('AWS::Config::ConfigRule', { Properties: { Source: { Owner: 'CUSTOM_LAMBDA', @@ -97,16 +96,16 @@ describe('rule', () => { 'Function76856677', 'FunctionServiceRole675BB04A', ], - }, ResourcePart.CompleteDefinition); + }); - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Principal: 'config.amazonaws.com', SourceAccount: { Ref: 'AWS::AccountId', }, }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { ManagedPolicyArns: [ { 'Fn::Join': [ @@ -147,7 +146,7 @@ describe('rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Scope: { ComplianceResourceId: 'i-1234', ComplianceResourceTypes: [ @@ -168,7 +167,7 @@ describe('rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Scope: { ComplianceResourceTypes: [ 'AWS::S3::Bucket', @@ -189,7 +188,7 @@ describe('rule', () => { }); // THEN - expect(stack).toHaveResource('AWS::Config::ConfigRule', { + Template.fromStack(stack).hasResourceProperties('AWS::Config::ConfigRule', { Scope: { TagKey: 'key', TagValue: 'value', @@ -247,7 +246,7 @@ describe('rule', () => { target: new targets.LambdaFunction(fn), }); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { EventPattern: { 'source': [ 'aws.config', diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index d70ae96f75854..4242c8e2a7622 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/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-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index b812d2b3e4742..4a6c44156f70f 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -1,13 +1,11 @@ -import { expect as expectCDK, haveResource, ResourcePart, arrayWith, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; - import { ClusterParameterGroup, DatabaseCluster, DatabaseSecret } from '../lib'; describe('DatabaseCluster', () => { - test('check that instantiation works', () => { // GIVEN const stack = testStack(); @@ -24,7 +22,7 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResource('AWS::DocDB::DBCluster', { Properties: { DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, MasterUsername: 'admin', @@ -34,20 +32,20 @@ describe('DatabaseCluster', () => { }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); + }); - expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Template.fromStack(stack).hasResource('AWS::DocDB::DBInstance', { DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); + }); - expectCDK(stack).to(haveResource('AWS::DocDB::DBSubnetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBSubnetGroup', { SubnetIds: [ { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, ], - })); + }); }); test('can create a cluster with a single instance', () => { @@ -67,12 +65,12 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, MasterUsername: 'admin', MasterUserPassword: 'tooshort', VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], - })); + }); }); test('errors when less than one instance is specified', () => { @@ -132,11 +130,11 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::SecretsManager::SecretTargetAttachment', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::SecretTargetAttachment', { SecretId: { Ref: 'DatabaseSecret3B817195' }, TargetId: { Ref: 'DatabaseB269D8BB' }, TargetType: 'AWS::DocDB::DBCluster', - })); + }); }); test('can create a cluster with imported vpc and security group', () => { @@ -160,12 +158,12 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, MasterUsername: 'admin', MasterUserPassword: 'tooshort', VpcSecurityGroupIds: ['SecurityGroupId12345'], - })); + }); }); test('can configure cluster deletion protection', () => { @@ -184,9 +182,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { DeletionProtection: true, - })); + }); }); test('cluster with parameter group', () => { @@ -213,9 +211,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { DBClusterParameterGroupName: { Ref: 'ParamsA8366201' }, - })); + }); }); test('cluster with imported parameter group', () => { @@ -237,9 +235,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { DBClusterParameterGroupName: 'ParamGroupName', - })); + }); }); test('creates a secret when master credentials are not specified', () => { @@ -257,7 +255,7 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { MasterUsername: { 'Fn::Join': [ '', @@ -282,16 +280,16 @@ describe('DatabaseCluster', () => { ], ], }, - })); + }); - expectCDK(stack).to(haveResource('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { GenerateSecretString: { ExcludeCharacters: '\"@/', GenerateStringKey: 'password', PasswordLength: 41, SecretStringTemplate: '{"username":"admin"}', }, - })); + }); }); test('creates a secret with excludeCharacters', () => { @@ -310,11 +308,11 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResourceLike('AWS::SecretsManager::Secret', { - GenerateSecretString: objectLike({ + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { + GenerateSecretString: Match.objectLike({ ExcludeCharacters: '\"@/()[]', }), - })); + }); }); test('creates a secret with secretName set', () => { @@ -333,9 +331,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResourceLike('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { Name: '/myapp/mydocdb/masteruser', - })); + }); }); test('create an encrypted cluster with custom KMS key', () => { @@ -354,7 +352,7 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { KmsKeyId: { 'Fn::GetAtt': [ 'Key961B73FD', @@ -362,7 +360,7 @@ describe('DatabaseCluster', () => { ], }, StorageEncrypted: true, - })); + }); }); test('creating a cluster defaults to using encryption', () => { @@ -380,9 +378,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { StorageEncrypted: true, - })); + }); }); test('supplying a KMS key with storageEncryption false throws an error', () => { @@ -442,9 +440,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBInstance', { DBInstanceIdentifier: `${instanceIdentifierBase}1`, - })); + }); }); test('cluster identifier used', () => { @@ -464,9 +462,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBInstance', { DBInstanceIdentifier: `${clusterIdentifier}instance1`, - })); + }); }); test('imported cluster has supplied attributes', () => { @@ -515,9 +513,9 @@ describe('DatabaseCluster', () => { cluster.connections.allowToAnyIpv4(ec2.Port.tcp(443)); // THEN - expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: 'sg-123456789', - })); + }); }); test('backup retention period respected', () => { @@ -538,9 +536,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { BackupRetentionPeriod: 20, - })); + }); }); test('backup maintenance window respected', () => { @@ -562,10 +560,10 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { BackupRetentionPeriod: 20, PreferredBackupWindow: '07:34-08:04', - })); + }); }); test('regular maintenance window respected', () => { @@ -584,9 +582,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { PreferredMaintenanceWindow: '07:34-08:04', - })); + }); }); test('can configure CloudWatchLogs for audit', () => { @@ -605,9 +603,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { EnableCloudwatchLogsExports: ['audit'], - })); + }); }); test('can configure CloudWatchLogs for profiler', () => { @@ -626,9 +624,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { EnableCloudwatchLogsExports: ['profiler'], - })); + }); }); test('can configure CloudWatchLogs for all logs', () => { @@ -648,9 +646,9 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { EnableCloudwatchLogsExports: ['audit', 'profiler'], - })); + }); }); test('can set CloudWatch log retention', () => { @@ -671,7 +669,7 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('Custom::LogRetention', { + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { ServiceToken: { 'Fn::GetAtt': [ 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', @@ -680,8 +678,8 @@ describe('DatabaseCluster', () => { }, LogGroupName: { 'Fn::Join': ['', ['/aws/docdb/', { Ref: 'DatabaseB269D8BB' }, '/audit']] }, RetentionInDays: 90, - })); - expectCDK(stack).to(haveResource('Custom::LogRetention', { + }); + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { ServiceToken: { 'Fn::GetAtt': [ 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', @@ -690,7 +688,7 @@ describe('DatabaseCluster', () => { }, LogGroupName: { 'Fn::Join': ['', ['/aws/docdb/', { Ref: 'DatabaseB269D8BB' }, '/profiler']] }, RetentionInDays: 90, - })); + }); }); test('single user rotation', () => { @@ -709,7 +707,7 @@ describe('DatabaseCluster', () => { cluster.addRotationSingleUser(cdk.Duration.days(5)); // THEN - expectCDK(stack).to(haveResource('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Location: { ApplicationId: { 'Fn::FindInMap': ['DatabaseRotationSingleUserSARMapping9AEB3E55', { Ref: 'AWS::Partition' }, 'applicationId'] }, SemanticVersion: { 'Fn::FindInMap': ['DatabaseRotationSingleUserSARMapping9AEB3E55', { Ref: 'AWS::Partition' }, 'semanticVersion'] }, @@ -742,8 +740,8 @@ describe('DatabaseCluster', () => { 'Fn::GetAtt': ['DatabaseRotationSingleUserSecurityGroupAC6E0E73', 'GroupId'], }, }, - })); - expectCDK(stack).to(haveResource('AWS::SecretsManager::RotationSchedule', { + }); + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'DatabaseSecretAttachmentE5D1B020' }, RotationLambdaARN: { 'Fn::GetAtt': ['DatabaseRotationSingleUser65F55654', 'Outputs.RotationLambdaARN'], @@ -751,7 +749,7 @@ describe('DatabaseCluster', () => { RotationRules: { AutomaticallyAfterDays: 5, }, - })); + }); }); test('single user rotation requires secret', () => { @@ -822,7 +820,7 @@ describe('DatabaseCluster', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Location: { ApplicationId: { 'Fn::FindInMap': ['DatabaseRotationSARMappingE46CFA92', { Ref: 'AWS::Partition' }, 'applicationId'] }, SemanticVersion: { 'Fn::FindInMap': ['DatabaseRotationSARMappingE46CFA92', { Ref: 'AWS::Partition' }, 'semanticVersion'] }, @@ -856,8 +854,8 @@ describe('DatabaseCluster', () => { }, masterSecretArn: { Ref: 'DatabaseSecretAttachmentE5D1B020' }, }, - })); - expectCDK(stack).to(haveResource('AWS::SecretsManager::RotationSchedule', { + }); + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'UserSecret0463E4F5' }, RotationLambdaARN: { 'Fn::GetAtt': ['DatabaseRotation6B6E1D86', 'Outputs.RotationLambdaARN'], @@ -865,7 +863,7 @@ describe('DatabaseCluster', () => { RotationRules: { AutomaticallyAfterDays: 5, }, - })); + }); }); test('multi user rotation requires secret', () => { @@ -916,9 +914,9 @@ describe('DatabaseCluster', () => { cluster.addSecurityGroups(securityGroup); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { - VpcSecurityGroupIds: arrayWith(stack.resolve(securityGroup.securityGroupId)), - })); + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBCluster', { + VpcSecurityGroupIds: Match.arrayWith([stack.resolve(securityGroup.securityGroupId)]), + }); }); }); diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts index f1382746db07d..d7e90af3e3e90 100644 --- a/packages/@aws-cdk/aws-docdb/test/instance.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -1,8 +1,7 @@ -import { expect as expectCDK, haveOutput, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; - import { DatabaseCluster, DatabaseInstance } from '../lib'; const CLUSTER_INSTANCE_TYPE = ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE); @@ -21,7 +20,7 @@ describe('DatabaseInstance', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Template.fromStack(stack).hasResource('AWS::DocDB::DBInstance', { Properties: { DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, DBInstanceClass: EXPECTED_SYNTH_INSTANCE_TYPE, @@ -29,7 +28,7 @@ describe('DatabaseInstance', () => { }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); + }); }); test.each([ @@ -48,7 +47,7 @@ describe('DatabaseInstance', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Template.fromStack(stack).hasResource('AWS::DocDB::DBInstance', { Properties: { DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, DBInstanceClass: EXPECTED_SYNTH_INSTANCE_TYPE, @@ -56,7 +55,7 @@ describe('DatabaseInstance', () => { }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); + }); }); test('check that the endpoint works', () => { @@ -75,9 +74,11 @@ describe('DatabaseInstance', () => { }); // THEN - expectCDK(stack).to(haveOutput({ - exportName, - outputValue: { + Template.fromStack(stack).hasOutput(exportName, { + Export: { + Name: exportName, + }, + Value: { 'Fn::Join': [ '', [ @@ -87,7 +88,7 @@ describe('DatabaseInstance', () => { ], ], }, - })); + }); }); test('check that instanceArn property works', () => { @@ -106,9 +107,11 @@ describe('DatabaseInstance', () => { }); // THEN - expectCDK(stack).to(haveOutput({ - exportName, - outputValue: { + Template.fromStack(stack).hasOutput(exportName, { + Export: { + Name: exportName, + }, + Value: { 'Fn::Join': [ '', [ @@ -119,7 +122,7 @@ describe('DatabaseInstance', () => { ], ], }, - })); + }); }); test('check importing works as expected', () => { @@ -147,9 +150,11 @@ describe('DatabaseInstance', () => { }); // THEN - expectCDK(stack).to(haveOutput({ - exportName: arnExportName, - outputValue: { + Template.fromStack(stack).hasOutput('ArnOutput', { + Export: { + Name: arnExportName, + }, + Value: { 'Fn::Join': [ '', [ @@ -159,11 +164,13 @@ describe('DatabaseInstance', () => { ], ], }, - })); - expectCDK(stack).to(haveOutput({ - exportName: endpointExportName, - outputValue: `${instanceEndpointAddress}:${port}`, - })); + }); + Template.fromStack(stack).hasOutput('EndpointOutput', { + Export: { + Name: endpointExportName, + }, + Value: `${instanceEndpointAddress}:${port}`, + }); }); }); @@ -191,4 +198,4 @@ class TestStack extends cdk.Stack { function testStack() { const stack = new TestStack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); return stack; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts b/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts index 66cf65e5ece60..03aaff0fb2e77 100644 --- a/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts @@ -1,9 +1,8 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; import { ClusterParameterGroup } from '../lib'; describe('ClusterParameterGroup', () => { - test('check that instantiation works', () => { // GIVEN const stack = new Stack(); @@ -18,14 +17,13 @@ describe('ClusterParameterGroup', () => { }); // THEN - expect(stack).to(haveResource('AWS::DocDB::DBClusterParameterGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBClusterParameterGroup', { Description: 'desc', Family: 'hello', Parameters: { key: 'value', }, - })); - + }); }); test('check automatically generated descriptions', () => { @@ -41,13 +39,12 @@ describe('ClusterParameterGroup', () => { }); // THEN - expect(stack).to(haveResource('AWS::DocDB::DBClusterParameterGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::DocDB::DBClusterParameterGroup', { Description: 'Cluster parameter group for hello', Family: 'hello', Parameters: { key: 'value', }, - })); - + }); }); }); diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 3c23858110111..146ec9cc2d741 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -79,19 +79,19 @@ }, "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", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.5.1", "jest": "^27.4.7", "sinon": "^9.2.4", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 3c125c1bc0061..448aa7119eee6 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -1,5 +1,4 @@ -import { arrayWith, ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as iam from '@aws-cdk/aws-iam'; import * as kinesis from '@aws-cdk/aws-kinesis'; @@ -84,20 +83,20 @@ describe('default properties', () => { test('hash key only', () => { new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [{ AttributeName: 'hashKey', AttributeType: 'S' }], KeySchema: [{ AttributeName: 'hashKey', KeyType: 'HASH' }], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.RETAIN }, ResourcePart.CompleteDefinition); + Template.fromStack(stack).hasResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.RETAIN }); }); test('removalPolicy is DESTROY', () => { new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, removalPolicy: RemovalPolicy.DESTROY }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.DELETE }, ResourcePart.CompleteDefinition); + Template.fromStack(stack).hasResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.DELETE }); }); @@ -107,7 +106,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, { AttributeName: 'sortKey', AttributeType: 'N' }, @@ -126,7 +125,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -146,7 +145,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -167,7 +166,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -188,7 +187,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -209,7 +208,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -234,7 +233,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -261,7 +260,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { KeySchema: [ { AttributeName: 'hashKey', KeyType: 'HASH' }, @@ -288,7 +287,7 @@ describe('default properties', () => { sortKey: TABLE_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { KeySchema: [ { AttributeName: 'hashKey', KeyType: 'HASH' }, @@ -313,8 +312,8 @@ describe('default properties', () => { // since the resource has not been used in a cross-environment manner, // so the name should not be filled - expect(stack).toHaveResourceLike('AWS::DynamoDB::Table', { - TableName: ABSENT, + Template.fromStack(stack).hasResource('AWS::DynamoDB::Table', { + TableName: Match.absent(), }); }); }); @@ -338,7 +337,7 @@ testDeprecated('when specifying every property', () => { }); Tags.of(table).add('Environment', 'Production'); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -377,7 +376,7 @@ test('when specifying sse with customer managed CMK', () => { }); Tags.of(table).add('Environment', 'Production'); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { 'SSESpecification': { 'KMSMasterKeyId': { 'Fn::GetAtt': [ @@ -403,7 +402,7 @@ test('when specifying only encryptionKey', () => { }); Tags.of(table).add('Environment', 'Production'); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { 'SSESpecification': { 'KMSMasterKeyId': { 'Fn::GetAtt': [ @@ -430,7 +429,7 @@ test('when specifying sse with customer managed CMK with encryptionKey provided }); Tags.of(table).add('Environment', 'Production'); - expect(stack).toHaveResource('AWS::DynamoDB::Table', { + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { 'SSESpecification': { 'KMSMasterKeyId': { 'Fn::GetAtt': [ @@ -514,15 +513,15 @@ testLegacyBehavior('if an encryption key is included, encrypt/decrypt permission }); const user = new iam.User(stack, 'MyUser'); table.grantReadWriteData(user); - expect(stack).toMatchTemplate({ - 'Resources': { - 'TableAKey07CC09EC': { - 'Type': 'AWS::KMS::Key', - 'Properties': { - 'KeyPolicy': { - 'Statement': [ + Template.fromStack(stack).templateMatches({ + Resources: { + TableAKey07CC09EC: { + Type: 'AWS::KMS::Key', + Properties: { + KeyPolicy: { + Statement: [ { - 'Action': [ + Action: [ 'kms:Create*', 'kms:Describe*', 'kms:Enable*', @@ -539,99 +538,99 @@ testLegacyBehavior('if an encryption key is included, encrypt/decrypt permission 'kms:TagResource', 'kms:UntagResource', ], - 'Effect': 'Allow', - 'Principal': { - 'AWS': { + Effect: 'Allow', + Principal: { + AWS: { 'Fn::Join': [ '', [ 'arn:', { - 'Ref': 'AWS::Partition', + Ref: 'AWS::Partition', }, ':iam::', { - 'Ref': 'AWS::AccountId', + Ref: 'AWS::AccountId', }, ':root', ], ], }, }, - 'Resource': '*', + Resource: '*', }, { - 'Action': [ + Action: [ 'kms:Decrypt', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*', ], - 'Effect': 'Allow', - 'Principal': { - 'AWS': { + Effect: 'Allow', + Principal: { + AWS: { 'Fn::GetAtt': [ 'MyUserDC45028B', 'Arn', ], }, }, - 'Resource': '*', + Resource: '*', }, ], - 'Version': '2012-10-17', + Version: '2012-10-17', }, - 'Description': 'Customer-managed key auto-created for encrypting DynamoDB table at Default/Table A', - 'EnableKeyRotation': true, + Description: 'Customer-managed key auto-created for encrypting DynamoDB table at Default/Table A', + EnableKeyRotation: true, }, - 'UpdateReplacePolicy': 'Retain', - 'DeletionPolicy': 'Retain', + UpdateReplacePolicy: 'Retain', + DeletionPolicy: 'Retain', }, - 'TableA3D7B5AFA': { - 'Type': 'AWS::DynamoDB::Table', - 'Properties': { - 'KeySchema': [ + TableA3D7B5AFA: { + Type: 'AWS::DynamoDB::Table', + Properties: { + KeySchema: [ { - 'AttributeName': 'hashKey', - 'KeyType': 'HASH', + AttributeName: 'hashKey', + KeyType: 'HASH', }, ], - 'AttributeDefinitions': [ + AttributeDefinitions: [ { - 'AttributeName': 'hashKey', - 'AttributeType': 'S', + AttributeName: 'hashKey', + AttributeType: 'S', }, ], - 'ProvisionedThroughput': { - 'ReadCapacityUnits': 5, - 'WriteCapacityUnits': 5, + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5, }, - 'SSESpecification': { - 'KMSMasterKeyId': { + SSESpecification: { + KMSMasterKeyId: { 'Fn::GetAtt': [ 'TableAKey07CC09EC', 'Arn', ], }, - 'SSEEnabled': true, - 'SSEType': 'KMS', + SSEEnabled: true, + SSEType: 'KMS', }, - 'TableName': 'MyTable', + TableName: 'MyTable', }, - 'UpdateReplacePolicy': 'Retain', - 'DeletionPolicy': 'Retain', + UpdateReplacePolicy: 'Retain', + DeletionPolicy: 'Retain', }, - 'MyUserDC45028B': { - 'Type': 'AWS::IAM::User', + MyUserDC45028B: { + Type: 'AWS::IAM::User', }, - 'MyUserDefaultPolicy7B897426': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - 'Action': [ + Action: [ 'dynamodb:BatchGetItem', 'dynamodb:GetRecords', 'dynamodb:GetShardIterator', @@ -644,8 +643,8 @@ testLegacyBehavior('if an encryption key is included, encrypt/decrypt permission 'dynamodb:UpdateItem', 'dynamodb:DeleteItem', ], - 'Effect': 'Allow', - 'Resource': [ + Effect: 'Allow', + Resource: [ { 'Fn::GetAtt': [ 'TableA3D7B5AFA', @@ -653,20 +652,20 @@ testLegacyBehavior('if an encryption key is included, encrypt/decrypt permission ], }, { - 'Ref': 'AWS::NoValue', + Ref: 'AWS::NoValue', }, ], }, { - 'Action': [ + Action: [ 'kms:Decrypt', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*', ], - 'Effect': 'Allow', - 'Resource': { + Effect: 'Allow', + Resource: { 'Fn::GetAtt': [ 'TableAKey07CC09EC', 'Arn', @@ -674,12 +673,12 @@ testLegacyBehavior('if an encryption key is included, encrypt/decrypt permission }, }, ], - 'Version': '2012-10-17', + Version: '2012-10-17', }, - 'PolicyName': 'MyUserDefaultPolicy7B897426', - 'Users': [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - 'Ref': 'MyUserDC45028B', + Ref: 'MyUserDC45028B', }, ], }, @@ -698,24 +697,24 @@ test('if an encryption key is included, encrypt/decrypt permissions are added to const user = new iam.User(stack, 'MyUser'); table.grantReadWriteData(user); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': [ + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([{ + Action: [ 'kms:Decrypt', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*', ], - 'Effect': 'Allow', - 'Resource': { + Effect: 'Allow', + Resource: { 'Fn::GetAtt': [ 'TableAKey07CC09EC', 'Arn', ], }, - }), + }]), }, }); }); @@ -728,7 +727,7 @@ test('when specifying PAY_PER_REQUEST billing mode', () => { partitionKey: TABLE_PARTITION_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { KeySchema: [ { AttributeName: 'hashKey', KeyType: 'HASH' }, @@ -891,7 +890,7 @@ test('when adding a global secondary index with hash key only', () => { writeCapacity: 1337, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -933,7 +932,7 @@ test('when adding a global secondary index with hash + range key', () => { writeCapacity: 1337, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -975,7 +974,7 @@ test('when adding a global secondary index with projection type KEYS_ONLY', () = projectionType: ProjectionType.KEYS_ONLY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1017,7 +1016,7 @@ test('when adding a global secondary index with projection type INCLUDE', () => writeCapacity: 1337, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1056,7 +1055,7 @@ test('when adding a global secondary index on a table with PAY_PER_REQUEST billi partitionKey: GSI_PARTITION_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1171,7 +1170,7 @@ test('when adding multiple global secondary indexes', () => { table.addGlobalSecondaryIndex(gsiGenerator.next().value); } - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1242,7 +1241,7 @@ test('when adding a global secondary index without specifying read and write cap partitionKey: GSI_PARTITION_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1277,7 +1276,7 @@ test('when adding a local secondary index with hash + range key', () => { sortKey: LSI_SORT_KEY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1312,7 +1311,7 @@ test('when adding a local secondary index with projection type KEYS_ONLY', () => projectionType: ProjectionType.KEYS_ONLY, }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1349,7 +1348,7 @@ test('when adding a local secondary index with projection type INCLUDE', () => { nonKeyAttributes: [lsiNonKeyAttributeGenerator.next().value, lsiNonKeyAttributeGenerator.next().value], }); - expect(stack).toHaveResource('AWS::DynamoDB::Table', + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { AttributeDefinitions: [ { AttributeName: 'hashKey', AttributeType: 'S' }, @@ -1426,13 +1425,13 @@ test('can enable Read AutoScaling', () => { table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); // THEN - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { MaxCapacity: 500, MinCapacity: 50, ScalableDimension: 'dynamodb:table:ReadCapacityUnits', ServiceNamespace: 'dynamodb', }); - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { PolicyType: 'TargetTrackingScaling', TargetTrackingScalingPolicyConfiguration: { PredefinedMetricSpecification: { PredefinedMetricType: 'DynamoDBReadCapacityUtilization' }, @@ -1450,13 +1449,13 @@ test('can enable Write AutoScaling', () => { table.autoScaleWriteCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); // THEN - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { MaxCapacity: 500, MinCapacity: 50, ScalableDimension: 'dynamodb:table:WriteCapacityUnits', ServiceNamespace: 'dynamodb', }); - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { PolicyType: 'TargetTrackingScaling', TargetTrackingScalingPolicyConfiguration: { PredefinedMetricSpecification: { PredefinedMetricType: 'DynamoDBWriteCapacityUtilization' }, @@ -1537,7 +1536,7 @@ test('can autoscale on a schedule', () => { }); // THEN - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { ScheduledActions: [ { ScalableTargetAction: { 'MaxCapacity': 10 }, @@ -1806,7 +1805,7 @@ describe('grants', () => { table.grant(user, 'dynamodb:action1', 'dynamodb:action2'); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -1874,7 +1873,7 @@ describe('grants', () => { Table.grantListStreams(user); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -1920,7 +1919,7 @@ describe('grants', () => { table.grantTableListStreams(user); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -1966,7 +1965,7 @@ describe('grants', () => { table.grantStreamRead(user); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -2007,7 +2006,7 @@ describe('grants', () => { table.grantReadData(user); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -2066,7 +2065,7 @@ describe('grants', () => { table.grant(user, 'dynamodb:*'); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2159,7 +2158,7 @@ describe('import', () => { table.grantReadData(role); // it is possible to obtain a permission statement for a ref - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -2201,7 +2200,7 @@ describe('import', () => { table.grantReadWriteData(role); // it is possible to obtain a permission statement for a ref - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -2284,7 +2283,7 @@ describe('import', () => { expect(table.grantTableListStreams(role)).toBeDefined(); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2312,7 +2311,7 @@ describe('import', () => { expect(table.grantStreamRead(role)).toBeDefined(); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2347,7 +2346,7 @@ describe('import', () => { table.grantReadData(role); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2410,7 +2409,7 @@ describe('global', () => { }); // THEN - expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Template.fromStack(stack).hasResource('Custom::DynamoDBReplica', { Properties: { TableName: { Ref: 'TableCD117FA1', @@ -2418,9 +2417,9 @@ describe('global', () => { Region: 'eu-west-2', }, Condition: 'TableStackRegionNotEqualseuwest2A03859E7', - }, ResourcePart.CompleteDefinition); + }); - expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Template.fromStack(stack).hasResource('Custom::DynamoDBReplica', { Properties: { TableName: { Ref: 'TableCD117FA1', @@ -2428,19 +2427,18 @@ describe('global', () => { Region: 'eu-central-1', }, Condition: 'TableStackRegionNotEqualseucentral199D46FC0', - }, ResourcePart.CompleteDefinition); + }); - expect(SynthUtils.toCloudFormation(stack).Conditions).toEqual({ - TableStackRegionNotEqualseuwest2A03859E7: { - 'Fn::Not': [ - { 'Fn::Equals': ['eu-west-2', { Ref: 'AWS::Region' }] }, - ], - }, - TableStackRegionNotEqualseucentral199D46FC0: { - 'Fn::Not': [ - { 'Fn::Equals': ['eu-central-1', { Ref: 'AWS::Region' }] }, - ], - }, + Template.fromStack(stack).hasCondition('TableStackRegionNotEqualseuwest2A03859E7', { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-west-2', { Ref: 'AWS::Region' }] }, + ], + }); + + Template.fromStack(stack).hasCondition('TableStackRegionNotEqualseucentral199D46FC0', { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-central-1', { Ref: 'AWS::Region' }] }, + ], }); }); @@ -2462,7 +2460,7 @@ describe('global', () => { }); // THEN - expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Template.fromStack(stack).hasResource('Custom::DynamoDBReplica', { Properties: { TableName: { Ref: 'TableCD117FA1', @@ -2471,9 +2469,9 @@ describe('global', () => { SkipReplicationCompletedWait: 'true', }, Condition: 'TableStackRegionNotEqualseuwest2A03859E7', - }, ResourcePart.CompleteDefinition); + }); - expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Template.fromStack(stack).hasResource('Custom::DynamoDBReplica', { Properties: { TableName: { Ref: 'TableCD117FA1', @@ -2482,19 +2480,18 @@ describe('global', () => { SkipReplicationCompletedWait: 'true', }, Condition: 'TableStackRegionNotEqualseucentral199D46FC0', - }, ResourcePart.CompleteDefinition); + }); - expect(SynthUtils.toCloudFormation(stack).Conditions).toEqual({ - TableStackRegionNotEqualseuwest2A03859E7: { - 'Fn::Not': [ - { 'Fn::Equals': ['eu-west-2', { Ref: 'AWS::Region' }] }, - ], - }, - TableStackRegionNotEqualseucentral199D46FC0: { - 'Fn::Not': [ - { 'Fn::Equals': ['eu-central-1', { Ref: 'AWS::Region' }] }, - ], - }, + Template.fromStack(stack).hasCondition('TableStackRegionNotEqualseuwest2A03859E7', { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-west-2', { Ref: 'AWS::Region' }] }, + ], + }); + + Template.fromStack(stack).hasCondition('TableStackRegionNotEqualseucentral199D46FC0', { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-central-1', { Ref: 'AWS::Region' }] }, + ], }); }); @@ -2523,7 +2520,7 @@ describe('global', () => { table.grantReadData(user); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2677,7 +2674,7 @@ describe('global', () => { table.grantReadData(user); // THEN - expect(stack2).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack2).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2822,7 +2819,7 @@ describe('global', () => { table.grantTableListStreams(user); // THEN - expect(stack2).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack2).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -2855,7 +2852,7 @@ describe('global', () => { // THEN expect(() => { - SynthUtils.synthesize(stack); + Template.fromStack(stack); }).toThrow(/A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity/); }); @@ -2882,7 +2879,7 @@ describe('global', () => { // THEN expect(() => { - SynthUtils.synthesize(stack); + Template.fromStack(stack); }).toThrow(/A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity with a policy/); }); @@ -2907,8 +2904,8 @@ describe('global', () => { maxCapacity: 10, }).scaleOnUtilization({ targetUtilizationPercent: 75 }); - expect(stack).toHaveResourceLike('AWS::DynamoDB::Table', { - BillingMode: ABSENT, // PROVISIONED is the default + Template.fromStack(stack).hasResource('AWS::DynamoDB::Table', { + BillingMode: Match.absent(), // PROVISIONED is the default }); }); @@ -2971,7 +2968,8 @@ describe('global', () => { }); // THEN - expect(SynthUtils.toCloudFormation(stack).Conditions).toBeUndefined(); + const conditions = Template.fromStack(stack).findConditions('*'); + expect(Object.keys(conditions).length).toEqual(0); }); test('can configure timeout', () => { @@ -3014,7 +3012,7 @@ test('L1 inside L2 expects removalpolicy to have been set', () => { new FakeTableL2(stack, 'Table'); expect(() => { - SynthUtils.toCloudFormation(stack); + Template.fromStack(stack); }).toThrow(/is a stateful resource type/); }); @@ -3029,7 +3027,7 @@ function testGrant(expectedActions: string[], invocation: (user: iam.IPrincipal, // THEN const action = expectedActions.length > 1 ? expectedActions.map(a => `dynamodb:${a}`) : `dynamodb:${expectedActions[0]}`; - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts index 1f454f9d63f65..e8b37bb10d15f 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts @@ -574,7 +574,7 @@ export class InterfaceVpcEndpoint extends VpcEndpoint implements IInterfaceVpcEn const subnets = subnetSelection.subnets; // Sanity check the subnet count - if (subnetSelection.subnets.length == 0) { + if (!subnetSelection.isPendingLookup && subnetSelection.subnets.length == 0) { throw new Error('Cannot create a VPC Endpoint with no subnets'); } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index a9033ef8da94d..05914a6d35e92 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -351,6 +351,17 @@ export interface SelectedSubnets { * Whether any of the given subnets are from the VPC's public subnets. */ readonly hasPublic: boolean; + + /** + * The subnet selection is not actually real yet + * + * If this value is true, don't validate anything about the subnets. The count + * or identities are not known yet, and the validation will most likely fail + * which will prevent a successful lookup. + * + * @default false + */ + readonly isPendingLookup?: boolean; } /** @@ -430,6 +441,7 @@ abstract class VpcBase extends Resource implements IVpc { internetConnectivityEstablished: tap(new CompositeDependable(), d => subnets.forEach(s => d.add(s.internetConnectivityEstablished))), subnets, hasPublic: subnets.some(s => pubs.has(s)), + isPendingLookup: this.incompleteSubnetDefinition, }; } diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index eb8c9cac4c78c..5d51459d3b4d2 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -79,14 +79,14 @@ }, "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", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "jest": "^27.4.7" }, 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 189244bc251f5..297de07f16005 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 @@ -1,9 +1,4 @@ -import { - countResources, - expect as expectCDK, - haveResourceLike, -} from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; @@ -70,19 +65,19 @@ describe('RequireImdsv2Aspect', () => { // THEN const launchTemplate = instance.node.tryFindChild('LaunchTemplate') as LaunchTemplate; expect(launchTemplate).toBeDefined(); - expectCDK(stack).to(haveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateName: stack.resolve(launchTemplate.launchTemplateName), LaunchTemplateData: { MetadataOptions: { HttpTokens: 'required', }, }, - })); - expectCDK(stack).to(haveResourceLike('AWS::EC2::Instance', { + }); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { LaunchTemplate: { LaunchTemplateName: stack.resolve(launchTemplate.launchTemplateName), }, - })); + }); }); test('does not toggle when Instance has a LaunchTemplate', () => { @@ -104,7 +99,7 @@ describe('RequireImdsv2Aspect', () => { // THEN // Aspect normally creates a LaunchTemplate for the Instance to toggle IMDSv1, // so we can assert that one was not created - expectCDK(stack).to(countResources('AWS::EC2::LaunchTemplate', 0)); + Template.fromStack(stack).resourceCountIs('AWS::EC2::LaunchTemplate', 0); expect(instance.node.metadataEntry).toContainEqual({ data: expect.stringContaining('Cannot toggle IMDSv1 because this Instance is associated with an existing Launch Template.'), type: 'aws:cdk:warning', @@ -238,13 +233,13 @@ describe('RequireImdsv2Aspect', () => { cdk.Aspects.of(stack).add(aspect); // THEN - expectCDK(stack).to(haveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { MetadataOptions: { HttpTokens: 'required', }, }, - })); + }); }); }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts index 38570e3306f8a..b60248a948bad 100644 --- a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { Duration, Stack } from '@aws-cdk/core'; import { BastionHostLinux, BlockDeviceVolume, CloudFormationInit, InitCommand, InstanceClass, InstanceSize, InstanceType, SubnetType, Vpc } from '../lib'; @@ -15,7 +14,7 @@ describe('bastion host', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { InstanceType: 't3.nano', SubnetId: { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, }); @@ -40,7 +39,7 @@ describe('bastion host', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { InstanceType: 't3.nano', SubnetId: { Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6' }, }); @@ -71,7 +70,7 @@ describe('bastion host', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { BlockDeviceMappings: [ { DeviceName: 'EBSBastionHost', @@ -96,7 +95,7 @@ describe('bastion host', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { ImageId: { Ref: 'SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter', }, @@ -116,7 +115,7 @@ describe('bastion host', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { ImageId: { Ref: 'SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmarm64gp2C96584B6F00A464EAD1953AFF4B05118Parameter', }, @@ -142,7 +141,7 @@ describe('bastion host', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Instance', { + Template.fromStack(stack).hasResource('AWS::EC2::Instance', { CreationPolicy: { ResourceSignal: { Timeout: 'PT30M', @@ -159,6 +158,6 @@ describe('bastion host', () => { }, }, }, - }, ResourcePart.CompleteDefinition); + }); }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts index 2a9cce5e76719..919a3a8c07baa 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts @@ -1,13 +1,13 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { arrayWith, ResourcePart, stringLike } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { Asset } from '@aws-cdk/aws-s3-assets'; import { AssetStaging, App, Aws, CfnResource, Stack, DefaultStackSynthesizer, IStackSynthesizer, FileAssetSource, FileAssetLocation } from '@aws-cdk/core'; import * as ec2 from '../lib'; +import { stringLike } from './util'; let app: App; let stack: Stack; @@ -305,7 +305,7 @@ const ASSET_STATEMENT = { 'arn:', { Ref: 'AWS::Partition' }, ':s3:::', - { Ref: stringLike('AssetParameter*S3Bucket*') }, + { Ref: stringLike(/AssetParameter.*S3Bucket.*/) }, ]], }, { @@ -313,7 +313,7 @@ const ASSET_STATEMENT = { 'arn:', { Ref: 'AWS::Partition' }, ':s3:::', - { Ref: stringLike('AssetParameter*S3Bucket*') }, + { Ref: stringLike(/AssetParameter.*S3Bucket.*/) }, '/*', ]], }, @@ -338,9 +338,9 @@ describe('assets n buckets', () => { init.attach(resource, linuxOptions()); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith(ASSET_STATEMENT), + Statement: Match.arrayWith([ASSET_STATEMENT]), Version: '2012-10-17', }, }); @@ -354,10 +354,10 @@ describe('assets n buckets', () => { 'https://s3.testregion.', { Ref: 'AWS::URLSuffix' }, '/', - { Ref: stringLike('AssetParameters*') }, + { Ref: stringLike(/AssetParameters.*/) }, '/', - { 'Fn::Select': [0, { 'Fn::Split': ['||', { Ref: stringLike('AssetParameters*') }] }] }, - { 'Fn::Select': [1, { 'Fn::Split': ['||', { Ref: stringLike('AssetParameters*') }] }] }, + { 'Fn::Select': [0, { 'Fn::Split': ['||', { Ref: stringLike(/AssetParameters.*/) }] }] }, + { 'Fn::Select': [1, { 'Fn::Split': ['||', { Ref: stringLike(/AssetParameters.*/) }] }] }, ]], }, }, @@ -369,7 +369,7 @@ describe('assets n buckets', () => { type: 'S3', roleName: { Ref: 'InstanceRole3CCE2F1D' }, buckets: [ - { Ref: stringLike('AssetParameters*S3Bucket*') }, + { Ref: stringLike(/AssetParameters.*S3Bucket.*/) }, ], }, }, @@ -392,9 +392,9 @@ describe('assets n buckets', () => { init.attach(resource, linuxOptions()); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith(ASSET_STATEMENT), + Statement: Match.arrayWith([ASSET_STATEMENT]), Version: '2012-10-17', }, }); @@ -407,10 +407,10 @@ describe('assets n buckets', () => { 'https://s3.testregion.', { Ref: 'AWS::URLSuffix' }, '/', - { Ref: stringLike('AssetParameters*') }, + { Ref: stringLike(/AssetParameters.*/) }, '/', - { 'Fn::Select': [0, { 'Fn::Split': ['||', { Ref: stringLike('AssetParameters*') }] }] }, - { 'Fn::Select': [1, { 'Fn::Split': ['||', { Ref: stringLike('AssetParameters*') }] }] }, + { 'Fn::Select': [0, { 'Fn::Split': ['||', { Ref: stringLike(/AssetParameters.*/) }] }] }, + { 'Fn::Select': [1, { 'Fn::Split': ['||', { Ref: stringLike(/AssetParameters.*/) }] }] }, ]], }, }, @@ -421,7 +421,7 @@ describe('assets n buckets', () => { type: 'S3', roleName: { Ref: 'InstanceRole3CCE2F1D' }, buckets: [ - { Ref: stringLike('AssetParameters*S3Bucket*') }, + { Ref: stringLike(/AssetParameters.*S3Bucket.*/) }, ], }, }, @@ -438,16 +438,16 @@ describe('assets n buckets', () => { init.attach(resource, linuxOptions()); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: ['s3:GetObject*', 's3:GetBucket*', 's3:List*'], Effect: 'Allow', Resource: [ { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket']] }, { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket/file.js']] }, ], - }), + }]), Version: '2012-10-17', }, }); @@ -481,16 +481,16 @@ describe('assets n buckets', () => { init.attach(resource, linuxOptions()); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: ['s3:GetObject*', 's3:GetBucket*', 's3:List*'], Effect: 'Allow', Resource: [ { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket']] }, { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket/file.zip']] }, ], - }), + }]), Version: '2012-10-17', }, }); @@ -528,9 +528,9 @@ describe('assets n buckets', () => { S3AccessCreds: { type: 'S3', roleName: { Ref: 'InstanceRole3CCE2F1D' }, - buckets: [ - { Ref: stringLike('AssetParameters*S3Bucket*') }, - ], + buckets: Match.arrayWith([ + { Ref: stringLike(/AssetParameters.*S3Bucket.*/) }, + ]), }, }, }); @@ -553,10 +553,10 @@ describe('assets n buckets', () => { S3AccessCreds: { type: 'S3', roleName: { Ref: 'InstanceRole3CCE2F1D' }, - buckets: arrayWith( - { Ref: stringLike('AssetParameters*S3Bucket*') }, + buckets: Match.arrayWith([ + { Ref: stringLike(/AssetParameters.*S3Bucket.*/) }, 'my-bucket', - ), + ]), }, }, }); @@ -632,9 +632,9 @@ function linuxOptions() { } function expectMetadataLike(pattern: any) { - expect(stack).toHaveResourceLike('CDK::Test::Resource', { + Template.fromStack(stack).hasResource('CDK::Test::Resource', { Metadata: pattern, - }, ResourcePart.CompleteDefinition); + }); } function expectLine(lines: string[], re: RegExp) { diff --git a/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts b/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts index 33ac16d355f15..45dc200f9c817 100644 --- a/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { App, Stack } from '@aws-cdk/core'; import { Connections, IClientVpnEndpoint } from '../lib'; @@ -29,7 +29,7 @@ describe('ClientVpnAuthorizationRule constructor', () => { cidr: '10.0.10.0/32', clientVpnEndpoint, }); - expect(stack).toCountResources('AWS::EC2::ClientVpnAuthorizationRule', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnAuthorizationRule', 1); expect(stack.node.children.length).toBe(1); }); test('either clientVpnEndoint (deprecated, typo) or clientVpnEndpoint is required', () => { @@ -97,7 +97,7 @@ describe('ClientVpnAuthorizationRule constructor', () => { cidr: '10.0.10.0/32', clientVpnEndoint, }); - expect(stack).toCountResources('AWS::EC2::ClientVpnAuthorizationRule', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnAuthorizationRule', 1); expect(stack.node.children.length).toBe(1); }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.test.ts b/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.test.ts index bd52982d76fd6..2bf2357f9c32f 100644 --- a/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.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 { SamlMetadataDocument, SamlProvider } from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import { Stack } from '@aws-cdk/core'; @@ -27,7 +26,7 @@ test('client vpn endpoint', () => { userBasedAuthentication: ClientVpnUserBasedAuthentication.federated(samlProvider), }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnEndpoint', { AuthenticationOptions: [ { MutualAuthentication: { @@ -73,9 +72,9 @@ test('client vpn endpoint', () => { }, }); - expect(stack).toCountResources('AWS::EC2::ClientVpnTargetNetworkAssociation', 2); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnTargetNetworkAssociation', 2); - expect(stack).toHaveResource('AWS::EC2::ClientVpnTargetNetworkAssociation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnTargetNetworkAssociation', { ClientVpnEndpointId: { Ref: 'VpcEndpoint6FF034F6', }, @@ -84,7 +83,7 @@ test('client vpn endpoint', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnTargetNetworkAssociation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnTargetNetworkAssociation', { ClientVpnEndpointId: { Ref: 'VpcEndpoint6FF034F6', }, @@ -93,9 +92,8 @@ test('client vpn endpoint', () => { }, }); - expect(stack).toHaveOutput({ - outputName: 'VpcEndpointSelfServicePortalUrl760AFE23', - outputValue: { + Template.fromStack(stack).hasOutput('VpcEndpointSelfServicePortalUrl760AFE23', { + Value: { 'Fn::Join': [ '', [ @@ -108,7 +106,7 @@ test('client vpn endpoint', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnAuthorizationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnAuthorizationRule', { ClientVpnEndpointId: { Ref: 'VpcEndpoint6FF034F6', }, @@ -133,7 +131,7 @@ test('client vpn endpoint with custom security groups', () => { ], }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnEndpoint', { SecurityGroupIds: [ { 'Fn::GetAtt': [ @@ -163,7 +161,7 @@ test('client vpn endpoint with custom logging', () => { logStream: logGroup.addStream('LogStream'), }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnEndpoint', { ConnectionLogOptions: { CloudwatchLogGroup: { Ref: 'LogGroupF5B46931', @@ -184,7 +182,7 @@ test('client vpn endpoint with logging disabled', () => { logging: false, }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnEndpoint', { ConnectionLogOptions: { Enabled: false, }, @@ -204,9 +202,9 @@ test('client vpn endpoint with custom authorization rules', () => { groupId: 'group-id', }); - expect(stack).toCountResources('AWS::EC2::ClientVpnAuthorizationRule', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnAuthorizationRule', 1); - expect(stack).toHaveResource('AWS::EC2::ClientVpnAuthorizationRule', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::ClientVpnAuthorizationRule', { ClientVpnEndpointId: { Ref: 'VpcEndpoint6FF034F6', }, @@ -229,7 +227,7 @@ test('client vpn endpoint with custom route', () => { target: ec2.ClientVpnRouteTarget.local(), }); - expect(stack).toHaveResource('AWS::EC2::ClientVpnRoute', { + Template.fromStack(stack).hasResource('AWS::EC2::ClientVpnRoute', { Properties: { ClientVpnEndpointId: { Ref: 'VpcEndpoint6FF034F6', @@ -241,7 +239,7 @@ test('client vpn endpoint with custom route', () => { 'VpcEndpointAssociation06B066321', 'VpcEndpointAssociation12B51A67F', ], - }, ResourcePart.CompleteDefinition); + }); }); test('throws with more than 2 dns servers', () => { diff --git a/packages/@aws-cdk/aws-ec2/test/client-vpn-route.test.ts b/packages/@aws-cdk/aws-ec2/test/client-vpn-route.test.ts index 5bb1ee9722139..213c10f0b438c 100644 --- a/packages/@aws-cdk/aws-ec2/test/client-vpn-route.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/client-vpn-route.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { SamlMetadataDocument, SamlProvider } from '@aws-cdk/aws-iam'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { App, Stack } from '@aws-cdk/core'; @@ -42,9 +42,9 @@ describe('ClientVpnRoute constructor', () => { cidr: '0.0.0.0/0', target: ClientVpnRouteTarget.local(), }); - expect(stack).toCountResources('AWS::EC2::VPC', 1); - expect(stack).toCountResources('AWS::EC2::ClientVpnEndpoint', 1); - expect(stack).toCountResources('AWS::EC2::ClientVpnRoute', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::VPC', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnEndpoint', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnRoute', 1); expect(stack.node.children.length).toBe(3); }); testDeprecated('either clientVpnEndoint (deprecated, typo) or clientVpnEndpoint is required', () => { @@ -96,7 +96,7 @@ describe('ClientVpnRoute constructor', () => { target: ClientVpnRouteTarget.local(), }); }).toThrow(); - expect(stack).toCountResources('AWS::EC2::VPC', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::VPC', 1); expect(stack.node.children.length).toBe(1); }); testDeprecated('supplying clientVpnEndoint (deprecated due to typo) should still work', () => { @@ -119,9 +119,9 @@ describe('ClientVpnRoute constructor', () => { cidr: '0.0.0.0/0', target: ClientVpnRouteTarget.local(), }); - expect(stack).toCountResources('AWS::EC2::VPC', 1); - expect(stack).toCountResources('AWS::EC2::ClientVpnEndpoint', 1); - expect(stack).toCountResources('AWS::EC2::ClientVpnRoute', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::VPC', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnEndpoint', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::ClientVpnRoute', 1); expect(stack.node.children.length).toBe(3); }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/connections.test.ts b/packages/@aws-cdk/aws-ec2/test/connections.test.ts index e5c48f2740f57..7853bebe58083 100644 --- a/packages/@aws-cdk/aws-ec2/test/connections.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/connections.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { App, Stack } from '@aws-cdk/core'; import { @@ -41,7 +41,7 @@ describe('connections', () => { somethingConnectable.connections.allowTo(securityGroup, Port.allTcp(), 'Connect there'); // THEN: rule to generated security group to connect to imported - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::GetAtt': ['SomeSecurityGroupEF219AD6', 'GroupId'] }, IpProtocol: 'tcp', Description: 'Connect there', @@ -51,7 +51,7 @@ describe('connections', () => { }); // THEN: rule to imported security group to allow connections from generated - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'Connect there', FromPort: 0, @@ -76,7 +76,7 @@ describe('connections', () => { connections.addSecurityGroup(sg2); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SecurityGroup1', SecurityGroupIngress: [ { @@ -89,7 +89,7 @@ describe('connections', () => { ], }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SecurityGroup2', SecurityGroupIngress: [ { @@ -121,14 +121,14 @@ describe('connections', () => { connections2.addSecurityGroup(sg3); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::GetAtt': ['SecurityGroup23BE86BB7', 'GroupId'] }, SourceSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, FromPort: 88, ToPort: 88, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::GetAtt': ['SecurityGroup3E5E374B9', 'GroupId'] }, SourceSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, FromPort: 88, @@ -151,14 +151,14 @@ describe('connections', () => { connections.addSecurityGroup(sg2); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, SourceSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, FromPort: 88, ToPort: 88, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { DestinationSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, GroupId: { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, FromPort: 88, @@ -186,12 +186,12 @@ describe('connections', () => { // THEN -- both rules are in Stack2 app.synth(); - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::GetAtt': ['SecurityGroupDD263621', 'GroupId'] }, SourceSecurityGroupId: { 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttSecurityGroupDD263621GroupIdDF6F8B09' }, }); - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttSecurityGroupDD263621GroupIdDF6F8B09' }, DestinationSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroupDD263621', 'GroupId'] }, }); @@ -217,12 +217,12 @@ describe('connections', () => { // THEN -- both rules are in Stack2 app.synth(); - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttSecurityGroupDD263621GroupIdDF6F8B09' }, SourceSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroupDD263621', 'GroupId'] }, }); - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::GetAtt': ['SecurityGroupDD263621', 'GroupId'] }, DestinationSecurityGroupId: { 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttSecurityGroupDD263621GroupIdDF6F8B09' }, }); @@ -250,12 +250,12 @@ describe('connections', () => { // THEN -- both egress rules are in Stack2 app.synth(); - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttSecurityGroupAED40ADC5GroupId1D10C76A' }, DestinationSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroupDD263621', 'GroupId'] }, }); - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttSecurityGroupB04591F90GroupIdFA7208D5' }, DestinationSecurityGroupId: { 'Fn::GetAtt': ['SecurityGroupDD263621', 'GroupId'] }, }); @@ -275,7 +275,7 @@ describe('connections', () => { somethingConnectable.connections.allowFrom(securityGroup, Port.allTcp(), 'Connect there'); // THEN: rule to generated security group to connect to imported - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::GetAtt': ['SomeSecurityGroupEF219AD6', 'GroupId'] }, IpProtocol: 'tcp', Description: 'Connect there', @@ -285,7 +285,7 @@ describe('connections', () => { }); // THEN: rule to imported security group to allow connections from generated - expect(stack).not.toHaveResource('AWS::EC2::SecurityGroupEgress'); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupEgress', 0); }); @@ -304,7 +304,7 @@ describe('connections', () => { somethingConnectable.connections.allowFrom(securityGroup, Port.allTcp(), 'Connect there'); // THEN: rule to generated security group to connect to imported - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: { 'Fn::GetAtt': ['SomeSecurityGroupEF219AD6', 'GroupId'] }, IpProtocol: 'tcp', Description: 'Connect there', @@ -314,7 +314,7 @@ describe('connections', () => { }); // THEN: rule to imported security group to allow connections from generated - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { IpProtocol: 'tcp', Description: 'Connect there', FromPort: 0, diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index afd3570466eee..e2d4e47e78fde 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -1,6 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert-internal/jest'; -import { arrayWith, ResourcePart, stringLike, SynthUtils } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import { Asset } from '@aws-cdk/aws-s3-assets'; import { StringParameter } from '@aws-cdk/aws-ssm'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; @@ -10,7 +9,6 @@ import { EbsDeviceVolumeType, InitCommand, Instance, InstanceArchitecture, InstanceClass, InstanceSize, InstanceType, LaunchTemplate, UserData, Vpc, } from '../lib'; - let stack: Stack; let vpc: Vpc; beforeEach(() => { @@ -19,34 +17,6 @@ beforeEach(() => { }); describe('instance', () => { - test('instance is created correctly', () => { - // GIVEN - const sampleInstances = [{ - instanceClass: InstanceClass.BURSTABLE4_GRAVITON, - instanceSize: InstanceSize.LARGE, - instanceType: 't4g.large', - }, { - instanceClass: InstanceClass.HIGH_COMPUTE_MEMORY1, - instanceSize: InstanceSize.XLARGE3, - instanceType: 'z1d.3xlarge', - }]; - - for (const [i, sampleInstance] of sampleInstances.entries()) { - // WHEN - new Instance(stack, `Instance${i}`, { - vpc, - machineImage: new AmazonLinuxImage(), - instanceType: InstanceType.of(sampleInstance.instanceClass, sampleInstance.instanceSize), - }); - - // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { - InstanceType: sampleInstance.instanceType, - }); - } - - - }); test('instance is created with source/dest check switched off', () => { // WHEN new Instance(stack, 'Instance', { @@ -57,7 +27,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { InstanceType: 't3.large', SourceDestCheck: false, }); @@ -77,7 +47,7 @@ describe('instance', () => { param.grantRead(instance); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -207,7 +177,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { PropagateTagsToVolumeOnCreation: true, }); }); @@ -242,7 +212,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { BlockDeviceMappings: [ { DeviceName: 'ebs', @@ -368,7 +338,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { InstanceType: 't3.large', PrivateIpAddress: '10.0.0.2', }); @@ -386,12 +356,12 @@ describe('instance', () => { }); // Force stack synth so the InstanceRequireImdsv2Aspect is applied - SynthUtils.synthesize(stack); + Template.fromStack(stack); // THEN const launchTemplate = instance.node.tryFindChild('LaunchTemplate') as LaunchTemplate; expect(launchTemplate).toBeDefined(); - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateName: stack.resolve(launchTemplate.launchTemplateName), LaunchTemplateData: { MetadataOptions: { @@ -399,7 +369,7 @@ describe('instance', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { LaunchTemplate: { LaunchTemplateName: stack.resolve(launchTemplate.launchTemplateName), }, @@ -407,7 +377,6 @@ describe('instance', () => { }); }); - test('add CloudFormation Init to instance', () => { // GIVEN new Instance(stack, 'Instance', { @@ -420,11 +389,11 @@ test('add CloudFormation Init to instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { UserData: { 'Fn::Base64': { 'Fn::Join': ['', [ - stringLike('#!/bin/bash\n# fingerprint: *\n(\n set +e\n /opt/aws/bin/cfn-init -v --region '), + '#!/bin/bash\n# fingerprint: 85ac432b1de1144f\n(\n set +e\n /opt/aws/bin/cfn-init -v --region ', { Ref: 'AWS::Region' }, ' --stack ', { Ref: 'AWS::StackName' }, @@ -437,24 +406,24 @@ test('add CloudFormation Init to instance', () => { }, }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: ['cloudformation:DescribeStackResource', 'cloudformation:SignalResource'], Effect: 'Allow', Resource: { Ref: 'AWS::StackId' }, - }), + }]), Version: '2012-10-17', }, }); - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResource('AWS::EC2::Instance', { CreationPolicy: { ResourceSignal: { Count: 1, Timeout: 'PT5M', }, }, - }, ResourcePart.CompleteDefinition); + }); }); test('cause replacement from s3 asset in userdata', () => { @@ -491,10 +460,10 @@ test('cause replacement from s3 asset in userdata', () => { // on the actual asset hash and not accidentally on the token stringification of them. // (which would base the hash on '${Token[1234.bla]}' const hash = 'f88eace39faf39d7'; - expect(SynthUtils.toCloudFormation(stack)).toEqual(expect.objectContaining({ - Resources: expect.objectContaining({ - [`InstanceOne5B821005${hash}`]: expect.objectContaining({ Type: 'AWS::EC2::Instance', Properties: expect.anything() }), - [`InstanceTwoDC29A7A7${hash}`]: expect.objectContaining({ Type: 'AWS::EC2::Instance', Properties: expect.anything() }), + Template.fromStack(stack).templateMatches(Match.objectLike({ + Resources: Match.objectLike({ + [`InstanceOne5B821005${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }), + [`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }), }), })); }); diff --git a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts index 6196a60541a12..499368608e7a6 100644 --- a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts @@ -1,7 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { - stringLike, -} from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { CfnInstanceProfile, Role, @@ -32,6 +29,7 @@ import { WindowsImage, WindowsVersion, } from '../lib'; +import { stringLike } from './util'; /* eslint-disable jest/expect-expect */ @@ -52,7 +50,7 @@ describe('LaunchTemplate', () => { // Note: The following is intentionally a haveResource instead of haveResourceLike // to ensure that only the bare minimum of properties have values when no properties // are given to a LaunchTemplate. - expect(stack).toHaveResource('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { TagSpecifications: [ { @@ -76,7 +74,7 @@ describe('LaunchTemplate', () => { ], }, }); - expect(stack).not.toHaveResource('AWS::IAM::InstanceProfile'); + Template.fromStack(stack).resourceCountIs('AWS::IAM::InstanceProfile', 0); expect(() => { template.grantPrincipal; }).toThrow(); expect(() => { template.connections; }).toThrow(); expect(template.osType).toBeUndefined(); @@ -127,7 +125,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateName: 'LTName', }); }); @@ -139,7 +137,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceType: 'tt.test', }, @@ -153,10 +151,10 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { ImageId: { - Ref: stringLike('SsmParameterValueawsserviceamiamazonlinuxlatestamznami*Parameter'), + Ref: stringLike('SsmParameterValueawsserviceamiamazonlinuxlatestamznami.*Parameter'), }, }, }); @@ -171,10 +169,10 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { ImageId: { - Ref: stringLike('SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishFullBase*Parameter'), + Ref: stringLike('SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishFullBase.*Parameter'), }, }, }); @@ -193,7 +191,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { UserData: { 'Fn::Base64': '#!/bin/bash\necho Test', @@ -215,15 +213,15 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toCountResources('AWS::IAM::Role', 1); - expect(stack).toHaveResourceLike('AWS::IAM::InstanceProfile', { + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 1); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::InstanceProfile', { Roles: [ { Ref: 'TestRole6C9272DF', }, ], }); - expect(stack).toHaveResource('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { IamInstanceProfile: { Arn: stack.resolve((template.node.findChild('Profile') as CfnInstanceProfile).getAtt('Arn')), @@ -286,7 +284,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { BlockDeviceMappings: [ { @@ -328,7 +326,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { CreditSpecification: { CpuCredits: expected, @@ -347,7 +345,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { DisableApiTermination: expected, }, @@ -364,7 +362,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { EbsOptimized: expected, }, @@ -381,7 +379,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { EnclaveOptions: { Enabled: expected, @@ -400,7 +398,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceInitiatedShutdownBehavior: expected, }, @@ -414,7 +412,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { KeyName: 'TestKeyname', }, @@ -431,7 +429,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { Monitoring: { Enabled: expected, @@ -451,7 +449,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { SecurityGroupIds: [ { @@ -476,7 +474,7 @@ describe('LaunchTemplate', () => { Tags.of(template).add('TestKey', 'TestValue'); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { TagSpecifications: [ { @@ -517,7 +515,7 @@ describe('LaunchTemplate', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { MetadataOptions: { HttpTokens: 'required', @@ -543,7 +541,7 @@ describe('LaunchTemplate marketOptions', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceMarketOptions: { MarketType: 'spot', @@ -589,7 +587,7 @@ describe('LaunchTemplate marketOptions', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceMarketOptions: { MarketType: 'spot', @@ -614,7 +612,7 @@ describe('LaunchTemplate marketOptions', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceMarketOptions: { MarketType: 'spot', @@ -639,7 +637,7 @@ describe('LaunchTemplate marketOptions', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceMarketOptions: { MarketType: 'spot', @@ -663,7 +661,7 @@ describe('LaunchTemplate marketOptions', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceMarketOptions: { MarketType: 'spot', @@ -684,7 +682,7 @@ describe('LaunchTemplate marketOptions', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::LaunchTemplate', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { InstanceMarketOptions: { MarketType: 'spot', diff --git a/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts b/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts index 39263075fdb21..bb6b86921101a 100644 --- a/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts @@ -1,4 +1,4 @@ -import { expect as cdkExpect, matchTemplate, MatchStyle } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { App, Stack } from '@aws-cdk/core'; import * as ec2 from '../lib'; @@ -44,7 +44,7 @@ test('can make and use a Linux image in agnostic stack', () => { }, }; - cdkExpect(stack).to(matchTemplate(expected, MatchStyle.EXACT)); + Template.fromStack(stack).templateMatches(expected); expect(stack.resolve(details.imageId)).toEqual({ 'Fn::FindInMap': ['AmiMap', { Ref: 'AWS::Region' }, 'ami'] }); expect(details.osType).toEqual(ec2.OperatingSystemType.LINUX); }); @@ -81,7 +81,7 @@ test('can make and use a Windows image in agnostic stack', () => { }, }; - cdkExpect(stack).to(matchTemplate(expected, MatchStyle.EXACT)); + Template.fromStack(stack).templateMatches(expected); expect(stack.resolve(details.imageId)).toEqual({ 'Fn::FindInMap': ['AmiMap', { Ref: 'AWS::Region' }, 'ami'] }); expect(details.osType).toEqual(ec2.OperatingSystemType.WINDOWS); }); @@ -270,4 +270,4 @@ function isWindowsUserData(ud: ec2.UserData) { function isLinuxUserData(ud: ec2.UserData) { return ud.render().indexOf('bash') > -1; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/test/security-group.test.ts b/packages/@aws-cdk/aws-ec2/test/security-group.test.ts index f4bdd13556457..4624d2a648b72 100644 --- a/packages/@aws-cdk/aws-ec2/test/security-group.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/security-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { App, Intrinsic, Lazy, Stack, Token } from '@aws-cdk/core'; import { Peer, Port, SecurityGroup, SecurityGroupProps, Vpc } from '../lib'; @@ -15,7 +15,7 @@ describe('security group', () => { new SecurityGroup(stack, 'SG1', { vpc, allowAllOutbound: true }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -38,7 +38,7 @@ describe('security group', () => { sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'This does not show up'); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -60,7 +60,7 @@ describe('security group', () => { new SecurityGroup(stack, 'SG1', { vpc, allowAllOutbound: false }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '255.255.255.255/32', @@ -85,7 +85,7 @@ describe('security group', () => { sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'This replaces the other one'); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -123,7 +123,7 @@ describe('security group', () => { sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'This rule was not added'); sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'This rule was not added'); - expect(stack).not.toHaveResource('AWS::EC2::SecurityGroup', { + const openEgressRules = Template.fromStack(stack).findResources('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -134,8 +134,9 @@ describe('security group', () => { }, ], }); + expect(Object.keys(openEgressRules).length).toBe(0); - expect(stack).not.toHaveResource('AWS::EC2::SecurityGroup', { + const openIngressRules = Template.fromStack(stack).findResources('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ { CidrIp: '0.0.0.0/0', @@ -146,8 +147,7 @@ describe('security group', () => { }, ], }); - - + expect(Object.keys(openIngressRules).length).toBe(0); }); describe('Inline Rule Control', () => { @@ -226,10 +226,10 @@ describe('security group', () => { sg.addIngressRule(peer2, Port.tcp(5432), 'Rule 2'); // THEN -- no crash - expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { Description: 'Rule 1', }); - expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { Description: 'Rule 2', }); }); @@ -402,7 +402,7 @@ describe('security group', () => { sg.addIngressRule(Peer.securityGroupId('sg-123456789'), Port.allTcp(), 'no owner id property'); //THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [{ SourceSecurityGroupId: 'sg-123456789', Description: 'no owner id property', @@ -423,7 +423,7 @@ describe('security group', () => { sg.addIngressRule(Peer.securityGroupId('sg-123456789', '000000000000'), Port.allTcp(), 'contains owner id property'); //THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [{ SourceSecurityGroupId: 'sg-123456789', SourceSecurityGroupOwnerId: '000000000000', @@ -445,7 +445,7 @@ describe('security group', () => { sg.addEgressRule(Peer.securityGroupId('sg-123456789', '000000000000'), Port.allTcp(), 'no owner id property'); //THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [{ DestinationSecurityGroupId: 'sg-123456789', Description: 'no owner id property', @@ -611,7 +611,7 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu // WHEN new SecurityGroup(stack, 'SG1', props); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), SecurityGroupEgress: [ @@ -622,8 +622,8 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu }, ], }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupEgress', {}); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupEgress', 0); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -638,7 +638,7 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu const sg = new SecurityGroup(stack, 'SG1', props); sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), SecurityGroupEgress: [ @@ -650,8 +650,8 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu ], }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupEgress', {}); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupEgress', 0); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -666,7 +666,7 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu const sg = new SecurityGroup(stack, 'SG1', props); sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), SecurityGroupIngress: [ @@ -701,7 +701,7 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu // WHEN new SecurityGroup(stack, 'SG1', props); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), SecurityGroupEgress: [ @@ -714,8 +714,8 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu }, ], }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -730,7 +730,7 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu const sg = new SecurityGroup(stack, 'SG1', props); sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An inline Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), SecurityGroupEgress: [ @@ -744,8 +744,8 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu ], }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupEgress', {}); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupEgress', 0); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -760,7 +760,7 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu const sg = new SecurityGroup(stack, 'SG1', props); sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), SecurityGroupIngress: [ @@ -783,8 +783,8 @@ function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | nu ], }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupEgress', {}); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupEgress', 0); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); }); @@ -805,17 +805,17 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | // WHEN const sg = new SecurityGroup(stack, 'SG1', props); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '0.0.0.0/0', Description: 'Allow all outbound traffic by default', IpProtocol: '-1', }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -830,19 +830,19 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | const sg = new SecurityGroup(stack, 'SG1', props); sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '0.0.0.0/0', Description: 'Allow all outbound traffic by default', IpProtocol: '-1', }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -857,18 +857,18 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | const sg = new SecurityGroup(stack, 'SG1', props); sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).not.toHaveResource('AWS::EC2::SecurityGroupEgress', { + const egressGroups = Template.fromStack(stack).findResources('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), Description: 'An external Rule', }); + expect(Object.keys(egressGroups).length).toBe(0); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); - + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); test('addIngressRule rule will add a new external ingress rule even if it could have been inlined', () => { @@ -882,12 +882,12 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | const sg = new SecurityGroup(stack, 'SG1', props); sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '0.0.0.0/0', Description: 'An external Rule', @@ -896,7 +896,7 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | ToPort: 86, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '0.0.0.0/0', Description: 'Allow all outbound traffic by default', @@ -917,12 +917,12 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | // WHEN const sg = new SecurityGroup(stack, 'SG1', props); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '255.255.255.255/32', Description: 'Disallow all traffic', @@ -944,16 +944,16 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | const sg = new SecurityGroup(stack, 'SG1', props); sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); + const egressGroups = Template.fromStack(stack).findResources('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '255.255.255.255/32', }); - + expect(Object.keys(egressGroups).length).toBe(0); }); test('addEgressRule rule will add a new external egress rule even if it could have been inlined', () => { @@ -967,12 +967,12 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | const sg = new SecurityGroup(stack, 'SG1', props); sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '0.0.0.0/0', Description: 'An external Rule', @@ -981,7 +981,7 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | ToPort: 86, }); - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroupIngress', {}); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SecurityGroupIngress', 0); }); @@ -996,12 +996,12 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | const sg = new SecurityGroup(stack, 'SG1', props); sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SG1', VpcId: stack.resolve(vpc.vpcId), }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '0.0.0.0/0', Description: 'An external Rule', @@ -1010,7 +1010,7 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | ToPort: 86, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: stack.resolve(sg.securityGroupId), CidrIp: '255.255.255.255/32', Description: 'Disallow all traffic', @@ -1022,4 +1022,4 @@ function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | }); }); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/test/util.ts b/packages/@aws-cdk/aws-ec2/test/util.ts new file mode 100644 index 0000000000000..9eabad6658a2a --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/util.ts @@ -0,0 +1,20 @@ +import { Matcher, MatchResult } from '@aws-cdk/assertions'; + +export function stringLike(pattern: string | RegExp): Matcher { + return new RegexMatcher(new RegExp(pattern)); +} + +export class RegexMatcher extends Matcher { + constructor(private readonly pattern: RegExp, public readonly name: string = 'RegexMatch') { super(); } + public test(actual: any): MatchResult { + const result = new MatchResult(actual); + if (!this.pattern.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${actual} to match ${this.pattern}`, + }); + } + return result; + } +} diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index 4ac7874c701d2..5e7d3591cd877 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -1,16 +1,12 @@ -import '@aws-cdk/assert-internal/jest'; -import { - arrayWith, - ResourcePart, -} from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import { AccountRootPrincipal, Role, } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { AmazonLinuxGeneration, EbsDeviceVolumeType, @@ -34,7 +30,7 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { AvailabilityZone: 'us-east-1a', MultiAttachEnabled: false, Size: 8, @@ -45,11 +41,11 @@ describe('volume', () => { Value: 'MyVolume', }, ], - }, ResourcePart.Properties); + }); - expect(stack).toHaveResource('AWS::EC2::Volume', { + Template.fromStack(stack).hasResource('AWS::EC2::Volume', { DeletionPolicy: 'Retain', - }, ResourcePart.CompleteDefinition); + }); }); test('fromVolumeAttributes', () => { @@ -85,7 +81,7 @@ describe('volume', () => { cdk.Tags.of(volume).add('TagKey', 'TagValue'); // THEN - expect(stack).toHaveResource('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { AvailabilityZone: 'us-east-1a', MultiAttachEnabled: false, Size: 8, @@ -94,7 +90,7 @@ describe('volume', () => { Key: 'TagKey', Value: 'TagValue', }], - }, ResourcePart.Properties); + }); }); @@ -111,9 +107,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { AutoEnableIO: true, - }, ResourcePart.Properties); + }); }); @@ -130,9 +126,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Encrypted: true, - }, ResourcePart.Properties); + }); }); @@ -151,7 +147,7 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Encrypted: true, KmsKeyId: { 'Fn::GetAtt': [ @@ -159,57 +155,54 @@ describe('volume', () => { 'Arn', ], }, - }, ResourcePart.Properties); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + }); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - { - Effect: 'Allow', - Principal: { - AWS: { + Statement: Match.arrayWith([{ + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Resource: '*', + Action: [ + 'kms:DescribeKey', + 'kms:GenerateDataKeyWithoutPlainText', + ], + Condition: { + StringEquals: { + 'kms:ViaService': { 'Fn::Join': [ '', [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', + 'ec2.', { - Ref: 'AWS::AccountId', + Ref: 'AWS::Region', }, - ':root', + '.amazonaws.com', ], ], }, - }, - Resource: '*', - Action: [ - 'kms:DescribeKey', - 'kms:GenerateDataKeyWithoutPlainText', - ], - Condition: { - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'ec2.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], - ], - }, - 'kms:CallerAccount': { - Ref: 'AWS::AccountId', - }, + 'kms:CallerAccount': { + Ref: 'AWS::AccountId', }, }, }, - ], + }]), }, }); @@ -233,18 +226,15 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - { - Action: [ - 'kms:DescribeKey', - 'kms:GenerateDataKeyWithoutPlainText', - 'kms:ReEncrypt*', - ], - }, - ], + Statement: Match.arrayWith([Match.objectLike({ + Action: [ + 'kms:DescribeKey', + 'kms:GenerateDataKeyWithoutPlainText', + 'kms:ReEncrypt*', + ], + })]), }, }); @@ -264,10 +254,10 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Iops: 500, VolumeType: 'io1', - }, ResourcePart.Properties); + }); }); @@ -286,9 +276,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { MultiAttachEnabled: true, - }, ResourcePart.Properties); + }); }); @@ -304,9 +294,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { SnapshotId: 'snap-00000000', - }, ResourcePart.Properties); + }); }); @@ -323,9 +313,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'standard', - }, ResourcePart.Properties); + }); }); @@ -343,9 +333,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'io1', - }, ResourcePart.Properties); + }); }); @@ -363,9 +353,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'io2', - }, ResourcePart.Properties); + }); }); @@ -382,9 +372,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'gp2', - }, ResourcePart.Properties); + }); }); @@ -401,9 +391,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'gp3', - }, ResourcePart.Properties); + }); }); @@ -420,9 +410,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'st1', - }, ResourcePart.Properties); + }); }); @@ -439,9 +429,9 @@ describe('volume', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { VolumeType: 'sc1', - }, ResourcePart.Properties); + }); }); @@ -459,7 +449,7 @@ describe('volume', () => { volume.grantAttachVolume(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -536,45 +526,41 @@ describe('volume', () => { volume.grantAttachVolume(role); // THEN - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - {}, - { - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', - ], - }, + Statement: Match.arrayWith([{ + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': [ + 'Role1ABCC5F0', + 'Arn', + ], }, - Action: 'kms:CreateGrant', - Condition: { - Bool: { - 'kms:GrantIsForAWSResource': true, - }, - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'ec2.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], + }, + Action: 'kms:CreateGrant', + Condition: { + Bool: { + 'kms:GrantIsForAWSResource': true, + }, + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'ec2.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', ], - }, - 'kms:GrantConstraintType': 'EncryptionContextSubset', + ], }, + 'kms:GrantConstraintType': 'EncryptionContextSubset', }, - Resource: '*', }, - ], + Resource: '*', + }]), }, }); @@ -597,9 +583,9 @@ describe('volume', () => { volume.grantAttachVolume(role); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Effect: 'Allow', Action: 'kms:CreateGrant', Condition: { @@ -628,7 +614,7 @@ describe('volume', () => { 'Arn', ], }, - }), + }]), }, }); @@ -670,42 +656,39 @@ describe('volume', () => { volume.grantAttachVolume(role); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', - Statement: [ - {}, - { - Effect: 'Allow', - Action: 'kms:CreateGrant', - Resource: { - 'Fn::GetAtt': [ - 'Key961B73FD', - 'Arn', - ], + Statement: Match.arrayWith([{ + Effect: 'Allow', + Action: 'kms:CreateGrant', + Resource: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + Condition: { + Bool: { + 'kms:GrantIsForAWSResource': true, }, - Condition: { - Bool: { - 'kms:GrantIsForAWSResource': true, - }, - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'ec2.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'ec2.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', ], - }, - 'kms:GrantConstraintType': 'EncryptionContextSubset', + ], }, + 'kms:GrantConstraintType': 'EncryptionContextSubset', }, }, - ], + }]), }, }); @@ -738,61 +721,58 @@ describe('volume', () => { volume.grantAttachVolume(role, [instance1, instance2]); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ Action: 'ec2:AttachVolume', Effect: 'Allow', - Resource: [ - {}, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/', - { - Ref: 'Instance14BC3991D', - }, - ], + Resource: Match.arrayWith([{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/', + { + Ref: 'Instance14BC3991D', + }, ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/', - { - Ref: 'Instance255F35265', - }, - ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/', + { + Ref: 'Instance255F35265', + }, ], - }, - ], + ], + }]), }], }, }); @@ -819,35 +799,32 @@ describe('volume', () => { volume.grantAttachVolumeByResourceTag(instance.grantPrincipal, [instance]); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ Action: 'ec2:AttachVolume', Effect: 'Allow', - Resource: [ - {}, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/*', - ], + Resource: Match.arrayWith([{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/*', ], - }, - ], + ], + }]), Condition: { 'ForAnyValue:StringEquals': { 'ec2:ResourceTag/VolumeGrantAttach-B2376B2BDA': 'b2376b2bda65cb40f83c290dd844c4aa', @@ -856,25 +833,20 @@ describe('volume', () => { }], }, }); - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Tags: [ { Key: 'VolumeGrantAttach-B2376B2BDA', Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], - }, ResourcePart.Properties); - expect(stack).toHaveResourceLike('AWS::EC2::Instance', { - Tags: [ - {}, - { - Key: 'VolumeGrantAttach-B2376B2BDA', - Value: 'b2376b2bda65cb40f83c290dd844c4aa', - }, - ], - }, ResourcePart.Properties); - - + }); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Tags: Match.arrayWith([{ + Key: 'VolumeGrantAttach-B2376B2BDA', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', + }]), + }); }); test('grantAttachVolume to instance self with suffix', () => { @@ -896,35 +868,32 @@ describe('volume', () => { volume.grantAttachVolumeByResourceTag(instance.grantPrincipal, [instance], 'TestSuffix'); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ Action: 'ec2:AttachVolume', Effect: 'Allow', - Resource: [ - {}, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/*', - ], + Resource: Match.arrayWith([{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/*', ], - }, - ], + ], + }]), Condition: { 'ForAnyValue:StringEquals': { 'ec2:ResourceTag/VolumeGrantAttach-TestSuffix': 'b2376b2bda65cb40f83c290dd844c4aa', @@ -933,23 +902,20 @@ describe('volume', () => { }], }, }); - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Tags: [ { Key: 'VolumeGrantAttach-TestSuffix', Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], - }, ResourcePart.Properties); - expect(stack).toHaveResourceLike('AWS::EC2::Instance', { - Tags: [ - {}, - { - Key: 'VolumeGrantAttach-TestSuffix', - Value: 'b2376b2bda65cb40f83c290dd844c4aa', - }, - ], - }, ResourcePart.Properties); + }); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Tags: Match.arrayWith([{ + Key: 'VolumeGrantAttach-TestSuffix', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', + }]), + }); }); @@ -966,7 +932,7 @@ describe('volume', () => { volume.grantDetachVolume(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -1049,61 +1015,58 @@ describe('volume', () => { volume.grantDetachVolume(role, [instance1, instance2]); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ Action: 'ec2:DetachVolume', Effect: 'Allow', - Resource: [ - {}, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/', - { - Ref: 'Instance14BC3991D', - }, - ], + Resource: Match.arrayWith([{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/', + { + Ref: 'Instance14BC3991D', + }, ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/', - { - Ref: 'Instance255F35265', - }, - ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/', + { + Ref: 'Instance255F35265', + }, ], - }, - ], + ], + }]), }], }, }); @@ -1130,35 +1093,32 @@ describe('volume', () => { volume.grantDetachVolumeByResourceTag(instance.grantPrincipal, [instance]); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ Action: 'ec2:DetachVolume', Effect: 'Allow', - Resource: [ - {}, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':instance/*', - ], + Resource: Match.arrayWith([{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ec2:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':instance/*', ], - }, - ], + ], + }]), Condition: { 'ForAnyValue:StringEquals': { 'ec2:ResourceTag/VolumeGrantDetach-B2376B2BDA': 'b2376b2bda65cb40f83c290dd844c4aa', @@ -1167,25 +1127,20 @@ describe('volume', () => { }], }, }); - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Tags: [ { Key: 'VolumeGrantDetach-B2376B2BDA', Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], - }, ResourcePart.Properties); - expect(stack).toHaveResourceLike('AWS::EC2::Instance', { - Tags: [ - {}, - { - Key: 'VolumeGrantDetach-B2376B2BDA', - Value: 'b2376b2bda65cb40f83c290dd844c4aa', - }, - ], - }, ResourcePart.Properties); - - + }); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Tags: Match.arrayWith([{ + Key: 'VolumeGrantDetach-B2376B2BDA', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', + }]), + }); }); test('grantDetachVolume from instance self with suffix', () => { @@ -1207,14 +1162,13 @@ describe('volume', () => { volume.grantDetachVolumeByResourceTag(instance.grantPrincipal, [instance], 'TestSuffix'); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ Action: 'ec2:DetachVolume', Effect: 'Allow', - Resource: [ - {}, + Resource: Match.arrayWith([ { 'Fn::Join': [ '', @@ -1235,7 +1189,7 @@ describe('volume', () => { ], ], }, - ], + ]), Condition: { 'ForAnyValue:StringEquals': { 'ec2:ResourceTag/VolumeGrantDetach-TestSuffix': 'b2376b2bda65cb40f83c290dd844c4aa', @@ -1244,23 +1198,20 @@ describe('volume', () => { }], }, }); - expect(stack).toHaveResourceLike('AWS::EC2::Volume', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Volume', { Tags: [ { Key: 'VolumeGrantDetach-TestSuffix', Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], - }, ResourcePart.Properties); - expect(stack).toHaveResourceLike('AWS::EC2::Instance', { - Tags: [ - {}, - { - Key: 'VolumeGrantDetach-TestSuffix', - Value: 'b2376b2bda65cb40f83c290dd844c4aa', - }, - ], - }, ResourcePart.Properties); + }); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Tags: Match.arrayWith([{ + Key: 'VolumeGrantDetach-TestSuffix', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', + }]), + }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts index 2b00460ec793b..3a1eb7edee100 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { ArnPrincipal } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; @@ -33,18 +33,18 @@ describe('vpc endpoint service', () => { allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpointService', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', { NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'], AcceptanceRequired: false, }); - expect(stack).not.toHaveResource('AWS::EC2::VPCEndpointServicePermissions', { + const servicePermissions = Template.fromStack(stack).findResources('AWS::EC2::VPCEndpointServicePermissions', { ServiceId: { Ref: 'EndpointServiceED36BE1F', }, AllowedPrincipals: [], }); - + expect(Object.keys(servicePermissions).length).toBe(0); }); test('create endpoint service with a principal', () => { @@ -60,12 +60,12 @@ describe('vpc endpoint service', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpointService', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', { NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'], AcceptanceRequired: false, }); - expect(stack).toHaveResource('AWS::EC2::VPCEndpointServicePermissions', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointServicePermissions', { ServiceId: { Ref: 'EndpointServiceED36BE1F', }, @@ -88,12 +88,12 @@ describe('vpc endpoint service', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpointService', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', { NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'], AcceptanceRequired: true, }); - expect(stack).toHaveResource('AWS::EC2::VPCEndpointServicePermissions', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointServicePermissions', { ServiceId: { Ref: 'EndpointServiceED36BE1F', }, diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts index c5724e91c2bcc..9baa7c9e7e437 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts @@ -1,9 +1,9 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { AnyPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { ContextProvider, Fn, Stack } from '@aws-cdk/core'; // eslint-disable-next-line max-len -import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, InterfaceVpcEndpoint, InterfaceVpcEndpointAwsService, InterfaceVpcEndpointService, SecurityGroup, SubnetType, Vpc } from '../lib'; +import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, InterfaceVpcEndpoint, InterfaceVpcEndpointAwsService, InterfaceVpcEndpointService, SecurityGroup, SubnetFilter, SubnetType, Vpc } from '../lib'; describe('vpc endpoint', () => { describe('gateway endpoint', () => { @@ -21,7 +21,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: { 'Fn::Join': [ '', @@ -71,7 +71,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: { 'Fn::Join': [ '', @@ -123,7 +123,7 @@ describe('vpc endpoint', () => { })); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { PolicyDocument: { Statement: [ { @@ -185,7 +185,7 @@ describe('vpc endpoint', () => { // THEN vpc.addGatewayEndpoint('Gateway', { service: GatewayVpcEndpointAwsService.S3 }); - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: { 'Fn::Join': ['', ['com.amazonaws.', { Ref: 'AWS::Region' }, '.s3']] }, VpcId: 'id', RouteTableIds: ['rt1', 'rt2', 'rt3'], @@ -222,7 +222,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: { 'Fn::Join': [ '', @@ -258,7 +258,7 @@ describe('vpc endpoint', () => { VpcEndpointType: 'Interface', }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/VpcNetwork/EcrDocker/SecurityGroup', VpcId: { Ref: 'VpcNetworkB258E83A', @@ -268,6 +268,25 @@ describe('vpc endpoint', () => { }); + describe('add interface endpoint to looked-up VPC', () => { + test('initial run', () => { + // GIVEN + const stack = new Stack(undefined, undefined, { env: { account: '1234', region: 'us-east-1' } }); + const vpc = Vpc.fromLookup(stack, 'Vpc', { + vpcId: 'doesnt-matter', + }); + + // THEN: doesn't throw + vpc.addInterfaceEndpoint('SecretsManagerEndpoint', { + service: InterfaceVpcEndpointAwsService.SECRETS_MANAGER, + subnets: { + subnetFilters: [SubnetFilter.byIds(['1234'])], + }, + }); + }); + }); + + test('import/export', () => { // GIVEN const stack2 = new Stack(); @@ -281,7 +300,7 @@ describe('vpc endpoint', () => { importedEndpoint.connections.allowDefaultPortFromAnyIpv4(); // THEN - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { GroupId: 'security-group-id', }); expect(importedEndpoint.vpcEndpointId).toEqual('vpc-endpoint-id'); @@ -319,7 +338,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { SecurityGroupIds: ['existing-id'], }); @@ -337,7 +356,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { SecurityGroupIds: ['existing-id'], }); @@ -354,14 +373,14 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ - { + Match.objectLike({ CidrIp: { 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'] }, FromPort: 443, IpProtocol: 'tcp', ToPort: 443, - }, + }), ], }); @@ -378,7 +397,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', PrivateDnsEnabled: false, }); @@ -400,7 +419,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-mktplacesvcwprdns', PrivateDnsEnabled: true, }); @@ -439,7 +458,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', SubnetIds: [ { @@ -476,7 +495,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', SubnetIds: [ { @@ -522,7 +541,7 @@ describe('vpc endpoint', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.us-east-1.execute-api', SubnetIds: [ { @@ -617,7 +636,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'cn.com.amazonaws.cn-north-1.ecr.api', }); @@ -634,7 +653,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'cn.com.amazonaws.cn-northwest-1.lambda', }); @@ -651,7 +670,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.cn-north-1.ecs', }); @@ -668,7 +687,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.cn-northwest-1.glue', }); @@ -685,7 +704,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.us-east-1.transcribe', }); @@ -702,7 +721,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'cn.com.amazonaws.cn-north-1.transcribe.cn', }); @@ -719,7 +738,7 @@ describe('vpc endpoint', () => { }); //THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'cn.com.amazonaws.cn-northwest-1.transcribe.cn', }); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts index 956632bf1a0a5..88e9cc8705f8e 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.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 s3 from '@aws-cdk/aws-s3'; @@ -13,23 +13,21 @@ describe('vpc flow logs', () => { resourceType: FlowLogResourceType.fromNetworkInterfaceId('eni-123455'), }); - expect(stack). - toHaveResource('AWS::EC2::FlowLog', { - ResourceType: 'NetworkInterface', - TrafficType: 'ALL', - ResourceId: 'eni-123455', - DeliverLogsPermissionArn: { - 'Fn::GetAtt': ['FlowLogsIAMRoleF18F4209', 'Arn'], - }, - LogGroupName: { - Ref: 'FlowLogsLogGroup9853A85F', - }, + Template.fromStack(stack).hasResourceProperties('AWS::EC2::FlowLog', { + ResourceType: 'NetworkInterface', + TrafficType: 'ALL', + ResourceId: 'eni-123455', + DeliverLogsPermissionArn: { + 'Fn::GetAtt': ['FlowLogsIAMRoleF18F4209', 'Arn'], }, - ); + LogGroupName: { + Ref: 'FlowLogsLogGroup9853A85F', + }, + }); - expect(stack).toCountResources('AWS::Logs::LogGroup', 1); - expect(stack).toCountResources('AWS::IAM::Role', 1); - expect(stack).not.toHaveResource('AWS::S3::Bucket'); + Template.fromStack(stack).resourceCountIs('AWS::Logs::LogGroup', 1); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 1); + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 0); }); test('with cloudwatch logs as the destination, allows use of existing resources', () => { @@ -48,13 +46,13 @@ describe('vpc flow logs', () => { ), }); - expect(stack).toHaveResource('AWS::Logs::LogGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::Logs::LogGroup', { RetentionInDays: 5, }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { RoleName: 'TestName', }); - expect(stack).not.toHaveResource('AWS::S3::Bucket'); + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 0); }); test('with s3 as the destination, allows use of existing resources', () => { @@ -69,9 +67,9 @@ describe('vpc flow logs', () => { ), }); - expect(stack).not.toHaveResource('AWS::Logs::LogGroup'); - expect(stack).not.toHaveResource('AWS::IAM::Role'); - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).resourceCountIs('AWS::Logs::LogGroup', 0); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { BucketName: 'testbucket', }); @@ -89,9 +87,9 @@ describe('vpc flow logs', () => { ), }); - expect(stack).not.toHaveResource('AWS::Logs::LogGroup'); - expect(stack).not.toHaveResource('AWS::IAM::Role'); - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).resourceCountIs('AWS::Logs::LogGroup', 0); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { BucketName: 'testbucket', }); @@ -104,19 +102,17 @@ describe('vpc flow logs', () => { destination: FlowLogDestination.toS3(), }); - expect(stack). - toHaveResource('AWS::EC2::FlowLog', { - ResourceType: 'NetworkInterface', - TrafficType: 'ALL', - ResourceId: 'eni-123456', - LogDestination: { - 'Fn::GetAtt': ['FlowLogsBucket87F67F60', 'Arn'], - }, + Template.fromStack(stack).hasResourceProperties('AWS::EC2::FlowLog', { + ResourceType: 'NetworkInterface', + TrafficType: 'ALL', + ResourceId: 'eni-123456', + LogDestination: { + 'Fn::GetAtt': ['FlowLogsBucket87F67F60', 'Arn'], }, - ); - expect(stack).not.toHaveResource('AWS::Logs::LogGroup'); - expect(stack).not.toHaveResource('AWS::IAM::Role'); - expect(stack).toCountResources('AWS::S3::Bucket', 1); + }); + Template.fromStack(stack).resourceCountIs('AWS::Logs::LogGroup', 0); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Role', 0); + Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1); }); test('create with vpc', () => { @@ -128,22 +124,20 @@ describe('vpc flow logs', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::VPC'); - expect(stack). - toHaveResource('AWS::EC2::FlowLog', { - ResourceType: 'VPC', - TrafficType: 'ALL', - ResourceId: { - Ref: 'VPCB9E5F0B4', - }, - DeliverLogsPermissionArn: { - 'Fn::GetAtt': ['VPCflowLogsIAMRole9D21E1A6', 'Arn'], - }, - LogGroupName: { - Ref: 'VPCflowLogsLogGroupE900F980', - }, + Template.fromStack(stack).resourceCountIs('AWS::EC2::VPC', 1); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::FlowLog', { + ResourceType: 'VPC', + TrafficType: 'ALL', + ResourceId: { + Ref: 'VPCB9E5F0B4', + }, + DeliverLogsPermissionArn: { + 'Fn::GetAtt': ['VPCflowLogsIAMRole9D21E1A6', 'Arn'], + }, + LogGroupName: { + Ref: 'VPCflowLogsLogGroupE900F980', }, - ); + }); }); test('add to vpc', () => { @@ -152,23 +146,20 @@ describe('vpc flow logs', () => { const vpc = new Vpc(stack, 'VPC'); vpc.addFlowLog('FlowLogs'); - expect(stack).toHaveResource('AWS::EC2::VPC'); - expect(stack). - toHaveResource('AWS::EC2::FlowLog', { - ResourceType: 'VPC', - TrafficType: 'ALL', - ResourceId: { - Ref: 'VPCB9E5F0B4', - }, - DeliverLogsPermissionArn: { - 'Fn::GetAtt': ['VPCFlowLogsIAMRole55343234', 'Arn'], - }, - LogGroupName: { - Ref: 'VPCFlowLogsLogGroupF48E1B0A', - }, + Template.fromStack(stack).resourceCountIs('AWS::EC2::VPC', 1); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::FlowLog', { + ResourceType: 'VPC', + TrafficType: 'ALL', + ResourceId: { + Ref: 'VPCB9E5F0B4', }, - ); - + DeliverLogsPermissionArn: { + 'Fn::GetAtt': ['VPCFlowLogsIAMRole55343234', 'Arn'], + }, + LogGroupName: { + Ref: 'VPCFlowLogsLogGroupF48E1B0A', + }, + }); }); }); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 1ef3e8094a5e7..3c9d54d25bf4f 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { isSuperObject, MatchStyle, SynthUtils } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { CfnOutput, CfnResource, Fn, Lazy, Stack, Tags } from '@aws-cdk/core'; import { @@ -48,7 +47,7 @@ describe('vpc', () => { test('it uses the correct network range', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC'); - expect(stack).toHaveResource('AWS::EC2::VPC', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: Vpc.DEFAULT_CIDR_RANGE, EnableDnsHostnames: true, EnableDnsSupport: true, @@ -59,15 +58,12 @@ describe('vpc', () => { test('the Name tag is defaulted to path', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC'); - expect(stack). - toHaveResource('AWS::EC2::VPC', - hasTags([{ Key: 'Name', Value: 'TestStack/TheVPC' }]), - ); - expect(stack). - toHaveResource('AWS::EC2::InternetGateway', - hasTags([{ Key: 'Name', Value: 'TestStack/TheVPC' }]), - ); - + Template.fromStack(stack).hasResource('AWS::EC2::VPC', + hasTags([{ Key: 'Name', Value: 'TestStack/TheVPC' }]), + ); + Template.fromStack(stack).hasResource('AWS::EC2::InternetGateway', + hasTags([{ Key: 'Name', Value: 'TestStack/TheVPC' }]), + ); }); }); @@ -81,7 +77,7 @@ describe('vpc', () => { defaultInstanceTenancy: DefaultInstanceTenancy.DEDICATED, }); - expect(stack).toHaveResource('AWS::EC2::VPC', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: '192.168.0.0/16', EnableDnsHostnames: false, EnableDnsSupport: false, @@ -112,7 +108,7 @@ describe('vpc', () => { defaultInstanceTenancy: DefaultInstanceTenancy.DEDICATED, }); - expect(stack).toHaveResource('AWS::EC2::VPC', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: '192.168.0.0/16', EnableDnsHostnames: input.dnsHostnames, EnableDnsSupport: input.dnsSupport, @@ -156,9 +152,9 @@ describe('vpc', () => { }, ], }); - expect(stack).not.toHaveResource('AWS::EC2::InternetGateway'); - expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::InternetGateway', 0); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 0); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { MapPublicIpOnLaunch: false, }); @@ -178,8 +174,8 @@ describe('vpc', () => { }, ], }); - expect(stack).toCountResources('AWS::EC2::InternetGateway', 1); - expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); + Template.fromStack(stack).resourceCountIs('AWS::EC2::InternetGateway', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 0); }); test('with private subnets and custom networkAcl.', () => { @@ -218,9 +214,9 @@ describe('vpc', () => { cidr: AclCidr.anyIpv4(), }); - expect(stack).toCountResources('AWS::EC2::NetworkAcl', 1); - expect(stack).toCountResources('AWS::EC2::NetworkAclEntry', 2); - expect(stack).toCountResources('AWS::EC2::SubnetNetworkAclAssociation', 3); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NetworkAcl', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NetworkAclEntry', 2); + Template.fromStack(stack).resourceCountIs('AWS::EC2::SubnetNetworkAclAssociation', 3); }); @@ -228,8 +224,8 @@ describe('vpc', () => { const stack = getTestStack(); const zones = stack.availabilityZones.length; new Vpc(stack, 'TheVPC', {}); - expect(stack).toCountResources('AWS::EC2::InternetGateway', 1); - expect(stack).toCountResources('AWS::EC2::NatGateway', zones); + Template.fromStack(stack).resourceCountIs('AWS::EC2::InternetGateway', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', zones); }); @@ -252,8 +248,8 @@ describe('vpc', () => { routerType: RouterType.GATEWAY, destinationCidrBlock: '8.8.8.8/32', }); - expect(stack).toHaveResource('AWS::EC2::InternetGateway'); - expect(stack).toHaveResourceLike('AWS::EC2::Route', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::InternetGateway', 1); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { DestinationCidrBlock: '8.8.8.8/32', GatewayId: {}, }); @@ -284,7 +280,7 @@ describe('vpc', () => { ], maxAzs: 3, }); - expect(stack).toCountResources('AWS::EC2::Subnet', 6); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 6); }); test('with reserved subnets, any other subnets should not have cidrBlock from within reserved space', () => { @@ -312,17 +308,18 @@ describe('vpc', () => { maxAzs: 3, }); for (let i = 0; i < 3; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); } for (let i = 3; i < 6; i++) { - expect(stack).not.toHaveResource('AWS::EC2::Subnet', { + const matchingSubnets = Template.fromStack(stack).findResources('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); + expect(Object.keys(matchingSubnets).length).toBe(0); } for (let i = 6; i < 9; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); } @@ -352,16 +349,16 @@ describe('vpc', () => { ], maxAzs: 3, }); - expect(stack).toCountResources('AWS::EC2::InternetGateway', 1); - expect(stack).toCountResources('AWS::EC2::NatGateway', zones); - expect(stack).toCountResources('AWS::EC2::Subnet', 9); + Template.fromStack(stack).resourceCountIs('AWS::EC2::InternetGateway', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', zones); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 9); for (let i = 0; i < 6; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); } for (let i = 0; i < 3; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.6.${i * 16}/28`, }); } @@ -391,16 +388,16 @@ describe('vpc', () => { ], maxAzs: 3, }); - expect(stack).toCountResources('AWS::EC2::InternetGateway', 1); - expect(stack).toCountResources('AWS::EC2::NatGateway', 2); - expect(stack).toCountResources('AWS::EC2::Subnet', 9); + Template.fromStack(stack).resourceCountIs('AWS::EC2::InternetGateway', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 2); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 9); for (let i = 0; i < 6; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); } for (let i = 0; i < 3; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.6.${i * 16}/28`, }); } @@ -426,9 +423,9 @@ describe('vpc', () => { }, ], }); - expect(stack).toCountResources('AWS::EC2::Subnet', 1); - expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 0); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { MapPublicIpOnLaunch: true, }); @@ -447,9 +444,9 @@ describe('vpc', () => { }, ], }); - expect(stack).toCountResources('AWS::EC2::Subnet', 1); - expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 0); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { MapPublicIpOnLaunch: true, }); }); @@ -466,9 +463,9 @@ describe('vpc', () => { }, ], }); - expect(stack).toCountResources('AWS::EC2::Subnet', 1); - expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 1); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 0); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { MapPublicIpOnLaunch: false, }); }); @@ -510,6 +507,7 @@ describe('vpc', () => { }); }).toThrow(/subnet cannot include mapPublicIpOnLaunch parameter/); }); + test('verify the Default VPC name', () => { const stack = getTestStack(); const tagName = { Key: 'Name', Value: `${stack.node.path}/VPC` }; @@ -526,16 +524,16 @@ describe('vpc', () => { }, ], }); - expect(stack).toCountResources('AWS::EC2::Subnet', 2); - expect(stack).toHaveResource('AWS::EC2::NatGateway'); - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 2); + Template.fromStack(stack).hasResource('AWS::EC2::NatGateway', Match.anyValue()); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { MapPublicIpOnLaunch: true, }); - expect(stack).toHaveResource('AWS::EC2::VPC', hasTags([tagName])); + Template.fromStack(stack).hasResource('AWS::EC2::VPC', hasTags([tagName])); }); + test('verify the assigned VPC name passing the "vpcName" prop', () => { const stack = getTestStack(); - const tagNameDefault = { Key: 'Name', Value: `${stack.node.path}/VPC` }; const tagName = { Key: 'Name', Value: 'CustomVPCName' }; new Vpc(stack, 'VPC', { maxAzs: 1, @@ -551,25 +549,24 @@ describe('vpc', () => { ], vpcName: 'CustomVPCName', }); - expect(stack).toCountResources('AWS::EC2::Subnet', 2); - expect(stack).toHaveResource('AWS::EC2::NatGateway'); - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 2); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::NatGateway', Match.anyValue()); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { MapPublicIpOnLaunch: true, }); - expect(stack).not.toHaveResource('AWS::EC2::VPC', hasTags([tagNameDefault])); - expect(stack).toHaveResource('AWS::EC2::VPC', hasTags([tagName])); + Template.fromStack(stack).hasResource('AWS::EC2::VPC', hasTags([tagName])); }); test('maxAZs defaults to 3 if unset', () => { const stack = getTestStack(); new Vpc(stack, 'VPC'); - expect(stack).toCountResources('AWS::EC2::Subnet', 6); - expect(stack).toCountResources('AWS::EC2::Route', 6); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 6); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Route', 6); for (let i = 0; i < 6; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i * 32}.0/19`, }); } - expect(stack).toHaveResourceLike('AWS::EC2::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { DestinationCidrBlock: '0.0.0.0/0', NatGatewayId: {}, }); @@ -578,14 +575,14 @@ describe('vpc', () => { test('with maxAZs set to 2', () => { const stack = getTestStack(); new Vpc(stack, 'VPC', { maxAzs: 2 }); - expect(stack).toCountResources('AWS::EC2::Subnet', 4); - expect(stack).toCountResources('AWS::EC2::Route', 4); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 4); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Route', 4); for (let i = 0; i < 4; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i * 64}.0/18`, }); } - expect(stack).toHaveResourceLike('AWS::EC2::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { DestinationCidrBlock: '0.0.0.0/0', NatGatewayId: {}, }); @@ -596,10 +593,10 @@ describe('vpc', () => { new Vpc(stack, 'VPC', { natGateways: 1, }); - expect(stack).toCountResources('AWS::EC2::Subnet', 6); - expect(stack).toCountResources('AWS::EC2::Route', 6); - expect(stack).toCountResources('AWS::EC2::NatGateway', 1); - expect(stack).toHaveResourceLike('AWS::EC2::Route', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 6); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Route', 6); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 1); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { DestinationCidrBlock: '0.0.0.0/0', NatGatewayId: {}, }); @@ -629,14 +626,14 @@ describe('vpc', () => { subnetGroupName: 'egress', }, }); - expect(stack).toCountResources('AWS::EC2::NatGateway', 3); + Template.fromStack(stack).resourceCountIs('AWS::EC2::NatGateway', 3); for (let i = 1; i < 4; i++) { - expect(stack).toHaveResource('AWS::EC2::Subnet', hasTags([{ - Key: 'Name', - Value: `TestStack/VPC/egressSubnet${i}`, - }, { + Template.fromStack(stack).hasResource('AWS::EC2::Subnet', hasTags([{ Key: 'aws-cdk:subnet-name', Value: 'egress', + }, { + Key: 'Name', + Value: `TestStack/VPC/egressSubnet${i}`, }])); } @@ -668,7 +665,7 @@ describe('vpc', () => { new Vpc(stack, 'VPC', { natGateways: 0, }); - expect(stack).toHaveResource('AWS::EC2::Subnet', hasTags([{ + Template.fromStack(stack).hasResource('AWS::EC2::Subnet', hasTags([{ Key: 'aws-cdk:subnet-type', Value: 'Isolated', }])); @@ -678,7 +675,7 @@ describe('vpc', () => { test('unspecified natGateways constructs with PRIVATE subnet', () => { const stack = getTestStack(); new Vpc(stack, 'VPC'); - expect(stack).toHaveResource('AWS::EC2::Subnet', hasTags([{ + Template.fromStack(stack).hasResource('AWS::EC2::Subnet', hasTags([{ Key: 'aws-cdk:subnet-type', Value: 'Private', }])); @@ -702,7 +699,7 @@ describe('vpc', () => { ], natGateways: 0, }); - expect(stack).toHaveResource('AWS::EC2::Subnet', hasTags([{ + Template.fromStack(stack).hasResource('AWS::EC2::Subnet', hasTags([{ Key: 'aws-cdk:subnet-name', Value: 'ingress', }])); @@ -728,8 +725,8 @@ describe('vpc', () => { natGatewayProvider: NatProvider.gateway({ eipAllocationIds: ['b'] }), natGateways: 1, }); - expect(stack).toCountResources('AWS::EC2::EIP', 0); - expect(stack).toHaveResource('AWS::EC2::NatGateway', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::EIP', 0); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::NatGateway', { AllocationId: 'b', }); }); @@ -762,12 +759,12 @@ describe('vpc', () => { vpnGatewayAsn: 65000, }); - expect(stack).toHaveResource('AWS::EC2::VPNGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNGateway', { AmazonSideAsn: 65000, Type: 'ipsec.1', }); - expect(stack).toHaveResource('AWS::EC2::VPCGatewayAttachment', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCGatewayAttachment', { VpcId: { Ref: 'VPCB9E5F0B4', }, @@ -776,7 +773,7 @@ describe('vpc', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::VPNGatewayRoutePropagation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNGatewayRoutePropagation', { RouteTableIds: [ { Ref: 'VPCPrivateSubnet1RouteTableBE8A6027', @@ -810,7 +807,7 @@ describe('vpc', () => { ], }); - expect(stack).toHaveResource('AWS::EC2::VPNGatewayRoutePropagation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNGatewayRoutePropagation', { RouteTableIds: [ { Ref: 'VPCIsolatedSubnet1RouteTableEB156210', @@ -848,7 +845,7 @@ describe('vpc', () => { ], }); - expect(stack).toHaveResource('AWS::EC2::VPNGatewayRoutePropagation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNGatewayRoutePropagation', { RouteTableIds: [ { Ref: 'VPCPrivateSubnet1RouteTableBE8A6027', @@ -886,7 +883,7 @@ describe('vpc', () => { vpnGateway: true, }); - expect(stack).toHaveResource('AWS::EC2::VPNGatewayRoutePropagation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNGatewayRoutePropagation', { RouteTableIds: [ { Ref: 'VPCIsolatedSubnet1RouteTableEB156210', @@ -914,7 +911,7 @@ describe('vpc', () => { vpnGateway: true, }); - expect(stack).toHaveResource('AWS::EC2::VPNGatewayRoutePropagation', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNGatewayRoutePropagation', { RouteTableIds: [ { Ref: 'VPCPublicSubnet1RouteTableFEE4B781', @@ -968,8 +965,6 @@ describe('vpc', () => { const vpc = new Vpc(stack, 'VpcNetwork'); expect(vpc.publicSubnets[0].node.defaultChild instanceof CfnSubnet).toEqual(true); - - }); test('CIDR cannot be a Token', () => { @@ -979,8 +974,6 @@ describe('vpc', () => { cidr: Lazy.string({ produce: () => 'abc' }), }); }).toThrow(/property must be a concrete CIDR string/); - - }); test('Default NAT gateway provider', () => { @@ -989,8 +982,6 @@ describe('vpc', () => { new Vpc(stack, 'VpcNetwork', { natGatewayProvider }); expect(natGatewayProvider.configuredGateways.length).toBeGreaterThan(0); - - }); test('NAT gateway provider with EIP allocations', () => { @@ -1000,14 +991,12 @@ describe('vpc', () => { }); new Vpc(stack, 'VpcNetwork', { natGatewayProvider }); - expect(stack).toHaveResource('AWS::EC2::NatGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::NatGateway', { AllocationId: 'a', }); - expect(stack).toHaveResource('AWS::EC2::NatGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::NatGateway', { AllocationId: 'b', }); - - }); test('NAT gateway provider with insufficient EIP allocations', () => { @@ -1015,8 +1004,6 @@ describe('vpc', () => { const natGatewayProvider = NatProvider.gateway({ eipAllocationIds: ['a'] }); expect(() => new Vpc(stack, 'VpcNetwork', { natGatewayProvider })) .toThrow(/Not enough NAT gateway EIP allocation IDs \(1 provided\) for the requested subnet count \(\d+ needed\)/); - - }); test('NAT gateway provider with token EIP allocations', () => { @@ -1025,14 +1012,12 @@ describe('vpc', () => { const natGatewayProvider = NatProvider.gateway({ eipAllocationIds }); new Vpc(stack, 'VpcNetwork', { natGatewayProvider }); - expect(stack).toHaveResource('AWS::EC2::NatGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::NatGateway', { AllocationId: stack.resolve(Fn.select(0, eipAllocationIds)), }); - expect(stack).toHaveResource('AWS::EC2::NatGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::NatGateway', { AllocationId: stack.resolve(Fn.select(1, eipAllocationIds)), }); - - }); test('Can add an IPv6 route', () => { @@ -1049,7 +1034,7 @@ describe('vpc', () => { // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { DestinationIpv6CidrBlock: '2001:4860:4860::8888/32', NetworkInterfaceId: 'router-1', }); @@ -1070,7 +1055,7 @@ describe('vpc', () => { // THEN - expect(stack).toHaveResourceLike('AWS::EC2::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { DestinationCidrBlock: '0.0.0.0/0', NetworkInterfaceId: 'router-1', }); @@ -1094,18 +1079,18 @@ describe('vpc', () => { new Vpc(stack, 'TheVPC', { natGatewayProvider }); // THEN - expect(stack).toCountResources('AWS::EC2::Instance', 3); - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).resourceCountIs('AWS::EC2::Instance', 3); + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { ImageId: 'ami-1', InstanceType: 'q86.mega', SourceDestCheck: false, }); - expect(stack).toHaveResource('AWS::EC2::Route', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Route', { RouteTableId: { Ref: 'TheVPCPrivateSubnet1RouteTableF6513BC2' }, DestinationCidrBlock: '0.0.0.0/0', InstanceId: { Ref: 'TheVPCPublicSubnet1NatInstanceCC514192' }, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -1141,9 +1126,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toCountResources('AWS::EC2::Instance', 1); - - + Template.fromStack(stack).resourceCountIs('AWS::EC2::Instance', 1); }); testDeprecated('can configure Security Groups of NAT instances with allowAllTraffic false', () => { @@ -1164,7 +1147,7 @@ describe('vpc', () => { provider.connections.allowFrom(Peer.ipv4('1.2.3.4/32'), Port.tcp(86)); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -1203,7 +1186,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -1240,7 +1223,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '0.0.0.0/0', @@ -1270,7 +1253,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { CidrIp: '255.255.255.255/32', @@ -1298,15 +1281,13 @@ describe('vpc', () => { value: (vpc.publicSubnets[0] as Subnet).subnetNetworkAclAssociationId, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Outputs: { Output: { Value: { 'Fn::GetAtt': ['TheVPCPublicSubnet1Subnet770D4FF2', 'NetworkAclAssociationId'] }, }, }, - }, MatchStyle.SUPERSET); - - + }); }); test('if ACL is replaced new ACL reference is returned', () => { @@ -1323,15 +1304,13 @@ describe('vpc', () => { subnetSelection: { subnetType: SubnetType.PUBLIC }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Outputs: { Output: { Value: { Ref: 'ACLDBD1BB49' }, }, }, - }, MatchStyle.SUPERSET); - - + }); }); }); @@ -1339,10 +1318,9 @@ describe('vpc', () => { test('vpc.vpcCidrBlock is the correct network range', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { cidr: '192.168.0.0/16' }); - expect(stack).toHaveResource('AWS::EC2::VPC', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: '192.168.0.0/16', }); - }); }); describe('When tagging', () => { @@ -1354,19 +1332,22 @@ describe('vpc', () => { const noPropTags = { BusinessUnit: 'Marketing', }; - const allTags = { ...tags, ...noPropTags }; + const allTags = { ...noPropTags, ...tags }; const vpc = new Vpc(stack, 'TheVPC'); // overwrite to set propagate Tags.of(vpc).add('BusinessUnit', 'Marketing', { includeResourceTypes: [CfnVPC.CFN_RESOURCE_TYPE_NAME] }); Tags.of(vpc).add('VpcType', 'Good'); - expect(stack).toHaveResource('AWS::EC2::VPC', hasTags(toCfnTags(allTags))); + Template.fromStack(stack).hasResource('AWS::EC2::VPC', hasTags(toCfnTags(allTags))); const taggables = ['Subnet', 'InternetGateway', 'NatGateway', 'RouteTable']; const propTags = toCfnTags(tags); const noProp = toCfnTags(noPropTags); for (const resource of taggables) { - expect(stack).toHaveResource(`AWS::EC2::${resource}`, hasTags(propTags)); - expect(stack).not.toHaveResource(`AWS::EC2::${resource}`, hasTags(noProp)); + Template.fromStack(stack).hasResourceProperties(`AWS::EC2::${resource}`, { + Tags: Match.arrayWith(propTags), + }); + const matchingResources = Template.fromStack(stack).findResources(`AWS::EC2::${resource}`, hasTags(noProp)); + expect(Object.keys(matchingResources).length).toBe(0); } }); @@ -1375,12 +1356,12 @@ describe('vpc', () => { const vpc = new Vpc(stack, 'TheVPC'); for (const subnet of vpc.publicSubnets) { const tag = { Key: 'Name', Value: subnet.node.path }; - expect(stack).toHaveResource('AWS::EC2::NatGateway', hasTags([tag])); - expect(stack).toHaveResource('AWS::EC2::RouteTable', hasTags([tag])); + Template.fromStack(stack).hasResource('AWS::EC2::NatGateway', hasTags([tag])); + Template.fromStack(stack).hasResource('AWS::EC2::RouteTable', hasTags([tag])); } for (const subnet of vpc.privateSubnets) { const tag = { Key: 'Name', Value: subnet.node.path }; - expect(stack).toHaveResource('AWS::EC2::RouteTable', hasTags([tag])); + Template.fromStack(stack).hasResource('AWS::EC2::RouteTable', hasTags([tag])); } }); @@ -1389,9 +1370,8 @@ describe('vpc', () => { const vpc = new Vpc(stack, 'TheVPC'); const tag = { Key: 'Late', Value: 'Adder' }; - expect(stack).not.toHaveResource('AWS::EC2::VPC', hasTags([tag])); Tags.of(vpc).add(tag.Key, tag.Value); - expect(stack).toHaveResource('AWS::EC2::VPC', hasTags([tag])); + Template.fromStack(stack).hasResource('AWS::EC2::VPC', hasTags([tag])); }); }); @@ -1573,24 +1553,15 @@ describe('vpc', () => { }); // THEN - No exception - expect(stack).toHaveResource('Some::Resource', { + Template.fromStack(stack).hasResourceProperties('Some::Resource', { subnetIds: { 'Fn::Split': [',', { 'Fn::ImportValue': 'myPublicSubnetIds' }] }, }); - // THEN - Warnings have been added to the stack metadata - const asm = SynthUtils.synthesize(stack); - expect(asm.messages).toEqual(expect.arrayContaining([ - expect.objectContaining( - { - entry: { - type: 'aws:cdk:warning', - data: "fromVpcAttributes: 'availabilityZones' is a list token: the imported VPC will not work with constructs that require a list of subnets at synthesis time. Use 'Vpc.fromLookup()' or 'Fn.importListValue' instead.", - }, - }, - ), - ])); - - + expect(vpc.node.metadataEntry).toContainEqual({ + data: expect.stringContaining("fromVpcAttributes: 'availabilityZones' is a list token: the imported VPC will not work with constructs that require a list of subnets at synthesis time. Use 'Vpc.fromLookup()' or 'Fn.importListValue' instead."), + type: 'aws:cdk:warning', + trace: undefined, + }); }); test('fromVpcAttributes using fixed-length list tokens', () => { @@ -1618,7 +1589,7 @@ describe('vpc', () => { // THEN - No exception const publicSubnetList = { 'Fn::Split': [',', { 'Fn::ImportValue': 'myPublicSubnetIds' }] }; - expect(stack).toHaveResource('Some::Resource', { + Template.fromStack(stack).hasResourceProperties('Some::Resource', { subnetIds: [ { 'Fn::Select': [0, publicSubnetList] }, { 'Fn::Select': [1, publicSubnetList] }, @@ -1723,7 +1694,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', SubnetIds: [ { @@ -1754,7 +1725,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', SubnetIds: [ { @@ -1806,7 +1777,7 @@ describe('vpc', () => { // THEN // 10.0.160.0/19 is the third subnet, sequentially, if you split // 10.0.0.0/16 into 6 pieces - expect(stack).toHaveResource('AWS::EC2::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { SubnetId: { Ref: 'VPCPrivateSubnet3Subnet3EDCD457', }, @@ -1837,7 +1808,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', SubnetIds: [ { @@ -1872,7 +1843,7 @@ describe('vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPCEndpoint', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', SubnetIds: ['priv-1', 'priv-2'], }); @@ -1915,29 +1886,10 @@ function toCfnTags(tags: any): Array<{Key: string, Value: string}> { }); } -function hasTags(expectedTags: Array<{Key: string, Value: string}>): (props: any) => boolean { - return (props: any) => { - try { - const tags = props.Tags; - const actualTags = tags.filter( (tag: {Key: string, Value: string}) => { - for (const expectedTag of expectedTags) { - if (isSuperObject(expectedTag, tag)) { - return true; - } else { - continue; - } - } - // no values in array so expecting empty - return false; - }); - return actualTags.length === expectedTags.length; - } catch (e) { - /* eslint-disable no-console */ - console.error('Tags are incorrect'); - console.error('found tags ', props.Tags); - console.error('expected tags ', expectedTags); - /* eslint-enable no-console */ - throw e; - } +function hasTags(expectedTags: Array<{Key: string, Value: string}>) { + return { + Properties: { + Tags: Match.arrayWith(expectedTags), + }, }; } diff --git a/packages/@aws-cdk/aws-ec2/test/vpn.test.ts b/packages/@aws-cdk/aws-ec2/test/vpn.test.ts index 8a4c99159e5ec..1152581defc8f 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpn.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpn.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Duration, Stack, Token } from '@aws-cdk/core'; import { PublicSubnet, Vpc, VpnConnection } from '../lib'; @@ -18,13 +18,13 @@ describe('vpn', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::CustomerGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::CustomerGateway', { BgpAsn: 65001, IpAddress: '192.0.2.1', Type: 'ipsec.1', }); - expect(stack).toHaveResource('AWS::EC2::VPNConnection', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNConnection', { CustomerGatewayId: { Ref: 'VpcNetworkVpnConnectionCustomerGateway8B56D9AF', }, @@ -56,7 +56,7 @@ describe('vpn', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::VPNConnection', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNConnection', { CustomerGatewayId: { Ref: 'VpcNetworkstaticCustomerGatewayAF2651CC', }, @@ -67,14 +67,14 @@ describe('vpn', () => { StaticRoutesOnly: true, }); - expect(stack).toHaveResource('AWS::EC2::VPNConnectionRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNConnectionRoute', { DestinationCidrBlock: '192.168.10.0/24', VpnConnectionId: { Ref: 'VpcNetworkstaticE33EA98C', }, }); - expect(stack).toHaveResource('AWS::EC2::VPNConnectionRoute', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNConnectionRoute', { DestinationCidrBlock: '192.168.20.0/24', VpnConnectionId: { Ref: 'VpcNetworkstaticE33EA98C', @@ -102,7 +102,7 @@ describe('vpn', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::VPNConnection', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPNConnection', { CustomerGatewayId: { Ref: 'VpcNetworkVpnConnectionCustomerGateway8B56D9AF', }, @@ -316,7 +316,7 @@ describe('vpn', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::CustomerGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::CustomerGateway', { Type: 'ipsec.1', }); @@ -336,7 +336,7 @@ describe('vpn', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::CustomerGateway', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::CustomerGateway', { IpAddress: '192.0.2.1', }); diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index e3e138fe64c21..38d1459a9a713 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -72,7 +72,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-ecr-assets/test/image-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts index a42fd2451d8e3..6c02f5acbed8e 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { expect as ourExpect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import { describeDeprecated, testDeprecated, testFutureBehavior } from '@aws-cdk/cdk-build-tools'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; @@ -159,7 +159,7 @@ describe('image asset', () => { asset.repository.grantPull(user); // THEN - ourExpect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { 'Statement': [ { @@ -204,9 +204,7 @@ describe('image asset', () => { 'Ref': 'MyUserDC45028B', }, ], - })); - - + }); }); test('fails if the directory does not exist', () => { @@ -291,8 +289,6 @@ describe('image asset', () => { expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules', 'one'))).toBeDefined(); expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules', 'some_dep'))).toBeDefined(); expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules', 'some_dep', 'file'))).toBeDefined(); - - }); testFutureBehavior('docker directory is staged without files specified in exclude option', flags, App, (app) => { @@ -319,8 +315,6 @@ describe('image asset', () => { directory: path.join(__dirname, 'demo-image'), buildArgs: { key: token }, })).toThrow(expected); - - }); testDeprecated('fails if using token as repositoryName', () => { @@ -333,8 +327,6 @@ describe('image asset', () => { directory: path.join(__dirname, 'demo-image'), repositoryName: token, })).toThrow(/Cannot use Token as value of 'repositoryName'/); - - }); testFutureBehavior('docker build options are included in the asset id', flags, App, (app) => { @@ -386,8 +378,6 @@ function testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(app: App expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'foobar.txt'))).toBeDefined(); expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory'))).toBeDefined(); expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); - - } function testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(app: App, ignoreMode?: IgnoreMode) { @@ -406,8 +396,6 @@ function testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(app: Ap expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'foobar.txt'))).toBeDefined(); expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory'))).toBeDefined(); expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); - - } testFutureBehavior('nested assemblies share assets: legacy synth edition', flags, App, (app) => { diff --git a/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts index 77e22f20dca9d..dec618738fc5a 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts @@ -1,11 +1,11 @@ import * as fs from 'fs'; import * as path from 'path'; -import { expect as ourExpect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { TarballImageAsset } from '../lib'; /* eslint-disable quote-props */ @@ -64,7 +64,7 @@ describe('image asset', () => { asset.repository.grantPull(user); // THEN - ourExpect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { 'Statement': [ { @@ -112,7 +112,7 @@ describe('image asset', () => { 'Ref': 'MyUserDC45028B', }, ], - })); + }); }); testFutureBehavior('docker directory is staged if asset staging is enabled', flags, App, (app) => { diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index e8e9c3402eed3..e2b8bccc7c29f 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -83,7 +83,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-ecr/test/auth-token.test.ts b/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts index f9be93b1e15d0..421ba7c2f6645 100644 --- a/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts +++ b/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts @@ -1,4 +1,4 @@ -import { expect as expectCDK, haveResourceLike } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { AuthorizationToken, PublicGalleryAuthorizationToken } from '../lib'; @@ -13,7 +13,7 @@ describe('auth-token', () => { AuthorizationToken.grantRead(user); // THEN - expectCDK(stack).to(haveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -23,7 +23,7 @@ describe('auth-token', () => { }, ], }, - })); + }); }); test('PublicGalleryAuthorizationToken.grantRead()', () => { @@ -35,7 +35,7 @@ describe('auth-token', () => { PublicGalleryAuthorizationToken.grantRead(user); // THEN - expectCDK(stack).to(haveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -48,6 +48,6 @@ describe('auth-token', () => { }, ], }, - })); + }); }); }); diff --git a/packages/@aws-cdk/aws-ecr/test/repository.test.ts b/packages/@aws-cdk/aws-ecr/test/repository.test.ts index 37cc58a8485eb..470638d89355e 100644 --- a/packages/@aws-cdk/aws-ecr/test/repository.test.ts +++ b/packages/@aws-cdk/aws-ecr/test/repository.test.ts @@ -1,5 +1,5 @@ import { EOL } from 'os'; -import { expect as expectCDK, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as ecr from '../lib'; @@ -15,7 +15,7 @@ describe('repository', () => { new ecr.Repository(stack, 'Repo'); // THEN - expectCDK(stack).toMatch({ + Template.fromStack(stack).templateMatches({ Resources: { Repo02AC86CF: { Type: 'AWS::ECR::Repository', @@ -34,11 +34,11 @@ describe('repository', () => { new ecr.Repository(stack, 'Repo', { imageScanOnPush: true }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { ImageScanningConfiguration: { ScanOnPush: true, }, - })); + }); }); test('tag-based lifecycle policy', () => { @@ -50,12 +50,12 @@ describe('repository', () => { repo.addLifecycleRule({ tagPrefixList: ['abc'], maxImageCount: 1 }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', }, - })); + }); }); test('image tag mutability can be set', () => { @@ -64,9 +64,9 @@ describe('repository', () => { new ecr.Repository(stack, 'Repo', { imageTagMutability: ecr.TagMutability.IMMUTABLE }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { ImageTagMutability: 'IMMUTABLE', - })); + }); }); test('add day-based lifecycle policy', () => { @@ -80,12 +80,12 @@ describe('repository', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"sinceImagePushed","countNumber":5,"countUnit":"days"},"action":{"type":"expire"}}]}', }, - })); + }); }); test('add count-based lifecycle policy', () => { @@ -99,12 +99,12 @@ describe('repository', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, - })); + }); }); test('mixing numbered and unnumbered rules', () => { @@ -117,12 +117,12 @@ describe('repository', () => { repo.addLifecycleRule({ rulePriority: 10, tagStatus: ecr.TagStatus.TAGGED, tagPrefixList: ['b'], maxImageCount: 5 }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["b"],"countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}},{"rulePriority":11,"selection":{"tagStatus":"tagged","tagPrefixList":["a"],"countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, - })); + }); }); test('tagstatus Any is automatically sorted to the back', () => { @@ -135,12 +135,12 @@ describe('repository', () => { repo.addLifecycleRule({ tagStatus: ecr.TagStatus.TAGGED, tagPrefixList: ['important'], maxImageCount: 999 }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"tagged","tagPrefixList":["important"],"countType":"imageCountMoreThan","countNumber":999},"action":{"type":"expire"}},{"rulePriority":2,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, - })); + }); }); test('lifecycle rules can be added upon initialization', () => { @@ -155,12 +155,12 @@ describe('repository', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { 'LifecyclePolicy': { // eslint-disable-next-line max-len 'LifecyclePolicyText': '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":3},"action":{"type":"expire"}}]}', }, - })); + }); }); test('calculate repository URI', () => { @@ -168,21 +168,24 @@ describe('repository', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); - // WHEN - const uri = repo.repositoryUri; + new cdk.CfnOutput(stack, 'RepoUri', { + value: repo.repositoryUri, + }); // THEN const arnSplit = { 'Fn::Split': [':', { 'Fn::GetAtt': ['Repo02AC86CF', 'Arn'] }] }; - expectCDK(stack.resolve(uri)).toMatch({ - 'Fn::Join': ['', [ - { 'Fn::Select': [4, arnSplit] }, - '.dkr.ecr.', - { 'Fn::Select': [3, arnSplit] }, - '.', - { Ref: 'AWS::URLSuffix' }, - '/', - { Ref: 'Repo02AC86CF' }, - ]], + Template.fromStack(stack).hasOutput('*', { + 'Value': { + 'Fn::Join': ['', [ + { 'Fn::Select': [4, arnSplit] }, + '.dkr.ecr.', + { 'Fn::Select': [3, arnSplit] }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/', + { Ref: 'Repo02AC86CF' }, + ]], + }, }); }); @@ -217,10 +220,20 @@ describe('repository', () => { repositoryArn: cdk.Fn.getAtt('Boom', 'Arn').toString(), repositoryName: cdk.Fn.getAtt('Boom', 'Name').toString(), }); + new cdk.CfnOutput(stack, 'RepoArn', { + value: repo.repositoryArn, + }); + new cdk.CfnOutput(stack, 'RepoName', { + value: repo.repositoryName, + }); // THEN - expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::GetAtt': ['Boom', 'Arn'] }); - expectCDK(stack.resolve(repo.repositoryName)).toMatch({ 'Fn::GetAtt': ['Boom', 'Name'] }); + Template.fromStack(stack).hasOutput('*', { + Value: { 'Fn::GetAtt': ['Boom', 'Arn'] }, + }); + Template.fromStack(stack).hasOutput('*', { + Value: { 'Fn::GetAtt': ['Boom', 'Name'] }, + }); }); test('import only with a repository name (arn is deduced)', () => { @@ -229,20 +242,30 @@ describe('repository', () => { // WHEN const repo = ecr.Repository.fromRepositoryName(stack, 'just-name', 'my-repo'); + new cdk.CfnOutput(stack, 'RepoArn', { + value: repo.repositoryArn, + }); + new cdk.CfnOutput(stack, 'RepoName', { + value: repo.repositoryName, + }); // THEN - expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':ecr:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':repository/my-repo', - ]], - }); - expect(stack.resolve(repo.repositoryName)).toBe('my-repo'); + Template.fromStack(stack).hasOutput('*', { + Value: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecr:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':repository/my-repo', + ]], + }, + }); + Template.fromStack(stack).hasOutput('*', { + Value: 'my-repo', + }); }); test('arnForLocalRepository can be used to render an ARN for a local repository', () => { @@ -255,20 +278,30 @@ describe('repository', () => { repositoryArn: ecr.Repository.arnForLocalRepository(repoName, stack), repositoryName: repoName, }); + new cdk.CfnOutput(stack, 'RepoArn', { + value: repo.repositoryArn, + }); + new cdk.CfnOutput(stack, 'RepoName', { + value: repo.repositoryName, + }); // THEN - expectCDK(stack.resolve(repo.repositoryName)).toMatch({ 'Fn::GetAtt': ['Boom', 'Name'] }); - expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':ecr:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':repository/', - { 'Fn::GetAtt': ['Boom', 'Name'] }, - ]], + Template.fromStack(stack).hasOutput('*', { + Value: { 'Fn::GetAtt': ['Boom', 'Name'] }, + }); + Template.fromStack(stack).hasOutput('*', { + Value: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecr:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':repository/', + { 'Fn::GetAtt': ['Boom', 'Name'] }, + ]], + }, }); }); @@ -284,7 +317,7 @@ describe('repository', () => { })); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { RepositoryPolicyText: { Statement: [ { @@ -295,7 +328,7 @@ describe('repository', () => { ], Version: '2012-10-17', }, - })); + }); }); test('fails if repository policy has no actions', () => { @@ -341,7 +374,7 @@ describe('repository', () => { }, }); - expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -360,7 +393,7 @@ describe('repository', () => { }, }, 'State': 'ENABLED', - })); + }); }); test('onImageScanCompleted without imageTags creates the correct event', () => { @@ -373,7 +406,7 @@ describe('repository', () => { }, }); - expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -390,7 +423,7 @@ describe('repository', () => { }, }, 'State': 'ENABLED', - })); + }); }); test('onImageScanCompleted with one imageTag creates the correct event', () => { @@ -404,7 +437,7 @@ describe('repository', () => { }, }); - expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -424,7 +457,7 @@ describe('repository', () => { }, }, 'State': 'ENABLED', - })); + }); }); test('onImageScanCompleted with multiple imageTags creates the correct event', () => { @@ -438,7 +471,7 @@ describe('repository', () => { }, }); - expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -460,7 +493,7 @@ describe('repository', () => { }, }, 'State': 'ENABLED', - })); + }); }); test('removal policy is "Retain" by default', () => { @@ -471,10 +504,10 @@ describe('repository', () => { new ecr.Repository(stack, 'Repo'); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResource('AWS::ECR::Repository', { 'Type': 'AWS::ECR::Repository', 'DeletionPolicy': 'Retain', - }, ResourcePart.CompleteDefinition)); + }); }); test('"Delete" removal policy can be set explicitly', () => { @@ -487,10 +520,10 @@ describe('repository', () => { }); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResource('AWS::ECR::Repository', { 'Type': 'AWS::ECR::Repository', 'DeletionPolicy': 'Delete', - }, ResourcePart.CompleteDefinition)); + }); }); test('grant adds appropriate resource-*', () => { @@ -502,7 +535,7 @@ describe('repository', () => { repo.grantPull(new iam.AnyPrincipal()); // THEN - expectCDK(stack).to(haveResource('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { 'RepositoryPolicyText': { 'Statement': [ { @@ -512,12 +545,12 @@ describe('repository', () => { 'ecr:BatchGetImage', ], 'Effect': 'Allow', - 'Principal': { AWS: '*' }, + 'Principal': { 'AWS': '*' }, }, ], 'Version': '2012-10-17', }, - })); + }); }); }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts index 0857b99ee8cfd..942f13e3439aa 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts @@ -347,7 +347,7 @@ export abstract class NetworkLoadBalancedServiceBase extends CoreConstruct { const loadBalancer = props.loadBalancer ?? new NetworkLoadBalancer(this, 'LB', lbProps); const listenerPort = props.listenerPort ?? 80; const targetProps = { - port: 80, + port: props.taskImageOptions?.containerPort ?? 80, }; this.listener = loadBalancer.addListener('PublicListener', { port: listenerPort }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts index 8eb751b07d13e..677caf8c2df9f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts @@ -374,7 +374,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends CoreConstru protected registerECSTargets(service: BaseService, container: ContainerDefinition, targets: NetworkTargetProps[]): NetworkTargetGroup { for (const targetProps of targets) { const targetGroup = this.findListener(targetProps.listener).addTargets(`ECSTargetGroup${container.containerName}${targetProps.containerPort}`, { - port: 80, + port: targetProps.containerPort ?? 80, targets: [ service.loadBalancerTarget({ containerName: container.containerName, diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index a61d4f4f355e8..8bdbe1e23f377 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -72,7 +72,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-ecs-patterns/test/ec2/l3s-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts index 767c7a13f0df6..322e503a44aaf 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts @@ -1,5 +1,4 @@ -import { SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { MachineImage, Vpc } from '@aws-cdk/aws-ec2'; @@ -44,16 +43,16 @@ describe('When Application Load Balancer', () => { }); // THEN - stack contains a load balancer, a service, and a target group. - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'EC2', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: 'test', LogConfiguration: { LogDriver: 'awslogs', @@ -76,7 +75,7 @@ describe('When Application Load Balancer', () => { Protocol: 'tcp', }, ], - }, + }), ], NetworkMode: 'bridge', RequiresCompatibilities: [ @@ -167,7 +166,7 @@ describe('When Application Load Balancer', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 3, LaunchType: 'EC2', EnableECSManagedTags: true, @@ -192,7 +191,7 @@ describe('When Application Load Balancer', () => { ServiceName: 'myService', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Cpu: 256, @@ -260,7 +259,7 @@ describe('When Application Load Balancer', () => { }, }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 443, Protocol: 'HTTPS', Certificates: [{ @@ -270,26 +269,6 @@ describe('When Application Load Balancer', () => { }); }); - test('set vpc instead of cluster', () => { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack does not contain a LaunchConfiguration - const template = SynthUtils.synthesize(stack, { skipValidation: true }); - expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); - expect(() => SynthUtils.synthesize(stack)).toThrow(); - }); - test('able to pass pre-defined task definition', () => { // GIVEN const stack = new Stack(); @@ -319,7 +298,7 @@ describe('When Application Load Balancer', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -408,8 +387,8 @@ describe('When Application Load Balancer', () => { }); // THEN - const template = SynthUtils.synthesize(stack).template.Outputs; - expect(template).toEqual({ + const outputs = Template.fromStack(stack).findOutputs('*'); + expect(outputs).toEqual({ ServiceLoadBalancerDNSlb175E78BFE: { Value: { 'Fn::GetAtt': [ @@ -596,7 +575,7 @@ describe('When Application Load Balancer', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { ServiceRegistries: [ { ContainerName: 'web', @@ -611,7 +590,7 @@ describe('When Application Load Balancer', () => { ], }); - expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Service', { DnsConfig: { DnsRecords: [ { @@ -926,14 +905,14 @@ describe('When Network Load Balancer', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'EC2', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -1066,7 +1045,7 @@ describe('When Network Load Balancer', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 3, EnableECSManagedTags: true, HealthCheckGracePeriodSeconds: 2, @@ -1092,7 +1071,7 @@ describe('When Network Load Balancer', () => { ServiceName: 'myService', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Cpu: 256, @@ -1161,26 +1140,6 @@ describe('When Network Load Balancer', () => { }); }); - test('set vpc instead of cluster', () => { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack does not contain a LaunchConfiguration - const template = SynthUtils.synthesize(stack, { skipValidation: true }); - expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); - expect(() => SynthUtils.synthesize(stack)).toThrow(); - }); - test('able to pass pre-defined task definition', () => { // GIVEN const stack = new Stack(); @@ -1210,7 +1169,7 @@ describe('When Network Load Balancer', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -1357,7 +1316,7 @@ describe('When Network Load Balancer', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { ServiceRegistries: [ { ContainerName: 'web', @@ -1372,7 +1331,7 @@ describe('When Network Load Balancer', () => { ], }); - expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Service', { DnsConfig: { DnsRecords: [ { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts index c8f29cfbc695c..db4764c1e4d6d 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts @@ -1,5 +1,4 @@ -import { ABSENT, arrayWith, objectLike, SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -42,16 +41,16 @@ test('test ECS loadbalanced construct', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 2, LaunchType: 'EC2', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'TEST_ENVIRONMENT_VARIABLE1', @@ -67,7 +66,7 @@ test('test ECS loadbalanced construct', () => { label1: 'labelValue1', label2: 'labelValue2', }, - }, + }), ], }); }); @@ -96,8 +95,8 @@ test('ApplicationLoadBalancedEc2Service desiredCount can be undefined when featu }, }); - expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + DesiredCount: Match.absent(), }); }); @@ -117,8 +116,8 @@ test('ApplicationLoadBalancedFargateService desiredCount can be undefined when f }, }); - expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + DesiredCount: Match.absent(), }); }); @@ -146,8 +145,8 @@ test('NetworkLoadBalancedEc2Service desiredCount can be undefined when feature f }, }); - expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + DesiredCount: Match.absent(), }); }); @@ -167,36 +166,11 @@ test('NetworkLoadBalancedFargateService desiredCount can be undefined when featu }, }); - expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + DesiredCount: Match.absent(), }); }); -test('set vpc instead of cluster', () => { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack does not contain a LaunchConfiguration\ - const template = SynthUtils.synthesize(stack, { skipValidation: true }); - expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); - expect(() => SynthUtils.synthesize(stack)).toThrow(); -}); - test('setting vpc and cluster throws error', () => { // GIVEN const stack = new cdk.Stack(); @@ -236,13 +210,13 @@ test('test ECS loadbalanced construct with memoryReservationMiB', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ MemoryReservation: 1024, - }, + }), ], }); }); @@ -279,7 +253,7 @@ test('creates AWS Cloud Map service for Private DNS namespace with application l }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { ServiceRegistries: [ { ContainerName: 'web', @@ -294,7 +268,7 @@ test('creates AWS Cloud Map service for Private DNS namespace with application l ], }); - expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Service', { DnsConfig: { DnsRecords: [ { @@ -355,7 +329,7 @@ test('creates AWS Cloud Map service for Private DNS namespace with network load }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { ServiceRegistries: [ { RegistryArn: { @@ -368,7 +342,7 @@ test('creates AWS Cloud Map service for Private DNS namespace with network load ], }); - expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Service', { DnsConfig: { DnsRecords: [ { @@ -418,10 +392,10 @@ test('test Fargate loadbalanced construct', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'TEST_ENVIRONMENT_VARIABLE1', @@ -444,16 +418,16 @@ test('test Fargate loadbalanced construct', () => { label1: 'labelValue1', label2: 'labelValue2', }, - }, + }), ], }); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 2, LaunchType: 'FARGATE', }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 80, Protocol: 'HTTP', }); @@ -480,9 +454,9 @@ test('test Fargate loadbalanced construct opting out of log driver creation', () }); // THEN - stack contains a load balancer and a service - expect(stack).not.toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'TEST_ENVIRONMENT_VARIABLE1', @@ -493,15 +467,8 @@ test('test Fargate loadbalanced construct opting out of log driver creation', () Value: 'test environment variable 2 value', }, ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, + LogConfiguration: Match.absent(), + }), ], }); }); @@ -526,9 +493,9 @@ test('test Fargate loadbalanced construct with TLS', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 443, Protocol: 'HTTPS', Certificates: [{ @@ -537,7 +504,7 @@ test('test Fargate loadbalanced construct with TLS', () => { SslPolicy: SslPolicy.TLS12_EXT, }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'HTTP', TargetType: 'ip', @@ -546,12 +513,12 @@ test('test Fargate loadbalanced construct with TLS', () => { }, }); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'api.example.com.', HostedZoneId: { Ref: 'HostedZoneDB99F866', @@ -583,7 +550,7 @@ test('test Fargateloadbalanced construct with TLS and default certificate', () = }); // THEN - stack contains a load balancer, a service, and a certificate - expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: 'api.example.com', DomainValidationOptions: [ { @@ -596,9 +563,9 @@ test('test Fargateloadbalanced construct with TLS and default certificate', () = ValidationMethod: 'DNS', }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 443, Protocol: 'HTTPS', Certificates: [{ @@ -608,12 +575,12 @@ test('test Fargateloadbalanced construct with TLS and default certificate', () = }], }); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'api.example.com.', HostedZoneId: { Ref: 'HostedZoneDB99F866', @@ -744,9 +711,9 @@ test('test Fargate loadbalanced construct with optional log driver input', () => }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'TEST_ENVIRONMENT_VARIABLE1', @@ -765,7 +732,7 @@ test('test Fargate loadbalanced construct with optional log driver input', () => 'awslogs-region': { Ref: 'AWS::Region' }, }, }, - }, + }), ], }); }); @@ -791,9 +758,9 @@ test('test Fargate loadbalanced construct with logging enabled', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'TEST_ENVIRONMENT_VARIABLE1', @@ -812,7 +779,7 @@ test('test Fargate loadbalanced construct with logging enabled', () => { 'awslogs-region': { Ref: 'AWS::Region' }, }, }, - }, + }), ], }); }); @@ -868,9 +835,9 @@ test('test Fargate application loadbalanced construct with taskDefinition provid memoryLimitMiB: 1024, }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: 'amazon/amazon-ecs-sample', Memory: 512, Name: 'passedTaskDef', @@ -880,7 +847,7 @@ test('test Fargate application loadbalanced construct with taskDefinition provid Protocol: 'tcp', }, ], - }, + }), ], }); }); @@ -954,7 +921,7 @@ test('ALBFargate - having *HealthyPercent properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { MinimumHealthyPercent: 100, MaximumPercent: 200, @@ -981,7 +948,7 @@ test('NLBFargate - having *HealthyPercent properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { MinimumHealthyPercent: 100, MaximumPercent: 200, @@ -1015,7 +982,7 @@ test('ALB - having *HealthyPercent properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { MinimumHealthyPercent: 100, MaximumPercent: 200, @@ -1052,7 +1019,7 @@ test('ALB - includes provided protocol version properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { ProtocolVersion: 'GRPC', }); }); @@ -1083,7 +1050,7 @@ test('NLB - having *HealthyPercent properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { MinimumHealthyPercent: 100, MaximumPercent: 200, @@ -1117,7 +1084,7 @@ test('ALB - having deployment controller', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentController: { Type: 'CODE_DEPLOY', }, @@ -1150,7 +1117,7 @@ test('NLB - having deployment controller', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentController: { Type: 'CODE_DEPLOY', }, @@ -1181,7 +1148,7 @@ test('ALB with circuit breaker', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { DeploymentCircuitBreaker: { Enable: true, @@ -1218,7 +1185,7 @@ test('NLB with circuit breaker', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { DeploymentCircuitBreaker: { Enable: true, @@ -1259,10 +1226,10 @@ test('NetworkLoadbalancedEC2Service accepts previously created load balancer', ( }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'EC2', }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Type: 'network', }); }); @@ -1302,12 +1269,12 @@ test('NetworkLoadBalancedEC2Service accepts imported load balancer', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'EC2', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + LoadBalancers: [Match.objectLike({ ContainerName: 'Container', ContainerPort: 80 })], }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::TargetGroup', 1); + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { LoadBalancerArn: nlb.loadBalancerArn, Port: 80, }); @@ -1345,10 +1312,10 @@ test('ApplicationLoadBalancedEC2Service accepts previously created load balancer }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'EC2', }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Type: 'application', }); }); @@ -1388,12 +1355,12 @@ test('ApplicationLoadBalancedEC2Service accepts imported load balancer', () => { taskDefinition: taskDef, }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'EC2', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + LoadBalancers: [Match.objectLike({ ContainerName: 'Container', ContainerPort: 80 })], }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::TargetGroup', 1); + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { LoadBalancerArn: alb.loadBalancerArn, Port: 80, }); @@ -1422,13 +1389,13 @@ test('test ECS loadbalanced construct default/open security group', () => { }); // THEN - Stack contains no ingress security group rules - expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroup', { - SecurityGroupIngress: [{ + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: [Match.objectLike({ CidrIp: '0.0.0.0/0', FromPort: 80, IpProtocol: 'tcp', ToPort: 80, - }], + })], }); }); @@ -1461,7 +1428,7 @@ test('test ECS loadbalanced construct closed security group', () => { }); // THEN - Stack contains no ingress security group rules - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroup', { - SecurityGroupIngress: arrayWith(objectLike({})), + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts index 9a64cfd40428e..e5b68caa55761 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts @@ -1,5 +1,4 @@ -import { ABSENT } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import { MachineImage } from '@aws-cdk/aws-ec2'; @@ -33,12 +32,12 @@ test('test ECS queue worker service construct - with only required props', () => }); // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'EC2', }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { RedrivePolicy: { deadLetterTargetArn: { 'Fn::GetAtt': [ @@ -50,13 +49,13 @@ test('test ECS queue worker service construct - with only required props', () => }, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { MessageRetentionPeriod: 1209600, }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'QUEUE_NAME', @@ -83,7 +82,7 @@ test('test ECS queue worker service construct - with only required props', () => Essential: true, Image: 'test', Memory: 512, - }, + }), ], Family: 'ServiceQueueProcessingTaskDef83DB34F1', }); @@ -112,8 +111,8 @@ test('test ECS queue worker service construct - with remove default desiredCount }); // THEN - QueueWorker is of EC2 launch type, and desiredCount is not defined on the Ec2Service. - expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + DesiredCount: Match.absent(), LaunchType: 'EC2', }); }); @@ -142,12 +141,12 @@ test('test ECS queue worker service construct - with optional props for queues', }); // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'EC2', }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { RedrivePolicy: { deadLetterTargetArn: { 'Fn::GetAtt': [ @@ -160,13 +159,13 @@ test('test ECS queue worker service construct - with optional props for queues', VisibilityTimeout: 300, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { MessageRetentionPeriod: 604800, }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'QUEUE_NAME', @@ -193,7 +192,7 @@ test('test ECS queue worker service construct - with optional props for queues', Essential: true, Image: 'test', Memory: 512, - }, + }), ], Family: 'ServiceQueueProcessingTaskDef83DB34F1', }); @@ -238,7 +237,7 @@ testDeprecated('test ECS queue worker service construct - with optional props', }); // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 2, DeploymentConfiguration: { MinimumHealthyPercent: 60, @@ -255,13 +254,13 @@ testDeprecated('test ECS queue worker service construct - with optional props', }, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { QueueName: 'ecs-test-sqs-queue', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Command: [ '-c', '4', @@ -294,7 +293,7 @@ testDeprecated('test ECS queue worker service construct - with optional props', Value: '256', }, ], - }, + }), ], Family: 'ecs-task-family', }); @@ -323,7 +322,7 @@ testDeprecated('can set desiredTaskCount to 0', () => { }); // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 0, LaunchType: 'EC2', }); @@ -375,11 +374,11 @@ test('can set custom containerName', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Name: 'my-container', - }, + }), ], }); }); @@ -412,8 +411,8 @@ test('can set capacity provider strategies', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { - LaunchType: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + LaunchType: Match.absent(), CapacityProviderStrategy: [ { CapacityProvider: { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts index 9524d7a4d145c..71d48850d3b0d 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import { MachineImage } from '@aws-cdk/aws-ec2'; @@ -32,7 +32,7 @@ test('Can create a scheduled Ec2 Task - with only required props', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { State: 'ENABLED', Targets: [ { @@ -48,7 +48,7 @@ test('Can create a scheduled Ec2 Task - with only required props', () => { ], }); - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -101,7 +101,7 @@ test('Can create a scheduled Ec2 Task - with optional props', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Name: 'sample-scheduled-task-rule', State: 'DISABLED', Targets: [ @@ -118,7 +118,7 @@ test('Can create a scheduled Ec2 Task - with optional props', () => { ], }); - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Cpu: 2, @@ -169,7 +169,7 @@ test('Scheduled ECS Task - with securityGroups defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -225,7 +225,7 @@ test('Scheduled Ec2 Task - with MemoryReservation defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -273,7 +273,7 @@ test('Scheduled Ec2 Task - with Command defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Command: [ diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json index 643ff38905d69..91413b0f0fd6f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json @@ -458,7 +458,7 @@ "myServicelb2listener2ECSTargetGroupweb90Group6841F924": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties": { - "Port": 80, + "Port": 90, "Protocol": "TCP", "TargetType": "ip", "VpcId": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json index 91c1f4e575e23..1af60f7eaf55c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json @@ -404,7 +404,7 @@ "FargateNlbServiceLBPublicListenerECSGroup7501571D": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties": { - "Port": 80, + "Port": 2015, "Protocol": "TCP", "TargetType": "ip", "VpcId": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts index 902d5412ee8bf..b196f4b0616b1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts @@ -1,9 +1,10 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { Vpc } from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; +import { ContainerImage } from '@aws-cdk/aws-ecs'; import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { Duration, Stack } from '@aws-cdk/core'; -import { ApplicationMultipleTargetGroupsFargateService, NetworkMultipleTargetGroupsFargateService, ApplicationLoadBalancedFargateService } from '../../lib'; +import { ApplicationLoadBalancedFargateService, ApplicationMultipleTargetGroupsFargateService, NetworkLoadBalancedFargateService, NetworkMultipleTargetGroupsFargateService } from '../../lib'; describe('When Application Load Balancer', () => { test('test Fargate loadbalanced construct with default settings', () => { @@ -21,9 +22,9 @@ describe('When Application Load Balancer', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', LoadBalancers: [ @@ -37,9 +38,9 @@ describe('When Application Load Balancer', () => { ], }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: 'test', LogConfiguration: { LogDriver: 'awslogs', @@ -60,7 +61,7 @@ describe('When Application Load Balancer', () => { Protocol: 'tcp', }, ], - }, + }), ], Cpu: '256', ExecutionRoleArn: { @@ -135,7 +136,7 @@ describe('When Application Load Balancer', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 3, EnableECSManagedTags: true, HealthCheckGracePeriodSeconds: 2, @@ -182,7 +183,7 @@ describe('When Application Load Balancer', () => { ServiceName: 'myService', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Environment: [ @@ -314,11 +315,11 @@ describe('When Application Load Balancer', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Name: 'alb-test-load-balancer', }); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', LoadBalancers: [ @@ -332,9 +333,9 @@ describe('When Application Load Balancer', () => { ], }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: 'test', LogConfiguration: { LogDriver: 'awslogs', @@ -355,7 +356,7 @@ describe('When Application Load Balancer', () => { Protocol: 'tcp', }, ], - }, + }), ], Cpu: '256', ExecutionRoleArn: { @@ -390,9 +391,9 @@ describe('When Network Load Balancer', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::LoadBalancer', 1); - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', LoadBalancers: [ @@ -406,9 +407,9 @@ describe('When Network Load Balancer', () => { ], }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: 'test', LogConfiguration: { LogDriver: 'awslogs', @@ -429,7 +430,7 @@ describe('When Network Load Balancer', () => { Protocol: 'tcp', }, ], - }, + }), ], Cpu: '256', ExecutionRoleArn: { @@ -500,7 +501,7 @@ describe('When Network Load Balancer', () => { }); // THEN - stack contains a load balancer and a service - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 3, EnableECSManagedTags: true, HealthCheckGracePeriodSeconds: 2, @@ -546,7 +547,7 @@ describe('When Network Load Balancer', () => { ServiceName: 'myService', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Environment: [ @@ -661,4 +662,75 @@ describe('When Network Load Balancer', () => { }); }).toThrow(/You must specify one of: taskDefinition or image/); }); + + test('test Fargate networkloadbalanced construct with custom Port', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + new NetworkLoadBalancedFargateService(stack, 'NLBService', { + cluster: cluster, + memoryLimitMiB: 1024, + cpu: 512, + taskImageOptions: { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + containerPort: 81, + }, + listenerPort: 8181, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 81, + Protocol: 'TCP', + TargetType: 'ip', + VpcId: { + Ref: 'VPCB9E5F0B4', + }, + }); + }); + + test('test Fargate multinetworkloadbalanced construct with custom Port', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + + new NetworkMultipleTargetGroupsFargateService(stack, 'NLBService', { + cluster: cluster, + memoryLimitMiB: 1024, + cpu: 512, + taskImageOptions: { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + loadBalancers: [ + { + name: 'lb1', + listeners: [ + { name: 'listener1', port: 8181 }, + ], + }, + ], + targetGroups: [{ + containerPort: 81, + }], + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 81, + Protocol: 'TCP', + TargetType: 'ip', + VpcId: { + Ref: 'VPCB9E5F0B4', + }, + }); + }); }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts index 0f4c0ab29ba86..70763a1bc2277 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts @@ -1,5 +1,4 @@ -import { SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -27,7 +26,7 @@ test('setting loadBalancerType to Network creates an NLB Public', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Type: 'network', Scheme: 'internet-facing', }); @@ -49,7 +48,7 @@ test('setting loadBalancerType to Network and publicLoadBalancer to false create }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Type: 'network', Scheme: 'internal', }); @@ -95,8 +94,9 @@ test('setting executionRole updated taskDefinition with given execution role', ( }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - expect(serviceTaskDefinition.Properties.ExecutionRoleArn).toEqual({ 'Fn::GetAtt': ['ExecutionRole605A040B', 'Arn'] }); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { + ExecutionRoleArn: { 'Fn::GetAtt': ['ExecutionRole605A040B', 'Arn'] }, + }); }); test('setting taskRole updated taskDefinition with given task role', () => { @@ -122,8 +122,9 @@ test('setting taskRole updated taskDefinition with given task role', () => { }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - expect(serviceTaskDefinition.Properties.TaskRoleArn).toEqual({ 'Fn::GetAtt': ['taskRoleTest9DA66B6E', 'Arn'] }); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { + TaskRoleArn: { 'Fn::GetAtt': ['taskRoleTest9DA66B6E', 'Arn'] }, + }); }); test('setting containerName updates container name with given name', () => { @@ -142,8 +143,13 @@ test('setting containerName updates container name with given name', () => { }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - expect(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name).toEqual('bob'); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + Match.objectLike({ + Name: 'bob', + }), + ], + }); }); test('not setting containerName updates container name with default', () => { @@ -161,8 +167,13 @@ test('not setting containerName updates container name with default', () => { }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - expect(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name).toEqual('web'); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + Match.objectLike({ + Name: 'web', + }), + ], + }); }); test('setting servicename updates service name with given name', () => { @@ -180,8 +191,9 @@ test('setting servicename updates service name with given name', () => { serviceName: 'bob', }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - expect(serviceTaskDefinition.Properties.ServiceName).toEqual('bob'); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceName: 'bob', + }); }); test('not setting servicename updates service name with default', () => { @@ -199,8 +211,9 @@ test('not setting servicename updates service name with default', () => { }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - expect(serviceTaskDefinition.Properties.ServiceName).toBeUndefined(); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + ServiceName: Match.absent(), + }); }); test('setting healthCheckGracePeriod works', () => { @@ -215,8 +228,9 @@ test('setting healthCheckGracePeriod works', () => { healthCheckGracePeriod: cdk.Duration.seconds(600), }); // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - expect(serviceTaskDefinition.Properties.HealthCheckGracePeriodSeconds).toEqual(600); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + HealthCheckGracePeriodSeconds: 600, + }); }); test('selecting correct vpcSubnets', () => { @@ -248,7 +262,7 @@ test('selecting correct vpcSubnets', () => { }, }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { NetworkConfiguration: { AwsvpcConfiguration: { Subnets: [ @@ -275,7 +289,7 @@ test('target group uses HTTP/80 as default', () => { }, }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'HTTP', }); @@ -293,7 +307,7 @@ test('target group uses HTTPS/443 when configured', () => { targetProtocol: ApplicationProtocol.HTTPS, }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 443, Protocol: 'HTTPS', }); @@ -311,7 +325,7 @@ test('setting platform version', () => { platformVersion: ecs.FargatePlatformVersion.VERSION1_4, }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, }); }); @@ -347,15 +361,15 @@ test('test load balanced service with family defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 2, LaunchType: 'FARGATE', ServiceName: 'fargate-test-service', }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'TEST_ENVIRONMENT_VARIABLE1', @@ -367,7 +381,7 @@ test('test load balanced service with family defined', () => { }, ], Image: '/aws/aws-example-app', - }, + }), ], Family: 'fargate-task-family', }); @@ -388,7 +402,7 @@ test('setting ALB deployment controller', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentController: { Type: 'CODE_DEPLOY', }, @@ -410,7 +424,7 @@ test('setting NLB deployment controller', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentController: { Type: 'CODE_DEPLOY', }, @@ -430,7 +444,7 @@ test('setting ALB circuitBreaker works', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { DeploymentCircuitBreaker: { Enable: true, @@ -456,7 +470,7 @@ test('setting NLB circuitBreaker works', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { DeploymentCircuitBreaker: { Enable: true, @@ -486,11 +500,11 @@ test('setting NLB special listener port to create the listener', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ - { + Match.objectLike({ Type: 'forward', - }, + }), ], Port: 2015, Protocol: 'TCP', @@ -514,11 +528,11 @@ test('setting ALB special listener port to create the listener', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ - { + Match.objectLike({ Type: 'forward', - }, + }), ], Port: 2015, Protocol: 'HTTP', @@ -547,11 +561,11 @@ test('setting ALB HTTPS protocol to create the listener on 443', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ - { + Match.objectLike({ Type: 'forward', - }, + }), ], Port: 443, Protocol: 'HTTPS', @@ -580,7 +594,7 @@ test('setting ALB HTTPS correctly sets the recordset name', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'test.domain.com.', }); }); @@ -608,7 +622,7 @@ test('setting ALB cname option correctly sets the recordset type', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'test.domain.com.', Type: 'CNAME', }); @@ -637,7 +651,7 @@ test('setting ALB record type to NONE correctly omits the recordset', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::Route53::RecordSet'); + Template.fromStack(stack).resourceCountIs('AWS::Route53::RecordSet', 0); }); @@ -663,7 +677,7 @@ test('setting NLB cname option correctly sets the recordset type', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'test.domain.com.', Type: 'CNAME', }); @@ -691,7 +705,7 @@ test('setting NLB record type to NONE correctly omits the recordset', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::Route53::RecordSet'); + Template.fromStack(stack).resourceCountIs('AWS::Route53::RecordSet', 0); }); test('setting ALB HTTP protocol to create the listener on 80', () => { @@ -711,11 +725,11 @@ test('setting ALB HTTP protocol to create the listener on 80', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ - { + Match.objectLike({ Type: 'forward', - }, + }), ], Port: 80, Protocol: 'HTTP', @@ -738,11 +752,11 @@ test('setting ALB without any protocol or listenerPort to create the listener on }); // THEN - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ - { + Match.objectLike({ Type: 'forward', - }, + }), ], Port: 80, Protocol: 'HTTP', @@ -765,11 +779,11 @@ test('passing in existing network load balancer to NLB Fargate Service', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Type: 'network', }); }); @@ -813,14 +827,14 @@ test('passing in imported network load balancer and resources to NLB Fargate ser }); // THEN - expect(stack2).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack2).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', - LoadBalancers: [{ ContainerName: 'myContainer', ContainerPort: 80 }], + LoadBalancers: [Match.objectLike({ ContainerName: 'myContainer', ContainerPort: 80 })], }); - expect(stack2).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + Template.fromStack(stack2).resourceCountIs('AWS::ElasticLoadBalancingV2::TargetGroup', 1); - expect(stack2).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack2).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { LoadBalancerArn: nlb2.loadBalancerArn, Port: 80, }); @@ -845,11 +859,11 @@ test('passing in previously created application load balancer to ALB Fargate Ser }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', }); - expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Type: 'application', }); }); @@ -890,14 +904,14 @@ test('passing in imported application load balancer and resources to ALB Fargate }); // THEN - expect(stack1).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack1).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + LoadBalancers: [Match.objectLike({ ContainerName: 'Container', ContainerPort: 80 })], }); - expect(stack1).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + Template.fromStack(stack1).resourceCountIs('AWS::ElasticLoadBalancingV2::TargetGroup', 1); - expect(stack1).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack1).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { LoadBalancerArn: alb.loadBalancerArn, Port: 80, }); @@ -925,11 +939,11 @@ test('passing in previously created security groups to ALB Fargate Service', () }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Example', GroupName: 'Rolly', SecurityGroupEgress: [ @@ -973,9 +987,7 @@ test('domainName and domainZone not required for HTTPS listener with provided ce }); // THEN - expect(stack).not.toHaveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - }); + Template.fromStack(stack).resourceCountIs('AWS::Route53::RecordSet', 0); }); test('test ALB load balanced service with docker labels defined', () => { @@ -994,15 +1006,15 @@ test('test ALB load balanced service with docker labels defined', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: '/aws/aws-example-app', DockerLabels: { label1: 'labelValue1', label2: 'labelValue2', }, - }, + }), ], }); }); @@ -1023,15 +1035,15 @@ test('test Network load balanced service with docker labels defined', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Image: '/aws/aws-example-app', DockerLabels: { label1: 'labelValue1', label2: 'labelValue2', }, - }, + }), ], }); }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts index 6f91b633d1249..b6ca462f52a2b 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts @@ -1,5 +1,4 @@ -import { ABSENT } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; import { MachineImage } from '@aws-cdk/aws-ec2'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -32,12 +31,12 @@ test('test fargate queue worker service construct - with only required props', ( }); // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { RedrivePolicy: { deadLetterTargetArn: { 'Fn::GetAtt': [ @@ -49,11 +48,11 @@ test('test fargate queue worker service construct - with only required props', ( }, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { MessageRetentionPeriod: 1209600, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -77,9 +76,9 @@ test('test fargate queue worker service construct - with only required props', ( }, }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'QUEUE_NAME', @@ -104,7 +103,7 @@ test('test fargate queue worker service construct - with only required props', ( }, }, Image: 'test', - }, + }), ], Family: 'ServiceQueueProcessingTaskDef83DB34F1', }); @@ -126,8 +125,8 @@ test('test fargate queue worker service construct - with remove default desiredC }); // THEN - QueueWorker is of FARGATE launch type, and desiredCount is not defined on the FargateService. - expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + DesiredCount: Match.absent(), LaunchType: 'FARGATE', }); }); @@ -156,12 +155,12 @@ test('test fargate queue worker service construct - with optional props for queu }); // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 1, LaunchType: 'FARGATE', }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { RedrivePolicy: { deadLetterTargetArn: { 'Fn::GetAtt': [ @@ -174,11 +173,11 @@ test('test fargate queue worker service construct - with optional props for queu VisibilityTimeout: 300, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { MessageRetentionPeriod: 604800, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -202,9 +201,9 @@ test('test fargate queue worker service construct - with optional props for queu }, }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Environment: [ { Name: 'QUEUE_NAME', @@ -229,7 +228,7 @@ test('test fargate queue worker service construct - with optional props for queu }, }, Image: 'test', - }, + }), ], Family: 'ServiceQueueProcessingTaskDef83DB34F1', }); @@ -276,7 +275,7 @@ test('test Fargate queue worker service construct - without desiredCount specifi }); // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DeploymentConfiguration: { MinimumHealthyPercent: 60, MaximumPercent: 150, @@ -289,16 +288,16 @@ test('test Fargate queue worker service construct - without desiredCount specifi }, }); - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { MaxCapacity: 5, MinCapacity: 2, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Command: [ '-c', '4', @@ -324,7 +323,7 @@ test('test Fargate queue worker service construct - without desiredCount specifi }, ], Image: 'test', - }, + }), ], Family: 'fargate-task-family', }); @@ -369,7 +368,7 @@ testDeprecated('test Fargate queue worker service construct - with optional prop }); // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { DesiredCount: 2, DeploymentConfiguration: { MinimumHealthyPercent: 60, @@ -387,11 +386,11 @@ testDeprecated('test Fargate queue worker service construct - with optional prop }, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Command: [ '-c', '4', @@ -417,7 +416,7 @@ testDeprecated('test Fargate queue worker service construct - with optional prop }, ], Image: 'test', - }, + }), ], Family: 'fargate-task-family', }); @@ -443,11 +442,11 @@ test('can set custom containerName', () => { image: ecs.ContainerImage.fromRegistry('test'), }); - expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ - { + Match.objectLike({ Name: 'my-container', - }, + }), ], }); }); @@ -482,7 +481,7 @@ test('can set custom networking options', () => { }); // THEN - NetworkConfiguration is created with the specific security groups and selected subnets - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', NetworkConfiguration: { AwsvpcConfiguration: { @@ -521,7 +520,7 @@ test('can set use public IP', () => { }); // THEN - The Subnets defaults to Public and AssignPublicIp settings change to ENABLED - expect(stack).toHaveResource('AWS::ECS::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { LaunchType: 'FARGATE', NetworkConfiguration: { AwsvpcConfiguration: { @@ -573,8 +572,8 @@ test('can set capacity provider strategies', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::Service', { - LaunchType: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + LaunchType: Match.absent(), CapacityProviderStrategy: [ { CapacityProvider: 'FARGATE_SPOT', diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts index 5d37bba01af2f..696a413ad2def 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; @@ -21,7 +21,7 @@ test('Can create a scheduled Fargate Task - with only required props', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { State: 'ENABLED', Targets: [ { @@ -56,7 +56,7 @@ test('Can create a scheduled Fargate Task - with only required props', () => { ], }); - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -100,7 +100,7 @@ test('Can create a scheduled Fargate Task - with optional props', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Name: 'sample-scheduled-task-rule', State: 'DISABLED', Targets: [ @@ -136,7 +136,7 @@ test('Can create a scheduled Fargate Task - with optional props', () => { ], }); - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Environment: [ @@ -180,7 +180,7 @@ test('Scheduled Fargate Task - with MemoryReservation defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -219,7 +219,7 @@ test('Scheduled Fargate Task - with Command defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Command: [ @@ -268,22 +268,22 @@ test('Scheduled Fargate Task - with subnetSelection defined', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ - { - EcsParameters: { + Match.objectLike({ + EcsParameters: Match.objectLike({ NetworkConfiguration: { - AwsVpcConfiguration: { + AwsVpcConfiguration: Match.objectLike({ AssignPublicIp: 'ENABLED', Subnets: [ { Ref: 'VpcPublicSubnet1Subnet5C2D37C4', }, ], - }, + }), }, - }, - }, + }), + }), ], }); }); @@ -305,7 +305,7 @@ test('Scheduled Fargate Task - with platformVersion defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -359,7 +359,7 @@ test('Scheduled Fargate Task - with securityGroups defined', () => { }); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index 1809000064f12..34eb1dc409975 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -470,7 +470,7 @@ export abstract class BaseService extends Resource resources: ['*'], })); - const logGroupArn = logConfiguration?.cloudWatchLogGroup ? `arn:aws:logs:${this.stack.region}:${this.stack.account}:log-group:${logConfiguration.cloudWatchLogGroup.logGroupName}:*` : '*'; + const logGroupArn = logConfiguration?.cloudWatchLogGroup ? `arn:${this.stack.partition}:logs:${this.stack.region}:${this.stack.account}:log-group:${logConfiguration.cloudWatchLogGroup.logGroupName}:*` : '*'; this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({ actions: [ 'logs:CreateLogStream', @@ -491,14 +491,14 @@ export abstract class BaseService extends Resource actions: [ 's3:PutObject', ], - resources: [`arn:aws:s3:::${logConfiguration.s3Bucket.bucketName}/*`], + resources: [`arn:${this.stack.partition}:s3:::${logConfiguration.s3Bucket.bucketName}/*`], })); if (logConfiguration.s3EncryptionEnabled) { this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({ actions: [ 's3:GetEncryptionConfiguration', ], - resources: [`arn:aws:s3:::${logConfiguration.s3Bucket.bucketName}`], + resources: [`arn:${this.stack.partition}:s3:::${logConfiguration.s3Bucket.bucketName}`], })); } } @@ -518,7 +518,7 @@ export abstract class BaseService extends Resource 'kms:*', ], resources: ['*'], - principals: [new iam.ArnPrincipal(`arn:aws:iam::${this.stack.account}:root`)], + principals: [new iam.ArnPrincipal(`arn:${this.stack.partition}:iam::${this.stack.account}:root`)], })); if (logging === ExecuteCommandLogging.DEFAULT || this.cluster.executeCommandConfiguration?.logConfiguration?.cloudWatchEncryptionEnabled) { @@ -533,7 +533,7 @@ export abstract class BaseService extends Resource resources: ['*'], principals: [new iam.ServicePrincipal(`logs.${this.stack.region}.amazonaws.com`)], conditions: { - ArnLike: { 'kms:EncryptionContext:aws:logs:arn': `arn:aws:logs:${this.stack.region}:${this.stack.account}:*` }, + ArnLike: { 'kms:EncryptionContext:aws:logs:arn': `arn:${this.stack.partition}:logs:${this.stack.region}:${this.stack.account}:*` }, }, })); } diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index 6dd3fd0dbbe40..e7a6d72b8ceb7 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -685,7 +685,7 @@ export class ContainerDefinition extends CoreConstruct { workingDirectory: this.props.workingDirectory, logConfiguration: this.logDriverConfig, environment: this.environment && Object.keys(this.environment).length ? renderKV(this.environment, 'name', 'value') : undefined, - environmentFiles: this.environmentFiles && renderEnvironmentFiles(this.environmentFiles), + environmentFiles: this.environmentFiles && renderEnvironmentFiles(cdk.Stack.of(this).partition, this.environmentFiles), secrets: this.secrets, extraHosts: this.props.extraHosts && renderKV(this.props.extraHosts, 'hostname', 'ipAddress'), healthCheck: this.props.healthCheck && renderHealthCheck(this.props.healthCheck), @@ -757,7 +757,7 @@ function renderKV(env: { [key: string]: string }, keyName: string, valueName: st return ret; } -function renderEnvironmentFiles(environmentFiles: EnvironmentFileConfig[]): any[] { +function renderEnvironmentFiles(partition: string, environmentFiles: EnvironmentFileConfig[]): any[] { const ret = []; for (const environmentFile of environmentFiles) { const s3Location = environmentFile.s3Location; @@ -768,7 +768,7 @@ function renderEnvironmentFiles(environmentFiles: EnvironmentFileConfig[]): any[ ret.push({ type: environmentFile.fileType, - value: `arn:aws:s3:::${s3Location.bucketName}/${s3Location.objectKey}`, + value: `arn:${partition}:s3:::${s3Location.bucketName}/${s3Location.objectKey}`, }); } return ret; diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index 47ee57b4625d6..a433e0049d83e 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -131,7 +131,11 @@ describe('container definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'AssetParameters872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724dS3Bucket7B2069B7', }, @@ -840,7 +844,11 @@ describe('container definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'AssetParameters872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724dS3Bucket7B2069B7', }, @@ -905,7 +913,11 @@ describe('container definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'Bucket83908E77', }, @@ -943,7 +955,11 @@ describe('container definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'AssetParameters872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724dS3Bucket7B2069B7', }, @@ -1008,7 +1024,11 @@ describe('container definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'Bucket83908E77', }, diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index 85c5d68568b22..61dc1dc3c1c8a 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -259,7 +259,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, @@ -288,7 +292,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'ExecBucket29559356', }, @@ -392,7 +400,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, @@ -421,7 +433,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'EcsExecBucket4F468651', }, @@ -491,7 +507,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:iam::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', { Ref: 'AWS::AccountId', }, @@ -598,7 +618,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, @@ -627,7 +651,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'EcsExecBucket4F468651', }, @@ -643,7 +671,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'EcsExecBucket4F468651', }, @@ -712,7 +744,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:iam::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', { Ref: 'AWS::AccountId', }, @@ -737,7 +773,11 @@ describe('ec2 service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index 27e10173bbfec..eeb20435d2cab 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -323,7 +323,11 @@ describe('ec2 task definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'AssetParameters872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724dS3Bucket7B2069B7', }, diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index 2f4e3c8498ea6..824783dc8c597 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -120,7 +120,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709S3Bucket2C6C817C" + "Ref": "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3Bucket09A62232" }, "S3Key": { "Fn::Join": [ @@ -133,7 +133,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709S3VersionKeyFA215BD6" + "Ref": "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3VersionKeyA28118BE" } ] } @@ -146,7 +146,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709S3VersionKeyFA215BD6" + "Ref": "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3VersionKeyA28118BE" } ] } @@ -940,6 +940,17 @@ } } }, + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" + } + ] + } + }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B": { "Type": "AWS::IAM::Role", "Properties": { @@ -986,17 +997,6 @@ ] } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup" - } - ] - } - }, "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookFFA63029": { "Type": "AWS::AutoScaling::LifecycleHook", "Properties": { @@ -1085,7 +1085,11 @@ "Fn::Join": [ "", [ - "arn:aws:s3:::", + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", { "Ref": "AssetParameters872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724dS3Bucket7B2069B7" }, @@ -1126,7 +1130,11 @@ "Fn::Join": [ "", [ - "arn:aws:s3:::", + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", { "Ref": "Bucket83908E77" }, @@ -1388,7 +1396,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4cS3Bucket1BE31DB0" + "Ref": "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3BucketB3DDCC13" }, "S3Key": { "Fn::Join": [ @@ -1401,7 +1409,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4cS3VersionKeyDC38E49C" + "Ref": "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3VersionKey3418DF70" } ] } @@ -1414,7 +1422,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4cS3VersionKeyDC38E49C" + "Ref": "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3VersionKey3418DF70" } ] } @@ -1501,17 +1509,17 @@ } }, "Parameters": { - "AssetParameters84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709S3Bucket2C6C817C": { + "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3Bucket09A62232": { "Type": "String", - "Description": "S3 bucket for asset \"84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709\"" + "Description": "S3 bucket for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709S3VersionKeyFA215BD6": { + "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824S3VersionKeyA28118BE": { "Type": "String", - "Description": "S3 key for asset version \"84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709\"" + "Description": "S3 key for asset version \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, - "AssetParameters84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709ArtifactHash17D48178": { + "AssetParametersbe270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824ArtifactHash76F8FCF2": { "Type": "String", - "Description": "Artifact hash for asset \"84e9b89449fe2573e51d08cc143e21116ed4608c6db56afffcb4ad85c8130709\"" + "Description": "Artifact hash for asset \"be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1525,17 +1533,17 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameters983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4cS3Bucket1BE31DB0": { + "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3BucketB3DDCC13": { "Type": "String", - "Description": "S3 bucket for asset \"983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4c\"" + "Description": "S3 bucket for asset \"e3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0\"" }, - "AssetParameters983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4cS3VersionKeyDC38E49C": { + "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0S3VersionKey3418DF70": { "Type": "String", - "Description": "S3 key for asset version \"983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4c\"" + "Description": "S3 key for asset version \"e3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0\"" }, - "AssetParameters983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4cArtifactHashBA6352EA": { + "AssetParameterse3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0ArtifactHash9D8F179A": { "Type": "String", - "Description": "Artifact hash for asset \"983c442a2fe823a8b4ebb18d241a5150ae15103dacbf3f038c7c6343e565aa4c\"" + "Description": "Artifact hash for asset \"e3d9996b6fafcc7da88312672e15e3cc925b02cffc6f01a615d81f22303e3ae0\"" }, "AssetParameters972240f9dd6e036a93d5f081af9a24315b2053828ac049b3b19b2fa12d7ae64aS3Bucket1F1A8472": { "Type": "String", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json index 3f032ba6cc07e..8748132b68636 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.exec-command.expected.json @@ -1,384 +1,399 @@ { - "Resources": { - "Vpc8378EB38": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc" - } - ] - } - }, - "VpcPublicSubnet1Subnet5C2D37C4": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.0.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] - } - }, - "VpcPublicSubnet1RouteTable6C95E38E": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] - } - }, - "VpcPublicSubnet1RouteTableAssociation97140677": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc" } - } - }, - "VpcPublicSubnet1DefaultRoute3DA9E72A": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VpcIGWD7BA715C" + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" }, - "DependsOn": [ - "VpcVPCGWBF912B6E" + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" + } ] - }, - "VpcPublicSubnet1EIPD7E02669": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] - } - }, - "VpcPublicSubnet1NATGateway4D7517AA": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VpcPublicSubnet1EIPD7E02669", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" } - }, - "VpcPublicSubnet2Subnet691E08A3": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.64.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } - ] + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" } }, - "VpcPublicSubnet2RouteTable94F7E489": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" ] - } - }, - "VpcPublicSubnet2RouteTableAssociationDD5762D8": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } - } - }, - "VpcPublicSubnet2DefaultRoute97F91067": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VpcIGWD7BA715C" + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" }, - "DependsOn": [ - "VpcVPCGWBF912B6E" + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" + } ] - }, - "VpcPublicSubnet2EIP3C605A87": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } - ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" } - }, - "VpcPublicSubnet2NATGateway9182C01D": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VpcPublicSubnet2EIP3C605A87", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } - ] + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" } }, - "VpcPrivateSubnet1Subnet536B997A": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.128.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" - } + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" ] - } - }, - "VpcPrivateSubnet1RouteTableB2C5B500": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" - } - ] - } - }, - "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" }, - "SubnetId": { - "Ref": "VpcPrivateSubnet1Subnet536B997A" + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } - } - }, - "VpcPrivateSubnet1DefaultRouteBE02A9ED": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" } - }, - "VpcPrivateSubnet2Subnet3788AAA1": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.192.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" - } - ] + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" } - }, - "VpcPrivateSubnet2RouteTableA678073B": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" - } - ] - } - }, - "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" }, - "SubnetId": { - "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } - } - }, - "VpcPrivateSubnet2DefaultRoute060D2087": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VpcPublicSubnet2NATGateway9182C01D" + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" } - }, - "VpcIGWD7BA715C": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc" - } - ] - } - }, - "VpcVPCGWBF912B6E": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "InternetGatewayId": { - "Ref": "VpcIGWD7BA715C" - } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" } - }, - "LogGroupF5B46931": { - "Type": "AWS::Logs::LogGroup", - "Properties": { - "RetentionInDays": "731", - "KmsKeyId": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc" } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "KmsKey46693ADD": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "KmsKey46693ADD": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Encrypt*", + "kms:Decrypt*", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Describe*" + ], + "Condition": { + "ArnLike": { + "kms:EncryptionContext:aws:logs:arn": { "Fn::Join": [ "", [ @@ -386,788 +401,772 @@ { "Ref": "AWS::Partition" }, - ":iam::", + ":logs:", { - "Ref": "AWS::AccountId" + "Ref": "AWS::Region" }, - ":root" - ] - ] - } - }, - "Resource": "*" - }, - { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:aws:iam::", + ":", { "Ref": "AWS::AccountId" }, - ":root" + ":*" ] ] } - }, - "Resource": "*" + } }, - { - "Action": [ - "kms:Encrypt*", - "kms:Decrypt*", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Describe*" - ], - "Condition": { - "ArnLike": { - "kms:EncryptionContext:aws:logs:arn": { - "Fn::Join": [ - "", - [ - "arn:aws:logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":*" - ] - ] - } - } - }, - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "logs.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" - ] + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "logs.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - } + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "KmsKeyId": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" + "RetentionInDays": 731 }, - "EcsExecBucket4F468651": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "KMSMasterKeyID": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] - }, - "SSEAlgorithm": "aws:kms" - } + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "EcsExecBucket4F468651": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] + }, + "SSEAlgorithm": "aws:kms" } - ] - } + } + ] } }, - "Ec2ClusterEE43E89D": { - "Type": "AWS::ECS::Cluster", - "Properties": { - "Configuration": { - "ExecuteCommandConfiguration": { - "KmsKeyId": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "Ec2ClusterEE43E89D": { + "Type": "AWS::ECS::Cluster", + "Properties": { + "Configuration": { + "ExecuteCommandConfiguration": { + "KmsKeyId": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] + }, + "LogConfiguration": { + "CloudWatchEncryptionEnabled": true, + "CloudWatchLogGroupName": { + "Ref": "LogGroupF5B46931" }, - "LogConfiguration": { - "CloudWatchEncryptionEnabled": true, - "CloudWatchLogGroupName": { - "Ref": "LogGroupF5B46931" - }, - "S3BucketName": { - "Ref": "EcsExecBucket4F468651" - }, - "S3EncryptionEnabled": true, - "S3KeyPrefix": "exec-output" + "S3BucketName": { + "Ref": "EcsExecBucket4F468651" }, + "S3EncryptionEnabled": true, + "S3KeyPrefix": "exec-output" + }, "Logging": "OVERRIDE" - } } } - }, - "Ec2ClusterDefaultAutoScalingGroupInstanceSecurityGroup149B0A9E": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/InstanceSecurityGroup", - "SecurityGroupEgress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - } - ], - "Tags": [ + } + }, + "Ec2ClusterDefaultAutoScalingGroupInstanceSecurityGroup149B0A9E": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } } ], - "VpcId": { - "Ref": "Vpc8378EB38" + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" } - } - }, - "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } - ] + ] + } + }, + "Ec2ClusterDefaultAutoScalingGroupInstanceRoleDefaultPolicy6D2DC2FD": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecs:DeregisterContainerInstance", + "ecs:RegisterContainerInstance", + "ecs:Submit*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Ec2ClusterEE43E89D", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:Poll", + "ecs:StartTelemetrySession" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "Ec2ClusterEE43E89D", + "Arn" ] } } - } - ], - "Version": "2012-10-17" - }, - "Tags": [ + }, + "Effect": "Allow", + "Resource": "*" + }, { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + "Action": [ + "ecs:DiscoverPollEndpoint", + "ecr:GetAuthorizationToken", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": "*" } - ] + ], + "Version": "2012-10-17" + }, + "PolicyName": "Ec2ClusterDefaultAutoScalingGroupInstanceRoleDefaultPolicy6D2DC2FD", + "Roles": [ + { + "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898" + } + ] + } + }, + "Ec2ClusterDefaultAutoScalingGroupInstanceProfileDB232471": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898" + } + ] + } + }, + "Ec2ClusterDefaultAutoScalingGroupLaunchConfig7B2FED3A": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "IamInstanceProfile": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceProfileDB232471" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupInstanceSecurityGroup149B0A9E", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "#!/bin/bash\necho ECS_CLUSTER=", + { + "Ref": "Ec2ClusterEE43E89D" + }, + " >> /etc/ecs/ecs.config\nsudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\nsudo service iptables save\necho ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config" + ] + ] + } } }, - "Ec2ClusterDefaultAutoScalingGroupInstanceRoleDefaultPolicy6D2DC2FD": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "ecs:DeregisterContainerInstance", - "ecs:RegisterContainerInstance", - "ecs:Submit*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] - } - }, - { - "Action": [ - "ecs:Poll", - "ecs:StartTelemetrySession" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ecs:DiscoverPollEndpoint", - "ecr:GetAuthorizationToken", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" + "DependsOn": [ + "Ec2ClusterDefaultAutoScalingGroupInstanceRoleDefaultPolicy6D2DC2FD", + "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898" + ] + }, + "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "1", + "MinSize": "1", + "LaunchConfigurationName": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLaunchConfig7B2FED3A" + }, + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" }, - "PolicyName": "Ec2ClusterDefaultAutoScalingGroupInstanceRoleDefaultPolicy6D2DC2FD", - "Roles": [ - { - "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898" - } - ] - } + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] }, - "Ec2ClusterDefaultAutoScalingGroupInstanceProfileDB232471": { - "Type": "AWS::IAM::InstanceProfile", - "Properties": { - "Roles": [ - { - "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898" - } - ] + "UpdatePolicy": { + "AutoScalingReplacingUpdate": { + "WillReplace": true + }, + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true } - }, - "Ec2ClusterDefaultAutoScalingGroupLaunchConfig7B2FED3A": { - "Type": "AWS::AutoScaling::LaunchConfiguration", - "Properties": { - "ImageId": { - "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" - }, - "InstanceType": "t2.micro", - "IamInstanceProfile": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceProfileDB232471" - }, - "SecurityGroups": [ + } + }, + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupInstanceSecurityGroup149B0A9E", - "GroupId" - ] + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } } ], - "UserData": { - "Fn::Base64": { - "Fn::Join": [ - "", - [ - "#!/bin/bash\necho ECS_CLUSTER=", - { - "Ref": "Ec2ClusterEE43E89D" - }, - " >> /etc/ecs/ecs.config\nsudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\nsudo service iptables save\necho ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config" - ] + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ] - } + ] + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" } - }, - "DependsOn": [ - "Ec2ClusterDefaultAutoScalingGroupInstanceRoleDefaultPolicy6D2DC2FD", - "Ec2ClusterDefaultAutoScalingGroupInstanceRole73D80898" ] - }, - "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0": { - "Type": "AWS::AutoScaling::AutoScalingGroup", - "Properties": { - "MaxSize": "1", - "MinSize": "1", - "LaunchConfigurationName": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLaunchConfig7B2FED3A" - }, - "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" - } - ], - "VPCZoneIdentifier": [ + } + }, + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRoleDefaultPolicy638C9E33": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ { - "Ref": "VpcPrivateSubnet1Subnet536B997A" + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeInstanceStatus", + "ec2:DescribeHosts" + ], + "Effect": "Allow", + "Resource": "*" }, { - "Ref": "VpcPrivateSubnet2Subnet3788AAA1" - } - ] - }, - "UpdatePolicy": { - "AutoScalingReplacingUpdate": { - "WillReplace": true - }, - "AutoScalingScheduledAction": { - "IgnoreUnmodifiedGroupSizeProperties": true - } - } - }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "ManagedPolicyArns": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + "Action": "autoscaling:CompleteLifecycleAction", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":autoscaling:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":autoScalingGroup:*:autoScalingGroupName/", + { + "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" + } + ] ] - ] - } - ], - "Tags": [ + } + }, { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" - } - ] - } - }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRoleDefaultPolicy638C9E33": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeInstanceAttribute", - "ec2:DescribeInstanceStatus", - "ec2:DescribeHosts" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "autoscaling:CompleteLifecycleAction", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":autoscaling:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":autoScalingGroup:*:autoScalingGroupName/", - { - "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" - } + "Action": [ + "ecs:DescribeContainerInstances", + "ecs:DescribeTasks" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "Ec2ClusterEE43E89D", + "Arn" ] - ] - } - }, - { - "Action": [ - "ecs:DescribeContainerInstances", - "ecs:DescribeTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] - } } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ecs:ListContainerInstances", - "ecs:SubmitContainerStateChange", - "ecs:SubmitTaskStateChange" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] } }, - { - "Action": [ - "ecs:UpdateContainerInstancesState", - "ecs:ListTasks" - ], - "Condition": { - "ArnEquals": { - "ecs:cluster": { - "Fn::GetAtt": [ - "Ec2ClusterEE43E89D", - "Arn" - ] - } - } - }, - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRoleDefaultPolicy638C9E33", - "Roles": [ + "Effect": "Allow", + "Resource": "*" + }, { - "Ref": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3" - } - ] - } - }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" - }, - "Role": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", - "Arn" - ] - }, - "Environment": { - "Variables": { - "CLUSTER": { - "Ref": "Ec2ClusterEE43E89D" + "Action": [ + "ecs:ListContainerInstances", + "ecs:SubmitContainerStateChange", + "ecs:SubmitTaskStateChange" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Ec2ClusterEE43E89D", + "Arn" + ] } - } - }, - "Handler": "index.lambda_handler", - "Runtime": "python3.6", - "Tags": [ + }, { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + "Action": [ + "ecs:UpdateContainerInstancesState", + "ecs:ListTasks" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "Ec2ClusterEE43E89D", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" } ], - "Timeout": 310 + "Version": "2012-10-17" }, - "DependsOn": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRoleDefaultPolicy638C9E33", - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3" + "PolicyName": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRoleDefaultPolicy638C9E33", + "Roles": [ + { + "Ref": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3" + } ] - }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C92983E1AD32": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", - "Arn" - ] - }, - "Principal": "sns.amazonaws.com", - "SourceArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + } + }, + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + }, + "Role": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", + "Arn" + ] + }, + "Environment": { + "Variables": { + "CLUSTER": { + "Ref": "Ec2ClusterEE43E89D" + } } - } - }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6": { - "Type": "AWS::SNS::Subscription", - "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - }, - "Endpoint": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", - "Arn" - ] + }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" } - } + ], + "Timeout": 310 }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "autoscaling.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" - } + "DependsOn": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRoleDefaultPolicy638C9E33", + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3" + ] + }, + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C92983E1AD32": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", + "Arn" ] + }, + "Principal": "sns.amazonaws.com", + "SourceArn": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" } - }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleDefaultPolicyE499974B": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleDefaultPolicyE499974B", - "Roles": [ - { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7" - } + } + }, + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6": { + "Type": "AWS::SNS::Subscription", + "Properties": { + "Protocol": "lambda", + "TopicArn": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + }, + "Endpoint": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", + "Arn" ] } - }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": { - "Type": "AWS::SNS::Topic", - "Properties": { - "Tags": [ + } + }, + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + } + ] + } + }, + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "autoscaling.amazonaws.com" + } } - ] - } - }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHook5CB1467E": { - "Type": "AWS::AutoScaling::LifecycleHook", - "Properties": { - "AutoScalingGroupName": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" - }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", - "DefaultResult": "CONTINUE", - "HeartbeatTimeout": 300, - "NotificationTargetARN": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - }, - "RoleARN": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7", - "Arn" - ] - } + ], + "Version": "2012-10-17" }, - "DependsOn": [ - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleDefaultPolicyE499974B", - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7" + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup" + } ] - }, - "TaskDefTaskRole1EDB4A67": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "ecs-tasks.amazonaws.com" - } + } + }, + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleDefaultPolicyE499974B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" } - ], - "Version": "2012-10-17" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleDefaultPolicyE499974B", + "Roles": [ + { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7" } + ] + } + }, + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHook5CB1467E": { + "Type": "AWS::AutoScaling::LifecycleHook", + "Properties": { + "AutoScalingGroupName": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" + }, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", + "DefaultResult": "CONTINUE", + "HeartbeatTimeout": 300, + "NotificationTargetARN": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + }, + "RoleARN": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7", + "Arn" + ] } }, - "TaskDefTaskRoleDefaultPolicyA592CB18": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "ssmmessages:CreateControlChannel", - "ssmmessages:CreateDataChannel", - "ssmmessages:OpenControlChannel", - "ssmmessages:OpenDataChannel" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:GenerateDataKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] - } - }, - { - "Action": "logs:DescribeLogGroups", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:DescribeLogStreams", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:", - { - "Ref": "LogGroupF5B46931" - }, - ":*" - ] - ] - } - }, - { - "Action": "s3:GetBucketLocation", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:PutObject", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:s3:::", - { - "Ref": "EcsExecBucket4F468651" - }, - "/*" - ] + "DependsOn": [ + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleDefaultPolicyE499974B", + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookRole71045ED7" + ] + }, + "TaskDefTaskRole1EDB4A67": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDefTaskRoleDefaultPolicyA592CB18": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ssmmessages:CreateControlChannel", + "ssmmessages:CreateDataChannel", + "ssmmessages:OpenControlChannel", + "ssmmessages:OpenDataChannel" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:GenerateDataKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] + } + }, + { + "Action": "logs:DescribeLogGroups", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:DescribeLogStreams", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:", + { + "Ref": "LogGroupF5B46931" + }, + ":*" ] - } - }, - { - "Action": "s3:GetEncryptionConfiguration", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:s3:::", - { - "Ref": "EcsExecBucket4F468651" - } - ] + ] + } + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "EcsExecBucket4F468651" + }, + "/*" ] - } + ] } - ], - "Version": "2012-10-17" - }, - "PolicyName": "TaskDefTaskRoleDefaultPolicyA592CB18", - "Roles": [{ - "Ref": "TaskDefTaskRole1EDB4A67" - }] - } - }, - "TaskDef54694570": { - "Type": "AWS::ECS::TaskDefinition", - "Properties": { - "ContainerDefinitions": [ + }, { - "Essential": true, - "Image": "amazon/amazon-ecs-sample", - "Memory": "256", - "Name": "web" + "Action": "s3:GetEncryptionConfiguration", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "EcsExecBucket4F468651" + } + ] + ] + } } ], - "Family": "awsecsintegexeccommandTaskDef44709274", - "NetworkMode": "bridge", - "RequiresCompatibilities": [ - "EC2" - ], - "TaskRoleArn": { - "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", - "Arn" - ] + "Version": "2012-10-17" + }, + "PolicyName": "TaskDefTaskRoleDefaultPolicyA592CB18", + "Roles": [ + { + "Ref": "TaskDefTaskRole1EDB4A67" } - } - }, - "Ec2Service04A33183": { - "Type": "AWS::ECS::Service", - "Properties": { - "Cluster": { - "Ref": "Ec2ClusterEE43E89D" - }, - "DeploymentConfiguration": { - "MaximumPercent": 200, - "MinimumHealthyPercent": 50 - }, - "LaunchType": "EC2", - "EnableECSManagedTags": false, - "EnableExecuteCommand": true, - "SchedulingStrategy": "REPLICA", - "TaskDefinition": { - "Ref": "TaskDef54694570" + ] + } + }, + "TaskDef54694570": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Memory": 256, + "Name": "web" } + ], + "Family": "awsecsintegexeccommandTaskDef44709274", + "NetworkMode": "bridge", + "RequiresCompatibilities": [ + "EC2" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] } } }, - "Parameters": { - "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { - "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + "Ec2Service04A33183": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "Ec2ClusterEE43E89D" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "EnableExecuteCommand": true, + "LaunchType": "EC2", + "SchedulingStrategy": "REPLICA", + "TaskDefinition": { + "Ref": "TaskDef54694570" + } } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts index 7963ea0cfa6a1..756569d405d6d 100644 --- a/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts @@ -216,7 +216,11 @@ describe('external task definition', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'AssetParameters872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724dS3Bucket7B2069B7', }, diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index 3780c43903284..e28ebda720b52 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -2433,7 +2433,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, @@ -2462,7 +2466,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'ExecBucket29559356', }, @@ -2566,7 +2574,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, @@ -2595,7 +2607,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'EcsExecBucket4F468651', }, @@ -2665,7 +2681,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:iam::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', { Ref: 'AWS::AccountId', }, @@ -2772,7 +2792,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, @@ -2801,7 +2825,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'EcsExecBucket4F468651', }, @@ -2817,7 +2845,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:s3:::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', { Ref: 'EcsExecBucket4F468651', }, @@ -2886,7 +2918,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:iam::', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', { Ref: 'AWS::AccountId', }, @@ -2911,7 +2947,11 @@ describe('fargate service', () => { 'Fn::Join': [ '', [ - 'arn:aws:logs:', + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', { Ref: 'AWS::Region', }, diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json index 083a16ee75820..19e6073340ac7 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.exec-command.expected.json @@ -1,384 +1,399 @@ { - "Resources": { - "Vpc8378EB38": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc" - } - ] - } - }, - "VpcPublicSubnet1Subnet5C2D37C4": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.0.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] - } - }, - "VpcPublicSubnet1RouteTable6C95E38E": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] - } - }, - "VpcPublicSubnet1RouteTableAssociation97140677": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc" } - } - }, - "VpcPublicSubnet1DefaultRoute3DA9E72A": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VpcIGWD7BA715C" + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" }, - "DependsOn": [ - "VpcVPCGWBF912B6E" + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" + } ] - }, - "VpcPublicSubnet1EIPD7E02669": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] - } - }, - "VpcPublicSubnet1NATGateway4D7517AA": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VpcPublicSubnet1EIPD7E02669", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" - } - ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" } - }, - "VpcPublicSubnet2Subnet691E08A3": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.64.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } - ] + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" } }, - "VpcPublicSubnet2RouteTable94F7E489": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" ] - } - }, - "VpcPublicSubnet2RouteTableAssociationDD5762D8": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } - } - }, - "VpcPublicSubnet2DefaultRoute97F91067": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VpcIGWD7BA715C" + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" }, - "DependsOn": [ - "VpcVPCGWBF912B6E" + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" + } ] - }, - "VpcPublicSubnet2EIP3C605A87": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } - ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" } - }, - "VpcPublicSubnet2NATGateway9182C01D": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VpcPublicSubnet2EIP3C605A87", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" - } - ] + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" } }, - "VpcPrivateSubnet1Subnet536B997A": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.128.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" - } + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" ] - } - }, - "VpcPrivateSubnet1RouteTableB2C5B500": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" - } - ] - } - }, - "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" }, - "SubnetId": { - "Ref": "VpcPrivateSubnet1Subnet536B997A" + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } - } - }, - "VpcPrivateSubnet1DefaultRouteBE02A9ED": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" } - }, - "VpcPrivateSubnet2Subnet3788AAA1": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.192.0/18", - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" - } - ] + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" } - }, - "VpcPrivateSubnet2RouteTableA678073B": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" - } - ] - } - }, - "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" }, - "SubnetId": { - "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } - } - }, - "VpcPrivateSubnet2DefaultRoute060D2087": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VpcPublicSubnet2NATGateway9182C01D" + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" } - }, - "VpcIGWD7BA715C": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-exec-command/Vpc" - } - ] - } - }, - "VpcVPCGWBF912B6E": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, - "InternetGatewayId": { - "Ref": "VpcIGWD7BA715C" - } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" } - }, - "LogGroupF5B46931": { - "Type": "AWS::Logs::LogGroup", - "Properties": { - "RetentionInDays": "731", - "KmsKeyId": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-exec-command/Vpc" } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "KmsKey46693ADD": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "KmsKey46693ADD": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Encrypt*", + "kms:Decrypt*", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Describe*" + ], + "Condition": { + "ArnLike": { + "kms:EncryptionContext:aws:logs:arn": { "Fn::Join": [ "", [ @@ -386,339 +401,323 @@ { "Ref": "AWS::Partition" }, - ":iam::", + ":logs:", { - "Ref": "AWS::AccountId" + "Ref": "AWS::Region" }, - ":root" - ] - ] - } - }, - "Resource": "*" - }, - { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:aws:iam::", + ":", { "Ref": "AWS::AccountId" }, - ":root" - ] - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt*", - "kms:Decrypt*", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Describe*" - ], - "Condition": { - "ArnLike": { - "kms:EncryptionContext:aws:logs:arn": { - "Fn::Join": [ - "", - [ - "arn:aws:logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":*" - ] - ] - } - } - }, - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "logs.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" + ":*" ] ] } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "EcsExecBucket4F468651": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "KMSMasterKeyID": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] - }, - "SSEAlgorithm": "aws:kms" - } - } - ] - } - } - }, - "FargateCluster7CCD5F93": { - "Type": "AWS::ECS::Cluster", - "Properties": { - "Configuration": { - "ExecuteCommandConfiguration": { - "KmsKeyId": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] - }, - "LogConfiguration": { - "CloudWatchEncryptionEnabled": true, - "CloudWatchLogGroupName": { - "Ref": "LogGroupF5B46931" - }, - "S3BucketName": { - "Ref": "EcsExecBucket4F468651" - }, - "S3EncryptionEnabled": true, - "S3KeyPrefix": "exec-output" - }, - "Logging": "OVERRIDE" - } - } - } - }, - "TaskDefTaskRole1EDB4A67": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "ecs-tasks.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "TaskDefTaskRoleDefaultPolicyA592CB18": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "ssmmessages:CreateControlChannel", - "ssmmessages:CreateDataChannel", - "ssmmessages:OpenControlChannel", - "ssmmessages:OpenDataChannel" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:GenerateDataKey" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "KmsKey46693ADD", - "Arn" - ] } }, - { - "Action": "logs:DescribeLogGroups", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "logs:CreateLogStream", - "logs:DescribeLogStreams", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { + "Effect": "Allow", + "Principal": { + "Service": { "Fn::Join": [ "", [ - "arn:aws:logs:", + "logs.", { "Ref": "AWS::Region" }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:", - { - "Ref": "LogGroupF5B46931" - }, - ":*" - ] - ] - } - }, - { - "Action": "s3:GetBucketLocation", - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": "s3:PutObject", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:s3:::", - { - "Ref": "EcsExecBucket4F468651" - }, - "/*" + ".amazonaws.com" ] ] } }, - { - "Action": "s3:GetEncryptionConfiguration", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:s3:::", - { - "Ref": "EcsExecBucket4F468651" - } - ] - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "TaskDefTaskRoleDefaultPolicyA592CB18", - "Roles": [{ - "Ref": "TaskDefTaskRole1EDB4A67" - }] - } - }, - "TaskDef54694570": { - "Type": "AWS::ECS::TaskDefinition", - "Properties": { - "ContainerDefinitions": [ - { - "Essential": true, - "Image": "amazon/amazon-ecs-sample", - "Name": "web" + "Resource": "*" } ], - "Cpu": "256", - "Family": "awsecsintegexeccommandTaskDef44709274", - "Memory": "512", - "NetworkMode": "awsvpc", - "RequiresCompatibilities": [ - "FARGATE" - ], - "TaskRoleArn": { - "Fn::GetAtt": [ - "TaskDefTaskRole1EDB4A67", - "Arn" - ] - } + "Version": "2012-10-17" } }, - "FargateServiceAC2B3B85": { - "Type": "AWS::ECS::Service", - "Properties": { - "Cluster": { - "Ref": "FargateCluster7CCD5F93" - }, - "DeploymentConfiguration": { - "MaximumPercent": 200, - "MinimumHealthyPercent": 50 - }, - "LaunchType": "FARGATE", - "EnableECSManagedTags": false, - "EnableExecuteCommand": true, - "NetworkConfiguration": { - "AwsvpcConfiguration": { - "AssignPublicIp": "DISABLED", - "SecurityGroups": [ - { + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "KmsKeyId": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] + }, + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "EcsExecBucket4F468651": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { "Fn::GetAtt": [ - "FargateServiceSecurityGroup0A0E79CB", - "GroupId" + "KmsKey46693ADD", + "Arn" ] - } - ], - "Subnets": [ - { - "Ref": "VpcPrivateSubnet1Subnet536B997A" }, - { - "Ref": "VpcPrivateSubnet2Subnet3788AAA1" - } - ] + "SSEAlgorithm": "aws:kms" + } } - }, - "TaskDefinition": { - "Ref": "TaskDef54694570" - } + ] } }, - "FargateServiceSecurityGroup0A0E79CB": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "aws-ecs-integ-exec-command/FargateService/SecurityGroup", - "SecurityGroupEgress": [ + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "FargateCluster7CCD5F93": { + "Type": "AWS::ECS::Cluster", + "Properties": { + "Configuration": { + "ExecuteCommandConfiguration": { + "KmsKeyId": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] + }, + "LogConfiguration": { + "CloudWatchEncryptionEnabled": true, + "CloudWatchLogGroupName": { + "Ref": "LogGroupF5B46931" + }, + "S3BucketName": { + "Ref": "EcsExecBucket4F468651" + }, + "S3EncryptionEnabled": true, + "S3KeyPrefix": "exec-output" + }, + "Logging": "OVERRIDE" + } + } + } + }, + "TaskDefTaskRole1EDB4A67": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDefTaskRoleDefaultPolicyA592CB18": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ssmmessages:CreateControlChannel", + "ssmmessages:CreateDataChannel", + "ssmmessages:OpenControlChannel", + "ssmmessages:OpenDataChannel" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:GenerateDataKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "KmsKey46693ADD", + "Arn" + ] + } + }, + { + "Action": "logs:DescribeLogGroups", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:DescribeLogStreams", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:", + { + "Ref": "LogGroupF5B46931" + }, + ":*" + ] + ] + } + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "EcsExecBucket4F468651" + }, + "/*" + ] + ] + } + }, { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" + "Action": "s3:GetEncryptionConfiguration", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "EcsExecBucket4F468651" + } + ] + ] + } } ], - "VpcId": { - "Ref": "Vpc8378EB38" + "Version": "2012-10-17" + }, + "PolicyName": "TaskDefTaskRoleDefaultPolicyA592CB18", + "Roles": [ + { + "Ref": "TaskDefTaskRole1EDB4A67" + } + ] + } + }, + "TaskDef54694570": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Name": "web" + } + ], + "Cpu": "256", + "Family": "awsecsintegexeccommandTaskDef44709274", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + } + }, + "FargateServiceAC2B3B85": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "FargateCluster7CCD5F93" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "EnableExecuteCommand": true, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "FargateServiceSecurityGroup0A0E79CB", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "TaskDefinition": { + "Ref": "TaskDef54694570" + } + } + }, + "FargateServiceSecurityGroup0A0E79CB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ-exec-command/FargateService/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" } + ], + "VpcId": { + "Ref": "Vpc8378EB38" } } } + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index e5554ffcf8ba2..79ea6601f9fff 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -84,13 +84,13 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "@types/sinon": "^9.0.11", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0", - "cdk8s": "^1.3.32", - "cdk8s-plus-21": "^1.0.0-beta.73", + "cdk8s": "^1.4.6", + "cdk8s-plus-21": "^1.0.0-beta.77", "jest": "^27.4.7", "sinon": "^9.2.4" }, diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 0d6efaeb65b48..190f42846901b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -72,7 +72,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-elasticloadbalancing/test/loadbalancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts index 457742ff5db70..5497f380c5f76 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Connections, Peer, SubnetType, Vpc } from '@aws-cdk/aws-ec2'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { Duration, Stack } from '@aws-cdk/core'; @@ -19,7 +19,7 @@ describe('tests', () => { internalPort: 8080, }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { Listeners: [{ InstancePort: '8080', InstanceProtocol: 'http', @@ -46,7 +46,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { HealthCheck: { HealthyThreshold: '2', Interval: '60', @@ -76,7 +76,7 @@ describe('tests', () => { elb.addTarget(new FakeTarget()); // THEN: at the very least it added a security group rule for the backend - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { Description: 'Port 8080 LB to fleet', @@ -101,7 +101,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { CrossZone: true, }); }); @@ -118,7 +118,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { CrossZone: false, }); }); @@ -134,7 +134,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { CrossZone: true, }); }); @@ -171,7 +171,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { Subnets: vpc.selectSubnets({ subnetGroupName: 'private1', }).subnetIds.map((subnetId: string) => stack.resolve(subnetId)), @@ -194,7 +194,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { Listeners: [{ InstancePort: '8080', InstanceProtocol: 'http', @@ -221,7 +221,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { Listeners: [{ InstancePort: '8080', InstanceProtocol: 'http', @@ -266,7 +266,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { AccessLoggingPolicy: { Enabled: true, S3BucketName: 'fakeBucket', @@ -289,7 +289,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancing::LoadBalancer', { AccessLoggingPolicy: { Enabled: false, S3BucketName: 'fakeBucket', diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index 5c626ac394a3d..90449a5d94204 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-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/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts index dad0adda17691..e747c60980660 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as cognito from '@aws-cdk/aws-cognito'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; @@ -35,7 +35,7 @@ test('Cognito Action', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { AuthenticateCognitoConfig: { @@ -56,5 +56,5 @@ test('Cognito Action', () => { Type: 'fixed-response', }, ], - })); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 01cdbc3349eb0..9990e7ea75a73 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/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/pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts index 1ccea0b91d1b2..b8c30af1f332a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; @@ -19,7 +19,7 @@ test('Can create target groups with alb target', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'TCP', Targets: [ @@ -34,7 +34,7 @@ test('Can create target groups with alb target', () => { VpcId: { Ref: 'Stack8A423254', }, - })); + }); }); test('Can create target groups with alb arn target', () => { @@ -51,7 +51,7 @@ test('Can create target groups with alb arn target', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'TCP', Targets: [ @@ -64,5 +64,5 @@ test('Can create target groups with alb arn target', () => { VpcId: { Ref: 'Stack8A423254', }, - })); + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts index 874adeffe2c36..55a731ac51dab 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; @@ -18,14 +18,14 @@ test('Can create target groups with instance id target', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'HTTP', Targets: [ { Id: 'i-1234' }, ], TargetType: 'instance', - })); + }); }); test('Can create target groups with instance target', () => { @@ -48,12 +48,12 @@ test('Can create target groups with instance target', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'HTTP', Targets: [ { Id: { Ref: 'InstanceC1063A87' } }, ], TargetType: 'instance', - })); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts index a1ab3b9f2896e..185ad0c877574 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; @@ -18,12 +18,12 @@ test('Can create target groups with lambda targets', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Port: 80, Protocol: 'HTTP', Targets: [ { Id: '1.2.3.4' }, ], TargetType: 'ip', - })); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts index b22584404fd09..2e757a0028aef 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -29,12 +29,12 @@ test('Can create target groups with lambda targets', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetType: 'lambda', Targets: [ { Id: { 'Fn::GetAtt': ['FunA2CCED21', 'Arn'] } }, ], - })); + }); }); test('Lambda targets create dependency on Invoke permission', () => { @@ -44,7 +44,7 @@ test('Lambda targets create dependency on Invoke permission', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', (def: any) => { + Template.fromStack(stack).hasResource('AWS::ElasticLoadBalancingV2::TargetGroup', (def: any) => { return (def.DependsOn ?? []).includes('FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4'); - }, ResourcePart.CompleteDefinition)); + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index be671153b306f..4d98964505e22 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/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-elasticloadbalancingv2/test/alb/actions.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts index b3a6397ba6eaa..5df99ef270b0a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../../lib'; @@ -25,7 +25,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { TargetGroupArn: { Ref: 'TargetGroup1E5480F51' }, @@ -45,7 +45,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { ForwardConfig: { @@ -81,7 +81,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { ForwardConfig: { @@ -122,7 +122,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { AuthenticateOidcConfig: { @@ -161,7 +161,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Actions: [ { TargetGroupArn: { Ref: 'TargetGroup2D571E5D7' }, @@ -190,7 +190,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Actions: [ { TargetGroupArn: { Ref: 'TargetGroup2D571E5D7' }, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts index 6864ecaa80c2b..e7d1bccab934b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as elbv2 from '../../lib'; describe('tests', () => { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts index 14f9bd51bee61..5caf1f756dd80 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts @@ -1,5 +1,4 @@ -import { MatchStyle } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acm from '@aws-cdk/aws-certificatemanager'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -24,7 +23,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'HTTPS', }); }); @@ -42,7 +41,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 80, }); }); @@ -60,7 +59,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ { Description: 'Allow from anyone on port 80', @@ -86,7 +85,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ { Description: 'Allow from anyone on port 80', @@ -138,7 +137,7 @@ describe('tests', () => { listener.addCertificates('Certs', [importedCertificate(stack, 'cert')]); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Certificates: [ { CertificateArn: 'cert' }, ], @@ -169,15 +168,15 @@ describe('tests', () => { expect(listener.node.tryFindChild('DefaultCertificates3')).not.toBeDefined(); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Certificates: [{ CertificateArn: 'cert1' }], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [{ CertificateArn: 'cert2' }], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [{ CertificateArn: 'cert3' }], }); }); @@ -195,7 +194,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetType: 'ip', }); }); @@ -213,7 +212,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Name: 'foo', }); }); @@ -237,7 +236,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { TargetGroupArn: { Ref: 'TargetGroup3D7CD9B8' }, @@ -245,7 +244,7 @@ describe('tests', () => { }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 10, Conditions: [ { @@ -282,7 +281,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { TargetGroupArn: { Ref: 'LBListenerTargetsGroup76EF81E8' }, @@ -290,7 +289,7 @@ describe('tests', () => { }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { VpcId: { Ref: 'Stack8A423254' }, Port: 80, Protocol: 'HTTP', @@ -298,7 +297,7 @@ describe('tests', () => { { Id: 'i-12345' }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Actions: [ { TargetGroupArn: { Ref: 'LBListenerWithPathGroupE889F9E5' }, @@ -306,7 +305,7 @@ describe('tests', () => { }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { VpcId: { Ref: 'Stack8A423254' }, Port: 80, Protocol: 'HTTP', @@ -328,7 +327,7 @@ describe('tests', () => { listener.addTargets('Targets', { port: 8080, targets: [new elbv2.IpTarget('1.2.3.4')] }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Certificates: [ { CertificateArn: 'cert' }, ], @@ -348,7 +347,7 @@ describe('tests', () => { listener2.addCertificates('Certs', [importedCertificate(stack2, 'cert')]); // THEN - expect(stack2).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack2).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [ { CertificateArn: 'cert' }, ], @@ -370,7 +369,7 @@ describe('tests', () => { group.enableCookieStickiness(cdk.Duration.hours(1)); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', @@ -403,7 +402,7 @@ describe('tests', () => { group.enableCookieStickiness(cdk.Duration.hours(1), 'MyDeliciousCookie'); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', @@ -445,7 +444,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { UnhealthyThresholdCount: 3, HealthCheckIntervalSeconds: 60, HealthCheckPath: '/test', @@ -494,7 +493,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { ProtocolVersion: 'GRPC', }); }); @@ -517,7 +516,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { ListenerArn: 'ieks', Priority: 30, Actions: [ @@ -547,7 +546,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { ListenerArn: 'ieks', Priority: 30, Actions: [ @@ -575,14 +574,14 @@ describe('tests', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches(Match.objectLike({ Resources: { SomeResource: { Type: 'Test::Resource', DependsOn: ['LoadBalancerListenerE1A099B9'], }, }, - }, MatchStyle.SUPERSET); + })); }); test('Exercise metrics', () => { @@ -648,14 +647,14 @@ describe('tests', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches(Match.objectLike({ Resources: { SomeResource: { Type: 'Test::Resource', DependsOn: ['LoadBalancerListenerSecondGroupRuleF5FDC196'], }, }, - }, MatchStyle.SUPERSET); + })); }); test('Can add fixed responses', () => { @@ -683,7 +682,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { FixedResponseConfig: { @@ -696,7 +695,7 @@ describe('tests', () => { ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Actions: [ { FixedResponseConfig: { @@ -733,7 +732,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { RedirectConfig: { @@ -746,7 +745,7 @@ describe('tests', () => { ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Actions: [ { RedirectConfig: { @@ -771,7 +770,7 @@ describe('tests', () => { lb.addRedirect(); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 80, Protocol: 'HTTP', DefaultActions: [ @@ -800,7 +799,7 @@ describe('tests', () => { loadBalancer.addRedirect({ open: false }); // THEN - expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroup', { + const matchingGroups = Template.fromStack(stack).findResources('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ { CidrIp: '0.0.0.0/0', @@ -809,7 +808,7 @@ describe('tests', () => { }, ], }); - + expect(Object.keys(matchingGroups).length).toBe(0); }); test('Can add simple redirect responses with custom values', () => { @@ -830,7 +829,7 @@ describe('tests', () => { listener.addCertificates('ListenerCertificateX', [importedCertificate(stack, 'cert3')]); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Port: 8443, Protocol: 'HTTPS', DefaultActions: [ @@ -859,7 +858,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'deregistration_delay.timeout_seconds', @@ -888,7 +887,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', @@ -1092,7 +1091,7 @@ describe('tests', () => { listener.connections.allowToAnyIpv4(ec2.Port.tcp(443)); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: 'security-group-id', }); }); @@ -1114,11 +1113,11 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'HTTPS', }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [{ CertificateArn: 'cert2' }], }); }); @@ -1137,11 +1136,11 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'HTTPS', }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [{ CertificateArn: 'cert2' }], }); }); @@ -1162,15 +1161,15 @@ describe('tests', () => { listener.addCertificateArns('ListenerCertificateX', ['cert3']); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'HTTPS', }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [{ CertificateArn: 'cert2' }], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [{ CertificateArn: 'cert3' }], }); }); @@ -1194,7 +1193,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 10, Conditions: [ { @@ -1257,7 +1256,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 10, Conditions: [ { @@ -1276,7 +1275,7 @@ describe('tests', () => { ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 20, Conditions: [ { @@ -1338,7 +1337,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 10, Conditions: [ { @@ -1370,7 +1369,7 @@ describe('tests', () => { ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 20, Conditions: [ { @@ -1389,7 +1388,7 @@ describe('tests', () => { ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 30, Conditions: [ { @@ -1407,7 +1406,7 @@ describe('tests', () => { ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 40, Conditions: [ { @@ -1445,7 +1444,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 10, Conditions: [ { @@ -1485,7 +1484,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 1, Conditions: [ { @@ -1560,7 +1559,7 @@ describe('tests', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::ElasticLoadBalancingV2::Listener'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 0); expect(listener.listenerArn).toEqual('arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/application/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2'); expect(listener.connections.securityGroups[0].securityGroupId).toEqual('sg-12345'); }); @@ -1592,7 +1591,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerRule', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { Priority: 5, }); }); @@ -1619,7 +1618,7 @@ describe('tests', () => { ]); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { Certificates: [ { CertificateArn: 'arn:something' }, ], diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts index d935a915d55e7..4b89f79b75d31 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts @@ -1,11 +1,10 @@ -import { ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as elbv2 from '../../lib'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; @@ -23,7 +22,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internet-facing', Subnets: [ { Ref: 'StackPublicSubnet1Subnet0AD81D22' }, @@ -45,12 +44,12 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { DependsOn: [ 'StackPublicSubnet1DefaultRoute16154E3D', 'StackPublicSubnet2DefaultRoute0319539B', ], - }, ResourcePart.CompleteDefinition); + }); }); test('Trivial construction: internal', () => { @@ -62,7 +61,7 @@ describe('tests', () => { new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internal', Subnets: [ { Ref: 'StackPrivateSubnet1Subnet47AC2BC7' }, @@ -86,7 +85,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { LoadBalancerAttributes: [ { Key: 'deletion_protection.enabled', @@ -116,13 +115,13 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - LoadBalancerAttributes: arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { + LoadBalancerAttributes: Match.arrayWith([ { Key: 'deletion_protection.enabled', Value: 'false', }, - ), + ]), }); }); @@ -143,7 +142,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 1); expect(loadBalancer.listeners).toContain(listener); }); @@ -160,8 +159,8 @@ describe('tests', () => { // THEN // verify that the LB attributes reference the bucket - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - LoadBalancerAttributes: arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { + LoadBalancerAttributes: Match.arrayWith([ { Key: 'access_logs.s3.enabled', Value: 'true', @@ -174,11 +173,11 @@ describe('tests', () => { Key: 'access_logs.s3.prefix', Value: '', }, - ), + ]), }); // verify the bucket policy allows the ALB to put objects in the bucket - expect(stack).toHaveResource('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -196,9 +195,9 @@ describe('tests', () => { }); // verify the ALB depends on the bucket *and* the bucket policy - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { DependsOn: ['AccessLoggingBucketPolicy700D7CC6', 'AccessLoggingBucketA6D88F29'], - }, ResourcePart.CompleteDefinition); + }); }); testFutureBehavior('access logging with prefix', s3GrantWriteCtx, cdk.App, (app) => { @@ -213,8 +212,8 @@ describe('tests', () => { // THEN // verify that the LB attributes reference the bucket - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - LoadBalancerAttributes: arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { + LoadBalancerAttributes: Match.arrayWith([ { Key: 'access_logs.s3.enabled', Value: 'true', @@ -227,11 +226,11 @@ describe('tests', () => { Key: 'access_logs.s3.prefix', Value: 'prefix-of-access-logs', }, - ), + ]), }); // verify the bucket policy allows the ALB to put objects in the bucket - expect(stack).toHaveResource('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -300,7 +299,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Name: 'myLoadBalancer', }); }); @@ -364,7 +363,7 @@ describe('tests', () => { listener.addTargets('Targets', { port: 8080 }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 1); expect(() => alb.listeners).toThrow(); }); @@ -393,7 +392,7 @@ describe('tests', () => { alb.addSecurityGroup(new ec2.SecurityGroup(stack, 'SecurityGroup2', { vpc })); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { SecurityGroups: [ { 'Fn::GetAtt': ['SecurityGroup1F554B36F', 'GroupId'] }, { 'Fn::GetAtt': ['SecurityGroup23BE86BB7', 'GroupId'] }, @@ -421,7 +420,7 @@ describe('tests', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::ElasticLoadBalancingV2::ApplicationLoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::ApplicationLoadBalancer', 0); expect(loadBalancer.loadBalancerArn).toEqual('arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/application/my-load-balancer/50dc6c495c0c9188'); expect(loadBalancer.loadBalancerCanonicalHostedZoneId).toEqual('Z3DZXE0EXAMPLE'); expect(loadBalancer.loadBalancerDnsName).toEqual('my-load-balancer-1234567890.us-west-2.elb.amazonaws.com'); @@ -453,7 +452,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 1); expect(() => loadBalancer.listeners).toThrow(); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts index 03d17a207f16a..e0aeafb44ee75 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -193,7 +193,7 @@ describe('tests', () => { fixture.listener.connections.allowDefaultPortFromAnyIpv4('Open to the world'); // THEN - expect(fixture.stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(fixture.stack).hasResourceProperties('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ { CidrIp: '0.0.0.0/0', @@ -220,7 +220,7 @@ describe('tests', () => { listener2.connections.allowDefaultPortFromAnyIpv4('Open to the world'); // THEN - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { CidrIp: '0.0.0.0/0', Description: 'Open to the world', IpProtocol: 'tcp', @@ -243,7 +243,7 @@ function expectedImportedSGRules(stack: cdk.Stack) { } function expectSGRules(stack: cdk.Stack, lbGroup: any) { - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: lbGroup, IpProtocol: 'tcp', Description: 'Load balancer to target', @@ -251,7 +251,7 @@ function expectSGRules(stack: cdk.Stack, lbGroup: any) { FromPort: 8008, ToPort: 8008, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'Load balancer to target', FromPort: 8008, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index 54848cae02679..98c25a1e5cb70 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -38,13 +38,14 @@ describe('tests', () => { }, }); - expect(stack).not.toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + const matches = Template.fromStack(stack).findResources('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', }, ], }); + expect(Object.keys(matches).length).toBe(0); }); test('Can add self-registering target to imported TargetGroup', () => { @@ -103,7 +104,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { HealthCheckEnabled: true, HealthCheckIntervalSeconds: 255, HealthCheckPath: '/arbitrary', @@ -130,7 +131,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', @@ -162,7 +163,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', @@ -197,7 +198,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'stickiness.enabled', @@ -233,7 +234,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { ProtocolVersion: 'GRPC', HealthCheckEnabled: true, HealthCheckIntervalSeconds: 255, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts index b6f53fa53d584..d01b0cd666db0 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../../lib'; @@ -27,7 +27,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { ForwardConfig: { @@ -63,7 +63,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { ForwardConfig: { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts index a5b3d5aea1e5c..b92df26e76bb7 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts @@ -1,5 +1,4 @@ -import { MatchStyle } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as ec2 from '@aws-cdk/aws-ec2'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; @@ -22,7 +21,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'TCP', Port: 443, }); @@ -40,7 +39,7 @@ describe('tests', () => { listener.addTargetGroups('Default', group); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { TargetGroupArn: { Ref: 'TargetGroup3D7CD9B8' }, @@ -64,7 +63,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { TargetGroupArn: { Ref: 'LBListenerTargetsGroup76EF81E8' }, @@ -72,7 +71,7 @@ describe('tests', () => { }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { VpcId: { Ref: 'Stack8A423254' }, Port: 80, Protocol: 'TCP', @@ -96,7 +95,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { DefaultActions: [ { TargetGroupArn: { Ref: 'LBListenerTargetsGroup76EF81E8' }, @@ -104,7 +103,7 @@ describe('tests', () => { }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { VpcId: { Ref: 'Stack8A423254' }, Port: 9700, Protocol: 'TCP_UDP', @@ -139,7 +138,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'TLS', Port: 443, Certificates: [ @@ -153,7 +152,7 @@ describe('tests', () => { }, ], }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { VpcId: { Ref: 'Stack8A423254' }, Port: 80, Protocol: 'TCP', @@ -180,7 +179,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { HealthCheckIntervalSeconds: 30, }); }); @@ -200,7 +199,7 @@ describe('tests', () => { new ResourceWithLBDependency(stack, 'MyResource', group); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches(Match.objectLike({ Resources: { MyResource: { Type: 'Test::Resource', @@ -212,7 +211,7 @@ describe('tests', () => { ], }, }, - }, MatchStyle.SUPERSET); + })); }); test('Trivial add TLS listener', () => { @@ -234,7 +233,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'TLS', Port: 443, Certificates: [ @@ -266,7 +265,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { Protocol: 'TLS', Port: 443, AlpnPolicy: ['HTTP2Only'], @@ -452,7 +451,7 @@ describe('tests', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::ElasticLoadBalancingV2::Listener'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 0); expect(listener.listenerArn).toEqual('arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/network/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2'); }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts index ccfb2924e211e..d0faa87d5cdaa 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts @@ -1,10 +1,9 @@ -import { ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as elbv2 from '../../lib'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; @@ -22,7 +21,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internet-facing', Subnets: [ { Ref: 'StackPublicSubnet1Subnet0AD81D22' }, @@ -41,7 +40,7 @@ describe('tests', () => { new elbv2.NetworkLoadBalancer(stack, 'LB', { vpc }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internal', Subnets: [ { Ref: 'StackPrivateSubnet1Subnet47AC2BC7' }, @@ -63,13 +62,13 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - LoadBalancerAttributes: arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { + LoadBalancerAttributes: Match.arrayWith([ { Key: 'load_balancing.cross_zone.enabled', Value: 'true', }, - ), + ]), }); }); @@ -86,8 +85,8 @@ describe('tests', () => { // THEN // verify that the LB attributes reference the bucket - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - LoadBalancerAttributes: arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { + LoadBalancerAttributes: Match.arrayWith([ { Key: 'access_logs.s3.enabled', Value: 'true', @@ -100,11 +99,11 @@ describe('tests', () => { Key: 'access_logs.s3.prefix', Value: '', }, - ), + ]), }); // verify the bucket policy allows the ALB to put objects in the bucket - expect(stack).toHaveResource('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -140,9 +139,9 @@ describe('tests', () => { }); // verify the ALB depends on the bucket *and* the bucket policy - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { DependsOn: ['AccessLoggingBucketPolicy700D7CC6', 'AccessLoggingBucketA6D88F29'], - }, ResourcePart.CompleteDefinition); + }); }); testFutureBehavior('access logging with prefix', s3GrantWriteCtx, cdk.App, (app) => { @@ -157,8 +156,8 @@ describe('tests', () => { // THEN // verify that the LB attributes reference the bucket - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - LoadBalancerAttributes: arrayWith( + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { + LoadBalancerAttributes: Match.arrayWith([ { Key: 'access_logs.s3.enabled', Value: 'true', @@ -171,11 +170,11 @@ describe('tests', () => { Key: 'access_logs.s3.prefix', Value: 'prefix-of-access-logs', }, - ), + ]), }); // verify the bucket policy allows the ALB to put objects in the bucket - expect(stack).toHaveResource('AWS::S3::BucketPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -223,7 +222,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Name: 'myLoadBalancer', }); }); @@ -285,7 +284,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internal', Subnets: [ { Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6' }, @@ -320,7 +319,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internal', Subnets: [ { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, @@ -355,7 +354,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internet-facing', Subnets: [ { Ref: 'VPCPublicSubnet1SubnetB4246D30' }, @@ -377,7 +376,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internal', Subnets: [ { Ref: 'VPCPublicSubnet1SubnetB4246D30' }, @@ -413,7 +412,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', { Scheme: 'internal', Subnets: [ { Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6' }, @@ -442,7 +441,7 @@ describe('tests', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::ElasticLoadBalancingV2::NetworkLoadBalancer'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::NetworkLoadBalancer', 0); expect(loadBalancer.loadBalancerArn).toEqual('arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/network/my-load-balancer/50dc6c495c0c9188'); expect(loadBalancer.loadBalancerCanonicalHostedZoneId).toEqual('Z3DZXE0EXAMPLE'); expect(loadBalancer.loadBalancerDnsName).toEqual('my-load-balancer-1234567890.us-west-2.elb.amazonaws.com'); @@ -478,8 +477,8 @@ describe('tests', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::ElasticLoadBalancingV2::NetworkLoadBalancer'); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener'); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::NetworkLoadBalancer', 0); + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 1); }); }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts index d1d516ea83665..7caaf465b045d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; @@ -18,7 +18,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'proxy_protocol_v2.enabled', @@ -41,7 +41,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'preserve_client_ip.enabled', @@ -64,7 +64,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'proxy_protocol_v2.enabled', @@ -87,7 +87,7 @@ describe('tests', () => { }); // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { TargetGroupAttributes: [ { Key: 'preserve_client_ip.enabled', @@ -107,7 +107,7 @@ describe('tests', () => { protocol: elbv2.Protocol.UDP, }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Protocol: 'UDP', }); }); @@ -121,7 +121,7 @@ describe('tests', () => { port: 80, }); - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', { Protocol: 'TCP', }); }); diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 3f3fec620eab6..0a5e8839a0843 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/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-elasticsearch/test/domain.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts index 5fc9035dc92f7..3242e75d2c253 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts @@ -1,6 +1,5 @@ /* eslint-disable jest/expect-expect */ -import '@aws-cdk/assert-internal/jest'; -import * as assert from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acm from '@aws-cdk/aws-certificatemanager'; import { Metric, Statistic } from '@aws-cdk/aws-cloudwatch'; import { Vpc, EbsDeviceVolumeType, SecurityGroup } from '@aws-cdk/aws-ec2'; @@ -53,7 +52,7 @@ test('subnets and security groups can be provided when vpc is used', () => { }); expect(domain.connections.securityGroups[0].securityGroupId).toEqual(securityGroup.securityGroupId); - expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { VPCOptions: { SecurityGroupIds: [ { @@ -70,7 +69,6 @@ test('subnets and security groups can be provided when vpc is used', () => { ], }, }); - }); test('default subnets and security group when vpc is used', () => { @@ -82,7 +80,7 @@ test('default subnets and security group when vpc is used', () => { }); expect(stack.resolve(domain.connections.securityGroups[0].securityGroupId)).toEqual({ 'Fn::GetAtt': ['DomainSecurityGroup48AA5FD6', 'GroupId'] }); - expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { VPCOptions: { SecurityGroupIds: [ { @@ -105,7 +103,6 @@ test('default subnets and security group when vpc is used', () => { ], }, }); - }); test('default removalpolicy is retain', () => { @@ -113,9 +110,9 @@ test('default removalpolicy is retain', () => { version: ElasticsearchVersion.V7_1, }); - expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResource('AWS::Elasticsearch::Domain', { DeletionPolicy: 'Retain', - }, assert.ResourcePart.CompleteDefinition); + }); }); test('grants kms permissions if needed', () => { @@ -151,7 +148,7 @@ test('grants kms permissions if needed', () => { Version: '2012-10-17', }; - const resources = assert.expect(stack).value.Resources; + const resources = Template.fromStack(stack).toJSON().Resources; expect(resources.AWS679f53fac002430cb0da5b7982bd2287ServiceRoleDefaultPolicyD28E1A5E.Properties.PolicyDocument).toStrictEqual(expectedPolicy); }); @@ -159,7 +156,7 @@ test('grants kms permissions if needed', () => { test('minimal example renders correctly', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1 }); - expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { CognitoOptions: { Enabled: false, }, @@ -179,10 +176,10 @@ test('minimal example renders correctly', () => { Enabled: false, }, LogPublishingOptions: { - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, NodeToNodeEncryptionOptions: { Enabled: false, @@ -196,11 +193,11 @@ test('can enable version upgrade update policy', () => { enableVersionUpgrade: true, }); - expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResource('AWS::Elasticsearch::Domain', { UpdatePolicy: { EnableVersionUpgrade: true, }, - }, assert.ResourcePart.CompleteDefinition); + }); }); describe('UltraWarm instances', () => { @@ -214,7 +211,7 @@ describe('UltraWarm instances', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { ElasticsearchClusterConfig: { DedicatedMasterEnabled: true, WarmEnabled: true, @@ -234,7 +231,7 @@ describe('UltraWarm instances', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { ElasticsearchClusterConfig: { DedicatedMasterEnabled: true, WarmEnabled: true, @@ -259,7 +256,7 @@ test('can use tokens in capacity configuration', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { ElasticsearchClusterConfig: { InstanceCount: { Ref: 'dataNodes', @@ -295,7 +292,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { SEARCH_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -306,9 +303,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -321,7 +318,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { INDEX_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -332,9 +329,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), }, }); }); @@ -347,7 +344,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -358,9 +355,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -381,7 +378,7 @@ describe('log groups', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { AUDIT_LOGS: { CloudWatchLogsLogGroupArn: { @@ -392,9 +389,9 @@ describe('log groups', () => { }, Enabled: true, }, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -416,7 +413,7 @@ describe('log groups', () => { slowIndexLogEnabled: true, }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -445,10 +442,10 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -477,7 +474,7 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), }, }); }); @@ -497,7 +494,7 @@ describe('log groups', () => { }); // Domain1 - expect(stack).toHaveResourceLike('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { Create: { 'Fn::Join': [ '', @@ -515,7 +512,7 @@ describe('log groups', () => { }, }); // Domain2 - expect(stack).toHaveResourceLike('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { Create: { 'Fn::Join': [ '', @@ -554,7 +551,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { SEARCH_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -565,9 +562,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -583,7 +580,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { INDEX_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -594,9 +591,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), }, }); }); @@ -612,7 +609,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -623,9 +620,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -649,7 +646,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { LogPublishingOptions: { AUDIT_LOGS: { CloudWatchLogsLogGroupArn: { @@ -660,9 +657,9 @@ describe('log groups', () => { }, Enabled: true, }, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -744,7 +741,7 @@ describe('grants', () => { domain.grantReadWrite(user); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -936,7 +933,7 @@ describe('import', () => { expect(imported.domainArn).toMatch(RegExp(`es:testregion:1234:domain/${domainName}$`)); expect(imported.domainEndpoint).toEqual(domainEndpointWithoutHttps); - expect(stack).not.toHaveResource('AWS::Elasticsearch::Domain'); + Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 0); }); test('static fromDomainAttributes(attributes) allows importing an external/existing domain', () => { @@ -953,7 +950,7 @@ describe('import', () => { expect(imported.domainArn).toEqual(domainArn); expect(imported.domainEndpoint).toEqual(domainEndpointWithoutHttps); - expect(stack).not.toHaveResource('AWS::Elasticsearch::Domain'); + Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 0); }); test('static fromDomainAttributes(attributes) allows importing with token arn and endpoint', () => { @@ -991,7 +988,7 @@ describe('import', () => { expect(imported.domainArn).toEqual(domainArn); expect(imported.domainEndpoint).toEqual(domainEndpoint); - expect(stack).not.toHaveResource('AWS::Elasticsearch::Domain'); + Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 0); }); }); @@ -1014,7 +1011,7 @@ describe('advanced security options', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: false, @@ -1048,7 +1045,7 @@ describe('advanced security options', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1082,7 +1079,7 @@ describe('advanced security options', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1113,7 +1110,7 @@ describe('advanced security options', () => { }, }); - expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { GenerateSecretString: { GenerateStringKey: 'password', }, @@ -1190,7 +1187,7 @@ describe('custom endpoints', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { DomainEndpointOptions: { EnforceHTTPS: true, CustomEndpointEnabled: true, @@ -1200,7 +1197,7 @@ describe('custom endpoints', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: customDomainName, ValidationMethod: 'EMAIL', }); @@ -1218,7 +1215,7 @@ describe('custom endpoints', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { DomainEndpointOptions: { EnforceHTTPS: true, CustomEndpointEnabled: true, @@ -1228,7 +1225,7 @@ describe('custom endpoints', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: customDomainName, DomainValidationOptions: [ { @@ -1240,7 +1237,7 @@ describe('custom endpoints', () => { ], ValidationMethod: 'DNS', }); - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'search.example.com.', Type: 'CNAME', HostedZoneId: { @@ -1276,7 +1273,7 @@ describe('custom endpoints', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { DomainEndpointOptions: { EnforceHTTPS: true, CustomEndpointEnabled: true, @@ -1286,7 +1283,7 @@ describe('custom endpoints', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'search.example.com.', Type: 'CNAME', HostedZoneId: { @@ -1548,7 +1545,7 @@ describe('custom error responses', () => { }, }); // both configurations pass synth-time validation - expect(stack).toCountResources('AWS::Elasticsearch::Domain', 2); + Template.fromStack(stack).resourceCountIs('AWS::Elasticsearch::Domain', 2); }); test('error when availabilityZoneCount is not 2 or 3', () => { @@ -1606,7 +1603,7 @@ describe('custom error responses', () => { test('can specify future version', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.of('8.2') }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { ElasticsearchVersion: '8.2', }); }); @@ -1618,7 +1615,7 @@ describe('unsigned basic auth', () => { useUnsignedBasicAuth: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1649,7 +1646,7 @@ describe('unsigned basic auth', () => { useUnsignedBasicAuth: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: false, @@ -1683,7 +1680,7 @@ describe('unsigned basic auth', () => { useUnsignedBasicAuth: true, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1746,7 +1743,7 @@ describe('advanced options', () => { }, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { AdvancedOptions: { 'rest.action.multi.allow_explicit_index': 'true', 'indices.fielddata.cache.size': '50', @@ -1759,8 +1756,8 @@ describe('advanced options', () => { version: ElasticsearchVersion.V7_1, }); - expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { - AdvancedOptions: assert.ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Elasticsearch::Domain', { + AdvancedOptions: Match.absent(), }); }); }); @@ -1800,7 +1797,7 @@ function testGrant( ? resolvedPaths : resolvedPaths[0]; - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts index 53d6afe3b2cb0..38ffc94c0c05b 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.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 { App, Stack } from '@aws-cdk/core'; import { ElasticsearchAccessPolicy } from '../lib/elasticsearch-access-policy'; @@ -26,7 +26,7 @@ test('minimal example renders correctly', () => { })], }); - expect(stack).toHaveResource('Custom::ElasticsearchAccessPolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::ElasticsearchAccessPolicy', { ServiceToken: { 'Fn::GetAtt': [ 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', diff --git a/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts index 68518297588c9..815c0086d4a99 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.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 { App, Stack } from '@aws-cdk/core'; import { LogGroupResourcePolicy } from '../lib/log-group-resource-policy'; @@ -24,7 +24,7 @@ test('minimal example renders correctly', () => { })], }); - expect(stack).toHaveResource('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { ServiceToken: { 'Fn::GetAtt': [ 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index eeb96c1f181a9..602a915b8be8a 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/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-batch": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts b/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts index 7c1033537dd41..06f4a84e3ce12 100644 --- a/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as api from '@aws-cdk/aws-apigateway'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; @@ -20,7 +20,7 @@ test('use api gateway rest api as an event rule target', () => { rule.addTarget(new targets.ApiGateway(restApi)); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { @@ -81,7 +81,7 @@ test('with stage, path, method setting', () => { })); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { @@ -147,7 +147,7 @@ test('with http parameters', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { HttpParameters: { @@ -204,7 +204,7 @@ test('with an explicit event role', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { RoleArn: { @@ -234,7 +234,7 @@ test('use a Dead Letter Queue', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { DeadLetterConfig: { diff --git a/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts b/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts index c605dfa64e992..cc6c58c51a43d 100644 --- a/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts @@ -1,7 +1,7 @@ -import { countResources, expect as cdkExpect, haveResource, SynthUtils } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import { Stack } from '@aws-cdk/core'; +import { App, Stack } from '@aws-cdk/core'; import * as targets from '../../lib'; test('use AwsApi as an event rule target', () => { @@ -32,7 +32,7 @@ test('use AwsApi as an event rule target', () => { })); // THEN - cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { @@ -70,12 +70,12 @@ test('use AwsApi as an event rule target', () => { }), }, ], - })); + }); // Uses a singleton function - cdkExpect(stack).to(countResources('AWS::Lambda::Function', 1)); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 1); - cdkExpect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -91,7 +91,7 @@ test('use AwsApi as an event rule target', () => { ], Version: '2012-10-17', }, - })); + }); }); test('with policy statement', () => { @@ -112,7 +112,7 @@ test('with policy statement', () => { })); // THEN - cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { @@ -128,9 +128,9 @@ test('with policy statement', () => { }), }, ], - })); + }); - cdkExpect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -141,7 +141,7 @@ test('with policy statement', () => { ], Version: '2012-10-17', }, - })); + }); }); test('with service not in AWS SDK', () => { @@ -163,7 +163,7 @@ test('with service not in AWS SDK', () => { rule.addTarget(awsApi); // THEN - const assembly = SynthUtils.synthesize(stack); + const assembly = App.of(stack)!.synth().getStackArtifact(stack.stackName); expect(assembly.messages.length).toBe(1); const message = assembly.messages[0]; expect(message.entry.type).toBe('aws:cdk:warning'); diff --git a/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts b/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts index c379b72a523c6..66d583db4263d 100644 --- a/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as batch from '@aws-cdk/aws-batch'; import { ContainerImage } from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; @@ -41,7 +41,7 @@ describe('Batch job event target', () => { rule.addTarget(new targets.BatchJob(jobQueue.jobQueueArn, jobQueue, jobDefinition.jobDefinitionArn, jobDefinition)); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 min)', State: 'ENABLED', Targets: [ @@ -62,9 +62,9 @@ describe('Batch job event target', () => { }, }, ], - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -81,7 +81,7 @@ describe('Batch job event target', () => { Roles: [ { Ref: 'MyJobEventsRoleCF43C336' }, ], - })); + }); }); test('use a Dead Letter Queue for the rule target', () => { @@ -108,7 +108,7 @@ describe('Batch job event target', () => { )); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { @@ -133,9 +133,9 @@ describe('Batch job event target', () => { }, }, ], - })); + }); - expect(stack).to(haveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -170,7 +170,7 @@ describe('Batch job event target', () => { Ref: 'Queue4A7E3555', }, ], - })); + }); }); test('specifying retry policy', () => { @@ -199,7 +199,7 @@ describe('Batch job event target', () => { )); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -235,6 +235,6 @@ describe('Batch job event target', () => { }, }, ], - })); + }); }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts index 9ad848433a981..c0b7db6d75026 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; @@ -27,7 +27,7 @@ describe('CodeBuild event target', () => { rule.addTarget(new targets.CodeBuildProject(project)); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: projectArn, @@ -35,9 +35,9 @@ describe('CodeBuild event target', () => { RoleArn: { 'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'] }, }, ], - })); + }); - expect(stack).to(haveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -48,9 +48,9 @@ describe('CodeBuild event target', () => { ], Version: '2012-10-17', }, - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -61,7 +61,7 @@ describe('CodeBuild event target', () => { ], Version: '2012-10-17', }, - })); + }); }); test('specifying event for codebuild project target', () => { @@ -82,7 +82,7 @@ describe('CodeBuild event target', () => { ); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: projectArn, @@ -93,7 +93,7 @@ describe('CodeBuild event target', () => { }, }, ], - })); + }); }); test('specifying custom role for codebuild project target', () => { @@ -111,7 +111,7 @@ describe('CodeBuild event target', () => { rule.addTarget(new targets.CodeBuildProject(project, { eventRole: role })); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: projectArn, @@ -119,7 +119,7 @@ describe('CodeBuild event target', () => { RoleArn: { 'Fn::GetAtt': ['MyRole', 'Arn'] }, }, ], - })); + }); }); test('specifying retry policy', () => { @@ -142,7 +142,7 @@ describe('CodeBuild event target', () => { ); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -167,7 +167,7 @@ describe('CodeBuild event target', () => { }, }, ], - })); + }); }); test('use a Dead Letter Queue for the rule target', () => { @@ -191,7 +191,7 @@ describe('CodeBuild event target', () => { ); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: projectArn, @@ -210,9 +210,9 @@ describe('CodeBuild event target', () => { }, }, ], - })); + }); - expect(stack).to(haveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -247,6 +247,6 @@ describe('CodeBuild event target', () => { Ref: 'Queue4A7E3555', }, ], - })); + }); }); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts index 79dc7408cd4f7..aeccbee05fd7c 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; @@ -67,7 +67,7 @@ describe('CodePipeline event target', () => { }); test("adds the pipeline's ARN and role to the targets of the rule", () => { - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: pipelineArn, @@ -75,11 +75,11 @@ describe('CodePipeline event target', () => { RoleArn: { 'Fn::GetAtt': ['PipelineEventsRole46BEEA7C', 'Arn'] }, }, ], - })); + }); }); test("creates a policy that has StartPipeline permissions on the pipeline's ARN", () => { - expect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -90,7 +90,7 @@ describe('CodePipeline event target', () => { ], Version: '2012-10-17', }, - })); + }); }); }); @@ -106,7 +106,7 @@ describe('CodePipeline event target', () => { })); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ @@ -155,7 +155,7 @@ describe('CodePipeline event target', () => { }, }, ], - })); + }); }); }); @@ -173,14 +173,14 @@ describe('CodePipeline event target', () => { }); test("points at the given event role in the rule's targets", () => { - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: pipelineArn, RoleArn: { 'Fn::GetAtt': ['MyRole', 'Arn'] }, }, ], - })); + }); }); }); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts index eb17b98622369..86045087ab756 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; @@ -48,7 +48,7 @@ test('Can use EC2 taskdef as EventRule target', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -119,7 +119,7 @@ test('Can import an EC2 task definition from task definition attributes as Event })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -190,7 +190,7 @@ test('Can import a Fargate task definition from task definition attributes as Ev })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -261,7 +261,7 @@ test('Can import a Task definition from task definition attributes as EventRule })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -307,7 +307,7 @@ test('Can use Fargate taskdef as EventRule target', () => { // THEN expect(target.securityGroups?.length).toBeGreaterThan(0); // Generated security groups should be accessible. - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -438,7 +438,7 @@ test('Isolated subnet does not have AssignPublicIp=true', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster2F191ADEC', 'Arn'] }, @@ -529,7 +529,7 @@ test('uses multiple security groups', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -586,7 +586,7 @@ test('uses existing IAM role', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -630,7 +630,7 @@ test('uses the specific fargate platform version', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, diff --git a/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts index a6552a10d7a57..cb2940fdb0cd7 100644 --- a/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -18,7 +18,7 @@ test('Use EventBus as an event rule target', () => { ), )); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: 'arn:aws:events:us-east-1:111111111111:default', @@ -32,7 +32,7 @@ test('Use EventBus as an event rule target', () => { }, ], }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [{ Effect: 'Allow', @@ -66,7 +66,7 @@ test('with supplied role', () => { { role }, )); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [{ Arn: 'arn:aws:events:us-east-1:123456789012:default', Id: 'Target0', @@ -78,7 +78,7 @@ test('with supplied role', () => { }, }], }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [{ Effect: 'Allow', @@ -109,7 +109,7 @@ test('with a Dead Letter Queue specified', () => { { deadLetterQueue: queue }, )); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [{ Arn: 'arn:aws:events:us-east-1:123456789012:default', Id: 'Target0', @@ -130,7 +130,7 @@ test('with a Dead Letter Queue specified', () => { }], }); - expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts index 6896f2c9bf934..1c0fb9ea9d88f 100644 --- a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as firehose from '@aws-cdk/aws-kinesisfirehose'; import { Stack } from '@aws-cdk/core'; @@ -30,7 +30,7 @@ describe('KinesisFirehoseStream event target', () => { }); test("adds the stream's ARN and role to the targets of the rule", () => { - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: streamArn, @@ -38,11 +38,11 @@ describe('KinesisFirehoseStream event target', () => { RoleArn: { 'Fn::GetAtt': ['MyStreamEventsRole5B6CC6AF', 'Arn'] }, }, ], - })); + }); }); test("creates a policy that has PutRecord and PutRecords permissions on the stream's ARN", () => { - expect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -53,7 +53,7 @@ describe('KinesisFirehoseStream event target', () => { ], Version: '2012-10-17', }, - })); + }); }); }); @@ -65,7 +65,7 @@ describe('KinesisFirehoseStream event target', () => { }); test('sets the input', () => { - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: streamArn, @@ -73,7 +73,7 @@ describe('KinesisFirehoseStream event target', () => { Input: '"fooBar"', }, ], - })); + }); }); }); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts b/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts index a36e57dfa4dc2..1fb4a4785340d 100644 --- a/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as kinesis from '@aws-cdk/aws-kinesis'; import { Stack } from '@aws-cdk/core'; @@ -30,7 +30,7 @@ describe('KinesisStream event target', () => { }); test("adds the stream's ARN and role to the targets of the rule", () => { - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: streamArn, @@ -38,11 +38,11 @@ describe('KinesisStream event target', () => { RoleArn: { 'Fn::GetAtt': ['MyStreamEventsRole5B6CC6AF', 'Arn'] }, }, ], - })); + }); }); test("creates a policy that has PutRecord and PutRecords permissions on the stream's ARN", () => { - expect(stack).to(haveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -53,7 +53,7 @@ describe('KinesisStream event target', () => { ], Version: '2012-10-17', }, - })); + }); }); }); @@ -65,7 +65,7 @@ describe('KinesisStream event target', () => { }); test('sets the partition key path', () => { - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: streamArn, @@ -76,7 +76,7 @@ describe('KinesisStream event target', () => { }, }, ], - })); + }); }); }); @@ -88,7 +88,7 @@ describe('KinesisStream event target', () => { }); test('sets the input', () => { - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: streamArn, @@ -96,7 +96,7 @@ describe('KinesisStream event target', () => { Input: '"fooBar"', }, ], - })); + }); }); }); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts b/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts index 5aa19af311b35..567f17e0a1fc9 100644 --- a/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -24,7 +24,7 @@ test('use lambda as an event rule target', () => { // THEN const lambdaId = 'MyLambdaCCE802FB'; - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -36,7 +36,7 @@ test('use lambda as an event rule target', () => { SourceArn: { 'Fn::GetAtt': ['Rule4C995B7F', 'Arn'] }, }); - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -48,8 +48,8 @@ test('use lambda as an event rule target', () => { SourceArn: { 'Fn::GetAtt': ['Rule270732244', 'Arn'] }, }); - expect(stack).toCountResources('AWS::Events::Rule', 2); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 2); + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { 'Fn::GetAtt': [lambdaId, 'Arn'] }, @@ -76,7 +76,7 @@ test('adding same lambda function as target mutiple times creates permission onl })); // THEN - expect(stack).toCountResources('AWS::Lambda::Permission', 1); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 1); }); test('adding different lambda functions as target mutiple times creates multiple permissions', () => { @@ -97,7 +97,7 @@ test('adding different lambda functions as target mutiple times creates multiple })); // THEN - expect(stack).toCountResources('AWS::Lambda::Permission', 2); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 2); }); test('adding same singleton lambda function as target mutiple times creates permission only once', () => { @@ -122,7 +122,7 @@ test('adding same singleton lambda function as target mutiple times creates perm })); // THEN - expect(stack).toCountResources('AWS::Lambda::Permission', 1); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 1); }); test('lambda handler and cloudwatch event across stacks', () => { @@ -145,7 +145,7 @@ test('lambda handler and cloudwatch event across stacks', () => { expect(() => app.synth()).not.toThrow(); // the Permission resource should be in the event stack - expect(eventStack).toCountResources('AWS::Lambda::Permission', 1); + Template.fromStack(eventStack).resourceCountIs('AWS::Lambda::Permission', 1); }); test('use a Dead Letter Queue for the rule target', () => { @@ -171,7 +171,7 @@ test('use a Dead Letter Queue for the rule target', () => { expect(() => app.synth()).not.toThrow(); // the Permission resource should be in the event stack - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Arn: { @@ -193,7 +193,7 @@ test('use a Dead Letter Queue for the rule target', () => { ], }); - expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -300,7 +300,7 @@ test('must display a warning when using a Dead Letter Queue from another account expect(() => app.synth()).not.toThrow(); // the Permission resource should be in the event stack - expect(stack1).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack1).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ @@ -319,7 +319,7 @@ test('must display a warning when using a Dead Letter Queue from another account ], }); - expect(stack1).not.toHaveResource('AWS::SQS::QueuePolicy'); + Template.fromStack(stack1).resourceCountIs('AWS::SQS::QueuePolicy', 0); let rule = stack1.node.children.find(child => child instanceof events.Rule); expect(rule?.node.metadataEntry[0].data).toMatch(/Cannot add a resource policy to your dead letter queue associated with rule .* because the queue is in a different account\. You must add the resource policy manually to the dead letter queue in account 222222222222\./); @@ -350,7 +350,7 @@ test('specifying retry policy', () => { expect(() => app.synth()).not.toThrow(); // the Permission resource should be in the event stack - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts b/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts index 4193c9899e3cb..bcf3309c030a1 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.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 { App, Stack } from '@aws-cdk/core'; import { LogGroupResourcePolicy } from '../../lib/log-group-resource-policy'; @@ -24,7 +24,7 @@ test('minimal example renders correctly', () => { })], }); - expect(stack).toHaveResource('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { ServiceToken: { 'Fn::GetAtt': [ 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts b/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts index e9c1170fe8bb0..509f09263f4fe 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as logs from '@aws-cdk/aws-logs'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -20,7 +20,7 @@ test('use log group as an event rule target', () => { rule1.addTarget(new targets.CloudWatchLogGroup(logGroup)); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ @@ -72,7 +72,7 @@ test('use log group as an event rule target with rule target input', () => { })); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ @@ -135,7 +135,7 @@ test('specifying retry policy and dead letter queue', () => { })); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ diff --git a/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts b/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts index 11d6a2c6806bd..ac1d0dc5e740b 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as sns from '@aws-cdk/aws-sns'; import { Duration, Stack } from '@aws-cdk/core'; @@ -16,7 +16,7 @@ test('sns topic as an event rule target', () => { rule.addTarget(new targets.SnsTopic(topic)); // THEN - expect(stack).to(haveResource('AWS::SNS::TopicPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { PolicyDocument: { Statement: [ { @@ -30,9 +30,9 @@ test('sns topic as an event rule target', () => { Version: '2012-10-17', }, Topics: [{ Ref: 'MyTopic86869434' }], - })); + }); - expect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -41,7 +41,7 @@ test('sns topic as an event rule target', () => { Id: 'Target0', }, ], - })); + }); }); test('multiple uses of a topic as a target results in a single policy statement', () => { @@ -58,7 +58,7 @@ test('multiple uses of a topic as a target results in a single policy statement' } // THEN - expect(stack).to(haveResource('AWS::SNS::TopicPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { PolicyDocument: { Statement: [ { @@ -72,5 +72,5 @@ test('multiple uses of a topic as a target results in a single policy statement' Version: '2012-10-17', }, Topics: [{ Ref: 'MyTopic86869434' }], - })); + }); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts b/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts index ad2a5296714e6..f224a91171fcf 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts @@ -1,4 +1,4 @@ -import { expect as cdkExpect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as sqs from '@aws-cdk/aws-sqs'; import { Duration, Stack } from '@aws-cdk/core'; @@ -16,7 +16,7 @@ test('sqs queue as an event rule target', () => { rule.addTarget(new targets.SqsQueue(queue)); // THEN - cdkExpect(stack).to(haveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -48,9 +48,9 @@ test('sqs queue as an event rule target', () => { Version: '2012-10-17', }, Queues: [{ Ref: 'MyQueueE6CA6235' }], - })); + }); - cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -64,7 +64,7 @@ test('sqs queue as an event rule target', () => { Id: 'Target0', }, ], - })); + }); }); test('multiple uses of a queue as a target results in multi policy statement because of condition', () => { @@ -81,7 +81,7 @@ test('multiple uses of a queue as a target results in multi policy statement bec } // THEN - cdkExpect(stack).to(haveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -138,7 +138,7 @@ test('multiple uses of a queue as a target results in multi policy statement bec Version: '2012-10-17', }, Queues: [{ Ref: 'MyQueueE6CA6235' }], - })); + }); }); test('fail if messageGroupId is specified on non-fifo queues', () => { @@ -161,7 +161,7 @@ test('fifo queues are synthesized correctly', () => { messageGroupId: 'MyMessageGroupId', })); - cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -178,7 +178,7 @@ test('fifo queues are synthesized correctly', () => { }, }, ], - })); + }); }); test('dead letter queue is configured correctly', () => { @@ -194,7 +194,7 @@ test('dead letter queue is configured correctly', () => { deadLetterQueue, })); - cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -216,7 +216,7 @@ test('dead letter queue is configured correctly', () => { }, }, ], - })); + }); }); test('specifying retry policy', () => { @@ -232,7 +232,7 @@ test('specifying retry policy', () => { maxEventAge: Duration.hours(2), })); - cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -250,5 +250,5 @@ test('specifying retry policy', () => { }, }, ], - })); + }); }); diff --git a/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts b/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts index d50e41c1debce..158b19f34fa0a 100644 --- a/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -22,14 +22,14 @@ test('State machine can be used as Event Rule target', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Input: '{"SomeParam":"SomeValue"}', }, ], }); - expect(stack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -42,7 +42,7 @@ test('State machine can be used as Event Rule target', () => { ], }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -77,14 +77,14 @@ test('Existing role can be used for State machine Rule target', () => { })); // THEN - expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { Targets: [ { Input: '{"SomeParam":"SomeValue"}', }, ], }); - expect(stack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -97,7 +97,7 @@ test('Existing role can be used for State machine Rule target', () => { ], }, }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -135,7 +135,7 @@ test('specifying retry policy', () => { })); // THEN - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 hour)', State: 'ENABLED', Targets: [ @@ -186,7 +186,7 @@ test('use a Dead Letter Queue for the rule target', () => { })); // the Permission resource should be in the event stack - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { ScheduleExpression: 'rate(1 minute)', State: 'ENABLED', Targets: [ @@ -214,7 +214,7 @@ test('use a Dead Letter Queue for the rule target', () => { ], }); - expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json index 703a1b6679e9d..4ead0ec949749 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/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/aws-globalaccelerator-endpoints/test/endpoints.test.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/endpoints.test.ts index 01b55508f11a0..c241c8ccd6646 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/endpoints.test.ts +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/endpoints.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as ga from '@aws-cdk/aws-globalaccelerator'; @@ -32,7 +32,7 @@ test('Application Load Balancer with all properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointConfigurations: [ { EndpointId: { Ref: 'ALBAEE750D2' }, @@ -57,7 +57,7 @@ test('Get region from imported ALB', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointGroupRegion: 'us-west-2', EndpointConfigurations: [ { @@ -79,7 +79,7 @@ test('Network Load Balancer with all properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointConfigurations: [ { EndpointId: { Ref: 'NLB55158F82' }, @@ -102,7 +102,7 @@ test('Get region from imported NLB', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointGroupRegion: 'us-west-2', EndpointConfigurations: [ { @@ -124,7 +124,7 @@ test('CFN EIP with all properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointConfigurations: [ { EndpointId: { 'Fn::GetAtt': ['ElasticIpAddress', 'AllocationId'] }, @@ -151,7 +151,7 @@ test('EC2 Instance with all properties', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointConfigurations: [ { EndpointId: { Ref: 'InstanceC1063A87' }, diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index c89513ed8fb57..14f3c7036f24b 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/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/aws-elasticloadbalancingv2": "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-globalaccelerator/test/globalaccelerator-security-group.test.ts b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts index 7191988ed2ed6..dfa4ea9a918bc 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ga from '../lib'; import { testFixture } from './util'; @@ -22,7 +22,7 @@ test('custom resource exists', () => { endpointGroup.connectionsPeer('GlobalAcceleratorSG', vpc); // THEN - expect(stack).to(haveResource('Custom::AWS', { + Template.fromStack(stack).hasResource('Custom::AWS', { Properties: { ServiceToken: { 'Fn::GetAtt': [ @@ -48,7 +48,7 @@ test('custom resource exists', () => { 'GroupGlobalAcceleratorSGCustomResourceCustomResourcePolicy9C957AD2', 'GroupC77FDACD', ], - }, ResourcePart.CompleteDefinition)); + }); }); test('can create security group rule', () => { @@ -73,7 +73,7 @@ test('can create security group rule', () => { instanceConnections.allowFrom(gaSg, ec2.Port.tcp(443)); // THEN - expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', FromPort: 443, GroupId: { @@ -89,5 +89,5 @@ test('can create security group rule', () => { ], }, ToPort: 443, - })); + }); }); diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts index bd46c697ac1c3..94296978b50b6 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import { Duration } from '@aws-cdk/core'; import * as ga from '../lib'; import { testFixture } from './util'; @@ -11,9 +11,9 @@ test('create accelerator', () => { new ga.Accelerator(stack, 'Accelerator'); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::Accelerator', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::Accelerator', { Enabled: true, - })); + }); }); test('create listener', () => { @@ -33,7 +33,7 @@ test('create listener', () => { }); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::Listener', { AcceleratorArn: { 'Fn::GetAtt': [ 'Accelerator8EB0B6B1', @@ -48,7 +48,7 @@ test('create listener', () => { ], Protocol: 'TCP', ClientAffinity: 'NONE', - })); + }); }); test('toPort defaults to fromPort if left out', () => { @@ -64,14 +64,14 @@ test('toPort defaults to fromPort if left out', () => { }); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::Listener', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::Listener', { PortRanges: [ { FromPort: 123, ToPort: 123, }, ], - })); + }); }); test('create endpointgroup', () => { @@ -92,7 +92,7 @@ test('create endpointgroup', () => { new ga.EndpointGroup(stack, 'Group', { listener }); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointGroupRegion: { Ref: 'AWS::Region', }, @@ -102,7 +102,7 @@ test('create endpointgroup', () => { 'ListenerArn', ], }, - })); + }); }); test('endpointgroup region is the first endpoint\'s region', () => { @@ -125,9 +125,9 @@ test('endpointgroup region is the first endpoint\'s region', () => { }); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointGroupRegion: 'us-bla-5', - })); + }); }); test('endpointgroup with all parameters', () => { @@ -156,7 +156,7 @@ test('endpointgroup with all parameters', () => { }); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointGroupRegion: 'us-bla-5', HealthCheckIntervalSeconds: 10, HealthCheckPath: '/ping', @@ -170,7 +170,7 @@ test('endpointgroup with all parameters', () => { ], ThresholdCount: 23, TrafficDialPercentage: 86, - })); + }); }); test('addEndpoint', () => { @@ -201,7 +201,7 @@ test('addEndpoint', () => { }); // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::GlobalAccelerator::EndpointGroup', { EndpointConfigurations: [ { EndpointId: 'i-123', @@ -209,5 +209,5 @@ test('addEndpoint', () => { Weight: 30, }, ], - })); + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index fec5003622341..abe60b8a954a0 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "@types/sinon": "^9.0.11", "jest": "^27.4.7", diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 03d0df77569ae..9b0c7831162cb 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/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-kms/test/alias.test.ts b/packages/@aws-cdk/aws-kms/test/alias.test.ts index 094d2a3e7dbed..01e0b6f353b62 100644 --- a/packages/@aws-cdk/aws-kms/test/alias.test.ts +++ b/packages/@aws-cdk/aws-kms/test/alias.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { ArnPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; import { Alias } from '../lib/alias'; @@ -15,7 +15,7 @@ test('default alias', () => { new Alias(stack, 'Alias', { targetKey: key, aliasName: 'alias/foo' }); - expect(stack).toHaveResource('AWS::KMS::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/foo', TargetKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] }, }); @@ -35,7 +35,7 @@ test('add "alias/" prefix if not given.', () => { targetKey: key, }); - expect(stack).toHaveResource('AWS::KMS::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/foo', TargetKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] }, }); @@ -51,7 +51,7 @@ test('can create alias directly while creating the key', () => { alias: 'foo', }); - expect(stack).toHaveResource('AWS::KMS::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/foo', TargetKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] }, }); @@ -140,13 +140,11 @@ test('can be used wherever a key is expected', () => { new MyConstruct(stack, 'MyConstruct', myAlias); /* eslint-enable @aws-cdk/no-core-construct */ - expect(stack).toHaveOutput({ - outputName: 'OutId', - outputValue: 'alias/myAlias', + Template.fromStack(stack).hasOutput('OutId', { + Value: 'alias/myAlias', }); - expect(stack).toHaveOutput({ - outputName: 'OutArn', - outputValue: { + Template.fromStack(stack).hasOutput('OutArn', { + Value: { 'Fn::Join': ['', [ 'arn:', { Ref: 'AWS::Partition' }, @@ -181,13 +179,11 @@ test('imported alias by name - can be used where a key is expected', () => { new MyConstruct(stack, 'MyConstruct', myAlias); /* eslint-enable @aws-cdk/no-core-construct */ - expect(stack).toHaveOutput({ - outputName: 'OutId', - outputValue: 'alias/myAlias', + Template.fromStack(stack).hasOutput('OutId', { + Value: 'alias/myAlias', }); - expect(stack).toHaveOutput({ - outputName: 'OutArn', - outputValue: { + Template.fromStack(stack).hasOutput('OutArn', { + Value: { 'Fn::Join': ['', [ 'arn:', { Ref: 'AWS::Partition' }, diff --git a/packages/@aws-cdk/aws-kms/test/key.from-lookup.test.ts b/packages/@aws-cdk/aws-kms/test/key.from-lookup.test.ts index f7af3c8c0dd14..72598e01708f1 100644 --- a/packages/@aws-cdk/aws-kms/test/key.from-lookup.test.ts +++ b/packages/@aws-cdk/aws-kms/test/key.from-lookup.test.ts @@ -3,7 +3,6 @@ import { ContextProvider, GetContextValueOptions, GetContextValueResult, Lazy, S import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { Key } from '../lib'; -import '@aws-cdk/assert-internal/jest'; test('requires concrete values', () => { expect(() => { diff --git a/packages/@aws-cdk/aws-kms/test/key.test.ts b/packages/@aws-cdk/aws-kms/test/key.test.ts index 5a42d030bf36a..a73d0b0cabf97 100644 --- a/packages/@aws-cdk/aws-kms/test/key.test.ts +++ b/packages/@aws-cdk/aws-kms/test/key.test.ts @@ -1,5 +1,4 @@ -import { arrayWith, countResources, expect as expectCdk, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import { describeDeprecated, testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -47,7 +46,7 @@ testFutureBehavior('default key', flags, cdk.App, (app) => { const stack = new cdk.Stack(app); new kms.Key(stack, 'MyKey'); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResource('AWS::KMS::Key', { Properties: { KeyPolicy: { Statement: [ @@ -65,14 +64,14 @@ testFutureBehavior('default key', flags, cdk.App, (app) => { }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition); + }); }); testFutureBehavior('default with no retention', flags, cdk.App, (app) => { const stack = new cdk.Stack(app); new kms.Key(stack, 'MyKey', { removalPolicy: cdk.RemovalPolicy.DESTROY }); - expect(stack).toHaveResource('AWS::KMS::Key', { DeletionPolicy: 'Delete', UpdateReplacePolicy: 'Delete' }, ResourcePart.CompleteDefinition); + Template.fromStack(stack).hasResource('AWS::KMS::Key', { DeletionPolicy: 'Delete', UpdateReplacePolicy: 'Delete' }); }); describe('key policies', () => { @@ -85,7 +84,7 @@ describe('key policies', () => { new kms.Key(stack, 'MyKey', { policy }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -110,7 +109,7 @@ describe('key policies', () => { const key = new kms.Key(stack, 'MyKey'); key.addToResourcePolicy(statement); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -146,7 +145,7 @@ describe('key policies', () => { // THEN // Key policy should be unmodified by the grant. - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -160,7 +159,7 @@ describe('key policies', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -185,7 +184,7 @@ describe('key policies', () => { // THEN // Key policy should be unmodified by the grant. - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -199,7 +198,7 @@ describe('key policies', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -226,7 +225,7 @@ describe('key policies', () => { key.grantEncrypt(principal); - expect(principalStack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(principalStack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -258,9 +257,9 @@ describe('key policies', () => { key.grantEncrypt(principal); - expect(keyStack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(keyStack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: arrayWith( + Statement: Match.arrayWith([ { Action: [ 'kms:Encrypt', @@ -271,11 +270,11 @@ describe('key policies', () => { Principal: { AWS: { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::', { Ref: 'AWS::AccountId' }, ':role/MyRolePhysicalName']] } }, Resource: '*', }, - ), + ]), Version: '2012-10-17', }, }); - expect(principalStack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(principalStack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -305,27 +304,22 @@ describe('key policies', () => { key.grantEncrypt(principal); - expect(keyStack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(keyStack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - { - // Default policy, unmodified - }, - { - Action: [ - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - Effect: 'Allow', - Principal: { AWS: { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::0123456789012:role/MyRolePhysicalName']] } }, - Resource: '*', - }, - ], + Statement: Match.arrayWith([{ + Action: [ + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Effect: 'Allow', + Principal: { AWS: { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::0123456789012:role/MyRolePhysicalName']] } }, + Resource: '*', + }]), Version: '2012-10-17', }, }); - expect(principalStack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(principalStack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -348,7 +342,7 @@ describe('key policies', () => { const adminRole = iam.Role.fromRoleArn(stack, 'Admin', 'arn:aws:iam::123456789012:role/TrustedAdmin'); new kms.Key(stack, 'MyKey', { admins: [adminRole] }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -380,7 +374,7 @@ describe('key policies', () => { }); new kms.Key(stack, 'MyKey', { admins: [adminRole] }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { // Unmodified - default key policy Statement: [ @@ -396,7 +390,7 @@ describe('key policies', () => { Version: '2012-10-17', }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -423,7 +417,7 @@ testFutureBehavior('key with some options', flags, cdk.App, (app) => { cdk.Tags.of(key).add('tag2', 'value2'); cdk.Tags.of(key).add('tag3', ''); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { Enabled: false, EnableKeyRotation: true, PendingWindowInDays: 7, @@ -460,7 +454,7 @@ describeDeprecated('trustAccountIdentities is deprecated', () => { testLegacyBehavior('trustAccountIdentities changes key policy to allow IAM control', cdk.App, (app) => { const stack = new cdk.Stack(app); new kms.Key(stack, 'MyKey', { trustAccountIdentities: true }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -487,8 +481,8 @@ testFutureBehavior('addAlias creates an alias', flags, cdk.App, (app) => { const alias = key.addAlias('alias/xoo'); expect(alias.aliasName).toBeDefined(); - expect(stack).toCountResources('AWS::KMS::Alias', 1); - expect(stack).toHaveResource('AWS::KMS::Alias', { + Template.fromStack(stack).resourceCountIs('AWS::KMS::Alias', 1); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/xoo', TargetKeyId: { 'Fn::GetAtt': [ @@ -511,8 +505,8 @@ testFutureBehavior('can run multiple addAlias', flags, cdk.App, (app) => { expect(alias1.aliasName).toBeDefined(); expect(alias2.aliasName).toBeDefined(); - expect(stack).toCountResources('AWS::KMS::Alias', 2); - expect(stack).toHaveResource('AWS::KMS::Alias', { + Template.fromStack(stack).resourceCountIs('AWS::KMS::Alias', 2); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/alias1', TargetKeyId: { 'Fn::GetAtt': [ @@ -521,7 +515,7 @@ testFutureBehavior('can run multiple addAlias', flags, cdk.App, (app) => { ], }, }); - expect(stack).toHaveResource('AWS::KMS::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { AliasName: 'alias/alias2', TargetKeyId: { 'Fn::GetAtt': [ @@ -540,9 +534,8 @@ testFutureBehavior('keyId resolves to a Ref', flags, cdk.App, (app) => { value: key.keyId, }); - expect(stack).toHaveOutput({ - outputName: 'Out', - outputValue: { Ref: 'MyKey6AB29FA6' }, + Template.fromStack(stack).hasOutput('Out', { + Value: { Ref: 'MyKey6AB29FA6' }, }); }); @@ -589,7 +582,7 @@ describe('imported keys', () => { expect(myKeyImported.keyId).toEqual('12345678-1234-1234-1234-123456789012'); - expect(stack2).toMatchTemplate({ + Template.fromStack(stack2).templateMatches({ Resources: { MyKeyImportedAliasB1C5269F: { Type: 'AWS::KMS::Alias', @@ -647,7 +640,7 @@ describe('fromCfnKey()', () => { }); test('preserves the KMS Key resource', () => { - expectCdk(stack).to(haveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -669,9 +662,8 @@ describe('fromCfnKey()', () => { ], Version: '2012-10-17', }, - })); - - expectCdk(stack).to(countResources('AWS::KMS::Key', 1)); + }); + Template.fromStack(stack).resourceCountIs('AWS::KMS::Key', 1); }); describe("calling 'addToResourcePolicy()' on the returned Key", () => { @@ -690,7 +682,7 @@ describe('fromCfnKey()', () => { }); test('preserves the mutating call in the resulting template', () => { - expectCdk(stack).to(haveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -718,7 +710,7 @@ describe('fromCfnKey()', () => { ], Version: '2012-10-17', }, - })); + }); }); }); @@ -736,7 +728,7 @@ describe('fromCfnKey()', () => { }); test('creates the correct IAM Policy', () => { - expectCdk(stack).to(haveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -748,11 +740,11 @@ describe('fromCfnKey()', () => { }, ], }, - })); + }); }); test('correctly mutates the Policy of the underlying CfnKey', () => { - expectCdk(stack).to(haveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -784,7 +776,7 @@ describe('fromCfnKey()', () => { ], Version: '2012-10-17', }, - })); + }); }); }); }); @@ -948,7 +940,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { const stack = new cdk.Stack(app); new kms.Key(stack, 'MyKey'); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResource('AWS::KMS::Key', { Properties: { KeyPolicy: { Statement: [ @@ -966,7 +958,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition); + }); }); testLegacyBehavior('policy if specified appends to the default key policy', cdk.App, (app) => { @@ -976,7 +968,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { p.addArnPrincipal('arn:aws:iam::111122223333:root'); key.addToResourcePolicy(p); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyKey6AB29FA6: { Type: 'AWS::KMS::Key', @@ -1015,7 +1007,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { const adminRole = iam.Role.fromRoleArn(stack, 'Admin', 'arn:aws:iam::123456789012:role/TrustedAdmin'); new kms.Key(stack, 'MyKey', { admins: [adminRole] }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -1047,7 +1039,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { }); new kms.Key(stack, 'MyKey', { admins: [adminRole] }); - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ { @@ -1070,7 +1062,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { Version: '2012-10-17', }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1095,7 +1087,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { key.grantDecrypt(user); // THEN - expect(stack).toHaveResource('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { Statement: [ // This one is there by default @@ -1117,7 +1109,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1144,9 +1136,9 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { key.grantEncrypt(principal); - expect(keyStack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(keyStack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: arrayWith({ + Statement: Match.arrayWith([{ Action: [ 'kms:Encrypt', 'kms:ReEncrypt*', @@ -1157,7 +1149,7 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { AWS: { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::', { Ref: 'AWS::AccountId' }, ':root']] }, }, Resource: '*', - }), + }]), }, }); }); @@ -1169,7 +1161,7 @@ describe('key specs and key usages', () => { const stack = new cdk.Stack(app); new kms.Key(stack, 'Key', { keySpec: kms.KeySpec.ECC_SECG_P256K1, keyUsage: kms.KeyUsage.SIGN_VERIFY }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeySpec: 'ECC_SECG_P256K1', KeyUsage: 'SIGN_VERIFY', }); @@ -1179,7 +1171,7 @@ describe('key specs and key usages', () => { const stack = new cdk.Stack(app); new kms.Key(stack, 'Key', { keyUsage: kms.KeyUsage.ENCRYPT_DECRYPT }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyUsage: 'ENCRYPT_DECRYPT', }); }); @@ -1188,7 +1180,7 @@ describe('key specs and key usages', () => { const stack = new cdk.Stack(app); new kms.Key(stack, 'Key', { keySpec: kms.KeySpec.RSA_4096 }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeySpec: 'RSA_4096', }); }); diff --git a/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts b/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts index 1e5eeb95f28ff..b00640f675378 100644 --- a/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts +++ b/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '../lib'; diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 96380582772ce..7f945078ba7e1 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/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/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts b/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts index 3be1f3d94f37f..d30d292c7e510 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts +++ b/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as events from '@aws-cdk/aws-events'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; @@ -28,7 +28,7 @@ test('event bus as destination', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { DestinationConfig: { OnSuccess: { Destination: { @@ -41,7 +41,7 @@ test('event bus as destination', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -71,7 +71,7 @@ test('lambda as destination', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { DestinationConfig: { OnSuccess: { Destination: { @@ -84,7 +84,7 @@ test('lambda as destination', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -116,7 +116,7 @@ test('lambda payload as destination', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { DestinationConfig: { OnSuccess: { Destination: { @@ -165,7 +165,7 @@ test('lambda payload as destination', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -197,7 +197,7 @@ test('lambda payload as destination', () => { }, }); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { EventPattern: { 'detail-type': [ 'Lambda Function Invocation Result - Success', @@ -236,7 +236,7 @@ test('lambda payload as destination', () => { ], }); - expect(stack).toHaveResource('AWS::Events::Rule', { + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { EventPattern: { 'detail-type': [ 'Lambda Function Invocation Result - Failure', @@ -287,7 +287,7 @@ test('sns as destination', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { DestinationConfig: { OnSuccess: { Destination: { @@ -297,7 +297,7 @@ test('sns as destination', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -324,7 +324,7 @@ test('sqs as destination', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { DestinationConfig: { OnSuccess: { Destination: { @@ -337,7 +337,7 @@ test('sqs as destination', () => { }, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 21f0c02004903..e7080c9ab72a0 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -192,6 +192,7 @@ new lambda.NodejsFunction(this, 'my-handler', { footer: '/* comments */', // requires esbuild >= 0.9.0, defaults to none charset: lambda.Charset.UTF8, // do not escape non-ASCII characters, defaults to Charset.ASCII format: lambda.OutputFormat.ESM, // ECMAScript module output format, defaults to OutputFormat.CJS (OutputFormat.ESM requires Node.js 14.x) + mainFields: ['module', 'main'], // prefer ECMAScript versions of dependencies }, }); ``` diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 62b5d56a0bc1d..d0cae32489818 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -211,6 +211,7 @@ export class Bundling implements cdk.BundlingOptions { ...this.props.banner ? [`--banner:js=${JSON.stringify(this.props.banner)}`] : [], ...this.props.footer ? [`--footer:js=${JSON.stringify(this.props.footer)}`] : [], ...this.props.charset ? [`--charset=${this.props.charset}`] : [], + ...this.props.mainFields ? [`--main-fields=${this.props.mainFields.join(',')}`] : [], ]; let depsCommand = ''; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index b74ac1df3b74a..e43dc6d41be1e 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -270,6 +270,14 @@ export interface BundlingOptions { * @default OutputFormat.CJS */ readonly format?: OutputFormat; + + /** + * How to determine the entry point for modules. + * Try ['module', 'main'] to default to ES module versions. + * + * @default ['main', 'module'] + */ + readonly mainFields?: string[]; } /** diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index 5941ce880a987..f9b8301eacacc 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -201,6 +201,7 @@ test('esbuild bundling with esbuild options', () => { footer: '/* comments */', charset: Charset.UTF8, forceDockerBundling: true, + mainFields: ['module', 'main'], define: { 'process.env.KEY': JSON.stringify('VALUE'), 'process.env.BOOL': 'true', @@ -224,7 +225,7 @@ test('esbuild bundling with esbuild options', () => { defineInstructions, '--log-level=silent --keep-names --tsconfig=/asset-input/lib/custom-tsconfig.ts', '--metafile=/asset-output/index.meta.json --banner:js="/* comments */" --footer:js="/* comments */"', - '--charset=utf8', + '--charset=utf8 --main-fields=module,main', ].join(' '), ], }), diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index a45dfbc33c284..c67a32c6e3085 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -83,13 +83,13 @@ }, "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", "@aws-cdk/cfnspec": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "@types/lodash": "^4.14.178", "jest": "^27.4.7", diff --git a/packages/@aws-cdk/aws-lambda/test/alias.test.ts b/packages/@aws-cdk/aws-lambda/test/alias.test.ts index a470ace2a366a..2a37ffb285060 100644 --- a/packages/@aws-cdk/aws-lambda/test/alias.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/alias.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; @@ -22,11 +21,11 @@ describe('alias', () => { version, }); - expect(stack).toHaveResource('AWS::Lambda::Version', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Version', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, }); - expect(stack).toHaveResource('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, FunctionVersion: stack.resolve(version.version), Name: 'prod', @@ -46,12 +45,12 @@ describe('alias', () => { version: fn.latestVersion, }); - expect(stack).toHaveResource('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, FunctionVersion: '$LATEST', Name: 'latest', }); - expect(stack).not.toHaveResource('AWS::Lambda::Version'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Version', 0); }); testDeprecated('can use newVersion to create a new Version', () => { @@ -69,11 +68,11 @@ describe('alias', () => { version, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Version', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Version', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, }); - expect(stack).toHaveResourceLike('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, Name: 'prod', }); @@ -97,7 +96,7 @@ describe('alias', () => { additionalVersions: [{ version: version2, weight: 0.1 }], }); - expect(stack).toHaveResource('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { FunctionVersion: stack.resolve(version1.version), RoutingConfig: { AdditionalVersionWeights: [ @@ -127,13 +126,13 @@ describe('alias', () => { provisionedConcurrentExecutions: pce, }); - expect(stack).toHaveResource('AWS::Lambda::Version', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Version', { ProvisionedConcurrencyConfig: { ProvisionedConcurrentExecutions: 5, }, }); - expect(stack).toHaveResource('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { FunctionVersion: stack.resolve(version.version), Name: 'prod', ProvisionedConcurrencyConfig: { @@ -194,7 +193,7 @@ describe('alias', () => { }); // THEN - expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { Dimensions: [{ Name: 'FunctionName', Value: { @@ -325,7 +324,7 @@ describe('alias', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: { Ref: 'fn5FF616E3', }, @@ -384,7 +383,7 @@ describe('alias', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: 'function-name', Qualifier: 'alias-name', MaximumRetryAttempts: 1, @@ -409,22 +408,23 @@ describe('alias', () => { alias.addAutoScaling({ maxCapacity: 5 }); // THEN - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { MinCapacity: 1, MaxCapacity: 5, - ResourceId: objectLike({ - 'Fn::Join': arrayWith(arrayWith( + ResourceId: Match.objectLike({ + 'Fn::Join': Match.arrayWith([Match.arrayWith([ 'function:', - objectLike({ - 'Fn::Select': arrayWith( + Match.objectLike({ + 'Fn::Select': Match.arrayWith([ { - 'Fn::Split': arrayWith( - { Ref: 'Alias325C5727' }), + 'Fn::Split': Match.arrayWith([ + { Ref: 'Alias325C5727' }, + ]), }, - ), + ]), }), ':prod', - )), + ])]), }), }); }); @@ -448,26 +448,27 @@ describe('alias', () => { alias.addAutoScaling({ maxCapacity: 5 }); // THEN - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { MinCapacity: 1, MaxCapacity: 5, - ResourceId: objectLike({ - 'Fn::Join': arrayWith(arrayWith( + ResourceId: Match.objectLike({ + 'Fn::Join': Match.arrayWith([Match.arrayWith([ 'function:', - objectLike({ - 'Fn::Select': arrayWith( + Match.objectLike({ + 'Fn::Select': Match.arrayWith([ { - 'Fn::Split': arrayWith( - { Ref: 'Alias325C5727' }), + 'Fn::Split': Match.arrayWith([ + { Ref: 'Alias325C5727' }, + ]), }, - ), + ]), }), ':prod', - )), + ])]), }), }); - expect(stack).toHaveResourceLike('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { ProvisionedConcurrencyConfig: { ProvisionedConcurrentExecutions: 10, }, @@ -495,7 +496,7 @@ describe('alias', () => { target.scaleOnUtilization({ utilizationTarget: Lazy.number({ produce: () => 0.95 }) }); // THEN: no exception - expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', { PolicyType: 'TargetTrackingScaling', TargetTrackingScalingPolicyConfiguration: { PredefinedMetricSpecification: { PredefinedMetricType: 'LambdaProvisionedConcurrencyUtilization' }, @@ -568,7 +569,7 @@ describe('alias', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + Template.fromStack(stack).hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', { ScheduledActions: [ { ScalableTargetAction: { MaxCapacity: 10 }, diff --git a/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts b/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts index 7b38e2cb7e178..68674b6f4bf6a 100644 --- a/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as signer from '@aws-cdk/aws-signer'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; @@ -18,7 +18,7 @@ describe('code signing config', () => { signingProfiles: [signingProfile], }); - expect(stack).toHaveResource('AWS::Lambda::CodeSigningConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::CodeSigningConfig', { AllowedPublishers: { SigningProfileVersionArns: [{ 'Fn::GetAtt': [ @@ -41,7 +41,7 @@ describe('code signing config', () => { signingProfiles: [signingProfile1, signingProfile2, signingProfile3], }); - expect(stack).toHaveResource('AWS::Lambda::CodeSigningConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::CodeSigningConfig', { AllowedPublishers: { SigningProfileVersionArns: [ { @@ -76,7 +76,7 @@ describe('code signing config', () => { description: 'test description', }); - expect(stack).toHaveResource('AWS::Lambda::CodeSigningConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::CodeSigningConfig', { CodeSigningPolicies: { UntrustedArtifactOnDeployment: 'Enforce', }, @@ -91,7 +91,7 @@ describe('code signing config', () => { expect(codeSigningConfig.codeSigningConfigArn).toBe(codeSigningConfigArn); expect(codeSigningConfig.codeSigningConfigId).toBe(codeSigningConfigId); - expect(stack).toCountResources('AWS::Lambda::CodeSigningConfig', 0); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::CodeSigningConfig', 0); }); test('fail import with malformed code signing config arn', () => { diff --git a/packages/@aws-cdk/aws-lambda/test/code.test.ts b/packages/@aws-cdk/aws-lambda/test/code.test.ts index 25e937b8e6415..76e771596d735 100644 --- a/packages/@aws-cdk/aws-lambda/test/code.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/code.test.ts @@ -1,6 +1,5 @@ -import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ecr from '@aws-cdk/aws-ecr'; import { testFutureBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -20,6 +19,7 @@ describe('code', () => { .toThrow(/Lambda source is too large, must be <= 4096 but is 4097/); }); }); + describe('lambda.Code.fromAsset', () => { test('fails if a non-zip asset is used', () => { // GIVEN @@ -71,13 +71,13 @@ describe('code', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Metadata: { [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: 'asset.9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232', [cxapi.ASSET_RESOURCE_METADATA_IS_BUNDLED_KEY]: false, [cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY]: 'Code', }, - }, ResourcePart.CompleteDefinition); + }); }); test('fails if asset is bound with a second stack', () => { @@ -111,7 +111,7 @@ describe('code', () => { handler: 'index.handler', }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { S3Bucket: { Ref: 'FunctionLambdaSourceBucketNameParameter9E9E108F', @@ -157,7 +157,7 @@ describe('code', () => { handler: 'index.handler', }); - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { S3Bucket: { Ref: 'BucketNameParam', @@ -207,11 +207,11 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { ImageUri: stack.resolve(repo.repositoryUriForTag('latest')), }, - ImageConfig: ABSENT, + ImageConfig: Match.absent(), }); }); @@ -233,7 +233,7 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { ImageUri: stack.resolve(repo.repositoryUriForTag('mytag')), }, @@ -258,7 +258,7 @@ describe('code', () => { }); // then - expect(stack).toHaveResourceLike('AWS::ECR::Repository', { + Template.fromStack(stack).hasResourceProperties('AWS::ECR::Repository', { RepositoryPolicyText: { Statement: [ { @@ -292,7 +292,7 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { ImageUri: { 'Fn::Join': ['', [ @@ -305,7 +305,7 @@ describe('code', () => { ]], }, }, - ImageConfig: ABSENT, + ImageConfig: Match.absent(), }); }); @@ -325,7 +325,7 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { ImageConfig: { Command: ['cmd', 'param1'], EntryPoint: ['entrypoint', 'param2'], @@ -382,7 +382,7 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Metadata: { [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: 'asset.650a009a909c30e767a843a84ff7812616447251d245e0ab65d9bfb37f413e32', [cxapi.ASSET_RESOURCE_METADATA_DOCKERFILE_PATH_KEY]: dockerfilePath, @@ -390,7 +390,7 @@ describe('code', () => { [cxapi.ASSET_RESOURCE_METADATA_DOCKER_BUILD_TARGET_KEY]: dockerBuildTarget, [cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY]: 'Code.ImageUri', }, - }, ResourcePart.CompleteDefinition); + }); }); test('adds code asset metadata with default dockerfile path', () => { @@ -406,13 +406,13 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Metadata: { [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: 'asset.a3cc4528c34874616814d9b3436ff0e5d01514c1d563ed8899657ca00982f308', [cxapi.ASSET_RESOURCE_METADATA_DOCKERFILE_PATH_KEY]: 'Dockerfile', [cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY]: 'Code.ImageUri', }, - }, ResourcePart.CompleteDefinition); + }); }); test('fails if asset is bound with a second stack', () => { @@ -470,13 +470,13 @@ describe('code', () => { }); // then - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Metadata: { [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: 'asset.fbafdbb9ae8d1bae0def415b791a93c486d18ebc63270c748abecc3ac0ab9533', [cxapi.ASSET_RESOURCE_METADATA_IS_BUNDLED_KEY]: false, [cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY]: 'Code', }, - }, ResourcePart.CompleteDefinition); + }); expect(fromBuildMock).toHaveBeenCalledWith(path.join(__dirname, 'docker-build-lambda'), {}); expect(cpMock).toHaveBeenCalledWith('/asset/.', undefined); diff --git a/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts b/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts index c974a7c82b4c4..793e9abb4c42d 100644 --- a/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts @@ -1,5 +1,4 @@ -import { ABSENT } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import { Code, EventSourceMapping, Function, Runtime } from '../lib'; @@ -165,7 +164,7 @@ describe('event source mapping', () => { kafkaTopic: topicNameParam.valueAsString, }); - expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { Topics: [{ Ref: 'TopicNameParam', }], @@ -234,7 +233,7 @@ describe('event source mapping', () => { kafkaTopic: topicNameParam.valueAsString, }); - expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { EventSourceArn: eventSourceArn, }); }); @@ -258,7 +257,7 @@ describe('event source mapping', () => { kafkaTopic: topicNameParam.valueAsString, }); - expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { SelfManagedEventSource: { Endpoints: { KafkaBootstrapServers: kafkaBootstrapServers } }, }); }); @@ -309,7 +308,7 @@ describe('event source mapping', () => { reportBatchItemFailures: true, }); - expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { FunctionResponseTypes: ['ReportBatchItemFailures'], }); }); @@ -328,8 +327,8 @@ describe('event source mapping', () => { eventSourceArn: '', }); - expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { - FunctionResponseTypes: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + FunctionResponseTypes: Match.absent(), }); }); @@ -348,8 +347,8 @@ describe('event source mapping', () => { reportBatchItemFailures: false, }); - expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { - FunctionResponseTypes: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + FunctionResponseTypes: Match.absent(), }); }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts index dbadd01b0975b..de07180924ef5 100644 --- a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import { resourceSpecification } from '@aws-cdk/cfnspec'; import { App, CfnOutput, CfnResource, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index 04a8ab862b5b7..d4f1af8f02cf0 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -1,6 +1,5 @@ -import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import { ProfilingGroup } from '@aws-cdk/aws-codeguruprofiler'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as efs from '@aws-cdk/aws-efs'; @@ -26,7 +25,7 @@ describe('function', () => { runtime: lambda.Runtime.NODEJS_10_X, }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: @@ -41,7 +40,7 @@ describe('function', () => { [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo' }, @@ -50,7 +49,7 @@ describe('function', () => { Runtime: 'nodejs10.x', }, DependsOn: ['MyLambdaServiceRole4539ECB6'], - }, ResourcePart.CompleteDefinition); + }); }); test('adds policy permissions', () => { @@ -61,7 +60,7 @@ describe('function', () => { runtime: lambda.Runtime.NODEJS_10_X, initialPolicy: [new iam.PolicyStatement({ actions: ['*'], resources: ['*'] })], }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: @@ -76,7 +75,7 @@ describe('function', () => { // eslint-disable-next-line max-len [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -95,7 +94,7 @@ describe('function', () => { ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo' }, Handler: 'index.handler', @@ -103,7 +102,7 @@ describe('function', () => { Runtime: 'nodejs10.x', }, DependsOn: ['MyLambdaServiceRoleDefaultPolicy5BBC6F68', 'MyLambdaServiceRole4539ECB6'], - }, ResourcePart.CompleteDefinition); + }); }); test('fails if inline code is used for an invalid runtime', () => { @@ -127,7 +126,7 @@ describe('function', () => { sourceArn: 'arn:aws:s3:::my_bucket', }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -145,7 +144,7 @@ describe('function', () => { [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo', @@ -162,9 +161,9 @@ describe('function', () => { DependsOn: [ 'MyLambdaServiceRole4539ECB6', ], - }, ResourcePart.CompleteDefinition); + }); - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:*', FunctionName: { 'Fn::GetAtt': [ @@ -209,7 +208,7 @@ describe('function', () => { fn.addPermission('S1', { principal: principal }); - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -272,7 +271,7 @@ describe('function', () => { fn.addToRolePolicy(new iam.PolicyStatement({ actions: ['explicit:explicit'], resources: ['*'] })); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -343,7 +342,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 1); }); test('imported Function w/ unresolved account', () => { @@ -360,7 +359,7 @@ describe('function', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::Lambda::Permission'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 0); }); test('imported Function w/ unresolved account & allowPermissions set', () => { @@ -378,7 +377,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 1); }); test('imported Function w/different account', () => { @@ -397,7 +396,7 @@ describe('function', () => { }); // THEN - expect(stack).not.toHaveResource('AWS::Lambda::Permission'); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 0); }); }); @@ -411,7 +410,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { S3Bucket: { Ref: 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3Bucket1354C645', @@ -445,7 +444,7 @@ describe('function', () => { deadLetterQueueEnabled: true, }); - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -473,7 +472,7 @@ describe('function', () => { }, ], }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -496,7 +495,7 @@ describe('function', () => { }, ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo', @@ -523,7 +522,7 @@ describe('function', () => { 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', 'MyLambdaServiceRole4539ECB6', ], - }, ResourcePart.CompleteDefinition); + }); }); test('default function with SQS DLQ when client sets deadLetterQueueEnabled to true and functionName not defined by client', () => { @@ -536,11 +535,11 @@ describe('function', () => { deadLetterQueueEnabled: true, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { MessageRetentionPeriod: 1209600, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { DeadLetterConfig: { TargetArn: { 'Fn::GetAtt': [ @@ -562,7 +561,7 @@ describe('function', () => { deadLetterQueueEnabled: false, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { ZipFile: 'foo', }, @@ -592,7 +591,7 @@ describe('function', () => { deadLetterQueue: dlQueue, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -610,7 +609,7 @@ describe('function', () => { }, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { DeadLetterConfig: { TargetArn: { 'Fn::GetAtt': [ @@ -638,7 +637,7 @@ describe('function', () => { deadLetterQueue: dlQueue, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -656,7 +655,7 @@ describe('function', () => { }, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { DeadLetterConfig: { TargetArn: { 'Fn::GetAtt': [ @@ -695,7 +694,7 @@ describe('function', () => { tracing: lambda.Tracing.ACTIVE, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -717,7 +716,7 @@ describe('function', () => { ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo', @@ -738,7 +737,7 @@ describe('function', () => { 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', 'MyLambdaServiceRole4539ECB6', ], - }, ResourcePart.CompleteDefinition); + }); }); test('default function with PassThrough tracing', () => { @@ -751,7 +750,7 @@ describe('function', () => { tracing: lambda.Tracing.PASS_THROUGH, }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -773,7 +772,7 @@ describe('function', () => { ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo', @@ -794,7 +793,7 @@ describe('function', () => { 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', 'MyLambdaServiceRole4539ECB6', ], - }, ResourcePart.CompleteDefinition); + }); }); test('default function with Disabled tracing', () => { @@ -807,29 +806,9 @@ describe('function', () => { tracing: lambda.Tracing.DISABLED, }); - expect(stack).not.toHaveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'xray:PutTraceSegments', - 'xray:PutTelemetryRecords', - ], - Effect: 'Allow', - Resource: '*', - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - Roles: [ - { - Ref: 'MyLambdaServiceRole4539ECB6', - }, - ], - }); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Policy', 0); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: { Code: { ZipFile: 'foo', @@ -846,7 +825,7 @@ describe('function', () => { DependsOn: [ 'MyLambdaServiceRole4539ECB6', ], - }, ResourcePart.CompleteDefinition); + }); }); test('runtime and handler set to FROM_IMAGE are set to undefined in CloudFormation', () => { @@ -858,9 +837,9 @@ describe('function', () => { runtime: lambda.Runtime.FROM_IMAGE, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { - Runtime: ABSENT, - Handler: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Runtime: Match.absent(), + Handler: Match.absent(), PackageType: 'Image', }); }); @@ -883,7 +862,7 @@ describe('function', () => { fn.grantInvoke(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -911,7 +890,7 @@ describe('function', () => { fn.grantInvoke(service); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -937,7 +916,7 @@ describe('function', () => { fn.grantInvoke(account); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -963,7 +942,7 @@ describe('function', () => { fn.grantInvoke(account); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -990,7 +969,7 @@ describe('function', () => { fn.grantInvoke(service); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -1017,7 +996,7 @@ describe('function', () => { fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); // THEN - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1046,7 +1025,7 @@ describe('function', () => { fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -1069,7 +1048,7 @@ describe('function', () => { fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', Principal: 'elasticloadbalancing.amazonaws.com', @@ -1097,7 +1076,7 @@ describe('function', () => { fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', Principal: 'elasticloadbalancing.amazonaws.com', @@ -1209,7 +1188,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { SOME: 'Variable', @@ -1233,7 +1212,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { SOME: 'Variable', @@ -1252,7 +1231,7 @@ describe('function', () => { reservedConcurrentExecutions: 10, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { ReservedConcurrentExecutions: 10, }); }); @@ -1304,7 +1283,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('Custom::LogRetention', { + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { LogGroupName: { 'Fn::Join': [ '', @@ -1335,7 +1314,7 @@ describe('function', () => { fn.connections.allowToAnyIpv4(ec2.Port.tcp(443)); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: 'sg-123456789', }); }); @@ -1360,7 +1339,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: { Ref: 'fn5FF616E3', }, @@ -1405,7 +1384,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: 'my-function', Qualifier: '$LATEST', MaximumRetryAttempts: 1, @@ -1427,7 +1406,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: { Ref: 'fn5FF616E3', }, @@ -1455,8 +1434,8 @@ describe('function', () => { fn._checkEdgeCompatibility(); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { - Environment: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Environment: Match.absent(), }); }); @@ -1678,7 +1657,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { SOME: 'Variable', @@ -1704,12 +1683,12 @@ describe('function', () => { profiling: true, }); - expect(stack).toHaveResource('AWS::CodeGuruProfiler::ProfilingGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::CodeGuruProfiler::ProfilingGroup', { ProfilingGroupName: 'MyLambdaProfilingGroupC5B6CCD8', ComputePlatform: 'AWSLambda', }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1733,7 +1712,7 @@ describe('function', () => { ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { AWS_CODEGURU_PROFILER_GROUP_ARN: { 'Fn::GetAtt': ['MyLambdaProfilingGroupEC6DE32F', 'Arn'] }, @@ -1753,7 +1732,7 @@ describe('function', () => { profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1777,7 +1756,7 @@ describe('function', () => { ], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { AWS_CODEGURU_PROFILER_GROUP_ARN: { @@ -1806,9 +1785,9 @@ describe('function', () => { profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), }); - expect(stack).not.toHaveResource('AWS::IAM::Policy'); + Template.fromStack(stack).resourceCountIs('AWS::IAM::Policy', 0); - expect(stack).not.toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', Match.not({ Environment: { Variables: { AWS_CODEGURU_PROFILER_GROUP_ARN: { @@ -1823,7 +1802,7 @@ describe('function', () => { AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', }, }, - }); + })); }); test('default function with profiling enabled and client provided env vars', () => { @@ -1936,8 +1915,8 @@ describe('function', () => { }); // THEN - const template1 = SynthUtils.synthesize(stack1).template; - const template2 = SynthUtils.synthesize(stack2).template; + const template1 = Template.fromStack(stack1).toJSON(); + const template2 = Template.fromStack(stack2).toJSON(); // these functions are different in their configuration but the original // logical ID of the version would be the same unless the logical ID @@ -1970,7 +1949,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FileSystemConfigs: [ { Arn: { @@ -2053,7 +2032,7 @@ describe('function', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { DependsOn: [ 'EfsEfsMountTarget195B2DD2E', 'EfsEfsMountTarget2315C927F', @@ -2062,7 +2041,7 @@ describe('function', () => { 'MyFunctionServiceRoleDefaultPolicyB705ABD4', 'MyFunctionServiceRole3C357FF2', ], - }, ResourcePart.CompleteDefinition); + }); }); }); @@ -2158,11 +2137,11 @@ describe('function', () => { runtime: lambda.Runtime.FROM_IMAGE, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Code: { ImageUri: 'ecr image uri', }, - ImageConfig: ABSENT, + ImageConfig: Match.absent(), }); }); @@ -2182,7 +2161,7 @@ describe('function', () => { runtime: lambda.Runtime.FROM_IMAGE, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { ImageConfig: { Command: ['cmd', 'param1'], EntryPoint: ['entrypoint', 'param2'], @@ -2211,7 +2190,7 @@ describe('function', () => { codeSigningConfig, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { CodeSigningConfigArn: { 'Fn::GetAtt': [ 'CodeSigningConfigD8D41C10', @@ -2247,7 +2226,7 @@ describe('function', () => { architectures: [lambda.Architecture.ARM_64], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Architectures: ['arm64'], }); }); @@ -2262,7 +2241,7 @@ describe('function', () => { architecture: lambda.Architecture.ARM_64, }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Architectures: ['arm64'], }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts index 581106e7a1f92..761d7262b412e 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts @@ -1,9 +1,8 @@ -import '@aws-cdk/assert-internal/jest'; -import { arrayWith, SynthUtils } from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; -import * as lambda from '../lib'; import { Fact, FactName } from '@aws-cdk/region-info'; +import * as lambda from '../lib'; /** * Boilerplate code to create a Function with a given insights version @@ -28,7 +27,7 @@ function functionWithInsightsVersion( * Check if the function's Role has the Lambda Insights IAM policy */ function verifyRoleHasCorrectPolicies(stack: cdk.Stack) { - expect(stack).toHaveResource('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { ManagedPolicyArns: [ { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }, @@ -47,7 +46,7 @@ describe('lambda-insights', () => { verifyRoleHasCorrectPolicies(stack); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: [layerArn], }); @@ -64,7 +63,7 @@ describe('lambda-insights', () => { verifyRoleHasCorrectPolicies(stack); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: ['arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:2'], }); @@ -91,7 +90,7 @@ describe('lambda-insights', () => { functionWithInsightsVersion(stack, 'MyLambda', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); // Still resolves because all elements of the mapping map to the same value - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: [{ 'Fn::FindInMap': [ 'CloudwatchlambdainsightsversionMap', @@ -115,23 +114,24 @@ describe('lambda-insights', () => { functionWithInsightsVersion(stack, 'MyLambda1', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); functionWithInsightsVersion(stack, 'MyLambda2', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda1', Layers: [{ 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_98_0_x86_64'], }], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda2', Layers: [{ 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_98_0_x86_64'], }], }); - const template = SynthUtils.toCloudFormation(stack); - expect(template.Mappings.CloudwatchlambdainsightsversionMap?.['af-south-1']).toEqual({ - '1_0_98_0_x86_64': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', + Template.fromStack(stack).hasMapping('CloudwatchlambdainsightsversionMap', { + 'af-south-1': { + '1_0_98_0_x86_64': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', + }, }); // On synthesis it should not throw an error @@ -146,18 +146,19 @@ describe('lambda-insights', () => { insightsVersion: lambda.LambdaInsightsVersion.VERSION_1_0_98_0, }); - expect(stack).toCountResources('AWS::Lambda::LayerVersion', 0); + Template.fromStack(stack).resourceCountIs('AWS::Lambda::LayerVersion', 0); - expect(stack).toHaveResourceLike('AWS::IAM::Role', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { Action: 'sts:AssumeRole', + Effect: 'Allow', Principal: { Service: 'lambda.amazonaws.com' }, }, ], }, - ManagedPolicyArns: arrayWith( + ManagedPolicyArns: Match.arrayWith([ { 'Fn::Join': ['', [ 'arn:', @@ -165,7 +166,7 @@ describe('lambda-insights', () => { ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', ]], }, - ), + ]), }); }); @@ -176,7 +177,7 @@ describe('lambda-insights', () => { }); functionWithInsightsVersion(stack, 'MyLambda', lambda.LambdaInsightsVersion.VERSION_1_0_119_0, lambda.Architecture.ARM_64); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: ['arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension-Arm64:1'], }); @@ -214,24 +215,25 @@ describe('lambda-insights', () => { functionWithInsightsVersion(stack, 'MyLambda1', lambda.LambdaInsightsVersion.VERSION_1_0_119_0); functionWithInsightsVersion(stack, 'MyLambda2', lambda.LambdaInsightsVersion.VERSION_1_0_119_0, lambda.Architecture.ARM_64); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda1', Layers: [{ 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_119_0_x86_64'], }], }); - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { FunctionName: 'MyLambda2', Layers: [{ 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_119_0_arm64'], }], }); - const template = SynthUtils.toCloudFormation(stack); - expect(template.Mappings.CloudwatchlambdainsightsversionMap?.['ap-south-1']).toEqual({ - '1_0_119_0_x86_64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16', - '1_0_119_0_arm64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', + Template.fromStack(stack).hasMapping('CloudwatchlambdainsightsversionMap', { + 'ap-south-1': { + '1_0_119_0_x86_64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16', + '1_0_119_0_arm64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', + }, }); // On synthesis it should not throw an error diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts index c5daabab66b5d..ed98e802998dd 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-version.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 lambda from '../lib'; @@ -14,7 +14,7 @@ describe('lambda version', () => { new cdk.CfnOutput(stack, 'Name', { value: version.functionName }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Outputs: { ARN: { Value: 'arn:aws:lambda:region:account-id:function:function-name:version', @@ -43,7 +43,7 @@ describe('lambda version', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: { Ref: 'Fn9270CBC0', }, @@ -91,12 +91,12 @@ describe('lambda version', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: 'function-name', Qualifier: 'version1', MaximumRetryAttempts: 1, }); - expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventInvokeConfig', { FunctionName: 'function-name', Qualifier: 'version2', MaximumRetryAttempts: 0, @@ -117,7 +117,7 @@ describe('lambda version', () => { version.addAlias('foo'); // THEN - expect(stack).toHaveResource('AWS::Lambda::Alias', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Alias', { FunctionName: { Ref: 'Fn9270CBC0', }, diff --git a/packages/@aws-cdk/aws-lambda/test/layers.test.ts b/packages/@aws-cdk/aws-lambda/test/layers.test.ts index c8c700585c686..5f818c480e2da 100644 --- a/packages/@aws-cdk/aws-lambda/test/layers.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/layers.test.ts @@ -1,6 +1,5 @@ -import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { canonicalizeTemplate, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; @@ -20,7 +19,7 @@ describe('layers', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', { Content: { S3Bucket: stack.resolve(bucket.bucketName), S3Key: 'ObjectKey', @@ -44,12 +43,12 @@ describe('layers', () => { layer.addPermission('GrantUsage-o-123456', { accountId: '*', organizationId: 'o-123456' }); // THEN - expect(stack).toHaveResource('AWS::Lambda::LayerVersionPermission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersionPermission', { Action: 'lambda:GetLayerVersion', LayerVersionArn: stack.resolve(layer.layerVersionArn), Principal: '123456789012', }); - expect(stack).toHaveResource('AWS::Lambda::LayerVersionPermission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersionPermission', { Action: 'lambda:GetLayerVersion', LayerVersionArn: stack.resolve(layer.layerVersionArn), Principal: '*', @@ -79,13 +78,13 @@ describe('layers', () => { }); // THEN - expect(canonicalizeTemplate(SynthUtils.toCloudFormation(stack))).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResource('AWS::Lambda::LayerVersion', { Metadata: { - 'aws:asset:path': 'asset.Asset1Hash', + 'aws:asset:path': 'asset.8811a2632ac5564a08fd269e159298f7e497f259578b0dc5e927a1f48ab24d34', 'aws:asset:is-bundled': false, 'aws:asset:property': 'Content', }, - }, ResourcePart.CompleteDefinition); + }); }); test('creating a layer with a removal policy', () => { @@ -99,10 +98,10 @@ describe('layers', () => { }); // THEN - expect(canonicalizeTemplate(SynthUtils.toCloudFormation(stack))).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResource('AWS::Lambda::LayerVersion', { UpdateReplacePolicy: 'Retain', DeletionPolicy: 'Retain', - }, ResourcePart.CompleteDefinition); + }); }); test('specified compatible architectures is recognized', () => { @@ -114,7 +113,7 @@ describe('layers', () => { compatibleArchitectures: [lambda.Architecture.ARM_64], }); - expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', { CompatibleArchitectures: ['arm64'], }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/runtime.test.ts b/packages/@aws-cdk/aws-lambda/test/runtime.test.ts index 17203a11f9d7e..f3976e70c4327 100644 --- a/packages/@aws-cdk/aws-lambda/test/runtime.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/runtime.test.ts @@ -1,4 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; import * as lambda from '../lib'; describe('runtime', () => { diff --git a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts index 1e9f984b4aee5..3e6db8d6ea422 100644 --- a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; @@ -23,7 +22,7 @@ describe('singleton lambda', () => { } // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235: { Type: 'AWS::IAM::Role', @@ -78,12 +77,12 @@ describe('singleton lambda', () => { singleton.addDependency(dependency); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { DependsOn: [ 'dependencyUser1B9CB07E', 'SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235', ], - }, ResourcePart.CompleteDefinition); + }); }); test('dependsOn are correctly added', () => { @@ -102,12 +101,12 @@ describe('singleton lambda', () => { singleton.dependOn(user); // THEN - expect(stack).toHaveResource('AWS::IAM::User', { + Template.fromStack(stack).hasResource('AWS::IAM::User', { DependsOn: [ 'SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235', ], - }, ResourcePart.CompleteDefinition); + }); }); test('Environment is added to Lambda, when .addEnvironment() is provided one key pair', () => { @@ -125,7 +124,7 @@ describe('singleton lambda', () => { singleton.addEnvironment('KEY', 'value'); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { KEY: 'value', @@ -154,7 +153,7 @@ describe('singleton lambda', () => { singleton.addLayers(layer); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: [{ Ref: 'myLayerBA1B098A', }], @@ -176,7 +175,7 @@ describe('singleton lambda', () => { const statement = stack.resolve(invokeResult.resourceStatement); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', Principal: 'events.amazonaws.com', }); @@ -256,7 +255,7 @@ describe('singleton lambda', () => { version.addAlias('foo'); // THEN - expect(stack).toHaveResource('AWS::Lambda::Version', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Version', { FunctionName: { Ref: 'SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', }, diff --git a/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts index 409ffc5fa3a45..aa7587411fa26 100644 --- a/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -29,7 +29,7 @@ describe('lambda + vpc', () => { test('has subnet and securitygroup', () => { // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['LambdaSecurityGroupE74659A1', 'GroupId'] }, @@ -52,7 +52,7 @@ describe('lambda + vpc', () => { securityGroup: new ec2.SecurityGroup(stack, 'CustomSecurityGroupX', { vpc }), }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['CustomSecurityGroupX6C7F3A78', 'GroupId'] }, @@ -78,7 +78,7 @@ describe('lambda + vpc', () => { ], }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['CustomSecurityGroupA267F62DE', 'GroupId'] }, @@ -118,7 +118,7 @@ describe('lambda + vpc', () => { fn.connections.allowTo(somethingConnectable, ec2.Port.allTcp(), 'Lambda can call connectable'); // THEN: Lambda can connect to SomeSecurityGroup - expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::GetAtt': ['LambdaSecurityGroupE74659A1', 'GroupId'] }, IpProtocol: 'tcp', Description: 'Lambda can call connectable', @@ -128,7 +128,7 @@ describe('lambda + vpc', () => { }); // THEN: SomeSecurityGroup accepts connections from Lambda - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'Lambda can call connectable', FromPort: 0, @@ -148,7 +148,7 @@ describe('lambda + vpc', () => { somethingConnectable.connections.allowFrom(fn.connections, ec2.Port.allTcp(), 'Lambda can call connectable'); // THEN: SomeSecurityGroup accepts connections from Lambda - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupEgress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::ImportValue': 'stack:ExportsOutputFnGetAttLambdaSecurityGroupE74659A1GroupId8F3EC6F1', }, @@ -165,7 +165,7 @@ describe('lambda + vpc', () => { }); // THEN: Lambda can connect to SomeSecurityGroup - expect(stack2).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack2).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'Lambda can call connectable', FromPort: 0, @@ -214,7 +214,7 @@ describe('lambda + vpc', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['PublicLambdaSecurityGroup61D896FD', 'GroupId'] }, @@ -243,7 +243,7 @@ describe('lambda + vpc', () => { // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['PrivateLambdaSecurityGroupF53C8342', 'GroupId'] }, @@ -279,7 +279,7 @@ describe('lambda + vpc', () => { // THEN - expect(stack).toHaveResource('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['IsolatedLambdaSecurityGroupCE25B6A9', 'GroupId'] }, diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index a2c39272e68d1..9837e00b2eb05 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", diff --git a/packages/@aws-cdk/aws-opensearchservice/package.json b/packages/@aws-cdk/aws-opensearchservice/package.json index 09d480a3c4331..f0d434006921e 100644 --- a/packages/@aws-cdk/aws-opensearchservice/package.json +++ b/packages/@aws-cdk/aws-opensearchservice/package.json @@ -84,7 +84,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-opensearchservice/test/domain.test.ts b/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts index 2389c30ab7c29..3739031d6f3b2 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts +++ b/packages/@aws-cdk/aws-opensearchservice/test/domain.test.ts @@ -1,6 +1,5 @@ /* eslint-disable jest/expect-expect */ -import '@aws-cdk/assert-internal/jest'; -import * as assert from '@aws-cdk/assert-internal'; +import { Match, Template } from '@aws-cdk/assertions'; import * as acm from '@aws-cdk/aws-certificatemanager'; import { Metric, Statistic } from '@aws-cdk/aws-cloudwatch'; import { Vpc, EbsDeviceVolumeType, SecurityGroup } from '@aws-cdk/aws-ec2'; @@ -55,7 +54,7 @@ test('subnets and security groups can be provided when vpc is used', () => { }); expect(domain.connections.securityGroups[0].securityGroupId).toEqual(securityGroup.securityGroupId); - expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { VPCOptions: { SecurityGroupIds: [ { @@ -84,7 +83,7 @@ test('default subnets and security group when vpc is used', () => { }); expect(stack.resolve(domain.connections.securityGroups[0].securityGroupId)).toEqual({ 'Fn::GetAtt': ['DomainSecurityGroup48AA5FD6', 'GroupId'] }); - expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { VPCOptions: { SecurityGroupIds: [ { @@ -115,9 +114,9 @@ test('default removalpolicy is retain', () => { version: defaultVersion, }); - expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResource('AWS::OpenSearchService::Domain', { DeletionPolicy: 'Retain', - }, assert.ResourcePart.CompleteDefinition); + }); }); test('grants kms permissions if needed', () => { @@ -153,7 +152,7 @@ test('grants kms permissions if needed', () => { Version: '2012-10-17', }; - const resources = assert.expect(stack).value.Resources; + const resources = Template.fromStack(stack).toJSON().Resources; expect(resources.AWS679f53fac002430cb0da5b7982bd2287ServiceRoleDefaultPolicyD28E1A5E.Properties.PolicyDocument).toStrictEqual(expectedPolicy); }); @@ -161,7 +160,7 @@ test('grants kms permissions if needed', () => { test('minimal example renders correctly', () => { new Domain(stack, 'Domain', { version: defaultVersion }); - expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { CognitoOptions: { Enabled: false, }, @@ -181,10 +180,10 @@ test('minimal example renders correctly', () => { Enabled: false, }, LogPublishingOptions: { - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, NodeToNodeEncryptionOptions: { Enabled: false, @@ -198,11 +197,11 @@ test('can enable version upgrade update policy', () => { enableVersionUpgrade: true, }); - expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResource('AWS::OpenSearchService::Domain', { UpdatePolicy: { EnableVersionUpgrade: true, }, - }, assert.ResourcePart.CompleteDefinition); + }); }); describe('UltraWarm instances', () => { @@ -216,7 +215,7 @@ describe('UltraWarm instances', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { ClusterConfig: { DedicatedMasterEnabled: true, WarmEnabled: true, @@ -236,7 +235,7 @@ describe('UltraWarm instances', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { ClusterConfig: { DedicatedMasterEnabled: true, WarmEnabled: true, @@ -261,7 +260,7 @@ test('can use tokens in capacity configuration', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { ClusterConfig: { InstanceCount: { Ref: 'dataNodes', @@ -297,7 +296,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { SEARCH_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -308,9 +307,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -323,7 +322,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { INDEX_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -334,9 +333,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), }, }); }); @@ -349,7 +348,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -360,9 +359,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -383,7 +382,7 @@ describe('log groups', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { AUDIT_LOGS: { CloudWatchLogsLogGroupArn: { @@ -394,9 +393,9 @@ describe('log groups', () => { }, Enabled: true, }, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -418,7 +417,7 @@ describe('log groups', () => { slowIndexLogEnabled: true, }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -447,10 +446,10 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -479,7 +478,7 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), }, }); }); @@ -499,7 +498,7 @@ describe('log groups', () => { }); // Domain1 - expect(stack).toHaveResourceLike('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { Create: { 'Fn::Join': [ '', @@ -517,7 +516,7 @@ describe('log groups', () => { }, }); // Domain2 - expect(stack).toHaveResourceLike('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { Create: { 'Fn::Join': [ '', @@ -556,7 +555,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { SEARCH_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -567,9 +566,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -585,7 +584,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { INDEX_SLOW_LOGS: { CloudWatchLogsLogGroupArn: { @@ -596,9 +595,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), }, }); }); @@ -614,7 +613,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { ES_APPLICATION_LOGS: { CloudWatchLogsLogGroupArn: { @@ -625,9 +624,9 @@ describe('log groups', () => { }, Enabled: true, }, - AUDIT_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + AUDIT_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -651,7 +650,7 @@ describe('log groups', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { LogPublishingOptions: { AUDIT_LOGS: { CloudWatchLogsLogGroupArn: { @@ -662,9 +661,9 @@ describe('log groups', () => { }, Enabled: true, }, - ES_APPLICATION_LOGS: assert.ABSENT, - SEARCH_SLOW_LOGS: assert.ABSENT, - INDEX_SLOW_LOGS: assert.ABSENT, + ES_APPLICATION_LOGS: Match.absent(), + SEARCH_SLOW_LOGS: Match.absent(), + INDEX_SLOW_LOGS: Match.absent(), }, }); }); @@ -746,7 +745,7 @@ describe('grants', () => { domain.grantReadWrite(user); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -938,7 +937,7 @@ describe('import', () => { expect(imported.domainArn).toMatch(RegExp(`es:testregion:1234:domain/${domainName}$`)); expect(imported.domainEndpoint).toEqual(domainEndpointWithoutHttps); - expect(stack).not.toHaveResource('AWS::OpenSearchService::Domain'); + Template.fromStack(stack).resourceCountIs('AWS::OpenSearchService::Domain', 0); }); test('static fromDomainAttributes(attributes) allows importing an external/existing domain', () => { @@ -955,7 +954,7 @@ describe('import', () => { expect(imported.domainArn).toEqual(domainArn); expect(imported.domainEndpoint).toEqual(domainEndpointWithoutHttps); - expect(stack).not.toHaveResource('AWS::OpenSearchService::Domain'); + Template.fromStack(stack).resourceCountIs('AWS::OpenSearchService::Domain', 0); }); test('static fromDomainAttributes(attributes) allows importing with token arn and endpoint', () => { @@ -993,7 +992,7 @@ describe('import', () => { expect(imported.domainArn).toEqual(domainArn); expect(imported.domainEndpoint).toEqual(domainEndpoint); - expect(stack).not.toHaveResource('AWS::OpenSearchService::Domain'); + Template.fromStack(stack).resourceCountIs('AWS::OpenSearchService::Domain', 0); }); }); @@ -1016,7 +1015,7 @@ describe('advanced security options', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: false, @@ -1050,7 +1049,7 @@ describe('advanced security options', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1084,7 +1083,7 @@ describe('advanced security options', () => { enforceHttps: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1115,7 +1114,7 @@ describe('advanced security options', () => { }, }); - expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { GenerateSecretString: { GenerateStringKey: 'password', }, @@ -1192,7 +1191,7 @@ describe('custom endpoints', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { DomainEndpointOptions: { EnforceHTTPS: true, CustomEndpointEnabled: true, @@ -1202,7 +1201,7 @@ describe('custom endpoints', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: customDomainName, ValidationMethod: 'EMAIL', }); @@ -1220,7 +1219,7 @@ describe('custom endpoints', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { DomainEndpointOptions: { EnforceHTTPS: true, CustomEndpointEnabled: true, @@ -1230,7 +1229,7 @@ describe('custom endpoints', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::CertificateManager::Certificate', { + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { DomainName: customDomainName, DomainValidationOptions: [ { @@ -1242,7 +1241,7 @@ describe('custom endpoints', () => { ], ValidationMethod: 'DNS', }); - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'search.example.com.', Type: 'CNAME', HostedZoneId: { @@ -1278,7 +1277,7 @@ describe('custom endpoints', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { DomainEndpointOptions: { EnforceHTTPS: true, CustomEndpointEnabled: true, @@ -1288,7 +1287,7 @@ describe('custom endpoints', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'search.example.com.', Type: 'CNAME', HostedZoneId: { @@ -1550,7 +1549,7 @@ describe('custom error responses', () => { }, }); // both configurations pass synth-time validation - expect(stack).toCountResources('AWS::OpenSearchService::Domain', 2); + Template.fromStack(stack).resourceCountIs('AWS::OpenSearchService::Domain', 2); }); test('error when availabilityZoneCount is not 2 or 3', () => { @@ -1608,7 +1607,7 @@ describe('custom error responses', () => { test('can specify future version', () => { new Domain(stack, 'Domain', { version: EngineVersion.elasticsearch('8.2') }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { EngineVersion: 'Elasticsearch_8.2', }); }); @@ -1620,7 +1619,7 @@ describe('unsigned basic auth', () => { useUnsignedBasicAuth: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1651,7 +1650,7 @@ describe('unsigned basic auth', () => { useUnsignedBasicAuth: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: false, @@ -1685,7 +1684,7 @@ describe('unsigned basic auth', () => { useUnsignedBasicAuth: true, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedSecurityOptions: { Enabled: true, InternalUserDatabaseEnabled: true, @@ -1748,7 +1747,7 @@ describe('advanced options', () => { }, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { AdvancedOptions: { 'rest.action.multi.allow_explicit_index': 'true', 'indices.fielddata.cache.size': '50', @@ -1761,8 +1760,8 @@ describe('advanced options', () => { version: defaultVersion, }); - expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { - AdvancedOptions: assert.ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::OpenSearchService::Domain', { + AdvancedOptions: Match.absent(), }); }); }); @@ -1802,7 +1801,7 @@ function testGrant( ? resolvedPaths : resolvedPaths[0]; - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { diff --git a/packages/@aws-cdk/aws-opensearchservice/test/log-group-resource-policy.test.ts b/packages/@aws-cdk/aws-opensearchservice/test/log-group-resource-policy.test.ts index 68518297588c9..815c0086d4a99 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/log-group-resource-policy.test.ts +++ b/packages/@aws-cdk/aws-opensearchservice/test/log-group-resource-policy.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 { App, Stack } from '@aws-cdk/core'; import { LogGroupResourcePolicy } from '../lib/log-group-resource-policy'; @@ -24,7 +24,7 @@ test('minimal example renders correctly', () => { })], }); - expect(stack).toHaveResource('Custom::CloudwatchLogResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::CloudwatchLogResourcePolicy', { ServiceToken: { 'Fn::GetAtt': [ 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', diff --git a/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts b/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts index 62e4361f76e46..6e449d3521adb 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.test.ts +++ b/packages/@aws-cdk/aws-opensearchservice/test/opensearch-access-policy.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 { App, Stack } from '@aws-cdk/core'; import { OpenSearchAccessPolicy } from '../lib/opensearch-access-policy'; @@ -28,7 +28,7 @@ test('minimal example renders correctly', () => { })], }); - expect(stack).toHaveResource('Custom::OpenSearchAccessPolicy', { + Template.fromStack(stack).hasResourceProperties('Custom::OpenSearchAccessPolicy', { ServiceToken: { 'Fn::GetAtt': [ 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', @@ -56,7 +56,7 @@ test('minimal example renders correctly', () => { physicalResourceId: { id: 'TestDomainAccessPolicy' }, }), }); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [{ Action: 'es:UpdateDomainConfig', diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index 56c34367c7147..f4e358cde998a 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -72,7 +72,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-route53-patterns/test/bucket-website-target.test.ts b/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts index a0046ab98d286..91f81a467a43f 100644 --- a/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts +++ b/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { HostedZone } from '@aws-cdk/aws-route53'; import { App, Stack } from '@aws-cdk/core'; @@ -20,7 +20,7 @@ test('create HTTPS redirect', () => { }); // THEN - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { WebsiteConfiguration: { RedirectAllRequestsTo: { HostName: 'bar.example.com', @@ -34,28 +34,28 @@ test('create HTTPS redirect', () => { RestrictPublicBuckets: true, }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { Aliases: ['foo.example.com', 'baz.example.com'], DefaultRootObject: '', }, }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'A', Name: 'foo.example.com.', HostedZoneId: 'ID', }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'AAAA', Name: 'foo.example.com.', HostedZoneId: 'ID', }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'A', Name: 'baz.example.com.', HostedZoneId: 'ID', }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'AAAA', Name: 'baz.example.com.', HostedZoneId: 'ID', @@ -77,7 +77,7 @@ test('create HTTPS redirect for apex', () => { }); // THEN - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { WebsiteConfiguration: { RedirectAllRequestsTo: { HostName: 'bar.example.com', @@ -85,11 +85,11 @@ test('create HTTPS redirect for apex', () => { }, }, }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'A', Name: 'example.com.', }); - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'AAAA', Name: 'example.com.', }); @@ -114,7 +114,7 @@ test('create HTTPS redirect with existing cert', () => { }); // THEN - expect(stack).toHaveResource('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { WebsiteConfiguration: { RedirectAllRequestsTo: { HostName: 'bar.example.com', @@ -122,7 +122,7 @@ test('create HTTPS redirect with existing cert', () => { }, }, }); - expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { DistributionConfig: { ViewerCertificate: { AcmCertificateArn: 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d', diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index ac38d7cd780b9..c51747d33eb5e 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/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-apigatewayv2": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts index 5658a1f56323a..f1561bd336d34 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts @@ -1,4 +1,4 @@ -import { expect as expectStack, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as apigw from '@aws-cdk/aws-apigateway'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as route53 from '@aws-cdk/aws-route53'; @@ -27,7 +27,7 @@ test('targets.ApiGateway can be used to the default domain of an APIGW', () => { }); // THEN - expectStack(stack).to(haveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'example.com.', Type: 'A', AliasTarget: { @@ -47,7 +47,7 @@ test('targets.ApiGateway can be used to the default domain of an APIGW', () => { HostedZoneId: { Ref: 'zoneEB40FF1E', }, - })); + }); }); test('targets.ApiGatewayDomain can be used to directly reference a domain', () => { @@ -66,7 +66,7 @@ test('targets.ApiGatewayDomain can be used to directly reference a domain', () = }); // THEN - expectStack(stack).to(haveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'example.com.', Type: 'A', AliasTarget: { @@ -86,7 +86,7 @@ test('targets.ApiGatewayDomain can be used to directly reference a domain', () = HostedZoneId: { Ref: 'zoneEB40FF1E', }, - })); + }); }); test('fails if an ApiGateway is used with an API that does not define a domain name', () => { @@ -132,7 +132,7 @@ test('targets.ApiGateway accepts a SpecRestApi', () => { }); // THEN - expectStack(stack).to(haveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'example.com.', Type: 'A', AliasTarget: { @@ -152,5 +152,5 @@ test('targets.ApiGateway accepts a SpecRestApi', () => { HostedZoneId: { Ref: 'zoneEB40FF1E', }, - })); + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts index d2a66e41bde26..1d8df0eb756b7 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts @@ -1,4 +1,4 @@ -import { expect as expectStack, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as apigwv2 from '@aws-cdk/aws-apigatewayv2'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as route53 from '@aws-cdk/aws-route53'; @@ -25,7 +25,7 @@ test('targets.ApiGatewayv2Domain can be used to directly reference a domain', () }); // THEN - expectStack(stack).to(haveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'example.com.', Type: 'A', AliasTarget: { @@ -45,5 +45,5 @@ test('targets.ApiGatewayv2Domain can be used to directly reference a domain', () HostedZoneId: { Ref: 'zoneEB40FF1E', }, - })); + }); }); diff --git a/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts index ff1938e66447b..2d4e77210abdf 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as route53 from '@aws-cdk/aws-route53'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Stack } from '@aws-cdk/core'; @@ -23,7 +23,7 @@ test('use S3 bucket website as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: 's3-website-us-east-1.amazonaws.com', HostedZoneId: 'Z3AQBSTGFYJSTF', @@ -47,7 +47,7 @@ test('use S3 bucket website as record target (fromBucketName)', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: 's3-website-us-east-1.amazonaws.com', HostedZoneId: 'Z3AQBSTGFYJSTF', diff --git a/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts index a89e1f194b1a6..afeeb7640cd65 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elb from '@aws-cdk/aws-elasticloadbalancing'; import * as route53 from '@aws-cdk/aws-route53'; @@ -26,7 +26,7 @@ test('use classic ELB as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['LB8A12904C', 'DNSName'] }]] }, HostedZoneId: { 'Fn::GetAtt': ['LB8A12904C', 'CanonicalHostedZoneNameID'] }, diff --git a/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts index 646547cb76bda..321726a893eec 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { SynthUtils } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as route53 from '@aws-cdk/aws-route53'; import * as s3 from '@aws-cdk/aws-s3'; @@ -14,16 +13,12 @@ test('use CloudFrontTarget partition hosted zone id mapping', () => { targets.CloudFrontTarget.getHostedZoneId(stack); // THEN - expect(SynthUtils.toCloudFormation(stack)).toEqual({ - Mappings: { - AWSCloudFrontPartitionHostedZoneIdMap: { - 'aws': { - zoneId: 'Z2FDTNDATAQYW2', - }, - 'aws-cn': { - zoneId: 'Z3RFFRIM2A3IF5', - }, - }, + Template.fromStack(stack).hasMapping('AWSCloudFrontPartitionHostedZoneIdMap', { + 'aws': { + zoneId: 'Z2FDTNDATAQYW2', + }, + 'aws-cn': { + zoneId: 'Z3RFFRIM2A3IF5', }, }); }); @@ -40,16 +35,12 @@ test('use CloudFrontTarget hosted zone id mappings in nested stacks', () => { // THEN for (let nestedStack of [nestedStackA, nestedStackB]) { - expect(SynthUtils.toCloudFormation(nestedStack)).toEqual({ - Mappings: { - AWSCloudFrontPartitionHostedZoneIdMap: { - 'aws': { - zoneId: 'Z2FDTNDATAQYW2', - }, - 'aws-cn': { - zoneId: 'Z3RFFRIM2A3IF5', - }, - }, + Template.fromStack(nestedStack).hasMapping('AWSCloudFrontPartitionHostedZoneIdMap', { + 'aws': { + zoneId: 'Z2FDTNDATAQYW2', + }, + 'aws-cn': { + zoneId: 'Z3RFFRIM2A3IF5', }, }); } @@ -81,7 +72,7 @@ test('use CloudFront as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: { 'Fn::GetAtt': ['MyDistributionCFDistributionDE147309', 'DomainName'] }, HostedZoneId: { diff --git a/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts index ed18f49362118..44cadae6e3b9f 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/elastic-beanstalk-environment-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as route53 from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; import * as targets from '../lib'; @@ -16,7 +16,7 @@ test('use EBS environment as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: 'mysampleenvironment.xyz.us-east-1.elasticbeanstalk.com', HostedZoneId: 'Z117KPS5GTRQ2G', diff --git a/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts index e39862e280951..0dc473d38c352 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as globalaccelerator from '@aws-cdk/aws-globalaccelerator'; import * as route53 from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; @@ -22,7 +22,7 @@ test('GlobalAcceleratorTarget creates an alias resource with a string domain nam }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: 'xyz.awsglobalaccelerator.com', HostedZoneId: 'Z2BJ6XQ5FK7U4H', @@ -45,7 +45,7 @@ test('GlobalAcceleratorTarget creates an alias resource with a Global Accelerato }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: { 'Fn::GetAtt': [ diff --git a/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts index bd13011e4700d..bcec3e3459a3a 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as route53 from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; @@ -29,7 +29,7 @@ test('use InterfaceVpcEndpoint as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { HostedZoneId: { 'Fn::Select': [ diff --git a/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts index d16592d3ec183..00c3b1dde24ed 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as route53 from '@aws-cdk/aws-route53'; @@ -26,7 +26,7 @@ test('use ALB as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['LB8A12904C', 'DNSName'] }]] }, HostedZoneId: { 'Fn::GetAtt': ['LB8A12904C', 'CanonicalHostedZoneID'] }, diff --git a/packages/@aws-cdk/aws-route53-targets/test/route53-record.test.ts b/packages/@aws-cdk/aws-route53-targets/test/route53-record.test.ts index 9b9bc7585a433..e4940198a6927 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/route53-record.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/route53-record.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { ARecord, PublicHostedZone, RecordTarget } from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; import { Route53RecordTarget } from '../lib'; @@ -19,7 +19,7 @@ test('use another route 53 record as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: { Ref: 'HostedZoneRecordB6AB510D', diff --git a/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts b/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts index 8badcaed9c047..d098ef1293f49 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { UserPool, UserPoolDomain } from '@aws-cdk/aws-cognito'; import { ARecord, PublicHostedZone, RecordTarget } from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; @@ -21,7 +21,7 @@ test('use user pool domain as record target', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { AliasTarget: { DNSName: { 'Fn::GetAtt': ['UserPoolDomainCloudFrontDomainName0B254952', 'DomainDescription.CloudFrontDistribution'], diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 454e121b690cd..849968f30b2f2 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -79,12 +79,12 @@ }, "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", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "aws-sdk": "^2.848.0", "jest": "^27.4.7" diff --git a/packages/@aws-cdk/aws-route53/test/hosted-zone-provider.test.ts b/packages/@aws-cdk/aws-route53/test/hosted-zone-provider.test.ts index 0b66c9589cd50..e5f8fbe21d6c9 100644 --- a/packages/@aws-cdk/aws-route53/test/hosted-zone-provider.test.ts +++ b/packages/@aws-cdk/aws-route53/test/hosted-zone-provider.test.ts @@ -1,5 +1,3 @@ -import '@aws-cdk/assert-internal/jest'; -import { SynthUtils } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { HostedZone } from '../lib'; @@ -7,14 +5,16 @@ describe('hosted zone provider', () => { describe('Hosted Zone Provider', () => { test('HostedZoneProvider will return context values if available', () => { // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack', { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'TestStack', { env: { account: '12345', region: 'us-east-1' }, }); const filter = { domainName: 'test.com' }; HostedZone.fromLookup(stack, 'Ref', filter); - const missing = SynthUtils.synthesize(stack).assembly.manifest.missing!; + const assembly = app.synth().getStackArtifact(stack.artifactId); + const missing = assembly.assembly.manifest.missing!; expect(missing && missing.length === 1).toEqual(true); const fakeZoneId = '11111111111111'; @@ -39,18 +39,20 @@ describe('hosted zone provider', () => { // THEN expect(zoneRef.hostedZoneId).toEqual(fakeZoneId); - }); + test('HostedZoneProvider will return context values if available when using plain hosted zone id', () => { // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack', { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'TestStack', { env: { account: '12345', region: 'us-east-1' }, }); const filter = { domainName: 'test.com' }; HostedZone.fromLookup(stack, 'Ref', filter); - const missing = SynthUtils.synthesize(stack).assembly.manifest.missing!; + const assembly = app.synth().getStackArtifact(stack.artifactId); + const missing = assembly.assembly.manifest.missing!; expect(missing && missing.length === 1).toEqual(true); const fakeZoneId = '11111111111111'; diff --git a/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts b/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts index 7939452fd3421..a60d277788691 100644 --- a/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts +++ b/packages/@aws-cdk/aws-route53/test/hosted-zone.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 cdk from '@aws-cdk/core'; import { HostedZone, PublicHostedZone } from '../lib'; @@ -26,8 +26,6 @@ describe('hosted zone', () => { ], ], }); - - }); }); @@ -42,7 +40,7 @@ describe('hosted zone', () => { cdk.Tags.of(hostedZone).add('zoneTag', 'inMyZone'); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { HostedZoneDB99F866: { Type: 'AWS::Route53::HostedZone', @@ -58,8 +56,6 @@ describe('hosted zone', () => { }, }, }); - - }); test('with crossAccountZoneDelegationPrincipal', () => { @@ -76,7 +72,7 @@ describe('hosted zone', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { HostedZoneDB99F866: { Type: 'AWS::Route53::HostedZone', @@ -149,8 +145,6 @@ describe('hosted zone', () => { }, }, }); - - }); test('with crossAccountZoneDelegationPrincipal, throws if name provided without principal', () => { @@ -166,7 +160,5 @@ describe('hosted zone', () => { crossAccountZoneDelegationRoleName: 'myrole', }); }).toThrow(/crossAccountZoneDelegationRoleName property is not supported without crossAccountZoneDelegationPrincipal/); - - }); }); diff --git a/packages/@aws-cdk/aws-route53/test/record-set.test.ts b/packages/@aws-cdk/aws-route53/test/record-set.test.ts index 7c716545a6f24..a48cb07bb5ab0 100644 --- a/packages/@aws-cdk/aws-route53/test/record-set.test.ts +++ b/packages/@aws-cdk/aws-route53/test/record-set.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ResourcePart } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import { Duration, RemovalPolicy, Stack } from '@aws-cdk/core'; import * as route53 from '../lib'; @@ -22,7 +21,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'CNAME', HostedZoneId: { @@ -33,7 +32,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('with custom ttl', () => { @@ -54,7 +52,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'aa.myzone.', Type: 'CNAME', HostedZoneId: { @@ -65,7 +63,6 @@ describe('record set', () => { ], TTL: '6077', }); - }); test('with ttl of 0', () => { @@ -86,10 +83,9 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { TTL: '0', }); - }); test('defaults to zone root', () => { @@ -108,7 +104,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'myzone.', Type: 'A', HostedZoneId: { @@ -118,7 +114,6 @@ describe('record set', () => { '1.2.3.4', ], }); - }); test('A record with ip addresses', () => { @@ -137,7 +132,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'A', HostedZoneId: { @@ -149,7 +144,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('A record with alias', () => { @@ -177,7 +171,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: '_foo.myzone.', HostedZoneId: { Ref: 'HostedZoneDB99F866', @@ -188,8 +182,6 @@ describe('record set', () => { DNSName: 'foo.example.com', }, }); - - }); test('AAAA record with ip addresses', () => { @@ -208,7 +200,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'AAAA', HostedZoneId: { @@ -219,7 +211,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('AAAA record with alias on zone root', () => { @@ -245,7 +236,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'myzone.', HostedZoneId: { Ref: 'HostedZoneDB99F866', @@ -256,8 +247,6 @@ describe('record set', () => { DNSName: 'foo.example.com', }, }); - - }); test('CNAME record', () => { @@ -276,7 +265,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'CNAME', HostedZoneId: { @@ -287,7 +276,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('TXT record', () => { @@ -306,7 +294,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'TXT', HostedZoneId: { @@ -317,7 +305,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('TXT record with value longer than 255 chars', () => { @@ -336,7 +323,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'TXT', HostedZoneId: { @@ -347,7 +334,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('SRV record', () => { @@ -371,7 +357,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'SRV', HostedZoneId: { @@ -382,7 +368,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('CAA record', () => { @@ -405,7 +390,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'CAA', HostedZoneId: { @@ -416,7 +401,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('CAA Amazon record', () => { @@ -433,7 +417,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'myzone.', Type: 'CAA', HostedZoneId: { @@ -444,7 +428,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('CAA Amazon record with record name', () => { @@ -462,7 +445,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'CAA', HostedZoneId: { @@ -473,7 +456,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('MX record', () => { @@ -495,7 +477,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'mail.myzone.', Type: 'MX', HostedZoneId: { @@ -506,7 +488,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('NS record', () => { @@ -525,7 +506,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'NS', HostedZoneId: { @@ -537,7 +518,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('DS record', () => { @@ -556,7 +536,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'www.myzone.', Type: 'DS', HostedZoneId: { @@ -567,7 +547,6 @@ describe('record set', () => { ], TTL: '1800', }); - }); test('Zone delegation record', () => { @@ -586,7 +565,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Name: 'foo.myzone.', Type: 'NS', HostedZoneId: { @@ -597,7 +576,6 @@ describe('record set', () => { ], TTL: '172800', }); - }); test('Cross account zone delegation record with parentHostedZoneId', () => { @@ -621,7 +599,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('Custom::CrossAccountZoneDelegation', { + Template.fromStack(stack).hasResourceProperties('Custom::CrossAccountZoneDelegation', { ServiceToken: { 'Fn::GetAtt': [ 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', @@ -646,11 +624,10 @@ describe('record set', () => { }, TTL: 60, }); - expect(stack).toHaveResource('Custom::CrossAccountZoneDelegation', { + Template.fromStack(stack).hasResource('Custom::CrossAccountZoneDelegation', { DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition); - + }); }); test('Cross account zone delegation record with parentHostedZoneName', () => { @@ -673,7 +650,7 @@ describe('record set', () => { }); // THEN - expect(stack).toHaveResource('Custom::CrossAccountZoneDelegation', { + Template.fromStack(stack).hasResourceProperties('Custom::CrossAccountZoneDelegation', { ServiceToken: { 'Fn::GetAtt': [ 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', @@ -696,7 +673,6 @@ describe('record set', () => { }, TTL: 60, }); - }); test('Cross account zone delegation record throws when parent id and name both/nither are supplied', () => { @@ -729,8 +705,6 @@ describe('record set', () => { ttl: Duration.seconds(60), }); }).toThrow(/Only one of parentHostedZoneName and parentHostedZoneId is supported/); - - }); test('Multiple cross account zone delegation records', () => { @@ -768,7 +742,7 @@ describe('record set', () => { ]; for (var childHostedZone of childHostedZones) { - expect(stack).toHaveResource('Custom::CrossAccountZoneDelegation', { + Template.fromStack(stack).hasResourceProperties('Custom::CrossAccountZoneDelegation', { ServiceToken: { 'Fn::GetAtt': [ 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', @@ -829,7 +803,7 @@ describe('record set', () => { ]; for (var policyName of policyNames) { - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyName: policyName, PolicyDocument: { Version: '2012-10-17', diff --git a/packages/@aws-cdk/aws-route53/test/route53.test.ts b/packages/@aws-cdk/aws-route53/test/route53.test.ts index f86b155592db7..d6a8a7ba63135 100644 --- a/packages/@aws-cdk/aws-route53/test/route53.test.ts +++ b/packages/@aws-cdk/aws-route53/test/route53.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { MatchStyle } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { HostedZone, PrivateHostedZone, PublicHostedZone, TxtRecord } from '../lib'; @@ -9,15 +8,8 @@ describe('route53', () => { test('public hosted zone', () => { const app = new TestApp(); new PublicHostedZone(app.stack, 'HostedZone', { zoneName: 'test.public' }); - expect(app.stack).toMatchTemplate({ - Resources: { - HostedZoneDB99F866: { - Type: 'AWS::Route53::HostedZone', - Properties: { - Name: 'test.public.', - }, - }, - }, + Template.fromStack(app.stack).hasResourceProperties('AWS::Route53::HostedZone', { + Name: 'test.public.', }); }); @@ -25,47 +17,32 @@ describe('route53', () => { const app = new TestApp(); const vpcNetwork = new ec2.Vpc(app.stack, 'VPC'); new PrivateHostedZone(app.stack, 'HostedZone', { zoneName: 'test.private', vpc: vpcNetwork }); - expect(app.stack).toMatchTemplate({ - Resources: { - HostedZoneDB99F866: { - Type: 'AWS::Route53::HostedZone', - Properties: { - Name: 'test.private.', - VPCs: [{ - VPCId: { Ref: 'VPCB9E5F0B4' }, - VPCRegion: 'bermuda-triangle', - }], - }, - }, - }, - }, MatchStyle.SUPERSET); - + Template.fromStack(app.stack).hasResourceProperties('AWS::Route53::HostedZone', { + Name: 'test.private.', + VPCs: [{ + VPCId: { Ref: 'VPCB9E5F0B4' }, + VPCRegion: 'bermuda-triangle', + }], + }); }); + test('when specifying multiple VPCs', () => { const app = new TestApp(); const vpcNetworkA = new ec2.Vpc(app.stack, 'VPC1'); const vpcNetworkB = new ec2.Vpc(app.stack, 'VPC2'); new PrivateHostedZone(app.stack, 'HostedZone', { zoneName: 'test.private', vpc: vpcNetworkA }) .addVpc(vpcNetworkB); - expect(app.stack).toMatchTemplate({ - Resources: { - HostedZoneDB99F866: { - Type: 'AWS::Route53::HostedZone', - Properties: { - Name: 'test.private.', - VPCs: [{ - VPCId: { Ref: 'VPC17DE2CF87' }, - VPCRegion: 'bermuda-triangle', - }, - { - VPCId: { Ref: 'VPC2C1F0E711' }, - VPCRegion: 'bermuda-triangle', - }], - }, - }, + Template.fromStack(app.stack).hasResourceProperties('AWS::Route53::HostedZone', { + Name: 'test.private.', + VPCs: [{ + VPCId: { Ref: 'VPC17DE2CF87' }, + VPCRegion: 'bermuda-triangle', }, - }, MatchStyle.SUPERSET); - + { + VPCId: { Ref: 'VPC2C1F0E711' }, + VPCRegion: 'bermuda-triangle', + }], + }); }); }); @@ -83,14 +60,12 @@ describe('route53', () => { values: ['SeeThere'], }); - expect(stack2).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack2).hasResourceProperties('AWS::Route53::RecordSet', { HostedZoneId: 'hosted-zone-id', Name: 'lookHere.cdk.local.', ResourceRecords: ['"SeeThere"'], Type: 'TXT', }); - - }); test('adds period to name if not provided', () => { @@ -103,10 +78,9 @@ describe('route53', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::HostedZone', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::HostedZone', { Name: 'zonename.', }); - }); test('fails if zone name ends with a trailing dot', () => { @@ -115,7 +89,6 @@ describe('route53', () => { // THEN expect(() => new HostedZone(stack, 'MyHostedZone', { zoneName: 'zonename.' })).toThrow(/zone name must not end with a trailing dot/); - }); test('a hosted zone can be assiciated with a VPC either upon creation or using "addVpc"', () => { @@ -133,7 +106,7 @@ describe('route53', () => { zone.addVpc(vpc3); // THEN - expect(stack).toHaveResource('AWS::Route53::HostedZone', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::HostedZone', { VPCs: [ { VPCId: { @@ -161,7 +134,6 @@ describe('route53', () => { }, ], }); - }); test('public zone cannot be associated with a vpc (runtime error)', () => { @@ -172,7 +144,6 @@ describe('route53', () => { // THEN expect(() => zone.addVpc(vpc)).toThrow(/Cannot associate public hosted zones with a VPC/); - }); test('setting up zone delegation', () => { @@ -185,14 +156,13 @@ describe('route53', () => { zone.addDelegation(delegate, { ttl: cdk.Duration.seconds(1337) }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'NS', Name: 'sub.top.test.', HostedZoneId: stack.resolve(zone.hostedZoneId), ResourceRecords: stack.resolve(delegate.hostedZoneNameServers), TTL: '1337', }); - }); test('public hosted zone wiht caaAmazon set to true', () => { @@ -206,14 +176,13 @@ describe('route53', () => { }); // THEN - expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { Type: 'CAA', Name: 'protected.com.', ResourceRecords: [ '0 issue "amazon.com"', ], }); - }); }); diff --git a/packages/@aws-cdk/aws-route53/test/util.test.ts b/packages/@aws-cdk/aws-route53/test/util.test.ts index f6ec2b7cd36a6..3f791d1a5bb63 100644 --- a/packages/@aws-cdk/aws-route53/test/util.test.ts +++ b/packages/@aws-cdk/aws-route53/test/util.test.ts @@ -5,13 +5,11 @@ import * as util from '../lib/util'; describe('util', () => { test('throws when zone name ending with a \'.\'', () => { expect(() => util.validateZoneName('zone.name.')).toThrow(/trailing dot/); - }); test('accepts a valid domain name', () => { const domainName = 'amazonaws.com'; util.validateZoneName(domainName); - }); test('providedName ending with a dot returns the name', () => { @@ -27,7 +25,6 @@ describe('util', () => { // THEN expect(qualified).toEqual('test.domain.com.'); - }); test('providedName that matches zoneName returns providedName with a trailing dot', () => { @@ -43,7 +40,6 @@ describe('util', () => { // THEN expect(qualified).toEqual('test.domain.com.'); - }); test('providedName that ends with zoneName returns providedName with a trailing dot', () => { @@ -59,7 +55,6 @@ describe('util', () => { // THEN expect(qualified).toEqual('test.domain.com.'); - }); test('providedName that does not match zoneName concatenates providedName and zoneName', () => { @@ -75,6 +70,5 @@ describe('util', () => { // THEN expect(qualified).toEqual('test.domain.com.'); - }); }); diff --git a/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts b/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts index 506a25e2a26df..e4155136af75a 100644 --- a/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts +++ b/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts @@ -1,5 +1,4 @@ -import { expect as cdkExpect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { IVpcEndpointServiceLoadBalancer, VpcEndpointService } from '@aws-cdk/aws-ec2'; import { Stack } from '@aws-cdk/core'; import { PublicHostedZone, VpcEndpointServiceDomainName } from '../lib'; @@ -44,7 +43,7 @@ test('create domain name resource', () => { }); // THEN - cdkExpect(stack).to(haveResourceLike('Custom::AWS', { + Template.fromStack(stack).hasResource('Custom::AWS', { Properties: { Create: { 'Fn::Join': [ @@ -87,10 +86,10 @@ test('create domain name resource', () => { 'EndpointDomainEnableDnsCustomResourcePolicy5E6DE7EB', 'VPCES3AE7D565', ], - }, ResourcePart.CompleteDefinition)); + }); // Have to use `haveResourceLike` because there is a property that, by design, changes on every build - cdkExpect(stack).to(haveResourceLike('Custom::AWS', { + Template.fromStack(stack).hasResource('Custom::AWS', { Properties: { Create: { 'Fn::Join': [ @@ -123,9 +122,9 @@ test('create domain name resource', () => { 'EndpointDomainGetNamesCustomResourcePolicy141775B1', 'VPCES3AE7D565', ], - }, ResourcePart.CompleteDefinition)); + }); - cdkExpect(stack).to(haveResource('AWS::Route53::RecordSet', { + Template.fromStack(stack).hasResource('AWS::Route53::RecordSet', { Properties: { Name: { 'Fn::Join': [ @@ -167,9 +166,9 @@ test('create domain name resource', () => { DependsOn: [ 'VPCES3AE7D565', ], - }, ResourcePart.CompleteDefinition)); + }); - cdkExpect(stack).to(haveResourceLike('Custom::AWS', { + Template.fromStack(stack).hasResource('Custom::AWS', { Properties: { Create: { 'Fn::Join': [ @@ -241,7 +240,7 @@ test('create domain name resource', () => { 'EndpointDomainStartVerificationCustomResourcePolicyD2BAC9A6', 'VPCES3AE7D565', ], - }, ResourcePart.CompleteDefinition)); + }); }); test('throws if creating multiple domains for a single service', () => { @@ -266,7 +265,6 @@ test('throws if creating multiple domains for a single service', () => { }).toThrow(/Cannot create a VpcEndpointServiceDomainName for service/); }); - test('endpoint domain name property equals input domain name', () => { // GIVEN vpces = new VpcEndpointService(stack, 'NameTest', { @@ -279,5 +277,4 @@ test('endpoint domain name property equals input domain name', () => { publicHostedZone: zone, }); expect(dn.domainName).toEqual('name-test.aws-cdk.dev'); - }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 4fd85b0b4152f..2c7ea2bc6b9f2 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "jest": "^27.4.7" }, diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 4f0c15f75940a..37ddba18cf79b 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -79,7 +79,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.4.0", "jest": "^27.4.7", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index 8149d88335146..a289566a2728c 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -80,7 +80,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-secretsmanager/test/rotation-schedule.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts index e38ffde417b18..fab58e80e82d2 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -26,7 +26,7 @@ test('create a rotation schedule with a rotation Lambda', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretA720EF05', }, @@ -58,7 +58,7 @@ test('assign permissions for rotation schedule with a rotation Lambda', () => { }); // THEN - expect(stack).toHaveResource('AWS::Lambda::Permission', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': [ @@ -69,7 +69,7 @@ test('assign permissions for rotation schedule with a rotation Lambda', () => { Principal: 'secretsmanager.amazonaws.com', }); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -118,9 +118,9 @@ test('assign kms permissions for rotation schedule with a rotation Lambda', () = }); // THEN - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [{}, {}, {}, + Statement: [Match.anyValue(), Match.anyValue(), Match.anyValue(), { Action: [ 'kms:Decrypt', @@ -172,7 +172,7 @@ describe('hosted rotation', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretA720EF05', }, @@ -188,7 +188,7 @@ describe('hosted rotation', () => { Transform: 'AWS::SecretsManager-2020-07-23', })); - expect(stack).toHaveResource('AWS::SecretsManager::ResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', { ResourcePolicy: { Statement: [ { @@ -236,7 +236,7 @@ describe('hosted rotation', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretA720EF05', }, @@ -251,7 +251,7 @@ describe('hosted rotation', () => { }, }); - expect(stack).toHaveResource('AWS::SecretsManager::ResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', { ResourcePolicy: { Statement: [ { @@ -302,7 +302,7 @@ describe('hosted rotation', () => { dbConnections.allowDefaultPortFrom(hostedRotation); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretA720EF05', }, @@ -334,7 +334,7 @@ describe('hosted rotation', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { FromPort: 3306, GroupId: { 'Fn::GetAtt': [ @@ -374,7 +374,7 @@ describe('hosted rotation', () => { dbConnections.allowDefaultPortFrom(hostedRotation); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretA720EF05', }, @@ -420,7 +420,7 @@ describe('hosted rotation', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { FromPort: 3306, GroupId: { 'Fn::GetAtt': [ diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts index 974aa0c611c4d..c6c153ce83ae6 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as secretsmanager from '../lib'; @@ -34,7 +34,7 @@ test('secret rotation single user', () => { }); // THEN - expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'from SecretRotationSecurityGroupAEC520AB:3306', FromPort: 3306, @@ -53,7 +53,7 @@ test('secret rotation single user', () => { ToPort: 3306, }); - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretA720EF05', }, @@ -68,11 +68,11 @@ test('secret rotation single user', () => { }, }); - expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { GroupDescription: 'Default/SecretRotation/SecurityGroup', }); - expect(stack).toHaveResource('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Location: { ApplicationId: { 'Fn::FindInMap': ['SecretRotationSARMappingC10A2F5D', { Ref: 'AWS::Partition' }, 'applicationId'], @@ -122,7 +122,7 @@ test('secret rotation single user', () => { }, }); - expect(stack).toHaveResource('AWS::SecretsManager::ResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', { ResourcePolicy: { Statement: [ { @@ -171,7 +171,7 @@ test('secret rotation multi user', () => { }); // THEN - expect(stack).toHaveResource('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Parameters: { endpoint: { 'Fn::Join': [ @@ -215,7 +215,7 @@ test('secret rotation multi user', () => { }, }); - expect(stack).toHaveResource('AWS::SecretsManager::ResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', { ResourcePolicy: { Statement: [ { @@ -261,7 +261,7 @@ test('secret rotation allows passing an empty string for excludeCharacters', () }); // THEN - expect(stack).toHaveResourceLike('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Parameters: { excludeCharacters: '', }, @@ -304,7 +304,7 @@ test('rotation function name does not exceed 64 chars', () => { }); // THEN - expect(stack).toHaveResource('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Parameters: { endpoint: { 'Fn::Join': [ @@ -364,7 +364,7 @@ test('with interface vpc endpoint', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Serverless::Application', { + Template.fromStack(stack).hasResourceProperties('AWS::Serverless::Application', { Parameters: { endpoint: { 'Fn::Join': ['', [ diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts index 0068a8d46652e..cd90bc9c715df 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts @@ -1,5 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; -import { ABSENT, expect as assertExpect, ResourcePart } 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 * as lambda from '@aws-cdk/aws-lambda'; @@ -19,7 +18,7 @@ test('default secret', () => { new secretsmanager.Secret(stack, 'Secret'); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { GenerateSecretString: {}, }); }); @@ -31,11 +30,9 @@ test('set removalPolicy to secret', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', - { - DeletionPolicy: 'Retain', - }, ResourcePart.CompleteDefinition, - ); + Template.fromStack(stack).hasResource('AWS::SecretsManager::Secret', { + DeletionPolicy: 'Retain', + }); }); test('secret with kms', () => { @@ -46,10 +43,9 @@ test('secret with kms', () => { new secretsmanager.Secret(stack, 'Secret', { encryptionKey: key }); // THEN - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, + Statement: Match.arrayWith([ { Effect: 'Allow', Resource: '*', @@ -136,7 +132,7 @@ test('secret with kms', () => { }, }, }, - ], + ]), Version: '2012-10-17', }, }); @@ -152,7 +148,7 @@ test('secret with generate secret string options', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { GenerateSecretString: { ExcludeUppercase: true, PasswordLength: 20, @@ -170,7 +166,7 @@ test('templated secret string', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { GenerateSecretString: { SecretStringTemplate: '{"username":"username"}', GenerateStringKey: 'password', @@ -192,8 +188,8 @@ describe('secretStringBeta1', () => { secretStringBeta1: secretsmanager.SecretStringValueBeta1.fromUnsafePlaintext('unsafeP@$$'), }); - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { - GenerateSecretString: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { + GenerateSecretString: Match.absent(), SecretString: 'unsafeP@$$', }); }); @@ -209,8 +205,8 @@ describe('secretStringBeta1', () => { secretStringBeta1: secretsmanager.SecretStringValueBeta1.fromToken(accessKey.secretAccessKey.toString()), }); - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { - GenerateSecretString: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { + GenerateSecretString: Match.absent(), SecretString: { 'Fn::GetAtt': ['MyKey6AB29FA6', 'SecretAccessKey'] }, }); }); @@ -224,8 +220,8 @@ describe('secretStringBeta1', () => { secretStringBeta1: secretString, }); - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { - GenerateSecretString: ABSENT, + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { + GenerateSecretString: Match.absent(), SecretString: { 'Fn::Join': [ '', @@ -275,7 +271,7 @@ test('grantRead', () => { secret.grantRead(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -316,7 +312,7 @@ test('grantRead with KMS Key', () => { secret.grantRead(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -329,12 +325,9 @@ test('grantRead with KMS Key', () => { }], }, }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - {}, - {}, + Statement: Match.arrayWith([ { Action: 'kms:Decrypt', Condition: { @@ -364,7 +357,7 @@ test('grantRead with KMS Key', () => { }, Resource: '*', }, - ], + ]), Version: '2012-10-17', }, }); @@ -380,7 +373,7 @@ test('grantRead cross account', () => { secret.grantRead(principal, ['FOO', 'bar']).assertSuccess(); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::ResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', { ResourcePolicy: { Statement: [ { @@ -423,48 +416,43 @@ test('grantRead cross account', () => { }, }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - {}, - {}, - { - Action: 'kms:Decrypt', - Condition: { - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'secretsmanager.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], - ], - }, - }, - }, - Effect: 'Allow', - Principal: { - AWS: { + Statement: Match.arrayWith([{ + Action: 'kms:Decrypt', + Condition: { + StringEquals: { + 'kms:ViaService': { 'Fn::Join': [ '', [ - 'arn:', + 'secretsmanager.', { - Ref: 'AWS::Partition', + Ref: 'AWS::Region', }, - ':iam::1234:root', + '.amazonaws.com', ], ], }, }, - Resource: '*', }, - ], + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::1234:root', + ], + ], + }, + }, + Resource: '*', + }]), Version: '2012-10-17', }, }); @@ -480,7 +468,7 @@ test('grantRead with version label constraint', () => { secret.grantRead(role, ['FOO', 'bar']); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -498,42 +486,37 @@ test('grantRead with version label constraint', () => { }], }, }); - expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - {}, - {}, - { - Action: 'kms:Decrypt', - Condition: { - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'secretsmanager.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], + Statement: Match.arrayWith([{ + Action: 'kms:Decrypt', + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', ], - }, - }, - }, - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', ], }, }, - Resource: '*', }, - ], + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': [ + 'Role1ABCC5F0', + 'Arn', + ], + }, + }, + Resource: '*', + }]), Version: '2012-10-17', }, }); @@ -548,7 +531,7 @@ test('grantWrite', () => { secret.grantWrite(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -573,8 +556,7 @@ test('grantWrite with kms', () => { secret.grantWrite(role); // THEN - const expectStack = expect(stack); - expectStack.toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -587,46 +569,41 @@ test('grantWrite with kms', () => { }], }, }); - expectStack.toHaveResourceLike('AWS::KMS::Key', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { KeyPolicy: { - Statement: [ - {}, - {}, - {}, - { - Action: [ - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - Condition: { - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'secretsmanager.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], + Statement: Match.arrayWith([{ + Action: [ + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', ], - }, - }, - }, - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', ], }, }, - Resource: '*', }, - ], + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': [ + 'Role1ABCC5F0', + 'Arn', + ], + }, + }, + Resource: '*', + }]), }, }); }); @@ -645,7 +622,7 @@ test('secretValue', () => { }); // THEN - expect(stack).toHaveResource('CDK::Phony::Resource', { + Template.fromStack(stack).hasResourceProperties('CDK::Phony::Resource', { value: { 'Fn::Join': ['', [ '{{resolve:secretsmanager:', @@ -664,9 +641,8 @@ describe('secretName', () => { }); // Creates secret name by parsing ARN. - expect(stack).toHaveOutput({ - outputName: 'MySecretName', - outputValue: { 'Fn::Select': [6, { 'Fn::Split': [':', { Ref: 'SecretA720EF05' }] }] }, + Template.fromStack(stack).hasOutput('*', { + Value: { 'Fn::Select': [6, { 'Fn::Split': [':', { Ref: 'SecretA720EF05' }] }] }, }); } @@ -699,9 +675,8 @@ describe('secretName', () => { const resourceName = { 'Fn::Select': [6, { 'Fn::Split': [':', { Ref: 'SecretA720EF05' }] }] }; - expect(stack).toHaveOutput({ - outputName: 'MySecretName', - outputValue: { + Template.fromStack(stack).hasOutput('MySecretName', { + Value: { 'Fn::Join': ['-', [ { 'Fn::Select': [0, { 'Fn::Split': ['-', resourceName] }] }, { 'Fn::Select': [1, { 'Fn::Split': ['-', resourceName] }] }, @@ -720,11 +695,8 @@ describe('secretName', () => { const resourceName = { 'Fn::Select': [6, { 'Fn::Split': [':', { Ref: 'SecretA720EF05' }] }] }; - expect(stack).toHaveOutput({ - outputName: 'MySecretName', - outputValue: { - 'Fn::Select': [0, { 'Fn::Split': ['-', resourceName] }], - }, + Template.fromStack(stack).hasOutput('MySecretName', { + Value: { 'Fn::Select': [0, { 'Fn::Split': ['-', resourceName] }] }, }); }); @@ -739,11 +711,8 @@ describe('secretName', () => { secretNameSegments.push({ 'Fn::Select': [i, { 'Fn::Split': ['-', resourceName] }] }); } - expect(stack).toHaveOutput({ - outputName: 'MySecretName', - outputValue: { - 'Fn::Join': ['-', secretNameSegments], - }, + Template.fromStack(stack).hasOutput('MySecretName', { + Value: { 'Fn::Join': ['-', secretNameSegments] }, }); } @@ -779,7 +748,7 @@ describe('secretName', () => { value: secret2.secretName, }); - const outputs = assertExpect(stack).value.Outputs; + const outputs = Template.fromStack(stack).findOutputs('*'); expect(outputs.MySecretName1).toEqual(outputs.MySecretName2); }); }); @@ -847,9 +816,8 @@ test('import by secretArn supports tokens for ARNs', () => { // THEN expect(secretB.secretArn).toBe(secretA.secretArn); - expect(stackB).toHaveOutput({ - outputName: 'secretBSecretName', - outputValue: { 'Fn::Select': [6, { 'Fn::Split': [':', { 'Fn::ImportValue': 'StackA:ExportsOutputRefSecretA188F281703FC8A52' }] }] }, + Template.fromStack(stackB).hasOutput('secretBSecretName', { + Value: { 'Fn::Select': [6, { 'Fn::Split': [':', { 'Fn::ImportValue': 'StackA:ExportsOutputRefSecretA188F281703FC8A52' }] }] }, }); }); @@ -894,7 +862,7 @@ test('fromSecretCompleteArn - grants', () => { secret.grantWrite(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -931,7 +899,7 @@ test('fromSecretCompleteArn - can be assigned to a property with type number', ( }); // THEN - expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { MemorySize: `{{resolve:secretsmanager:${secretArn}:SecretString:LambdaFunctionMemorySize::}}`, }); }); @@ -963,7 +931,7 @@ test('fromSecretPartialArn - grants', () => { secret.grantWrite(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -1088,7 +1056,7 @@ testDeprecated('import by secret name with grants', () => { ':secret:MySecret*', ]], }; - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -1156,7 +1124,7 @@ test('import by secret name v2 with grants', () => { ':secret:MySecret-??????', ]], }; - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [{ @@ -1192,7 +1160,7 @@ test('can attach a secret with attach()', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::SecretTargetAttachment', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::SecretTargetAttachment', { SecretId: { Ref: 'SecretA720EF05', }, @@ -1237,7 +1205,7 @@ test('add a rotation schedule to an attached secret', () => { }); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::RotationSchedule', { SecretId: { Ref: 'SecretAttachment2E1B7C3B', // The secret returned by the attachment, not the secret itself. }, @@ -1284,7 +1252,7 @@ test('can add to the resource policy of a secret', () => { })); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::ResourcePolicy', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::ResourcePolicy', { ResourcePolicy: { Statement: [ { @@ -1337,20 +1305,14 @@ test('fails if secret policy has no IAM principals', () => { test('with replication regions', () => { // WHEN const secret = new secretsmanager.Secret(stack, 'Secret', { - replicaRegions: [ - { - region: 'eu-west-1', - }, - ], + replicaRegions: [{ region: 'eu-west-1' }], }); secret.addReplicaRegion('eu-central-1', kms.Key.fromKeyArn(stack, 'Key', 'arn:aws:kms:eu-central-1:123456789012:key/my-key-id')); // THEN - expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', { ReplicaRegions: [ - { - Region: 'eu-west-1', - }, + { Region: 'eu-west-1' }, { KmsKeyId: 'arn:aws:kms:eu-central-1:123456789012:key/my-key-id', Region: 'eu-central-1', diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index 9a9d267d35904..3fcee22ba4a66 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -75,7 +75,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-servicediscovery/test/instance.test.ts b/packages/@aws-cdk/aws-servicediscovery/test/instance.test.ts index 89ee3a81f4bfa..0fb472c1b1130 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/instance.test.ts +++ b/packages/@aws-cdk/aws-servicediscovery/test/instance.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as cdk from '@aws-cdk/core'; @@ -24,7 +24,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Instance', { InstanceAttributes: { AWS_INSTANCE_IPV4: '10.0.0.0', AWS_INSTANCE_IPV6: '0:0:0:0:0:ffff:a00:0', @@ -62,7 +62,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Instance', { InstanceAttributes: { AWS_INSTANCE_IPV4: '54.239.25.192', AWS_INSTANCE_IPV6: '0:0:0:0:0:ffff:a00:0', @@ -102,7 +102,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Instance', { InstanceAttributes: { AWS_INSTANCE_IPV4: '10.0.0.0', AWS_INSTANCE_IPV6: '0:0:0:0:0:ffff:a00:0', @@ -256,7 +256,7 @@ describe('instance', () => { service.registerLoadBalancer('Loadbalancer', alb, customAttributes); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Instance', { InstanceAttributes: { AWS_ALIAS_DNS_NAME: { 'Fn::GetAtt': [ @@ -343,7 +343,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Instance', { InstanceAttributes: { AWS_INSTANCE_CNAME: 'foo.com', dogs: 'good', @@ -397,7 +397,7 @@ describe('instance', () => { }); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::Instance', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Instance', { InstanceAttributes: { dogs: 'good', }, @@ -494,7 +494,7 @@ describe('instance', () => { }); // THEN - expect(stack).toCountResources('AWS::ServiceDiscovery::Instance', 2); + Template.fromStack(stack).resourceCountIs('AWS::ServiceDiscovery::Instance', 2); }); diff --git a/packages/@aws-cdk/aws-servicediscovery/test/namespace.test.ts b/packages/@aws-cdk/aws-servicediscovery/test/namespace.test.ts index d0c70b057534b..30ccf20fc85f1 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/namespace.test.ts +++ b/packages/@aws-cdk/aws-servicediscovery/test/namespace.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as servicediscovery from '../lib'; @@ -11,7 +11,7 @@ describe('namespace', () => { name: 'foobar.com', }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::HttpNamespace', @@ -32,7 +32,7 @@ describe('namespace', () => { name: 'foobar.com', }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::PublicDnsNamespace', @@ -55,7 +55,7 @@ describe('namespace', () => { vpc, }); - expect(stack).toHaveResource('AWS::ServiceDiscovery::PrivateDnsNamespace', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::PrivateDnsNamespace', { Name: 'foobar.com', Vpc: { Ref: 'MyVpcF9F0CA6F', diff --git a/packages/@aws-cdk/aws-servicediscovery/test/service.test.ts b/packages/@aws-cdk/aws-servicediscovery/test/service.test.ts index 44c5ba3e97c6b..556bc6c2c7260 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/service.test.ts +++ b/packages/@aws-cdk/aws-servicediscovery/test/service.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as servicediscovery from '../lib'; @@ -21,7 +21,7 @@ describe('service', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::HttpNamespace', @@ -69,7 +69,7 @@ describe('service', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::HttpNamespace', @@ -118,7 +118,7 @@ describe('service', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::PublicDnsNamespace', @@ -176,7 +176,7 @@ describe('service', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::PublicDnsNamespace', @@ -233,7 +233,7 @@ describe('service', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Resources: { MyNamespaceD0BB8558: { Type: 'AWS::ServiceDiscovery::PublicDnsNamespace', @@ -417,11 +417,11 @@ describe('service', () => { }); // THEN - expect(stack).toHaveResource('AWS::ServiceDiscovery::PrivateDnsNamespace', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::PrivateDnsNamespace', { Name: 'private', }); - expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + Template.fromStack(stack).hasResourceProperties('AWS::ServiceDiscovery::Service', { Description: 'service description', DnsConfig: { DnsRecords: [ diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 64ad0fc5f67ce..9b49c6d9b0933 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/jest": "^27.4.0", "jest": "^27.4.7" }, diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 70e1045d1695b..68dd03f7ecc6c 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/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/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index 671937a3ed01e..546fe9a3c6dae 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; @@ -22,7 +22,7 @@ beforeEach(() => { test('url subscription', () => { topic.addSubscription(new subs.UrlSubscription('https://foobar.com/')); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -54,7 +54,7 @@ test('url subscription with user provided dlq', () => { deadLetterQueue: dlQueue, })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -134,7 +134,7 @@ test('url subscription (with raw delivery)', () => { rawMessageDelivery: true, })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -160,7 +160,7 @@ test('url subscription (unresolved url with protocol)', () => { const urlToken = Token.asString({ Ref: 'my-url-1' }); topic.addSubscription(new subs.UrlSubscription(urlToken, { protocol: sns.SubscriptionProtocol.HTTPS })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -190,7 +190,7 @@ test('url subscription (double unresolved url with protocol)', () => { topic.addSubscription(new subs.UrlSubscription(urlToken1, { protocol: sns.SubscriptionProtocol.HTTPS })); topic.addSubscription(new subs.UrlSubscription(urlToken2, { protocol: sns.SubscriptionProtocol.HTTPS })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -240,7 +240,7 @@ test('queue subscription', () => { topic.addSubscription(new subs.SqsSubscription(queue)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -332,7 +332,7 @@ test('queue subscription cross region', () => { topic1.addSubscription(new subs.SqsSubscription(queue)); - expect(topicStack).toMatchTemplate({ + Template.fromStack(topicStack).templateMatches({ 'Resources': { 'TopicBFC7AF6E': { 'Type': 'AWS::SNS::Topic', @@ -344,7 +344,7 @@ test('queue subscription cross region', () => { }, }); - expect(queueStack).toMatchTemplate({ + Template.fromStack(queueStack).templateMatches({ 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', @@ -438,7 +438,7 @@ test('queue subscription cross region, env agnostic', () => { topic1.addSubscription(new subs.SqsSubscription(queue)); - expect(topicStack).toMatchTemplate({ + Template.fromStack(topicStack).templateMatches({ 'Resources': { 'TopicBFC7AF6E': { 'Type': 'AWS::SNS::Topic', @@ -460,7 +460,7 @@ test('queue subscription cross region, env agnostic', () => { }, }); - expect(queueStack).toMatchTemplate({ + Template.fromStack(queueStack).templateMatches({ 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', @@ -540,7 +540,7 @@ test('queue subscription cross region, topic env agnostic', () => { topic1.addSubscription(new subs.SqsSubscription(queue)); - expect(topicStack).toMatchTemplate({ + Template.fromStack(topicStack).templateMatches({ 'Resources': { 'TopicBFC7AF6E': { 'Type': 'AWS::SNS::Topic', @@ -552,7 +552,7 @@ test('queue subscription cross region, topic env agnostic', () => { }, }); - expect(queueStack).toMatchTemplate({ + Template.fromStack(queueStack).templateMatches({ 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', @@ -666,7 +666,7 @@ test('queue subscription cross region, queue env agnostic', () => { topic1.addSubscription(new subs.SqsSubscription(queue)); - expect(topicStack).toMatchTemplate({ + Template.fromStack(topicStack).templateMatches({ 'Resources': { 'TopicBFC7AF6E': { 'Type': 'AWS::SNS::Topic', @@ -678,7 +678,7 @@ test('queue subscription cross region, queue env agnostic', () => { }, }); - expect(queueStack).toMatchTemplate({ + Template.fromStack(queueStack).templateMatches({ 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', @@ -768,7 +768,7 @@ test('queue subscription with user provided dlq', () => { deadLetterQueue: dlQueue, })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -893,7 +893,7 @@ test('queue subscription (with raw delivery)', () => { topic.addSubscription(new subs.SqsSubscription(queue, { rawMessageDelivery: true })); - expect(stack).toHaveResource('AWS::SNS::Subscription', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { 'Endpoint': { 'Fn::GetAtt': [ 'MyQueueE6CA6235', @@ -920,7 +920,7 @@ test('encrypted queue subscription', () => { topic.addSubscription(new subs.SqsSubscription(queue)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1067,7 +1067,7 @@ test('lambda subscription', () => { topic.addSubscription(new subs.LambdaSubscription(fction)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1178,7 +1178,7 @@ test('lambda subscription, cross region env agnostic', () => { topic1.addSubscription(new subs.LambdaSubscription(fction)); - expect(lambdaStack).toMatchTemplate({ + Template.fromStack(lambdaStack).templateMatches({ 'Resources': { 'MyFuncServiceRole54065130': { 'Type': 'AWS::IAM::Role', @@ -1292,7 +1292,7 @@ test('lambda subscription, cross region', () => { topic1.addSubscription(new subs.LambdaSubscription(fction)); - expect(lambdaStack).toMatchTemplate({ + Template.fromStack(lambdaStack).templateMatches({ 'Resources': { 'MyFuncServiceRole54065130': { 'Type': 'AWS::IAM::Role', @@ -1401,7 +1401,7 @@ test('lambda subscription, cross region', () => { test('email subscription', () => { topic.addSubscription(new subs.EmailSubscription('foo@bar.com')); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1428,7 +1428,7 @@ test('email subscription with unresolved', () => { const emailToken = Token.asString({ Ref: 'my-email-1' }); topic.addSubscription(new subs.EmailSubscription(emailToken)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1459,7 +1459,7 @@ test('email and url subscriptions with unresolved', () => { topic.addSubscription(new subs.EmailSubscription(emailToken)); topic.addSubscription(new subs.UrlSubscription(urlToken, { protocol: sns.SubscriptionProtocol.HTTPS })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1507,7 +1507,7 @@ test('email and url subscriptions with unresolved - four subscriptions', () => { topic.addSubscription(new subs.EmailSubscription(emailToken3)); topic.addSubscription(new subs.EmailSubscription(emailToken4)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1579,7 +1579,7 @@ test('multiple subscriptions', () => { topic.addSubscription(new subs.SqsSubscription(queue)); topic.addSubscription(new subs.LambdaSubscription(func)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1759,7 +1759,7 @@ test('with filter policy', () => { }, })); - expect(stack).toHaveResource('AWS::SNS::Subscription', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { 'FilterPolicy': { 'color': [ 'red', @@ -1797,7 +1797,7 @@ test('region property is present on an imported topic - sqs', () => { const queue = new sqs.Queue(stack, 'myqueue'); imported.addSubscription(new subs.SqsSubscription(queue)); - expect(stack).toHaveResource('AWS::SNS::Subscription', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Region: 'us-east-1', }); }); @@ -1808,7 +1808,7 @@ test('region property on an imported topic as a parameter - sqs', () => { const queue = new sqs.Queue(stack, 'myqueue'); imported.addSubscription(new subs.SqsSubscription(queue)); - expect(stack).toHaveResource('AWS::SNS::Subscription', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Region: { 'Fn::Select': [3, { 'Fn::Split': [':', { 'Ref': 'topicArn' }] }], }, @@ -1824,7 +1824,7 @@ test('region property is present on an imported topic - lambda', () => { }); imported.addSubscription(new subs.LambdaSubscription(func)); - expect(stack).toHaveResource('AWS::SNS::Subscription', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Region: 'us-east-1', }); }); @@ -1839,7 +1839,7 @@ test('region property on an imported topic as a parameter - lambda', () => { }); imported.addSubscription(new subs.LambdaSubscription(func)); - expect(stack).toHaveResource('AWS::SNS::Subscription', { + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Region: { 'Fn::Select': [3, { 'Fn::Split': [':', { 'Ref': 'topicArn' }] }], }, @@ -1849,7 +1849,7 @@ test('region property on an imported topic as a parameter - lambda', () => { test('sms subscription', () => { topic.addSubscription(new subs.SmsSubscription('+15551231234')); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', @@ -1876,7 +1876,7 @@ test('sms subscription with unresolved', () => { const smsToken = Token.asString({ Ref: 'my-sms-1' }); topic.addSubscription(new subs.SmsSubscription(smsToken)); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyTopic86869434': { 'Type': 'AWS::SNS::Topic', diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 3b87e34a0a151..d318be9283996 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/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-s3": "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-sqs/test/sqs.test.ts b/packages/@aws-cdk/aws-sqs/test/sqs.test.ts index b444220caf198..6a4d5fda6c02c 100644 --- a/packages/@aws-cdk/aws-sqs/test/sqs.test.ts +++ b/packages/@aws-cdk/aws-sqs/test/sqs.test.ts @@ -1,5 +1,4 @@ -import { ResourcePart } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; +import { Match, Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { CfnParameter, Duration, Stack, App, Token } from '@aws-cdk/core'; @@ -13,7 +12,7 @@ test('default properties', () => { expect(q.fifo).toEqual(false); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -23,9 +22,9 @@ test('default properties', () => { }, }); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResource('AWS::SQS::Queue', { DeletionPolicy: 'Delete', - }, ResourcePart.CompleteDefinition); + }); }); test('with a dead letter queue', () => { @@ -34,7 +33,7 @@ test('with a dead letter queue', () => { const dlqProps = { queue: dlq, maxReceiveCount: 3 }; const queue = new sqs.Queue(stack, 'Queue', { deadLetterQueue: dlqProps }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'DLQ581697C4': { 'Type': 'AWS::SQS::Queue', @@ -91,7 +90,7 @@ test('message retention period can be provided as a parameter', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Parameters': { 'myretentionperiod': { 'Type': 'Number', @@ -122,7 +121,7 @@ test('addToPolicy will automatically create a policy for this queue', () => { principals: [new iam.ArnPrincipal('arn')], })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', @@ -323,7 +322,7 @@ describe('grants', () => { queue.grantPurge(user); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -350,7 +349,7 @@ describe('queue encryption', () => { const queue = new sqs.Queue(stack, 'Queue', { encryptionMasterKey: key }); expect(queue.encryptionMasterKey).toEqual(key); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, }); }); @@ -360,8 +359,8 @@ describe('queue encryption', () => { new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS }); - expect(stack).toHaveResource('AWS::KMS::Key'); - expect(stack).toHaveResource('AWS::SQS::Queue', { + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', Match.anyValue()); + Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { 'KmsMasterKeyId': { 'Fn::GetAtt': [ 'QueueKey39FCBAE6', @@ -375,7 +374,7 @@ describe('queue encryption', () => { const stack = new Stack(); new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS_MANAGED }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -403,7 +402,7 @@ describe('queue encryption', () => { queue.grantSendMessages(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -440,7 +439,7 @@ test('test ".fifo" suffixed queues register as fifo', () => { expect(queue.fifo).toEqual(true); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -463,7 +462,7 @@ test('test a fifo queue is observed when the "fifo" property is specified', () = expect(queue.fifo).toEqual(true); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -486,7 +485,7 @@ test('test a fifo queue is observed when high throughput properties are specifie }); expect(queue.fifo).toEqual(true); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -584,7 +583,7 @@ function testGrant(action: (q: sqs.Queue, principal: iam.IPrincipal) => void, .. action(queue, principal); - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 236638ce521f9..674b3633a1128 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/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-ssm/test/parameter-store-string.test.ts b/packages/@aws-cdk/aws-ssm/test/parameter-store-string.test.ts index a8ce58f22fded..d9da8a0697535 100644 --- a/packages/@aws-cdk/aws-ssm/test/parameter-store-string.test.ts +++ b/packages/@aws-cdk/aws-ssm/test/parameter-store-string.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 ssm from '../lib'; @@ -26,7 +26,7 @@ test('can reference SSMPS string - latest version', () => { }); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Parameters: { RefParameter: { Type: 'AWS::SSM::Parameter::Value', diff --git a/packages/@aws-cdk/aws-ssm/test/parameter.test.ts b/packages/@aws-cdk/aws-ssm/test/parameter.test.ts index 272a477523623..48594d1e3ee41 100644 --- a/packages/@aws-cdk/aws-ssm/test/parameter.test.ts +++ b/packages/@aws-cdk/aws-ssm/test/parameter.test.ts @@ -1,6 +1,6 @@ /* eslint-disable max-len */ -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; @@ -19,7 +19,7 @@ test('creating a String SSM Parameter', () => { }); // THEN - expect(stack).toHaveResource('AWS::SSM::Parameter', { + Template.fromStack(stack).hasResourceProperties('AWS::SSM::Parameter', { AllowedPattern: '.*', Description: 'The value Foo', Name: 'FooParameter', @@ -50,7 +50,7 @@ test('dataType can be specified', () => { }); // THEN - expect(stack).toHaveResource('AWS::SSM::Parameter', { + Template.fromStack(stack).hasResourceProperties('AWS::SSM::Parameter', { Value: 'myValue', DataType: 'aws:ec2:image', }); @@ -70,7 +70,7 @@ test('expect String SSM Parameter to have tier properly set', () => { }); // THEN - expect(stack).toHaveResource('AWS::SSM::Parameter', { + Template.fromStack(stack).hasResourceProperties('AWS::SSM::Parameter', { Tier: 'Advanced', }); }); @@ -110,7 +110,7 @@ test('creating a StringList SSM Parameter', () => { }); // THEN - expect(stack).toHaveResource('AWS::SSM::Parameter', { + Template.fromStack(stack).hasResourceProperties('AWS::SSM::Parameter', { AllowedPattern: '(Foo|Bar)', Description: 'The values Foo and Bar', Name: 'FooParameter', @@ -340,7 +340,7 @@ test('StringParameter.fromStringParameterName', () => { expect(stack.resolve(param.parameterName)).toEqual('MyParamName'); expect(stack.resolve(param.parameterType)).toEqual('String'); expect(stack.resolve(param.stringValue)).toEqual({ Ref: 'MyParamNameParameter' }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Parameters: { MyParamNameParameter: { Type: 'AWS::SSM::Parameter::Value', @@ -487,7 +487,7 @@ test('StringParameter.fromSecureStringParameterAttributes with encryption key cr param.grantRead(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -547,7 +547,7 @@ test('StringParameter.fromSecureStringParameterAttributes with encryption key cr param.grantWrite(role); // THEN - expect(stack).toHaveResource('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -658,7 +658,7 @@ describe('valueForStringParameter', () => { const value = ssm.StringParameter.valueForStringParameter(stack, 'my-param-name'); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Parameters: { SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter: { Type: 'AWS::SSM::Parameter::Value', @@ -680,7 +680,7 @@ describe('valueForStringParameter', () => { ssm.StringParameter.valueForStringParameter(stack, 'my-param-name'); // THEN - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ Parameters: { SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter: { Type: 'AWS::SSM::Parameter::Value', diff --git a/packages/@aws-cdk/aws-ssm/test/ssm-document.test.ts b/packages/@aws-cdk/aws-ssm/test/ssm-document.test.ts index 36f6f54c566e6..ba57c2ed0e4a3 100644 --- a/packages/@aws-cdk/aws-ssm/test/ssm-document.test.ts +++ b/packages/@aws-cdk/aws-ssm/test/ssm-document.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { Template } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as ssm from '../lib'; @@ -16,11 +16,11 @@ test('association name is rendered properly in L1 construct', () => { }); // THEN - expect(stack).to(haveResource('AWS::SSM::Association', { + Template.fromStack(stack).hasResourceProperties('AWS::SSM::Association', { Name: 'document', Parameters: { a: ['a'], B: [], }, - })); + }); }); diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index a7c70ef7540e1..57eaad18b6af9 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -11,6 +11,12 @@ * AWS::SageMaker is at 51.0.0 +## 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 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 5b6f0ce4d8f0c..584d3f0218535 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 @@ -1735,7 +1735,7 @@ }, "AWS::AppConfig::ConfigurationProfile.Validators": { "attributes": {}, - "description": "A validator provides a syntactic or semantic check to ensure the configuration that you want to deploy functions as intended. To validate your application configuration data, you provide a schema or a Lambda function that runs against the configuration. The configuration deployment or update can only proceed when the configuration data is valid.", + "description": "A validator provides a syntactic or semantic check to ensure the configuration that you want to deploy functions as intended. To validate your application configuration data, you provide a schema or an AWS Lambda function that runs against the configuration. The configuration deployment or update can only proceed when the configuration data is valid.", "properties": { "Content": "Either the JSON Schema content or the Amazon Resource Name (ARN) of an Lambda function.", "Type": "AWS AppConfig supports validators of type `JSON_SCHEMA` and `LAMBDA`" @@ -8317,18 +8317,18 @@ }, "AWS::Cognito::UserPool.CustomEmailSender": { "attributes": {}, - "description": "", + "description": "A custom email sender AWS Lambda trigger.", "properties": { - "LambdaArn": "", - "LambdaVersion": "" + "LambdaArn": "The Amazon Resource Name (ARN) of the AWS Lambda function that Amazon Cognito triggers to send email notifications to users.", + "LambdaVersion": "The Lambda version represents the signature of the \"request\" attribute in the \"event\" information that Amazon Cognito passes to your custom email sender AWS Lambda function. The only supported value is `V1_0` ." } }, "AWS::Cognito::UserPool.CustomSMSSender": { "attributes": {}, - "description": "", + "description": "A custom SMS sender AWS Lambda trigger.", "properties": { - "LambdaArn": "", - "LambdaVersion": "" + "LambdaArn": "The Amazon Resource Name (ARN) of the AWS Lambda function that Amazon Cognito triggers to send SMS notifications to users.", + "LambdaVersion": "The Lambda version represents the signature of the \"request\" attribute in the \"event\" information Amazon Cognito passes to your custom SMS sender Lambda function. The only supported value is `V1_0` ." } }, "AWS::Cognito::UserPool.DeviceConfiguration": { @@ -8364,11 +8364,11 @@ "description": "Specifies the configuration for AWS Lambda triggers.", "properties": { "CreateAuthChallenge": "Creates an authentication challenge.", - "CustomEmailSender": "", + "CustomEmailSender": "A custom email sender AWS Lambda trigger.", "CustomMessage": "A custom Message AWS Lambda trigger.", - "CustomSMSSender": "", + "CustomSMSSender": "A custom SMS sender AWS Lambda trigger.", "DefineAuthChallenge": "Defines the authentication challenge.", - "KMSKeyID": "", + "KMSKeyID": "The Amazon Resource Name of a AWS Key Management Service ( AWS KMS ) key. Amazon Cognito uses the key to encrypt codes and temporary passwords sent to `CustomEmailSender` and `CustomSMSSender` .", "PostAuthentication": "A post-authentication AWS Lambda trigger.", "PostConfirmation": "A post-confirmation AWS Lambda trigger.", "PreAuthentication": "A pre-authentication AWS Lambda trigger.", @@ -8500,7 +8500,7 @@ "attributes": {}, "description": "The Amazon Pinpoint analytics configuration for collecting metrics for a user pool.\n\n> In Regions where Pinpoint isn't available, User Pools only supports sending events to Amazon Pinpoint projects in us-east-1. In Regions where Pinpoint is available, User Pools will support sending events to Amazon Pinpoint projects within that same Region.", "properties": { - "ApplicationArn": "", + "ApplicationArn": "The Amazon Resource Name (ARN) of an Amazon Pinpoint project. You can use the Amazon Pinpoint project for integration with the chosen user pool client. Amazon Cognito publishes events to the Amazon Pinpoint project that the app ARN declares.", "ApplicationId": "The application ID for an Amazon Pinpoint application.", "ExternalId": "The external ID.", "RoleArn": "The ARN of an AWS Identity and Access Management role that authorizes Amazon Cognito to publish events to Amazon Pinpoint analytics.", @@ -8768,7 +8768,7 @@ }, "AWS::Config::ConfigurationAggregator": { "attributes": { - "ConfigurationAggregatorArn": "", + "ConfigurationAggregatorArn": "The Amazon Resource Name (ARN) of the aggregator.", "Ref": "`Ref` returns the ConfigurationAggregatorName, such as `myConfigurationAggregator` ." }, "description": "The details about the configuration aggregator, including information about source accounts, regions, and metadata of the aggregator.", @@ -8999,8 +8999,8 @@ }, "AWS::Config::StoredQuery": { "attributes": { - "QueryArn": "", - "QueryId": "", + "QueryArn": "Amazon Resource Name (ARN) of the query. For example, arn:partition:service:region:account-id:resource-type/resource-name/resource-id.", + "QueryId": "The ID of the query.", "Ref": "" }, "description": "Provides the details of a stored query.", @@ -13883,7 +13883,7 @@ }, "AWS::ECS::TaskDefinition.EphemeralStorage": { "attributes": {}, - "description": "The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate . For more information, see [Fargate task storage](https://docs.aws.amazon.com/AmazonECS/latest/userguide/using_data_volumes.html) in the *Amazon ECS User Guide for AWS Fargate* .\n\n> This parameter is only supported for tasks hosted on Fargate using the following platform versions:\n> \n> - Linux platform version `1.4.0` or later.\n> - Windows platform version `1.0.0` or later.", + "description": "The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate . For more information, see [Fargate task storage](https://docs.aws.amazon.com/AmazonECS/latest/userguide/using_data_volumes.html) in the *Amazon ECS User Guide for AWS Fargate* .\n\n> This parameter is only supported for tasks hosted on Fargate using Linux platform version `1.4.0` or later. This parameter is not supported for Windows containers on Fargate.", "properties": { "SizeInGiB": "The total amount, in GiB, of ephemeral storage to set for the task. The minimum supported value is `21` GiB and the maximum supported value is `200` GiB." } @@ -14145,13 +14145,13 @@ "attributes": { "AccessPointId": "The ID of the EFS access point.", "Arn": "The Amazon Resource Name (ARN) of the access point.", - "Ref": "`Ref` returns the resource ID. For example:\n\n`{\"Ref\":\"fsap-0123456789abcdef0\"}` .\n\nRef returns the access point ID." + "Ref": "`Ref` returns the AccessPoint ID. For example:\n\n`{\"Ref\":\"access_point-logical_id\"}` returns\n\n`fsap-0123456789abcdef0`" }, "description": "The `AWS::EFS::AccessPoint` resource creates an EFS access point. An access point is an application-specific view into an EFS file system that applies an operating system user and group, and a file system path, to any file system request made through the access point. The operating system user and group override any identity information provided by the NFS client. The file system path is exposed as the access point's root directory. Applications using the access point can only access data in its own directory and below. To learn more, see [Mounting a file system using EFS access points](https://docs.aws.amazon.com/efs/latest/ug/efs-access-points.html) .\n\nThis operation requires permissions for the `elasticfilesystem:CreateAccessPoint` action.", "properties": { "AccessPointTags": "An array of key-value pairs to apply to this resource.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) .", "ClientToken": "The opaque string specified in the request to ensure idempotent creation.", - "FileSystemId": "The ID of the EFS file system that the access point applies to.", + "FileSystemId": "The ID of the EFS file system that the access point applies to. Accepts only the ID format for input when specifying a file system, for example `fs-0123456789abcedf2` .", "PosixUser": "The full POSIX identity, including the user ID, group ID, and secondary group IDs on the access point that is used for all file operations by NFS clients using the access point.", "RootDirectory": "The directory on the Amazon EFS file system that the access point exposes as the root directory to NFS clients using the access point." } @@ -14192,15 +14192,15 @@ }, "AWS::EFS::FileSystem": { "attributes": { - "Arn": "The Amazon Resource Name (ARN) of the EFS file system. For example: `arn:aws:elasticfilesystem:us-west-2:1111333322228888:file-system/fs-12345678`", + "Arn": "The Amazon Resource Name (ARN) of the EFS file system.\n\nExample: `arn:aws:elasticfilesystem:us-west-2:1111333322228888:file-system/fs-0123456789abcdef8`", "FileSystemId": "The ID of the EFS file system. For example: `fs-12345678`", - "Ref": "`Ref` returns the resource ID. For example:\n\n`{\"Ref\":\"fs-12345678\"}` .\n\nFor the Amazon EFS file system `fs-12345678` , Ref returns the file system ID." + "Ref": "`Ref` returns the FileSystem ID. For example:\n\n`{\"Ref\":\"file_system-logical_id\"}` returns\n\n`fs-0123456789abcdef2`" }, "description": "The `AWS::EFS::FileSystem` resource creates a new, empty file system in Amazon Elastic File System ( Amazon EFS ). You must create a mount target ( [AWS::EFS::MountTarget](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html) ) to mount your EFS file system on an Amazon EC2 or other AWS cloud compute resource.", "properties": { "AvailabilityZoneName": "Used to create a file system that uses One Zone storage classes. It specifies the AWS Availability Zone in which to create the file system. Use the format `us-east-1a` to specify the Availability Zone. For more information about One Zone storage classes, see [Using EFS storage classes](https://docs.aws.amazon.com/efs/latest/ug/storage-classes.html) in the *Amazon EFS User Guide* .\n\n> One Zone storage classes are not available in all Availability Zones in AWS Regions where Amazon EFS is available.", "BackupPolicy": "Use the `BackupPolicy` to turn automatic backups on or off for the file system.", - "BypassPolicyLockoutSafetyCheck": "", + "BypassPolicyLockoutSafetyCheck": "(Optional) Use this boolean to use or bypass the `FileSystemPolicy` lockout safety check. The policy lockout safety check determines if the `FileSystemPolicy` in the request will lock out the IAM principal making the request, preventing them from making future `PutFileSystemPolicy` requests on the file system. Set `BypassPolicyLockoutSafetyCheck` to `True` only when you intend to prevent the IAM principal that is making the request from making a subsequent `PutFileSystemPolicy` request on the file system. The default value is `False` .", "Encrypted": "A Boolean value that, if true, creates an encrypted file system. When creating an encrypted file system, you have the option of specifying a KmsKeyId for an existing AWS KMS key . If you don't specify a KMS key , then the default KMS key for Amazon EFS , `/aws/elasticfilesystem` , is used to protect the encrypted file system.", "FileSystemPolicy": "The `FileSystemPolicy` for the EFS file system. A file system policy is an IAM resource policy used to control NFS access to an EFS file system. For more information, see [Using IAM to control NFS access to Amazon EFS](https://docs.aws.amazon.com/efs/latest/ug/iam-access-control-nfs-efs.html) in the *Amazon EFS User Guide* .", "FileSystemTags": "Use to create one or more tags associated with the file system. Each tag is a user-defined key-value pair. Name your file system on creation by including a `\"Key\":\"Name\",\"Value\":\"{value}\"` key-value pair. Each key must be unique. For more information, see [Tagging AWS resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) in the *AWS General Reference Guide* .", @@ -14236,9 +14236,9 @@ }, "AWS::EFS::MountTarget": { "attributes": { - "Id": "", - "IpAddress": "The IPv4 address of the mount target.", - "Ref": "`Ref` returns the resource ID. For example:\n\n`{\"Ref\":\"fsmt-12345678\"}` .\n\nFor the Amazon EFS file system mount target `fsmt-12345678` , Ref returns the mount target ID." + "Id": "The ID of the Amazon EFS file system that the mount target provides access to.\n\nExample: `fs-0123456789111222a`", + "IpAddress": "The IPv4 address of the mount target.\n\nExample: 192.0.2.0", + "Ref": "`Ref` returns the MountTarget ID. For example:\n\n`{\"Ref\":\"logical_mount_target_id\"}` returns\n\n`fsmt-0123456789abcdef8` ." }, "description": "The `AWS::EFS::MountTarget` resource is an Amazon EFS resource that creates a mount target for an EFS file system. You can then mount the file system on Amazon EC2 instances or other resources by using the mount target.", "properties": { @@ -16795,12 +16795,12 @@ }, "AWS::FSx::FileSystem": { "attributes": { - "DNSName": "Use the DNSName value to access the DNS name of your Amazon FSx file system. The DNS name identifies the file system.", - "LustreMountName": "Use the LustreMountName value when mounting an Amazon FSx for Lustre file system. For SCRATCH_1 deployment types, this value is always \"fsx\". For SCRATCH_2 and PERSISTENT_1 deployment types, this value is a string that is unique within an AWS Region . For more information, see [Mounting from an Amazon EC2 Instance](https://docs.aws.amazon.com/fsx/latest/LustreGuide/mounting-ec2-instance.html) .", - "Ref": "`Ref` returns the function returns the file system resource ID. For example:\n\n`{\"Ref\":\"fs-01234567890123456\"}`\n\nFor the Amazon FSx file system `fs-01234567890123456` , Ref returns the file system ID.", - "RootVolumeId": "" + "DNSName": "Returns the FSx for Windows file system's DNSName.\n\nExample: `amznfsxp1honlek.corp.example.com`", + "LustreMountName": "Returns the file system's LustreMountName.\n\nExample for SCRATCH_1 deployment types: This value is always `fsx` .\n\nExample for SCRATCH_2 and PERSISTENT deployment types: `2p3fhbmv`", + "Ref": "`Ref` returns the file system resource ID. For example:\n\n`{\"Ref\":\"file_system_logical_id\"}`\n\nReturns `fs-0123456789abcdef6` .", + "RootVolumeId": "Returns the root volume ID of the FSx for OpenZFS file system.\n\nExample: `fsvol-0123456789abcdefa`" }, - "description": "The `AWS::FSx::FileSystem` resource is an Amazon FSx resource type that creates either an Amazon FSx for Windows File Server file system or an Amazon FSx for Lustre file system.", + "description": "The `AWS::FSx::FileSystem` resource is an Amazon FSx resource type that creates an Amazon FSx file system. You can create any of the following supported file system types:\n\n- Amazon FSx for Lustre\n- Amazon FSx for NetApp ONTAP\n- Amazon FSx for OpenZFS\n- Amazon FSx for Windows File Server", "properties": { "BackupId": "The ID of the source backup. Specifies the backup that you are copying.", "FileSystemType": "The type of Amazon FSx file system, which can be `LUSTRE` , `WINDOWS` , `ONTAP` , or `OPENZFS` .", @@ -16936,7 +16936,7 @@ "properties": { "ActiveDirectoryId": "The ID for an existing AWS Managed Microsoft Active Directory (AD) instance that the file system should join when it's created.", "Aliases": "An array of one or more DNS alias names that you want to associate with the Amazon FSx file system. Aliases allow you to use existing DNS names to access the data in your Amazon FSx file system. You can associate up to 50 aliases with a file system at any time.\n\nFor more information, see [Working with DNS Aliases](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/managing-dns-aliases.html) and [Walkthrough 5: Using DNS aliases to access your file system](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/walkthrough05-file-system-custom-CNAME.html) , including additional steps you must take to be able to access your file system using a DNS alias.\n\nAn alias name has to meet the following requirements:\n\n- Formatted as a fully-qualified domain name (FQDN), `hostname.domain` , for example, `accounting.example.com` .\n- Can contain alphanumeric characters, the underscore (_), and the hyphen (-).\n- Cannot start or end with a hyphen.\n- Can start with a numeric.\n\nFor DNS alias names, Amazon FSx stores alphabetical characters as lowercase letters (a-z), regardless of how you specify them: as uppercase letters, lowercase letters, or the corresponding letters in escape codes.", - "AuditLogConfiguration": "", + "AuditLogConfiguration": "The configuration that Amazon FSx for Windows File Server uses to audit and log user accesses of files, folders, and file shares on the Amazon FSx for Windows File Server file system.", "AutomaticBackupRetentionDays": "The number of days to retain automatic backups. The default is to retain backups for 7 days. Setting this value to 0 disables the creation of automatic backups. The maximum retention period for backups is 90 days.", "CopyTagsToBackups": "A Boolean flag indicating whether tags for the file system should be copied to backups. This value defaults to false. If it's set to true, all tags for the file system are copied to all automatic and user-initiated backups where the user doesn't specify tags. If this value is true, and you specify one or more tags, only the specified tags are copied to backups. If you specify one or more tags when creating a user-initiated backup, no tags are copied from the file system, regardless of this value.", "DailyAutomaticBackupStartTime": "The preferred time to take daily automatic backups, formatted HH:MM in the UTC time zone.", @@ -16949,8 +16949,8 @@ }, "AWS::FSx::Snapshot": { "attributes": { - "Ref": "", - "ResourceARN": "`Ref` returns the Amazon Resource Name (ARN)." + "Ref": "`Ref` returns the ID of the snapshot. For example:\n\n`{\"Ref\":\"logical_snapshot_id\"}`\n\nReturns `fsvolsnap-0123456789abcedf5` .", + "ResourceARN": "Returns the snapshot's Amazon Resource Name (ARN).\n\nExample: `arn:aws:fsx:us-east-2:111133334444:snapshot/fsvol-01234567890123456/fsvolsnap-0123456789abcedf5`" }, "description": "A snapshot of an Amazon FSx for OpenZFS volume.", "properties": { @@ -16961,10 +16961,10 @@ }, "AWS::FSx::StorageVirtualMachine": { "attributes": { - "Ref": "", - "ResourceARN": "`Ref` returns the Amazon Resource Name (ARN).", - "StorageVirtualMachineId": "`Ref` returns the SVM's system generated unique ID.", - "UUID": "`Ref` returns the volume's universally unique identifier (UUID)." + "Ref": "`Ref` returns the resource ID, such as `svm-01234567890123456` . For example:\n\n`{\"Ref\": \"svm_logical_id\"}` returns\n\n`svm-01234567890123456`", + "ResourceARN": "Returns the storage virtual machine's Amazon Resource Name (ARN).\n\nExample: `arn:aws:fsx:us-east-2:111111111111:storage-virtual-machine/fs-0123456789abcdef1/svm-01234567890123456`", + "StorageVirtualMachineId": "Returns the storgage virtual machine's system generated ID.\n\nExample: `svm-0123456789abcedf1`", + "UUID": "Returns the storage virtual machine's system generated unique identifier (UUID).\n\nExample: `abcd0123-cd45-ef67-11aa-1111aaaa23bc`" }, "description": "Creates a storage virtual machine (SVM) for an Amazon FSx for ONTAP file system.", "properties": { @@ -16998,10 +16998,10 @@ }, "AWS::FSx::Volume": { "attributes": { - "Ref": "", - "ResourceARN": "`Ref` returns the Amazon Resource Name (ARN).", - "UUID": "`Ref` returns the volume's universally unique identifier (UUID).", - "VolumeId": "`Ref` returns the system-generated, unique ID of the volume." + "Ref": "`Ref` returns the ID for the volume. For example:\n\n`{\"Ref\":\"vol_logical_id\"}`\n\nReturns `fsvol-0123456789abcdef6` .", + "ResourceARN": "Returns the volume's Amazon Resource Name (ARN).\n\nExample: `arn:aws:fsx:us-east-2:111122223333:volume/fs-0123456789abcdef9/fsvol-01234567891112223`", + "UUID": "Returns the volume's universally unique identifier (UUID).\n\nExample: `abcd0123-cd45-ef67-11aa-1111aaaa23bc`", + "VolumeId": "Returns the volume's ID.\n\nExample: `fsvol-0123456789abcdefa`" }, "description": "Creates an Amazon FSx for NetApp ONTAP or Amazon FSx for OpenZFS storage volume.", "properties": { @@ -17982,10 +17982,10 @@ }, "AWS::Glue::Database.PrincipalPrivileges": { "attributes": {}, - "description": "", + "description": "the permissions granted to a principal", "properties": { - "Permissions": "", - "Principal": "" + "Permissions": "The permissions that are granted to the principal.", + "Principal": "The principal who is granted permissions." } }, "AWS::Glue::DevEndpoint": { @@ -22798,7 +22798,7 @@ "ServiceNowConfiguration": "Provides configuration for data sources that connect to ServiceNow instances.", "SharePointConfiguration": "Provides information necessary to create a data source connector for a Microsoft SharePoint site.", "WebCrawlerConfiguration": "Provides the configuration information required for Amazon Kendra Web Crawler.", - "WorkDocsConfiguration": "" + "WorkDocsConfiguration": "Provides the configuration information to connect to WorkDocs as your data source." } }, "AWS::Kendra::DataSource.DataSourceToIndexFieldMapping": { @@ -22873,11 +22873,11 @@ }, "AWS::Kendra::DataSource.ProxyConfiguration": { "attributes": {}, - "description": "", + "description": "Provides the configuration information for a web proxy to connect to website hosts.", "properties": { - "Credentials": "", - "Host": "", - "Port": "" + "Credentials": "Your secret ARN, which you can create in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)\n\nThe credentials are optional. You use a secret if web proxy credentials are required to connect to a website host. Amazon Kendra currently support basic authentication to connect to a web proxy server. The secret stores your credentials.", + "Host": "The name of the website host you want to connect to via a web proxy server.\n\nFor example, the host name of https://a.example.com/page1.html is \"a.example.com\".", + "Port": "The port number of the website host you want to connect to via a web proxy server.\n\nFor example, the port for https://a.example.com/page1.html is 443, the standard port for HTTPS." } }, "AWS::Kendra::DataSource.S3DataSourceConfiguration": { @@ -23023,7 +23023,7 @@ "SslCertificateS3Path": "Information required to find a specific file in an Amazon S3 bucket.", "Urls": "The URLs of the Microsoft SharePoint site that contains the documents that should be indexed.", "UseChangeLog": "Set to `TRUE` to use the Microsoft SharePoint change log to determine the documents that need to be updated in the index. Depending on the size of the SharePoint change log, it may take longer for Amazon Kendra to use the change log than it takes it to determine the changed documents using the Amazon Kendra document crawler.", - "VpcConfiguration": "" + "VpcConfiguration": "Provides information for connecting to an Amazon VPC." } }, "AWS::Kendra::DataSource.SqlConfiguration": { @@ -23053,15 +23053,15 @@ "attributes": {}, "description": "", "properties": { - "AuthenticationConfiguration": "", - "CrawlDepth": "", - "MaxContentSizePerPageInMegaBytes": "", - "MaxLinksPerPage": "", - "MaxUrlsPerMinuteCrawlRate": "", - "ProxyConfiguration": "", - "UrlExclusionPatterns": "", - "UrlInclusionPatterns": "", - "Urls": "Specifies the seed or starting point URLs of the websites or the sitemap URLs of the websites you want to crawl.\n\nYou can include website subdomains. You can list up to 100 seed URLs and up to three sitemap URLs.\n\nYou can only crawl websites that use the secure communication protocol, Hypertext Transfer Protocol Secure (HTTPS). If you receive an error when crawling a website, it could be that the website is blocked from crawling.\n\n*When selecting websites to index, you must adhere to the [Amazon Acceptable Use Policy](https://docs.aws.amazon.com/aup/) and all other Amazon terms. Remember that you must only use the Amazon Kendra web crawler to index your own webpages, or webpages that you have authorization to index.*" + "AuthenticationConfiguration": "Provides configuration information required to connect to websites using authentication.\n\nYou can connect to websites using basic authentication of user name and password.\n\nYou must provide the website host name and port number. For example, the host name of https://a.example.com/page1.html is \"a.example.com\" and the port is 443, the standard port for HTTPS. You use a secret in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) to store your authentication credentials.", + "CrawlDepth": "Specifies the number of levels in a website that you want to crawl.\n\nThe first level begins from the website seed or starting point URL. For example, if a website has 3 levels \u2013 index level (i.e. seed in this example), sections level, and subsections level \u2013 and you are only interested in crawling information up to the sections level (i.e. levels 0-1), you can set your depth to 1.\n\nThe default crawl depth is set to 2.", + "MaxContentSizePerPageInMegaBytes": "The maximum size (in MB) of a webpage or attachment to crawl.\n\nFiles larger than this size (in MB) are skipped/not crawled.\n\nThe default maximum size of a webpage or attachment is set to 50 MB.", + "MaxLinksPerPage": "The maximum number of URLs on a webpage to include when crawling a website. This number is per webpage.\n\nAs a website\u2019s webpages are crawled, any URLs the webpages link to are also crawled. URLs on a webpage are crawled in order of appearance.\n\nThe default maximum links per page is 100.", + "MaxUrlsPerMinuteCrawlRate": "The maximum number of URLs crawled per website host per minute.\n\nA minimum of one URL is required.\n\nThe default maximum number of URLs crawled per website host per minute is 300.", + "ProxyConfiguration": "Provides configuration information required to connect to your internal websites via a web proxy.\n\nYou must provide the website host name and port number. For example, the host name of https://a.example.com/page1.html is \"a.example.com\" and the port is 443, the standard port for HTTPS.\n\nWeb proxy credentials are optional and you can use them to connect to a web proxy server that requires basic authentication. To store web proxy credentials, you use a secret in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) .", + "UrlExclusionPatterns": "The regular expression pattern to exclude certain URLs to crawl.\n\nIf there is a regular expression pattern to include certain URLs that conflicts with the exclude pattern, the exclude pattern takes precedence.", + "UrlInclusionPatterns": "The regular expression pattern to include certain URLs to crawl.\n\nIf there is a regular expression pattern to exclude certain URLs that conflicts with the include pattern, the exclude pattern takes precedence.", + "Urls": "Specifies the seed or starting point URLs of the websites or the sitemap URLs of the websites you want to crawl.\n\nYou can include website subdomains. You can list up to 100 seed URLs and up to three sitemap URLs.\n\nYou can only crawl websites that use the secure communication protocol, Hypertext Transfer Protocol Secure (HTTPS). If you receive an error when crawling a website, it could be that the website is blocked from crawling.\n\n*When selecting websites to index, you must adhere to the [Amazon Acceptable Use Policy](https://docs.aws.amazon.com/aup/) and all other Amazon terms. Remember that you must only use Amazon Kendra Web Crawler to index your own webpages, or webpages that you have authorization to index.*" } }, "AWS::Kendra::DataSource.WebCrawlerSeedUrlConfiguration": { @@ -23076,7 +23076,7 @@ "attributes": {}, "description": "Provides the configuration information of the sitemap URLs to crawl.\n\n*When selecting websites to index, you must adhere to the [Amazon Acceptable Use Policy](https://docs.aws.amazon.com/aup/) and all other Amazon terms. Remember that you must only use the Amazon Kendra web crawler to index your own webpages, or webpages that you have authorization to index.*", "properties": { - "SiteMaps": "" + "SiteMaps": "The list of sitemap URLs of the websites you want to crawl.\n\nThe list can include a maximum of three sitemap URLs." } }, "AWS::Kendra::DataSource.WebCrawlerUrls": { @@ -23089,14 +23089,14 @@ }, "AWS::Kendra::DataSource.WorkDocsConfiguration": { "attributes": {}, - "description": "", + "description": "Provides the configuration information to connect to Amazon WorkDocs as your data source.\n\nAmazon WorkDocs connector is available in Oregon, North Virginia, Sydney, Singapore and Ireland regions.", "properties": { - "CrawlComments": "", - "ExclusionPatterns": "", - "FieldMappings": "", - "InclusionPatterns": "", - "OrganizationId": "", - "UseChangeLog": "" + "CrawlComments": "`TRUE` to include comments on documents in your index. Including comments in your index means each comment is a document that can be searched on.\n\nThe default is set to `FALSE` .", + "ExclusionPatterns": "A list of regular expression patterns to exclude certain files in your Amazon WorkDocs site repository. Files that match the patterns are excluded from the index. Files that don\u2019t match the patterns are included in the index. If a file matches both an inclusion pattern and an exclusion pattern, the exclusion pattern takes precedence and the file isn\u2019t included in the index.", + "FieldMappings": "A list of `DataSourceToIndexFieldMapping` objects that map Amazon WorkDocs field names to custom index field names in Amazon Kendra. You must first create the custom index fields using the `UpdateIndex` operation before you map to Amazon WorkDocs fields. For more information, see [Mapping Data Source Fields](https://docs.aws.amazon.com/kendra/latest/dg/field-mapping.html) . The Amazon WorkDocs data source field names need to exist in your Amazon WorkDocs custom metadata.", + "InclusionPatterns": "A list of regular expression patterns to include certain files in your Amazon WorkDocs site repository. Files that match the patterns are included in the index. Files that don't match the patterns are excluded from the index. If a file matches both an inclusion pattern and an exclusion pattern, the exclusion pattern takes precedence and the file isn\u2019t included in the index.", + "OrganizationId": "The identifier of the directory corresponding to your Amazon WorkDocs site repository.\n\nYou can find the organization ID in the [AWS Directory Service](https://docs.aws.amazon.com/directoryservicev2/) by going to *Active Directory* , then *Directories* . Your Amazon WorkDocs site directory has an ID, which is the organization ID. You can also set up a new Amazon WorkDocs directory in the AWS Directory Service console and enable a Amazon WorkDocs site for the directory in the Amazon WorkDocs console.", + "UseChangeLog": "`TRUE` to use the change logs to update documents in your index instead of scanning all documents.\n\nIf you are syncing your Amazon WorkDocs data source with your index for the first time, all documents are scanned. After your first sync, you can use the change logs to update your documents in your index for future syncs.\n\nThe default is set to `FALSE` ." } }, "AWS::Kendra::Faq": { @@ -24547,7 +24547,7 @@ "FilterCriteria": "(Streams and Amazon SQS) An object that defines the filter criteria that determine whether Lambda should process an event. For more information, see [Lambda event filtering](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) .", "FunctionName": "The name of the Lambda function.\n\n**Name formats** - *Function name* - `MyFunction` .\n- *Function ARN* - `arn:aws:lambda:us-west-2:123456789012:function:MyFunction` .\n- *Version or Alias ARN* - `arn:aws:lambda:us-west-2:123456789012:function:MyFunction:PROD` .\n- *Partial ARN* - `123456789012:function:MyFunction` .\n\nThe length constraint applies only to the full ARN. If you specify only the function name, it's limited to 64 characters in length.", "FunctionResponseTypes": "(Streams and SQS) A list of current response type enums applied to the event source mapping.\n\nValid Values: `ReportBatchItemFailures`", - "MaximumBatchingWindowInSeconds": "(Streams and Amazon SQS standard queues) The maximum amount of time, in seconds, that Lambda spends gathering records before invoking the function.\n\nDefault: 0", + "MaximumBatchingWindowInSeconds": "The maximum amount of time, in seconds, that Lambda spends gathering records before invoking the function.\n\n*Default ( Kinesis , DynamoDB , Amazon SQS event sources)* : 0\n\n*Default ( Amazon MSK , Kafka, Amazon MQ event sources)* : 500 ms", "MaximumRecordAgeInSeconds": "(Streams only) Discard records older than the specified age. The default value is -1,\nwhich sets the maximum age to infinite. When the value is set to infinite, Lambda never discards old records.", "MaximumRetryAttempts": "(Streams only) Discard records after the specified number of retries. The default value is -1,\nwhich sets the maximum number of retries to infinite. When MaximumRetryAttempts is infinite, Lambda retries failed records until the record expires in the event source.", "ParallelizationFactor": "(Streams only) The number of batches to process concurrently from each shard. The default value is 1.", @@ -36800,8 +36800,8 @@ "MasterSecretKmsKeyArn": "The ARN of the KMS key that Secrets Manager uses to encrypt the elevated secret if you use the [alternating users strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) . If you don't specify this value and you use the alternating users strategy, then Secrets Manager uses the key `aws/secretsmanager` . If `aws/secretsmanager` doesn't yet exist, then Secrets Manager creates it for you automatically the first time it encrypts the secret value.", "RotationLambdaName": "The name of the Lambda rotation function.", "RotationType": "The type of rotation template to use. For more information, see [Secrets Manager rotation function templates](https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html) .\n\nYou can specify one of the following `RotationTypes` :\n\n- MySQLSingleUser\n- MySQLMultiUser\n- PostgreSQLSingleUser\n- PostgreSQLMultiUser\n- OracleSingleUser\n- OracleMultiUser\n- MariaDBSingleUser\n- MariaDBMultiUser\n- SQLServerSingleUser\n- SQLServerMultiUser\n- RedshiftSingleUser\n- RedshiftMultiUser\n- MongoDBSingleUser\n- MongoDBMultiUser", - "SuperuserSecretArn": "", - "SuperuserSecretKmsKeyArn": "", + "SuperuserSecretArn": "The ARN of the secret that contains elevated credentials. The Lambda rotation function uses this secret for the [Alternating users rotation strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) .", + "SuperuserSecretKmsKeyArn": "The ARN of the KMS key that Secrets Manager uses to encrypt the elevated secret if you use the [alternating users strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-two-users) . If you don't specify this value and you use the alternating users strategy, then Secrets Manager uses the key `aws/secretsmanager` . If `aws/secretsmanager` doesn't yet exist, then Secrets Manager creates it for you automatically the first time it encrypts the secret value.", "VpcSecurityGroupIds": "A comma-separated list of security group IDs applied to the target database.\n\nThe templates applies the same security groups as on the Lambda rotation function that is created as part of this stack.", "VpcSubnetIds": "A comma separated list of VPC subnet IDs of the target database network. The Lambda rotation function is in the same subnet group." } @@ -36859,7 +36859,7 @@ "description": "The `AWS::SecretsManager::SecretTargetAttachment` resource completes the final link between a Secrets Manager secret and the associated database. This is required because each has a dependency on the other. No matter which one you create first, the other doesn't exist yet. To resolve this, you must create the resources in the following order:\n\n- Define the secret without referencing the service or database. You can't reference the service or database because it doesn't exist yet. The secret must contain a user name and password.\n- Next, define the service or database. Include the reference to the secret to use stored credentials to define the database admin user and password.\n- Finally, define a `SecretTargetAttachment` resource type to finish configuring the secret with the required database engine type and the connection details of the service or database. The rotation function requires the details, if you attach one later by defining a [AWS::SecretsManager::RotationSchedule](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-rotationschedule.html) resource type.", "properties": { "SecretId": "The ARN or name of the secret. To reference a secret also created in this template, use the see [Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) function with the secret's logical ID.", - "TargetId": "The ARN of the database or cluster.", + "TargetId": "The ID of the database or cluster.", "TargetType": "A string that defines the type of service or database associated with the secret. This value instructs Secrets Manager how to update the secret with the details of the service or database. This value must be one of the following:\n\n- AWS::RDS::DBInstance\n- AWS::RDS::DBCluster\n- AWS::Redshift::Cluster\n- AWS::DocDB::DBInstance\n- AWS::DocDB::DBCluster" } }, diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 6cbf48e79210d..0db6702ef67f0 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -38,7 +38,7 @@ "@types/string-width": "^4.0.1", "fast-check": "^2.21.0", "jest": "^27.4.7", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index 425756e78a3c7..aadda87535b0b 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -448,13 +448,13 @@ "constructs": "^3.3.69" }, "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", "@types/jest": "^27.4.0", "jest": "^27.4.7", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "bundledDependencies": [ "yaml" diff --git a/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts index 326b80a3585f8..fb2f4697f610e 100644 --- a/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts @@ -1,15 +1,15 @@ import * as path from 'path'; -import { SynthUtils } from '@aws-cdk/assert-internal'; -import '@aws-cdk/assert-internal/jest'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as inc from '../lib'; describe('CDK Include', () => { + let app: core.App; let stack: core.Stack; beforeEach(() => { - stack = new core.Stack(); + app = new core.App(); + stack = new core.Stack(app); }); test('throws a validation exception for a template with a missing required top-level resource property', () => { @@ -22,7 +22,7 @@ describe('CDK Include', () => { includeTestTemplate(stack, 'bucket-with-cors-rules-not-an-array.json'); expect(() => { - SynthUtils.synthesize(stack); + app.synth(); }).toThrow(/corsRules: "CorsRules!" should be a list/); }); @@ -30,7 +30,7 @@ describe('CDK Include', () => { includeTestTemplate(stack, 'bucket-with-cors-rules-null-element.json'); expect(() => { - SynthUtils.synthesize(stack); + app.synth(); }).toThrow(/allowedMethods: required but missing/); }); @@ -38,7 +38,7 @@ describe('CDK Include', () => { includeTestTemplate(stack, 'bucket-with-invalid-cors-rule.json'); expect(() => { - SynthUtils.synthesize(stack); + app.synth(); }).toThrow(/allowedOrigins: required but missing/); }); @@ -130,7 +130,7 @@ describe('CDK Include', () => { includeTestTemplate(stack, 'alphabetical-string-passed-to-number.json'); expect(() => { - SynthUtils.synthesize(stack); + app.synth(); }).toThrow(/"abc" should be a number/); }); diff --git a/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts b/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts index 2a323657f089e..4e73005db1e54 100644 --- a/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts @@ -1,6 +1,5 @@ import * as path from 'path'; -import { ABSENT, ResourcePart } 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 core from '@aws-cdk/core'; import * as inc from '../lib'; @@ -27,7 +26,7 @@ describe('CDK Include for nested stacks', () => { }); const childStack = parentTemplate.getNestedStack('ChildStack'); - expect(childStack.stack).toMatchTemplate( + Template.fromStack(childStack.stack).templateMatches( loadTestFileToJsObject('grandchild-import-stack.json'), ); }); @@ -47,11 +46,11 @@ describe('CDK Include for nested stacks', () => { const childStack = parentTemplate.getNestedStack('ChildStack'); const anotherChildStack = parentTemplate.getNestedStack('AnotherChildStack'); - expect(childStack.stack).toMatchTemplate( + Template.fromStack(childStack.stack).templateMatches( loadTestFileToJsObject('grandchild-import-stack.json'), ); - expect(anotherChildStack.stack).toMatchTemplate( + Template.fromStack(anotherChildStack.stack).templateMatches( loadTestFileToJsObject('grandchild-import-stack.json'), ); }); @@ -73,11 +72,11 @@ describe('CDK Include for nested stacks', () => { const childStack = parentTemplate.getNestedStack('ChildStack'); const grandChildStack = childStack.includedTemplate.getNestedStack('GrandChildStack'); - expect(childStack.stack).toMatchTemplate( + Template.fromStack(childStack.stack).templateMatches( loadTestFileToJsObject('child-import-stack.expected.json'), ); - expect(grandChildStack.stack).toMatchTemplate( + Template.fromStack(grandChildStack.stack).templateMatches( loadTestFileToJsObject('grandchild-import-stack.json'), ); }); @@ -188,7 +187,7 @@ describe('CDK Include for nested stacks', () => { bucket.bucketName = 'modified-bucket-name'; - expect(childTemplate.stack).toHaveResource('AWS::S3::Bucket', { BucketName: 'modified-bucket-name' }); + Template.fromStack(childTemplate.stack).hasResourceProperties('AWS::S3::Bucket', { BucketName: 'modified-bucket-name' }); }); test('can use a condition', () => { @@ -218,7 +217,7 @@ describe('CDK Include for nested stacks', () => { const assetParam = 'AssetParameters5dc7d4a99cfe2979687dc74f2db9fd75f253b5505a1912b5ceecf70c9aefba50S3BucketEAA24F0C'; const assetParamKey = 'AssetParameters5dc7d4a99cfe2979687dc74f2db9fd75f253b5505a1912b5ceecf70c9aefba50S3VersionKey1194CAB2'; - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Parameters": { [assetParam]: { "Type": "String", @@ -284,7 +283,7 @@ describe('CDK Include for nested stacks', () => { templateFile: testTemplateFilePath('parent-two-children.json'), }); - expect(stack).toMatchTemplate(loadTestFileToJsObject('parent-two-children.json')); + Template.fromStack(stack).templateMatches(loadTestFileToJsObject('parent-two-children.json')); }); test('getNestedStack() throws an exception when getting a resource that does not exist in the template', () => { @@ -344,7 +343,7 @@ describe('CDK Include for nested stacks', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::Stack', { "Parameters": { "Param1": { "Ref": "Param", @@ -370,7 +369,7 @@ describe('CDK Include for nested stacks', () => { const parameter = parentTemplate.getParameter('Param'); parameter.overrideLogicalId('DifferentParameter'); - expect(stack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::Stack', { "Parameters": { "Param1": { "Ref": "DifferentParameter", @@ -417,7 +416,7 @@ describe('CDK Include for nested stacks', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResource('AWS::CloudFormation::Stack', { "Metadata": { "Property1": "Value1", }, @@ -426,7 +425,7 @@ describe('CDK Include for nested stacks', () => { "AnotherChildStack", ], "UpdateReplacePolicy": "Retain", - }, ResourcePart.CompleteDefinition); + }); }); test('correctly parses NotificationsARNs, Timeout', () => { @@ -442,11 +441,11 @@ describe('CDK Include for nested stacks', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::Stack', { "NotificationARNs": ["arn1"], "TimeoutInMinutes": 5, }); - expect(stack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::Stack', { "NotificationARNs": { "Ref": "ArrayParam" }, "TimeoutInMinutes": { "Fn::Select": [0, { @@ -466,7 +465,7 @@ describe('CDK Include for nested stacks', () => { }, }); - expect(stack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(stack).hasResourceProperties('AWS::CloudFormation::Stack', { "Parameters": { "Number": "60", }, @@ -481,7 +480,7 @@ describe('CDK Include for nested stacks', () => { templateFile: testTemplateFilePath('child-no-bucket.json'), }); - expect(includedChild.stack).toMatchTemplate( + Template.fromStack(includedChild.stack).templateMatches( loadTestFileToJsObject('child-no-bucket.json'), ); expect(includedChild.includedTemplate.getResource('GrandChildStack')).toBeDefined(); @@ -536,7 +535,7 @@ describe('CDK Include for nested stacks', () => { }); test('correctly creates parameters in the parent stack, and passes them to the child stack', () => { - expect(assetStack).toMatchTemplate({ + Template.fromStack(assetStack).templateMatches({ "Parameters": { [parentBucketParam]: { "Type": "String", @@ -616,7 +615,7 @@ describe('CDK Include for nested stacks', () => { }); test('correctly creates parameters in the child stack, and passes them to the grandchild stack', () => { - expect(child.stack).toMatchTemplate({ + Template.fromStack(child.stack).templateMatches({ "Parameters": { "MyBucketParameter": { "Type": "String", @@ -676,7 +675,7 @@ describe('CDK Include for nested stacks', () => { }); test('leaves grandchild stack unmodified', () => { - expect(grandChild.stack).toMatchTemplate( + Template.fromStack(grandChild.stack).templateMatches( loadTestFileToJsObject('grandchild-import-stack.json'), ); }); @@ -703,7 +702,7 @@ describe('CDK Include for nested stacks', () => { }); test('correctly removes the parameter from the child stack', () => { - expect(childStack).toMatchTemplate({ + Template.fromStack(childStack).templateMatches({ "Parameters": { "SecondParameter": { "Type": "String", @@ -733,9 +732,9 @@ describe('CDK Include for nested stacks', () => { }); test('correctly removes the parameter from the parent stack', () => { - expect(parentStack).toHaveResourceLike('AWS::CloudFormation::Stack', { + Template.fromStack(parentStack).hasResourceProperties('AWS::CloudFormation::Stack', { "Parameters": { - "FirstParameter": ABSENT, + "FirstParameter": Match.absent(), "SecondParameter": "second-value", }, }); diff --git a/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts b/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts index ce0d044bb4ed3..706afb615ec72 100644 --- a/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as inc from '../lib'; @@ -18,7 +18,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with only a minimal SAM function using S3Location for CodeUri, and output it unchanged', () => { includeTestTemplate(stack, 'only-minimal-sam-function-codeuri-as-s3location.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-minimal-sam-function-codeuri-as-s3location.yaml'), ); }); @@ -26,7 +26,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with only a SAM function using an array with DDB CRUD for Policies, and output it unchanged', () => { includeTestTemplate(stack, 'only-sam-function-policies-array-ddb-crud.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-sam-function-policies-array-ddb-crud.yaml'), ); }); @@ -34,7 +34,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with only a minimal SAM function using a parameter for CodeUri, and output it unchanged', () => { includeTestTemplate(stack, 'only-minimal-sam-function-codeuri-as-param.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-minimal-sam-function-codeuri-as-param.yaml'), ); }); @@ -42,7 +42,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with only a minimal SAM function using a parameter for CodeUri Bucket property, and output it unchanged', () => { includeTestTemplate(stack, 'only-minimal-sam-function-codeuri-bucket-as-param.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-minimal-sam-function-codeuri-bucket-as-param.yaml'), ); }); @@ -50,7 +50,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with only a SAM function using an array with DDB CRUD for Policies with an Fn::If expression, and output it unchanged', () => { includeTestTemplate(stack, 'only-sam-function-policies-array-ddb-crud-if.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-sam-function-policies-array-ddb-crud-if.yaml'), ); }); @@ -58,7 +58,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with a a union-type property provided as an object, and output it unchanged', () => { includeTestTemplate(stack, 'api-endpoint-config-object.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('api-endpoint-config-object.yaml'), ); }); @@ -66,7 +66,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with a a union-type property provided as a string, and output it unchanged', () => { includeTestTemplate(stack, 'api-endpoint-config-string.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('api-endpoint-config-string.yaml'), ); }); @@ -74,7 +74,7 @@ describe('CDK Include for templates with SAM transform', () => { test('can ingest a template with a a union-type property provided as an empty string, and output it unchanged', () => { includeTestTemplate(stack, 'api-endpoint-config-string-empty.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('api-endpoint-config-string-empty.yaml'), ); }); diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json index c53229d2844d8..7daef9f79f9a4 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json @@ -4,7 +4,14 @@ "Type": "AWS::S3::Bucket", "Properties": { "BucketName": { - "Fn::Sub": "${ELB.SourceSecurityGroup.GroupName}" + "Fn::Sub": [ + "${ELB.SourceSecurityGroup.GroupName}-${LoadBalancerName}", + { + "LoadBalancerName": { + "Ref": "ELB" + } + } + ] } } }, @@ -14,7 +21,7 @@ "AvailabilityZones": [ "us-east-1a" ], - "CrossZone": "true", + "CrossZone": true, "Listeners": [{ "LoadBalancerPort": "80", "InstancePort": "80", diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json index fb1f6f2aab1b2..e1440a46193be 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json @@ -53,7 +53,7 @@ "BeforeAllowTrafficHook" : "Lambda2", "DeploymentGroupName" : { "Ref": "CodeDeployDg" } }, - "EnableVersionUpgrade": "true", + "EnableVersionUpgrade": true, "UseOnlineResharding": false } } diff --git a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts index 0741b7f9d23df..65cd7e981cc81 100644 --- a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts @@ -1,6 +1,5 @@ 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 * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as ssm from '@aws-cdk/aws-ssm'; @@ -22,7 +21,7 @@ describe('CDK Include', () => { test('can ingest a template with only an empty S3 Bucket, and output it unchanged', () => { includeTestTemplate(stack, 'only-empty-bucket.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-empty-bucket.json'), ); }); @@ -41,7 +40,7 @@ describe('CDK Include', () => { const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; cfnBucket.bucketName = 'my-bucket-name'; - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -58,7 +57,7 @@ describe('CDK Include', () => { const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; expect((cfnBucket.corsConfiguration as any).corsRules).toHaveLength(1); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-bucket-complex-props.json'), ); }); @@ -75,7 +74,7 @@ describe('CDK Include', () => { resources: [cfnBucket.attrArn], })); - expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { "PolicyDocument": { "Statement": [ { @@ -95,7 +94,7 @@ describe('CDK Include', () => { test('can ingest a template with a Bucket Ref-erencing a KMS Key, and output it unchanged', () => { includeTestTemplate(stack, 'bucket-with-encryption-key.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('bucket-with-encryption-key.json'), ); }); @@ -103,25 +102,39 @@ describe('CDK Include', () => { test('accepts strings for properties with type number', () => { includeTestTemplate(stack, 'string-for-number.json'); - expect(stack).toMatchTemplate( - loadTestFileToJsObject('string-for-number.json'), - ); + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { + "CorsConfiguration": { + "CorsRules": [ + { + "MaxAge": 10, + }, + ], + }, + }); }); test('accepts numbers for properties with type string', () => { includeTestTemplate(stack, 'number-for-string.json'); - expect(stack).toMatchTemplate( - loadTestFileToJsObject('number-for-string.json'), - ); + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { + "WebsiteConfiguration": { + "RoutingRules": [ + { + "RedirectRule": { + "HttpRedirectCode": "403", + }, + }, + ], + }, + }); }); test('accepts booleans for properties with type string', () => { includeTestTemplate(stack, 'boolean-for-string.json'); - expect(stack).toMatchTemplate( - loadTestFileToJsObject('boolean-for-string.json'), - ); + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { + "AccessControl": "true", + }); }); test('correctly changes the logical IDs, including references, if imported with preserveLogicalIds=false', () => { @@ -135,7 +148,7 @@ describe('CDK Include', () => { const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; cfnBucket.bucketName = 'my-bucket-name'; - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "MyScopeKey7673692F": { "Type": "AWS::KMS::Key", @@ -202,7 +215,7 @@ describe('CDK Include', () => { test('can ingest a template with an Fn::If expression for simple values, and output it unchanged', () => { includeTestTemplate(stack, 'if-simple-property.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('if-simple-property.json'), ); }); @@ -210,7 +223,7 @@ describe('CDK Include', () => { test('can ingest a template with an Fn::If expression for complex values, and output it unchanged', () => { includeTestTemplate(stack, 'if-complex-property.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('if-complex-property.json'), ); }); @@ -218,7 +231,7 @@ describe('CDK Include', () => { test('can ingest a UserData script, and output it unchanged', () => { includeTestTemplate(stack, 'user-data.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('user-data.json'), ); }); @@ -226,7 +239,7 @@ describe('CDK Include', () => { test('can correctly ingest a resource with a property of type: Map of Lists of primitive types', () => { const cfnTemplate = includeTestTemplate(stack, 'ssm-association.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('ssm-association.json'), ); const association = cfnTemplate.getResource('Association') as ssm.CfnAssociation; @@ -236,7 +249,7 @@ describe('CDK Include', () => { test('can ingest a template with intrinsic functions and conditions, and output it unchanged', () => { includeTestTemplate(stack, 'functions-and-conditions.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('functions-and-conditions.json'), ); }); @@ -244,7 +257,7 @@ describe('CDK Include', () => { test('can ingest a JSON template with string-form Fn::GetAtt, and output it unchanged', () => { includeTestTemplate(stack, 'get-att-string-form.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('get-att-string-form.json'), ); }); @@ -252,7 +265,7 @@ describe('CDK Include', () => { test('can ingest a template with Fn::Sub in string form with escaped and unescaped references and output it unchanged', () => { includeTestTemplate(stack, 'fn-sub-string.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-string.json'), ); }); @@ -260,15 +273,15 @@ describe('CDK Include', () => { test('can parse the string argument Fn::Sub with escaped references that contain whitespace', () => { includeTestTemplate(stack, 'fn-sub-escaping.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-escaping.json'), ); }); - test('can ingest a template with Fn::Sub in map form and output it unchanged', () => { + test('can ingest a template with Fn::Sub using dotted attributes in map form and output it unchanged', () => { includeTestTemplate(stack, 'fn-sub-map-dotted-attributes.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-map-dotted-attributes.json'), ); }); @@ -276,7 +289,7 @@ describe('CDK Include', () => { test('preserves an empty map passed to Fn::Sub', () => { includeTestTemplate(stack, 'fn-sub-map-empty.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-map-empty.json'), ); }); @@ -284,7 +297,7 @@ describe('CDK Include', () => { test('can ingest a template with Fn::Sub shadowing a logical ID from the template and output it unchanged', () => { includeTestTemplate(stack, 'fn-sub-shadow.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-shadow.json'), ); }); @@ -292,7 +305,7 @@ describe('CDK Include', () => { test('can ingest a template with Fn::Sub attribute expression shadowing a logical ID from the template, and output it unchanged', () => { includeTestTemplate(stack, 'fn-sub-shadow-attribute.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-shadow-attribute.json'), ); }); @@ -302,7 +315,7 @@ describe('CDK Include', () => { cfnTemplate.getResource('AnotherBucket').overrideLogicalId('NewBucket'); - expect(stack).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { "BucketName": { "Fn::Sub": [ "${AnotherBucket}", @@ -319,7 +332,7 @@ describe('CDK Include', () => { cfnTemplate.getResource('Bucket').overrideLogicalId('NewBucket'); - expect(stack).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', { "BucketName": { "Fn::Sub": "${NewBucket}-${!Bucket}-${NewBucket.DomainName}", }, @@ -329,7 +342,7 @@ describe('CDK Include', () => { test('can ingest a template with Fn::Sub with brace edge cases and output it unchanged', () => { includeTestTemplate(stack, 'fn-sub-brace-edges.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('fn-sub-brace-edges.json'), ); }); @@ -342,7 +355,7 @@ describe('CDK Include', () => { }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Parameters": { "AnotherParam": { "Type": "String", @@ -375,7 +388,7 @@ describe('CDK Include', () => { test('can ingest a template with a Ref expression for an array value, and output it unchanged', () => { includeTestTemplate(stack, 'ref-array-property.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('ref-array-property.json'), ); }); @@ -383,7 +396,7 @@ describe('CDK Include', () => { test('renders non-Resources sections unchanged', () => { includeTestTemplate(stack, 'only-empty-bucket-with-parameters.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-empty-bucket-with-parameters.json'), ); }); @@ -394,14 +407,14 @@ describe('CDK Include', () => { expect(cfnBucket2.node.dependencies).toHaveLength(1); // we always render dependsOn as an array, even if it's a single string - expect(stack).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromStack(stack).hasResource('AWS::S3::Bucket', { "Properties": { "BucketName": "bucket2", }, "DependsOn": [ "Bucket1", ], - }, ResourcePart.CompleteDefinition); + }); }); test('resolves DependsOn with an array of String values to the actual L1 class instances', () => { @@ -409,7 +422,7 @@ describe('CDK Include', () => { const cfnBucket2 = cfnTemplate.getResource('Bucket2'); expect(cfnBucket2.node.dependencies).toHaveLength(2); - expect(stack).toHaveResourceLike('AWS::S3::Bucket', { + Template.fromStack(stack).hasResource('AWS::S3::Bucket', { "Properties": { "BucketName": "bucket2", }, @@ -417,7 +430,7 @@ describe('CDK Include', () => { "Bucket0", "Bucket1", ], - }, ResourcePart.CompleteDefinition); + }); }); test('correctly parses Conditions and the Condition resource attribute', () => { @@ -426,7 +439,7 @@ describe('CDK Include', () => { const cfnBucket = cfnTemplate.getResource('Bucket'); expect(cfnBucket.cfnOptions.condition).toBe(alwaysFalseCondition); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('resource-attribute-condition.json'), ); }); @@ -434,7 +447,7 @@ describe('CDK Include', () => { test('allows Conditions to reference Mappings', () => { includeTestTemplate(stack, 'condition-using-mapping.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('condition-using-mapping.json'), ); }); @@ -444,7 +457,7 @@ describe('CDK Include', () => { const alwaysFalse = cfnTemplate.getCondition('AlwaysFalse'); alwaysFalse.overrideLogicalId('TotallyFalse'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Parameters": { "Param": { "Type": "String", @@ -481,7 +494,7 @@ describe('CDK Include', () => { }); const originalTemplate = loadTestFileToJsObject('bucket-with-parameters.json'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { ...originalTemplate.Resources, "NewBucket": { @@ -526,7 +539,7 @@ describe('CDK Include', () => { numberParam.type = "NewType"; const originalTemplate = loadTestFileToJsObject('bucket-with-parameters.json'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { ...originalTemplate.Resources, }, @@ -559,7 +572,7 @@ describe('CDK Include', () => { alwaysFalseCondition.expression = core.Fn.conditionEquals(1, 2); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Conditions": { "AlwaysFalseCond": { "Fn::Equals": [1, 2], @@ -580,7 +593,7 @@ describe('CDK Include', () => { expect(cfnBucket.cfnOptions.creationPolicy).toBeDefined(); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('resource-attribute-creation-policy.json'), ); }); @@ -590,8 +603,7 @@ describe('CDK Include', () => { const cfnBucket = cfnTemplate.getResource('Bucket'); expect(cfnBucket.cfnOptions.updatePolicy).toBeDefined(); - - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('resource-attribute-update-policy.json'), ); }); @@ -612,7 +624,7 @@ describe('CDK Include', () => { resources: [cfnBucket.attrArn], })); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ ...loadTestFileToJsObject('only-empty-bucket.json'), "Outputs": { "ExportsOutputFnGetAttBucketArn436138FE": { @@ -626,7 +638,7 @@ describe('CDK Include', () => { }, }); - expect(otherStack).toHaveResourceLike('AWS::IAM::Policy', { + Template.fromStack(otherStack).hasResourceProperties('AWS::IAM::Policy', { "PolicyDocument": { "Statement": [ { @@ -646,7 +658,7 @@ describe('CDK Include', () => { cfnKey.overrideLogicalId('TotallyDifferentKey'); const originalTemplate = loadTestFileToJsObject('bucket-with-encryption-key.json'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -679,7 +691,7 @@ describe('CDK Include', () => { test('can include a template with a custom resource that uses attributes', () => { const cfnTemplate = includeTestTemplate(stack, 'custom-resource-with-attributes.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('custom-resource-with-attributes.json'), ); @@ -706,7 +718,7 @@ describe('CDK Include', () => { const originalTemplate = loadTestFileToJsObject('outputs-with-references.json'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Conditions": { ...originalTemplate.Conditions, "MyCondition": { @@ -747,7 +759,7 @@ describe('CDK Include', () => { expect(output.value).toBeDefined(); expect(output.exportName).toBeDefined(); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('outputs-with-references.json'), ); }); @@ -766,7 +778,7 @@ describe('CDK Include', () => { someMapping.setValue('region', 'key2', 'value2'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Mappings": { "SomeMapping": { "region": { @@ -803,7 +815,7 @@ describe('CDK Include', () => { test('can ingest a template that uses Fn::FindInMap with the first argument being a dynamic reference', () => { includeTestTemplate(stack, 'find-in-map-with-dynamic-mapping.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('find-in-map-with-dynamic-mapping.json'), ); }); @@ -814,7 +826,7 @@ describe('CDK Include', () => { someMapping.overrideLogicalId('DifferentMapping'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Mappings": { "DifferentMapping": { "region": { @@ -842,7 +854,7 @@ describe('CDK Include', () => { test('can ingest a template that uses Fn::FindInMap for the value of a boolean property', () => { includeTestTemplate(stack, 'find-in-map-for-boolean-property.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('find-in-map-for-boolean-property.json'), ); }); @@ -853,7 +865,7 @@ describe('CDK Include', () => { expect(rule).toBeDefined(); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('only-parameters-and-rule.json'), ); }); @@ -881,7 +893,7 @@ describe('CDK Include', () => { const hook = cfnTemplate.getHook('EcsBlueGreenCodeDeployHook'); expect(hook).toBeDefined(); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('hook-code-deploy-blue-green-ecs.json'), ); }); @@ -901,7 +913,7 @@ describe('CDK Include', () => { }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Transform": { "Name": "AWS::Include", "Parameters": { @@ -948,7 +960,7 @@ describe('CDK Include', () => { }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -973,7 +985,7 @@ describe('CDK Include', () => { }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -994,7 +1006,7 @@ describe('CDK Include', () => { }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -1020,7 +1032,7 @@ describe('CDK Include', () => { }, }); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -1065,7 +1077,7 @@ describe('CDK Include', () => { test('can ingest a template that contains properties not in the current CFN spec, and output it unchanged', () => { includeTestTemplate(stack, 'properties-not-in-cfn-spec.json'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('properties-not-in-cfn-spec.json'), ); }); diff --git a/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts index 06beafcdeb62c..4c693bd1026dc 100644 --- a/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; @@ -19,7 +19,7 @@ describe('CDK Include', () => { test('can ingest a template with all long-form CloudFormation functions and output it unchanged', () => { includeTestTemplate(stack, 'long-form-vpc.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('long-form-vpc.yaml'), ); }); @@ -27,7 +27,7 @@ describe('CDK Include', () => { test('can ingest a template with year-month-date parsed as string instead of Date', () => { includeTestTemplate(stack, 'year-month-date-as-strings.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "AWSTemplateFormatVersion": "2010-09-09", "Resources": { "Role": { @@ -54,7 +54,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form Base64 function', () => { includeTestTemplate(stack, 'short-form-base64.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Base64Bucket": { "Type": "AWS::S3::Bucket", @@ -71,7 +71,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form !Cidr function', () => { includeTestTemplate(stack, 'short-form-cidr.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "CidrVpc1": { "Type": "AWS::EC2::VPC", @@ -104,7 +104,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form !FindInMap function, in both hyphen and bracket notation', () => { includeTestTemplate(stack, 'short-form-find-in-map.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Mappings": { "RegionMap": { "region-1": { @@ -145,7 +145,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form !GetAtt function', () => { includeTestTemplate(stack, 'short-form-get-att.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "ELB": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", @@ -187,7 +187,7 @@ describe('CDK Include', () => { test('can ingest a template with short form Select, GetAZs, and Ref functions', () => { includeTestTemplate(stack, 'short-form-select.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Subnet1": { "Type": "AWS::EC2::Subnet", @@ -220,7 +220,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form !ImportValue function', () => { includeTestTemplate(stack, 'short-form-import-value.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket1": { "Type": "AWS::S3::Bucket", @@ -237,7 +237,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form !Join function', () => { includeTestTemplate(stack, 'short-form-join.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -257,7 +257,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form !Split function that uses both brackets and hyphens', () => { includeTestTemplate(stack, 'short-form-split.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket1": { "Type": "AWS::S3::Bucket", @@ -287,7 +287,7 @@ describe('CDK Include', () => { // Note that this yaml template fails validation. It is unclear how to invoke !Transform. includeTestTemplate(stack, 'invalid/short-form-transform.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Resources": { "Bucket": { "Type": "AWS::S3::Bucket", @@ -310,7 +310,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form conditionals', () => { includeTestTemplate(stack, 'short-form-conditionals.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Conditions": { "AlwaysTrueCond": { "Fn::And": [ @@ -348,7 +348,7 @@ describe('CDK Include', () => { test('can ingest a template with the short form Conditions', () => { includeTestTemplate(stack, 'short-form-conditions.yaml'); - expect(stack).toMatchTemplate({ + Template.fromStack(stack).templateMatches({ "Conditions": { "AlwaysTrueCond": { "Fn::Not": [ @@ -393,7 +393,7 @@ describe('CDK Include', () => { test('can ingest a yaml with long-form functions and output it unchanged', () => { includeTestTemplate(stack, 'long-form-subnet.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('long-form-subnet.yaml'), ); }); @@ -401,7 +401,7 @@ describe('CDK Include', () => { test('can ingest a YAML template with Fn::Sub in string form and output it unchanged', () => { includeTestTemplate(stack, 'short-form-fnsub-string.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('short-form-fnsub-string.yaml'), ); }); @@ -409,7 +409,7 @@ describe('CDK Include', () => { test('can ingest a YAML template with Fn::Sub in map form and output it unchanged', () => { includeTestTemplate(stack, 'short-form-sub-map.yaml'); - expect(stack).toMatchTemplate( + Template.fromStack(stack).templateMatches( loadTestFileToJsObject('short-form-sub-map.yaml'), ); }); diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 5889ed8517559..686c71aaba3cf 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -178,7 +178,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/fs-extra": "^8.1.2", "@types/jest": "^27.4.0", "@types/lodash": "^4.14.178", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index cb6707b8b1611..11f7254664669 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.89", + "@types/aws-lambda": "^8.10.90", "@types/fs-extra": "^8.1.2", "@types/jest": "^27.4.0", "@types/sinon": "^9.0.11", diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index af4a3ca611c2e..88b6a6748cd6f 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/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-kubectl/test/kubectl-layer.test.ts b/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts index c7591af7b3c2b..68374424b0085 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts +++ b/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts @@ -1,6 +1,6 @@ import { Stack } from '@aws-cdk/core'; import { KubectlLayer } 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 KubectlLayer(stack, 'MyLayer'); // THEN - expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', { Description: '/opt/kubectl/kubectl and /opt/helm/helm', }); }); diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json index 010c9e517040f..b4e0211270c66 100644 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json @@ -66,7 +66,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-node-proxy-agent/test/proxy-agent-layer.test.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts index 14264a8d080dc..72b1b1f85d4a0 100644 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts @@ -1,6 +1,6 @@ +import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; import { NodeProxyAgentLayer } from '../lib'; -import '@aws-cdk/assert-internal/jest'; test('synthesized to a layer version', () => { //GIVEN @@ -10,7 +10,7 @@ test('synthesized to a layer version', () => { new NodeProxyAgentLayer(stack, 'MyLayer'); // THEN - expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', { Description: '/opt/nodejs/node_modules/proxy-agent', }); }); diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts index 294a8844b81bb..5d73e23784314 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts @@ -273,6 +273,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { const project = new codebuild.PipelineProject(projectScope, this.constructId, { projectName: this.props.projectName, + description: `Pipeline step ${options.pipeline.pipeline.pipelineName}/${stage.stageName}/${actionName}`, environment, vpc: projectOptions.vpc, subnetSelection: projectOptions.subnetSelection, diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts index c905c3cbc4cfa..01069ee7adee0 100644 --- a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts @@ -43,6 +43,28 @@ test('additionalinputs creates the right commands', () => { }); }); +test('CodeBuild projects have a description', () => { + new cdkp.CodePipeline(pipelineStack, 'Pipeline', { + synth: new cdkp.CodeBuildStep('Synth', { + commands: ['/bin/true'], + input: cdkp.CodePipelineSource.gitHub('test/test', 'main'), + }), + }); + + // THEN + Template.fromStack(pipelineStack).hasResourceProperties( + 'AWS::CodeBuild::Project', + { + Description: { + 'Fn::Join': [ + '', + ['Pipeline step ', { Ref: 'Pipeline9850B417' }, '/Build/Synth'], + ], + }, + }, + ); +}); + test('long duration steps are supported', () => { // WHEN new cdkp.CodePipeline(pipelineStack, 'Pipeline', { diff --git a/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json b/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json index c0d89b2bf135a..1b6de60c8e589 100644 --- a/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.newpipeline-with-vpc.expected.json @@ -1355,6 +1355,18 @@ "Cache": { "Type": "NO_CACHE" }, + "Description": { + "Fn::Join": [ + "", + [ + "Pipeline step ", + { + "Ref": "Pipeline9850B417" + }, + "/Build/Synth" + ] + ] + }, "EncryptionKey": "alias/aws/s3", "VpcConfig": { "SecurityGroupIds": [ @@ -1942,6 +1954,18 @@ "Cache": { "Type": "NO_CACHE" }, + "Description": { + "Fn::Join": [ + "", + [ + "Pipeline step ", + { + "Ref": "Pipeline9850B417" + }, + "/UpdatePipeline/SelfMutate" + ] + ] + }, "EncryptionKey": "alias/aws/s3", "VpcConfig": { "SecurityGroupIds": [ @@ -2284,6 +2308,18 @@ "Cache": { "Type": "NO_CACHE" }, + "Description": { + "Fn::Join": [ + "", + [ + "Pipeline step ", + { + "Ref": "Pipeline9850B417" + }, + "/Assets/FileAsset1" + ] + ] + }, "EncryptionKey": "alias/aws/s3", "VpcConfig": { "SecurityGroupIds": [ @@ -2385,6 +2421,18 @@ "Cache": { "Type": "NO_CACHE" }, + "Description": { + "Fn::Join": [ + "", + [ + "Pipeline step ", + { + "Ref": "Pipeline9850B417" + }, + "/Assets/FileAsset2" + ] + ] + }, "EncryptionKey": "alias/aws/s3", "VpcConfig": { "SecurityGroupIds": [ diff --git a/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json b/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json index 6e12dae20df4d..6e8c76b176b7f 100644 --- a/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.newpipeline.expected.json @@ -2036,6 +2036,18 @@ "Cache": { "Type": "NO_CACHE" }, + "Description": { + "Fn::Join": [ + "", + [ + "Pipeline step ", + { + "Ref": "Pipeline9850B417" + }, + "/Build/Synth" + ] + ] + }, "EncryptionKey": "alias/aws/s3" } }, @@ -2335,6 +2347,18 @@ "Cache": { "Type": "NO_CACHE" }, + "Description": { + "Fn::Join": [ + "", + [ + "Pipeline step ", + { + "Ref": "Pipeline9850B417" + }, + "/UpdatePipeline/SelfMutate" + ] + ] + }, "EncryptionKey": "alias/aws/s3" } } diff --git a/packages/@aws-cdk/pipelines/test/testhelpers/matchers.ts b/packages/@aws-cdk/pipelines/test/testhelpers/matchers.ts index 97a02fc1dc10d..f7ba6458f7449 100644 --- a/packages/@aws-cdk/pipelines/test/testhelpers/matchers.ts +++ b/packages/@aws-cdk/pipelines/test/testhelpers/matchers.ts @@ -26,7 +26,7 @@ class StringLike extends Matcher { public test(actual: any): MatchResult { if (typeof(actual) !== 'string') { - throw new Error(`Expected string but found ${typeof(actual)}`); + throw new Error(`Expected string but found ${typeof(actual)} ${JSON.stringify(actual)}`); } const re = new RegExp(`^${this.pattern.split('*').map(escapeRegex).join('.*')}$`); diff --git a/packages/@aws-cdk/region-info/build-tools/fact-tables.ts b/packages/@aws-cdk/region-info/build-tools/fact-tables.ts index e641f654ba532..b36ff4818838d 100644 --- a/packages/@aws-cdk/region-info/build-tools/fact-tables.ts +++ b/packages/@aws-cdk/region-info/build-tools/fact-tables.ts @@ -102,6 +102,7 @@ export const PARTITION_MAP: { [region: string]: Region } = { }; // https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html#access-logging-bucket-permissions +// https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-access-logs.html#attach-bucket-policy export const ELBV2_ACCOUNTS: { [region: string]: string } = { 'af-south-1': '098369216593', 'ap-east-1': '754344448648', @@ -111,6 +112,7 @@ export const ELBV2_ACCOUNTS: { [region: string]: string } = { 'ap-south-1': '718504428378', 'ap-southeast-1': '114774131450', 'ap-southeast-2': '783225319266', + 'ap-southeast-3': '589379963580', 'ca-central-1': '985666609251', 'cn-north-1': '638102146993', 'cn-northwest-1': '037604701340', diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index ac8eb9375ba08..f5880d8195f90 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -41,7 +41,7 @@ "jest": "^27.4.7", "monocdk": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "ts-jest": "^27.1.2" + "ts-jest": "^27.1.3" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0" diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 3480b90dbd3a1..e2404ac8515a8 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -62,7 +62,7 @@ "nock": "^13.2.2", "@aws-cdk/pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^27.1.2", + "ts-jest": "^27.1.3", "ts-mock-imports": "^1.3.8", "xml-js": "^1.6.11" }, @@ -76,7 +76,7 @@ "aws-sdk": "^2.979.0", "camelcase": "^6.3.0", "cdk-assets": "0.0.0", - "chokidar": "^3.5.2", + "chokidar": "^3.5.3", "chalk": "^4", "decamelize": "^5.0.1", "fs-extra": "^9.1.0", diff --git a/packages/decdk/.gitignore b/packages/decdk/.gitignore deleted file mode 100644 index 88e6bb7a9196f..0000000000000 --- a/packages/decdk/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.js -*.d.ts -!deps.js -test/fixture/.jsii -cdk.schema.json diff --git a/packages/decdk/.npmignore b/packages/decdk/.npmignore deleted file mode 100644 index 9f3f17837f80a..0000000000000 --- a/packages/decdk/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# The basics -*.ts -*.tgz -*.snk -!*.d.ts -!*.js - -# Coverage -coverage -.nyc_output -.nycrc - -# Build gear -dist -.LAST_BUILD -.LAST_PACKAGE -.jsii - - -# Include .jsii -!.jsii - -*.tsbuildinfo - diff --git a/packages/decdk/README.md b/packages/decdk/README.md index 8d21c445a0c79..3a8d3178800f3 100644 --- a/packages/decdk/README.md +++ b/packages/decdk/README.md @@ -1,277 +1,2 @@ -# deCDK - Declarative CDK +Moved to [cdklabs/decdk](https://github.com/cdklabs/decdk) -[![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges) - -Define AWS CDK applications declaratively. - -This tool reads CloudFormation-like JSON/YAML templates which can contain both normal CloudFormation resources (`AWS::S3::Bucket`) and also reference AWS CDK resources (`@aws-cdk/aws-s3.Bucket`). - -## Getting Started - -Install the AWS CDK CLI and the `decdk` tool: - -```console -$ npm i -g aws-cdk decdk -``` - -This is optional (but highly recommended): You can use `decdk-schema` to generate a JSON schema and use it for IDE completion and validation: - -```console -$ decdk-schema > cdk.schema.json -``` - -Okay, we are ready to begin with a simple example. Create a file called `hello.json`: - -```json -{ - "$schema": "./cdk.schema.json", - "Resources": { - "MyQueue": { - "Type": "@aws-cdk/aws-sqs.Queue", - "Properties": { - "fifo": true - } - } - } -} -``` - -Now, you can use it as a CDK app (you'll need to `npm install -g aws-cdk`): - -```console -$ cdk -a "decdk hello.json" synth -Resources: - MyQueueE6CA6235: - Type: AWS::SQS::Queue - Properties: - FifoQueue: true - Metadata: - aws:cdk:path: hello2/MyQueue/Resource -``` - -As you can see, the deCDK has the same semantics as a CloudFormation template. It contains a section for “Resources”, where each resource is defined by a *type* and a set of *properties*. deCDK allows using constructs from AWS Construct Library in templates by identifying the class name (in this case `@aws-cdk/aws-sqs.Queue`). - -When deCDK processes a template, it identifies these special resources and under-the-hood, it instantiates an object of that type, passing in the properties to the object's constructor. All CDK constructs have a uniform signature, so this is actually straightforward. - -## Development - -### Examples/Tests - -When you build this module, it will produce a `cdk.schema.json` file at the root, which is referenced by the examples in the [`examples`](./examples) directory. This directory includes working examples of deCDK templates for various areas. We also snapshot-test those to ensure there are no unwanted regressions. - -## Design - -"Deconstruction" is the process of reflecting on the AWS Construct Library's type system and determining what would be the declarative interface for each API. This section describes how various elements in the library's type system are represented through the template format. - -### Constructs - -Constructs can be defined in the `Resources` section of the template. The `Type` of the resource is the fully-qualified class name (e.g. `@aws-cdk/aws-s3.Bucket`) and `Properties` are mapped to the deconstructed type of the construct's "Props" interface (e.g. `BucketProps`). - -### Data Interfaces ("Props") - -jsii has a concept of "data interfaces", which are basically interfaces that do not have methods. For example, all construct "props" are data interfaces. - -> In some languages (Python, Ruby), if a method accepts a data interface as the last argument, interface properties can be used as keyword arguments in the method call. Other languages have a different idiomatic representation of data such as Java PoJos and Builders. - -deCDK maps data interfaces to closed JSON objects (no additional properties), and will recursively deconstruct all property types. - -### Primitives - -Strings, numbers, booleans, dates, lists and maps are all deconstructed 1:1 to their JSON representation. - -### Enums - -Enums are mapped to JSON schema enums. - -### References - -If deCDK encounters a reference to another __construct__ (a type that extends `cdk.Construct` or an interface that extends `cdk.IConstruct`), it will allow referencing it via a “Ref” intrinsic. For example, here's a definition of an ECS cluster that references a VPC: - -```yaml -Resources: - VPC: - Type: "@aws-cdk/aws-ec2.Vpc" - Properties: - maxAZs: 1 - Cluster: - Type: "@aws-cdk/aws-ecs.Cluster" - Properties: - vpc: - Ref: VPC -``` - -### Enum-like Classes - -Based on the AWS Construct Library's consistent guidelines and conventions, which are also enforced by a tool we use called “awslint”, deCDK is also capable of expressive more complex idioms. For example, enum-like classes, which are classes that expose a set of static properties or methods can be mapped to JSON enums or method invocations. For example, this is how you define an AWS Lambda function in the CDK (TypeScript): - -```ts -new lambda.Function(this, 'MyHandler', { - handler: 'index.handler', - runtime: lambda.Runtime.NodeJS810, - code: lambda.Code.asset('./src') -}); -``` - -And here's the deCDK version: - -```json -{ - "MyHandler": { - "Type": "@aws-cdk/aws-lambda.Function", - "Properties": { - "handler": "index.handler", - "runtime": "NodeJS810", - "code": { "asset": { "path": "./src" } } - } - } -} -``` - -### Polymorphism - -Due to the decoupled nature of AWS, The AWS Construct Library highly utilizes polymorphism to expose rich APIs to users. In many cases, APIs would accept an interface of some kind, and various AWS services provide an implementation for that interface. deCDK is able to find all concrete implementation of an interface or an abstract class and offer the user an enum-like experience. The following example shows how this approach can be used to define AWS Lambda events: - -```json -{ - "Resources": { - "MyTopic": { - "Type": "@aws-cdk/aws-sns.Topic" - }, - "Table": { - "Type": "@aws-cdk/aws-dynamodb.Table", - "Properties": { - "partitionKey": { - "name": "ID", - "type": "String" - }, - "streamSpecification": "NewAndOldImages" - } - }, - "HelloWorldFunction": { - "Type": "@aws-cdk/aws-lambda.Function", - "Properties": { - "handler": "app.hello_handler", - "runtime": "Python36", - "code": { - "asset": { "path": "." } - }, - "environment": { - "Param": "f" - }, - "events": [ - { "@aws-cdk/aws-lambda-event-sources.DynamoEventSource": { "table": { "Ref": "Table" }, "startingPosition": "TrimHorizon" } }, - { "@aws-cdk/aws-lambda-event-sources.ApiEventSource": { "method": "GET", "path": "/hello" } }, - { "@aws-cdk/aws-lambda-event-sources.ApiEventSource": { "method": "POST", "path": "/hello" } }, - { "@aws-cdk/aws-lambda-event-sources.SnsEventSource": { "topic": { "Ref": "MyTopic" } } } - ] - } - } - } -} -``` - -The keys in the “events” array are all fully qualified names of classes in the AWS Construct Library. The declaration is “Array”. When deCDK deconstructs the objects in this array, it will create objects of these types and pass them in as IEventSource objects. - -### `Fn::GetAtt` - -deCDK also supports referencing specific attributes of CDK resources by the intrinsic `Fn::GetAtt`. When processing the template, if an `Fn::GetAtt` is found, and references a CDK construct, the attribute name is treated as a property name of the construct and its value is used. - -The following example shows how to output the “url” property of a `@aws-cdk/aws-lambda.Function` from above: - -```yaml -Outputs: - HelloWorldApi: - Description: API Gateway endpoint URL for Prod stage for Hello World function - Value: - Fn::GetAtt: - - MyHandler - - url -``` - -### Raw CloudFormation - -If deCDK doesn't identify a resource type as a CDK resource, it will just pass it through to the resulting output. This means that any existing CloudFormation/SAM resources (such as `AWS::SQS::Queue`) can be used as-is. - -The decdk JSON schema will simply pass through any resources that have a type that includes `::`, so don't expect any validation of raw CloudFormation resource properties. - -## Roadmap - -There is much more we can do here. This section lists API surfaces with ideas on how to deconstruct them. - -### Imports - -When decdk encounters a reference to an AWS construct, it currently requires a `Ref` to another resource in the template. We should also support importing external resources by reflecting on the various static `fromXxx`, `importXxx` and deconstructing those methods. - -For example if we have a property `Bucket` that's modeled as an `s3.IBucket`, at the moment it will only accept: - -```json -"Bucket": { "Ref": "MyBucket" } -``` - -But this requires that `MyBucket` is defined within the same template. If we want to reference a bucket by ARN, we should be able to do this: - -```json -"Bucket": { "arn": "arn-of-bucket" } -``` - -Which should be translated to a call: - -```ts -bucket: Bucket.fromBucketArn(this, 'arn-of-bucket') -``` - -### Grants - -AWS constructs expose a set of "grant" methods that can be used to grant IAM principals permissions to perform certain actions on a resource (e.g. `table.grantRead` or `lambda.grantInvoke`). - -deCDK should be able to provide a declarative-style for expressing those grants: - -```json -"MyFunction": { - "Type": "@aws-cdk/aws-lambda.Function", - "Properties": { - "grants": { - "invoke": [ { "Ref": "MyRole" }, { "Ref": "AnotherRole" } ] - } - } -} -``` - -### Events - -The CDK employs a loose pattern for event-driven programming by exposing a set of `onXxx` methods from AWS constructs. This pattern is used for various types of event systems such as CloudWatch events, bucket notifications, etc. - -It might be possible to add a bit more rigor to these patterns and expose them also via a declarative API: - -```json -"MyBucket": { - "Type": "@aws-cdk/aws-s3.Bucket", - "Properties": { - "on": { - "objectCreated": [ - { - "target": { "Ref": "MyFunction" }, - "prefix": "foo/" - } - ] - } - } -} -``` - -### addXxxx - -We should enforce in our APIs that anything that can be "added" to a construct can also be defined in props as an array. `awslint` can enforce this and ensure that `addXxx` methods always return `void` and have a corresponding prop. - -### Supporting user-defined constructs - -deCDK can deconstruct APIs that adhere to the standards defined by __awslint__ and exposed through jsii (it reflects on the jsii type system). Technically, nothing prevents us from allowing users to "bring their own constructs" to decdk, but those requirements must be met. - -### Fully qualified type names - -As you might have observed, whenever users need to reference a type in deCDK templates they are required to reference the fully qualified name (e.g. `@aws-cdk/aws-s3.Bucket`). We can obvsiouly come up with a more concise way to reference these types, as long as it will be possible to deterministically translate back and forth. - -### Special Types - -`iam.PolicyDocument` is tricky since it utilizes a fluent API. We need to think whether we want to revise the PolicyDocument API to be more compatible or add a utility class that can help. -- We should enable shorthand tags for intrinsics in YAML diff --git a/packages/decdk/bin/decdk b/packages/decdk/bin/decdk deleted file mode 100755 index a606284619892..0000000000000 --- a/packages/decdk/bin/decdk +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('./decdk.js'); diff --git a/packages/decdk/bin/decdk-schema b/packages/decdk/bin/decdk-schema deleted file mode 100755 index 2576c1d9ae5a4..0000000000000 --- a/packages/decdk/bin/decdk-schema +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('./decdk-schema.js'); diff --git a/packages/decdk/bin/decdk-schema.ts b/packages/decdk/bin/decdk-schema.ts deleted file mode 100644 index 4a1e66dcd3bf2..0000000000000 --- a/packages/decdk/bin/decdk-schema.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { loadTypeSystem } from '../lib'; -import { renderFullSchema } from '../lib/cdk-schema'; - -/* eslint-disable no-console */ - -async function main() { - const typeSystem = await loadTypeSystem(); - const schema = await renderFullSchema(typeSystem, { colors: true, warnings: true }); - console.log(JSON.stringify(schema, undefined, 2)); -} - -main().catch(e => { - console.error(e); - process.exit(1); -}); \ No newline at end of file diff --git a/packages/decdk/bin/decdk.ts b/packages/decdk/bin/decdk.ts deleted file mode 100644 index 0249084234e83..0000000000000 --- a/packages/decdk/bin/decdk.ts +++ /dev/null @@ -1,26 +0,0 @@ -import * as cdk from '@aws-cdk/core'; -import * as chalk from 'chalk'; -import { DeclarativeStack, loadTypeSystem, readTemplate, stackNameFromFileName } from '../lib'; - -async function main() { - const args = require('yargs') - .usage('$0 ', 'Hydrate a deconstruct file', (yargs: any) => { - yargs.positional('filename', { type: 'string', required: true }); - }) - .parse(); - - const templateFile = args.filename; - const template = await readTemplate(templateFile); - const stackName = stackNameFromFileName(templateFile); - const typeSystem = await loadTypeSystem(); - - const app = new cdk.App(); - new DeclarativeStack(app, stackName, { template, typeSystem }); - app.synth(); -} - -main().catch(e => { - // eslint-disable-next-line no-console - console.error(chalk.red(e)); - process.exit(1); -}); diff --git a/packages/decdk/cloudformation.schema.json b/packages/decdk/cloudformation.schema.json deleted file mode 100644 index 03259e64ab270..0000000000000 --- a/packages/decdk/cloudformation.schema.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "additionalProperties": false, - "definitions": { - "Parameter": { - "additionalProperties": false, - "properties": { - "AllowedPattern": { - "type": "string" - }, - "AllowedValues": { - "type": "array" - }, - "ConstraintDescription": { - "type": "string" - }, - "Default": { - "type": "string" - }, - "Description": { - "type": "string" - }, - "MaxLength": { - "type": "string" - }, - "MaxValue": { - "type": "string" - }, - "MinLength": { - "type": "string" - }, - "MinValue": { - "type": "string" - }, - "NoEcho": { - "type": [ - "string", - "boolean" - ] - }, - "Type": { - "type": "string" - } - }, - "required": [ - "Type" - ], - "type": "object" - }, - "Tag": { - "additionalProperties": false, - "properties": { - "Key": { - "type": "string" - }, - "Value": { - "type": "string" - } - }, - "required": [ - "Key", - "Value" - ], - "type": "object" - } - }, - "properties": { - "AWSTemplateFormatVersion": { - "enum": [ - "2010-09-09" - ], - "type": "string" - }, - "Conditions": { - "additionalProperties": false, - "patternProperties": { - "^[a-zA-Z0-9]+$": { - "type": "object" - } - }, - "type": "object" - }, - "Description": { - "description": "Template description", - "maxLength": 1024, - "type": "string" - }, - "Mappings": { - "additionalProperties": false, - "patternProperties": { - "^[a-zA-Z0-9]+$": { - "type": "object" - } - }, - "type": "object" - }, - "Metadata": { - "type": "object" - }, - "Outputs": { - "additionalProperties": false, - "maxProperties": 60, - "minProperties": 1, - "patternProperties": { - "^[a-zA-Z0-9]+$": { - "type": "object" - } - }, - "type": "object" - }, - "Parameters": { - "additionalProperties": false, - "maxProperties": 50, - "patternProperties": { - "^[a-zA-Z0-9]+$": { - "$ref": "#/definitions/Parameter" - } - }, - "type": "object" - }, - "Resources": { - "additionalProperties": false, - "patternProperties": { - "^[a-zA-Z0-9]+$": { - "anyOf": [ - { } - ] - } - }, - "type": "object" - }, - "Transform": { - "type": [ - "object", - "string" - ] - } - }, - "required": [ - "Resources" - ], - "type": "object" -} \ No newline at end of file diff --git a/packages/decdk/deps.js b/packages/decdk/deps.js deleted file mode 100644 index c7b66f27d0827..0000000000000 --- a/packages/decdk/deps.js +++ /dev/null @@ -1,64 +0,0 @@ -// +------------------------------------------------------------------------------------------------ -// | this script runs during build to verify that this package depends on the entire aws construct -// | library. the script will fail (and update package.json) if this is not true. -// | -const fs = require('fs'); -const path = require('path'); - -const pkg = require('./package.json'); -const deps = pkg.dependencies || (pkg.dependencies = {}); - -const root = path.resolve('..', '..', 'packages', '@aws-cdk'); -const modules = fs.readdirSync(root); -let errors = false; - -for (const dir of modules) { - const module = path.resolve(root, dir); - const meta = require(path.join(module, 'package.json')); - - // skip non-jsii modules - if (!meta.jsii) { - continue; - } - - // skip the `@aws-cdk/cloudformation-include` module - if (dir === 'cloudformation-include') { - continue; - } - - const exists = deps[meta.name]; - - if (meta.deprecated) { - if (exists) { - console.error(`spurious dependency on deprecated: ${meta.name}`); - errors = true; - } - delete deps[meta.name]; - continue; - } - // skip private packages - if (meta.private) { - continue; - } - - if (!exists) { - console.error(`missing dependency: ${meta.name}`); - errors = true; - } - - const requirement = `${meta.version}`; - - if (exists && exists !== requirement) { - console.error(`invalid version requirement: expecting '${requirement}', got ${exists}`); - errors = true; - } - - deps[meta.name] = requirement; -} - -fs.writeFileSync(path.join(__dirname, 'package.json'), JSON.stringify(pkg, undefined, 2) + '\n'); - -if (errors) { - console.error('errors found. updated package.json'); - process.exit(1); -} diff --git a/packages/decdk/examples/apigw.json b/packages/decdk/examples/apigw.json deleted file mode 100644 index 458d3abf969e5..0000000000000 --- a/packages/decdk/examples/apigw.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "HelloLambda": { - "Type": "@aws-cdk/aws-lambda.Function", - "Properties": { - "code": { - "asset": { "path": "." } - }, - "runtime": "PYTHON_3_6", - "handler": "index.handler" - } - }, - "MyApi": { - "Type": "@aws-cdk/aws-apigateway.LambdaRestApi", - "Properties": { - "handler": { "Ref": "HelloLambda" } - } - }, - "GetRoot": { - "Type": "@aws-cdk/aws-apigateway.Method", - "Properties": { - "resource": { "Fn::GetAtt": [ "MyApi", "root" ] }, - "httpMethod": "GET" - } - } - } -} \ No newline at end of file diff --git a/packages/decdk/examples/ecs.json b/packages/decdk/examples/ecs.json deleted file mode 100644 index 86d63cbcf8489..0000000000000 --- a/packages/decdk/examples/ecs.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "VPC": { - "Type": "@aws-cdk/aws-ec2.Vpc", - "Properties": { - "maxAzs": 1 - } - }, - "Cluster": { - "Type": "@aws-cdk/aws-ecs.Cluster", - "Properties": { - "vpc": { "Ref": "VPC" } - } - }, - "MyTaskDef": { - "Type": "@aws-cdk/aws-ecs.TaskDefinition", - "Properties": { - "compatibility": "FARGATE", - "family": "redis", - "cpu": "1024", - "memoryMiB": "1GB", - "networkMode": "AWS_VPC" - } - }, - "ContainerDef": { - "Type": "@aws-cdk/aws-ecs.ContainerDefinition", - "Properties": { - "taskDefinition": { "Ref": "MyTaskDef" }, - "essential": true, - "memoryLimitMiB": 1024, - "image": { - "fromRegistry": { - "name": "redis" - } - } - } - }, - "Service": { - "Type": "@aws-cdk/aws-ecs.FargateService", - "Properties": { - "cluster": { "Ref": "Cluster" }, - "taskDefinition": { "Ref": "MyTaskDef" } - } - } - } -} diff --git a/packages/decdk/examples/lambda-events.json b/packages/decdk/examples/lambda-events.json deleted file mode 100644 index 0c364b1d14dd6..0000000000000 --- a/packages/decdk/examples/lambda-events.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "MyTopic": { - "Type": "@aws-cdk/aws-sns.Topic" - }, - "Table": { - "Type": "@aws-cdk/aws-dynamodb.Table", - "Properties": { - "partitionKey": { - "name": "ID", - "type": "STRING" - }, - "stream": "NEW_AND_OLD_IMAGES" - } - }, - "HelloWorldFunction": { - "Type": "@aws-cdk/aws-lambda.Function", - "Properties": { - "handler": "app.hello_handler", - "runtime": "PYTHON_3_6", - "code": { - "asset": { "path": "." } - }, - "environment": { - "Param": "f" - }, - "events": [ - { "@aws-cdk/aws-lambda-event-sources.DynamoEventSource": { "table": { "Ref": "Table" }, "startingPosition": "TRIM_HORIZON" } }, - { "@aws-cdk/aws-lambda-event-sources.ApiEventSource": { "method": "GET", "path": "/hello" } }, - { "@aws-cdk/aws-lambda-event-sources.ApiEventSource": { "method": "POST", "path": "/hello" } }, - { "@aws-cdk/aws-lambda-event-sources.SnsEventSource": { "topic": { "Ref": "MyTopic" } } } - ] - } - } - } -} \ No newline at end of file diff --git a/packages/decdk/examples/lambda-topic.json b/packages/decdk/examples/lambda-topic.json deleted file mode 100644 index 073202c663cce..0000000000000 --- a/packages/decdk/examples/lambda-topic.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "Topic": { - "Type": "@aws-cdk/aws-sns.Topic" - }, - "Lambda": { - "Type": "@aws-cdk/aws-lambda.Function", - "Properties": { - "code": { "asset": { "path": "." } }, - "runtime": "NODEJS", - "handler": "index.handler", - "events": [ - { "@aws-cdk/aws-lambda-event-sources.SnsEventSource": { "topic": { "Ref": "Topic" } } } - ] - } - } - } -} diff --git a/packages/decdk/examples/pipeline.json b/packages/decdk/examples/pipeline.json deleted file mode 100644 index 8c0c2ee5d315f..0000000000000 --- a/packages/decdk/examples/pipeline.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "Repo": { - "Type": "@aws-cdk/aws-codecommit.Repository", - "Properties": { - "repositoryName": "my-first-decdk-repo" - } - }, - "Key": { - "Type": "@aws-cdk/aws-kms.Key" - }, - "BuildProject": { - "Type": "@aws-cdk/aws-codebuild.PipelineProject", - "Properties": { - "encryptionKey": { "Ref": "Key" } - } - }, - "Pipeline": { - "Type": "@aws-cdk/aws-codepipeline.Pipeline", - "Properties": { - "stages": [ - { - "stageName": "Source", - "actions": [ - { - "@aws-cdk/aws-codepipeline-actions.CodeCommitSourceAction": { - "repository": { "Ref": "Repo" }, - "output": { - "artifact": { - "name": "Source" - } - }, - "actionName": "Source" - } - } - ] - }, - { - "stageName": "Build", - "actions": [ - { - "@aws-cdk/aws-codepipeline-actions.CodeBuildAction": { - "actionName": "Build", - "project": { "Ref": "BuildProject" }, - "input": { - "artifact": { - "name": "Source" - } - }, - "outputs": [ - { - "artifact": { - "name": "Build" - } - } - ] - } - } - ] - }, - { - "stageName": "Deploy", - "actions": [ - { - "@aws-cdk/aws-codepipeline-actions.CloudFormationCreateUpdateStackAction": { - "actionName": "Deploy", - "stackName": "MyStack", - "adminPermissions": true, - "templatePath": { - "artifactPath": { - "artifactName": "Build", - "fileName": "template.yaml" - } - } - } - } - ] - } - ] - } - } - } -} diff --git a/packages/decdk/examples/pure-cfn.json b/packages/decdk/examples/pure-cfn.json deleted file mode 100644 index 3d81a99da4978..0000000000000 --- a/packages/decdk/examples/pure-cfn.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "Hello": { - "Type": "@aws-cdk/aws-sqs.Queue", - "Properties": { - "encryption": "Unencrypted" - } - }, - "MyLogGroup": { - "Type": "AWS::Logs::LogGroup", - "Properties": { - "LogGroupName": { "Ref": "AWS::AccountId" } - } - } - } -} \ No newline at end of file diff --git a/packages/decdk/examples/queue-kms.json b/packages/decdk/examples/queue-kms.json deleted file mode 100644 index 50f7da4af5379..0000000000000 --- a/packages/decdk/examples/queue-kms.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "MyQueue": { - "Type": "@aws-cdk/aws-sqs.Queue", - "Properties": { - "encryption": "KMS" - } - } - } -} \ No newline at end of file diff --git a/packages/decdk/examples/vpc.json b/packages/decdk/examples/vpc.json deleted file mode 100644 index 091920e330a39..0000000000000 --- a/packages/decdk/examples/vpc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "../cdk.schema.json", - "Resources": { - "VPC": { - "Type": "@aws-cdk/aws-ec2.Vpc" - } - } -} \ No newline at end of file diff --git a/packages/decdk/jest.config.js b/packages/decdk/jest.config.js deleted file mode 100644 index f4cc833bdc324..0000000000000 --- a/packages/decdk/jest.config.js +++ /dev/null @@ -1,183 +0,0 @@ -// For a detailed explanation regarding each configuration property, visit: -// https://jestjs.io/docs/en/configuration.html - -module.exports = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // Respect "browser" field in package.json when resolving modules - // browser: false, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/n2/6v4_tbz97ws0h4bn5gbyvzb0m8vcjb/T/jest_b92skr", - - // Automatically clear mock calls and instances between every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: null, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: null, - - // A path to a custom dependency extractor - // dependencyExtractor: null, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files usin a array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: null, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: null, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - moduleFileExtensions: [ - "js", - "json", - "jsx", - "node" - ], - - // A map from regular expressions to module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: null, - - // Run tests from one or more projects - // projects: null, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: null, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: null, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: null, - - // This option allows use of a custom test runner - // testRunner: "jasmine2", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: null, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: null, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/packages/decdk/lib/cdk-schema.ts b/packages/decdk/lib/cdk-schema.ts deleted file mode 100644 index f12de0d5afa62..0000000000000 --- a/packages/decdk/lib/cdk-schema.ts +++ /dev/null @@ -1,125 +0,0 @@ -import * as chalk from 'chalk'; -import * as jsiiReflect from 'jsii-reflect'; -import { SchemaContext, schemaForTypeReference } from '../lib/jsii2schema'; - -/* eslint-disable no-console */ - -export interface RenderSchemaOptions { - warnings?: boolean; - - /** - * Use colors when printing ouput. - * @default true if tty is enabled - */ - colors?: boolean; -} - -export function renderFullSchema(typeSystem: jsiiReflect.TypeSystem, options: RenderSchemaOptions = { }) { - if (!process.stdin.isTTY || options.colors === false) { - // Disable chalk color highlighting - process.env.FORCE_COLOR = '0'; - } - - // Find all constructs for which the props interface - // (transitively) only consists of JSON primitives or interfaces - // that consist of JSON primitives - const constructType = typeSystem.findClass('constructs.Construct'); - const constructs = typeSystem.classes.filter(c => c.extends(constructType)); - - const deconstructs = constructs - .map(unpackConstruct) - .filter(c => c && !isCfnResource(c.constructClass)) as ConstructAndProps[]; - - const output = require('../cloudformation.schema.json'); - - output.definitions = output.definitions || { }; - - const ctx = SchemaContext.root(output.definitions); - - for (const deco of deconstructs) { - const resource = schemaForResource(deco, ctx); - if (resource) { - output.properties.Resources.patternProperties["^[a-zA-Z0-9]+$"].anyOf.push(resource); - } - } - - output.properties.$schema = { - type: 'string' - }; - - if (options.warnings) { - printWarnings(ctx); - } - - return output; -} - -function printWarnings(node: SchemaContext, indent = '') { - if (!node.hasWarningsOrErrors) { - return; - } - - console.error(indent + node.name); - - for (const warning of node.warnings) { - console.error(chalk.yellow(indent + ' ' + warning)); - } - - for (const error of node.errors) { - console.error(chalk.red(indent + ' ' + error)); - } - - if (!node.root) { - indent += ' '; - } - - for (const child of node.children) { - printWarnings(child, indent); - } -} - -export function schemaForResource(construct: ConstructAndProps, ctx: SchemaContext) { - ctx = ctx.child('resource', construct.constructClass.fqn); - - const propsSchema = schemaForTypeReference(construct.propsTypeRef, ctx); - if (!propsSchema) { - return undefined; - } - - return ctx.define(construct.constructClass.fqn, () => { - return { - additionalProperties: false, - properties: { - Properties: propsSchema, - Type: { - enum: [ construct.constructClass.fqn ], - type: "string" - } - } - }; - }); -} - -function isCfnResource(klass: jsiiReflect.ClassType) { - const resource = klass.system.findClass('@aws-cdk/core.CfnResource'); - return klass.extends(resource); -} - -function unpackConstruct(klass: jsiiReflect.ClassType): ConstructAndProps | undefined { - - if (!klass.initializer || klass.abstract) { return undefined; } - if (klass.initializer.parameters.length < 3) { return undefined; } - - const propsParam = klass.initializer.parameters[2]; - if (propsParam.type.fqn === undefined) { return undefined; } - - return { - constructClass: klass, - propsTypeRef: klass.initializer.parameters[2].type - }; -} - -export interface ConstructAndProps { - constructClass: jsiiReflect.ClassType; - propsTypeRef: jsiiReflect.TypeReference; -} diff --git a/packages/decdk/lib/declarative-stack.ts b/packages/decdk/lib/declarative-stack.ts deleted file mode 100644 index a093d16a5922f..0000000000000 --- a/packages/decdk/lib/declarative-stack.ts +++ /dev/null @@ -1,457 +0,0 @@ -import * as cdk from '@aws-cdk/core'; -import * as reflect from 'jsii-reflect'; -import * as jsonschema from 'jsonschema'; -import { renderFullSchema } from './cdk-schema'; -import { isConstruct, isDataType, isEnumLikeClass, isSerializableInterface, SchemaContext, schemaForPolymorphic } from './jsii2schema'; - -export interface DeclarativeStackProps extends cdk.StackProps { - typeSystem: reflect.TypeSystem; - template: any; - workingDirectory?: string; -} - -export class DeclarativeStack extends cdk.Stack { - constructor(scope: cdk.App, id: string, props: DeclarativeStackProps) { - super(scope, id); - - const typeSystem = props.typeSystem; - const template = props.template; - - const schema = renderFullSchema(typeSystem); - - const result = jsonschema.validate(template, schema); - if (!result.valid) { - throw new ValidationError('Schema validation errors:\n ' + result.errors.map(e => `"${e.property}" ${e.message}`).join('\n ')); - } - - // Replace every resource that starts with CDK:: - for (const [logicalId, resourceProps] of Object.entries(template.Resources || {})) { - const rprops: any = resourceProps; - if (!rprops.Type) { - throw new Error('Resource is missing type: ' + JSON.stringify(resourceProps)); - } - - if (isCfnResourceType(rprops.Type)) { - continue; - } - - const typeInfo = typeSystem.findFqn(rprops.Type + 'Props'); - const typeRef = new reflect.TypeReference(typeSystem, typeInfo); - const Ctor = resolveType(rprops.Type); - - // Changing working directory if needed, such that relative paths in the template are resolved relative to the - // template's location, and not to the current process' CWD. - _cwd(props.workingDirectory, () => - new Ctor(this, logicalId, deserializeValue(this, typeRef, true, 'Properties', rprops.Properties))); - - delete template.Resources[logicalId]; - } - - delete template.$schema; - - // Add an Include construct with what's left of the template - new cdk.CfnInclude(this, 'Include', { template }); - - // replace all "Fn::GetAtt" with tokens that resolve correctly both for - // constructs and raw resources. - processReferences(this); - } -} - -function resolveType(fqn: string) { - const [ mod, ...className ] = fqn.split('.'); - const module = require(mod); - return module[className.join('.')]; -} - -function tryResolveIntrinsic(value: any) { - if (Object.keys(value).length !== 1) { - return undefined; - } - - const name = Object.keys(value)[0]; - const val = value[name]; - return { name, val }; -} - -function tryResolveRef(value: any) { - const fn = tryResolveIntrinsic(value); - if (!fn) { - return undefined; - } - - if (fn.name !== 'Ref') { - return undefined; - } - - return fn.val; -} - -function tryResolveGetAtt(value: any) { - const fn = tryResolveIntrinsic(value); - if (!fn || fn.name !== 'Fn::GetAtt') { - return undefined; - } - - return fn.val; -} - -function deserializeValue(stack: cdk.Stack, typeRef: reflect.TypeReference, optional: boolean, key: string, value: any): any { - // console.error('====== deserializer ==================='); - // console.error(`type: ${typeRef}`); - // console.error(`value: ${JSON.stringify(value, undefined, 2)}`); - // console.error('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`'); - - if (value === undefined) { - if (optional) { - return undefined; - } - - throw new Error(`Missing required value for ${key} in ${typeRef}`); - } - - // deserialize arrays - if (typeRef.arrayOfType) { - if (!Array.isArray(value)) { - throw new Error(`Expecting array for ${key} in ${typeRef}`); - } - - return value.map((x, i) => deserializeValue(stack, typeRef.arrayOfType!, false, `${key}[${i}]`, x)); - } - - const asRef = tryResolveRef(value); - if (asRef) { - if (isConstruct(typeRef)) { - return findConstruct(stack, value.Ref); - } - - throw new Error( - `{ Ref } can only be used when a construct type is expected and this is ${typeRef}. ` + - `Use { Fn::GetAtt } to represent specific resource attributes`); - } - - const getAtt = tryResolveGetAtt(value); - if (getAtt) { - const [ logical, attr ] = getAtt; - - if (isConstruct(typeRef)) { - const obj: any = findConstruct(stack, logical); - return obj[attr]; - } - - if (typeRef.primitive === 'string') { - // return a lazy value, so we only try to find after all constructs - // have been added to the stack. - return deconstructGetAtt(stack, logical, attr); - } - - throw new Error(`Fn::GetAtt can only be used for string primitives and ${key} is ${typeRef}`); - } - - // deserialize maps - if (typeRef.mapOfType) { - if (typeof(value) !== 'object') { - throw new ValidationError(`Expecting object for ${key} in ${typeRef}`); - } - - const out: any = { }; - for (const [ k, v ] of Object.entries(value)) { - out[k] = deserializeValue(stack, typeRef.mapOfType, false, `${key}.${k}`, v); - } - - return out; - } - - if (typeRef.unionOfTypes) { - const errors = new Array(); - for (const x of typeRef.unionOfTypes) { - try { - return deserializeValue(stack, x, optional, key, value); - } catch (e) { - if (!(e instanceof ValidationError)) { - throw e; - } - errors.push(e); - continue; - } - } - - throw new ValidationError(`Failed to deserialize union. Errors: \n ${errors.map(e => e.message).join('\n ')}`); - } - - const enm = deconstructEnum(stack, typeRef, key, value); - if (enm) { - return enm; - } - - // if this is an interface, deserialize each property - const ifc = deconstructInterface(stack, typeRef, key, value); - if (ifc) { - return ifc; - } - - // if this is an enum type, use the name to dereference - if (typeRef.type instanceof reflect.EnumType) { - const enumType = resolveType(typeRef.type.fqn); - return enumType[value]; - } - - if (typeRef.primitive) { - return value; - } - - const enumLike = deconstructEnumLike(stack, typeRef, value); - if (enumLike) { - return enumLike; - } - - const asType = deconstructType(stack, typeRef, value); - if (asType) { - return asType; - } - - throw new Error(`Unable to deconstruct "${JSON.stringify(value)}" for type ref ${typeRef}`); -} - -function deconstructEnum(_stack: cdk.Stack, typeRef: reflect.TypeReference, _key: string, value: any) { - if (!(typeRef.type instanceof reflect.EnumType)) { - return undefined; - } - - const enumType = resolveType(typeRef.type.fqn); - return enumType[value]; -} - -function deconstructInterface(stack: cdk.Stack, typeRef: reflect.TypeReference, key: string, value: any) { - if (!isSerializableInterface(typeRef.type)) { - return undefined; - } - - const out: any = { }; - for (const prop of typeRef.type.allProperties) { - const propValue = value[prop.name]; - if (!propValue) { - if (!prop.optional) { - throw new ValidationError(`Missing required property ${key}.${prop.name} in ${typeRef}`); - } - continue; - } - - out[prop.name] = deserializeValue(stack, prop.type, prop.optional, `${key}.${prop.name}`, propValue); - } - - return out; -} - -function deconstructEnumLike(stack: cdk.Stack, typeRef: reflect.TypeReference, value: any) { - if (!isEnumLikeClass(typeRef.type)) { - return undefined; - } - - // if the value is a string, we deconstruct it as a static property - if (typeof(value) === 'string') { - return deconstructStaticProperty(typeRef.type, value); - } - - // if the value is an object, we deconstruct it as a static method - if (typeof(value) === 'object' && !Array.isArray(value)) { - return deconstructStaticMethod(stack, typeRef.type, value); - } - - throw new Error(`Invalid value for enum-like class ${typeRef.fqn}: ${JSON.stringify(value)}`); -} - -function deconstructType(stack: cdk.Stack, typeRef: reflect.TypeReference, value: any) { - const schemaDefs: any = {}; - const ctx = SchemaContext.root(schemaDefs); - const schemaRef = schemaForPolymorphic(typeRef.type, ctx); - if (!schemaRef) { - return undefined; - } - - const def = findDefinition(schemaDefs, schemaRef.$ref); - - const keys = Object.keys(value); - if (keys.length !== 1) { - throw new ValidationError(`Cannot parse class type ${typeRef} with value ${value}`); - } - - const className = keys[0]; - - // now we need to check if it's an enum or a normal class - const schema = def.anyOf.find((x: any) => x.properties && x.properties[className]); - if (!schema) { - throw new ValidationError(`Cannot find schema for ${className}`); - } - - const def2 = findDefinition(schemaDefs, schema.properties[className].$ref); - const methodFqn = def2.comment; - - const parts = methodFqn.split('.'); - const last = parts[parts.length - 1]; - if (last !== '') { - throw new Error(`Expectring an initializer`); - } - - const classFqn = parts.slice(0, parts.length - 1).join('.'); - const method = typeRef.system.findClass(classFqn).initializer; - if (!method) { - throw new Error(`Cannot find the initializer for ${classFqn}`); - } - - return invokeMethod(stack, method, value[className]); -} - -function findDefinition(defs: any, $ref: string) { - const k = $ref.split('/').slice(2).join('/'); - return defs[k]; -} - -function deconstructStaticProperty(typeRef: reflect.ClassType, value: string) { - const typeClass = resolveType(typeRef.fqn); - return typeClass[value]; -} - -function deconstructStaticMethod(stack: cdk.Stack, typeRef: reflect.ClassType, value: any) { - const methods = typeRef.allMethods.filter(m => m.static); - const members = methods.map(x => x.name); - - if (typeof(value) === 'object') { - const entries: Array<[ string, any ]> = Object.entries(value); - if (entries.length !== 1) { - throw new Error(`Value for enum-like class ${typeRef.fqn} must be an object with a single key (one of: ${members.join(',')})`); - } - - const [ methodName, args ] = entries[0]; - const method = methods.find(m => m.name === methodName); - if (!method) { - throw new Error(`Invalid member "${methodName}" for enum-like class ${typeRef.fqn}. Options: ${members.join(',')}`); - } - - if (typeof(args) !== 'object') { - throw new Error(`Expecting enum-like member ${methodName} to be an object for enum-like class ${typeRef.fqn}`); - } - - return invokeMethod(stack, method, args); - } -} - -function invokeMethod(stack: cdk.Stack, method: reflect.Callable, parameters: any) { - const typeClass = resolveType(method.parentType.fqn); - const args = new Array(); - - for (let i = 0; i < method.parameters.length; ++i) { - const p = method.parameters[i]; - - // kwargs: if this is the last argument and a data type, flatten (treat as keyword args) - if (i === method.parameters.length - 1 && isDataType(p.type.type)) { - // we pass in all parameters are the value, and the positional arguments will be ignored since - // we are promised there are no conflicts - const kwargs = deserializeValue(stack, p.type, p.optional, p.name, parameters); - args.push(kwargs); - } else { - const val = parameters[p.name]; - if (val === undefined && !p.optional) { - throw new Error(`Missing required parameter '${p.name}' for ${method.parentType.fqn}.${method.name}`); - } - - if (val !== undefined) { - args.push(deserializeValue(stack, p.type, p.optional, p.name, val)); - } - } - } - - if (reflect.Initializer.isInitializer(method)) { - return new typeClass(...args); - } - - const methodFn: (...args: any[]) => any = typeClass[method.name]; - if (!methodFn) { - throw new Error(`Cannot find method named ${method.name} in ${typeClass.fqn}`); - } - - return methodFn.apply(typeClass, args); -} - -/** - * Returns a lazy string that includes a deconstructed Fn::GetAt to a certain - * resource or construct. - * - * If `id` points to a CDK construct, the resolved value will be the value returned by - * the property `attribute`. If `id` points to a "raw" resource, the resolved value will be - * an `Fn::GetAtt`. - */ -function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { - return cdk.Lazy.string({ produce: () => { - const res = stack.node.tryFindChild(id); - if (!res) { - const include = stack.node.tryFindChild('Include') as cdk.CfnInclude; - if (!include) { - throw new Error(`Unexpected - "Include" should be in the stack at this point`); - } - - const raw = (include.template as any).Resources[id]; - if (!raw) { - throw new Error(`Unable to find a resource ${id}`); - } - - // just leak - return { "Fn::GetAtt": [ id, attribute ] }; - } - return (res as any)[attribute]; - }}); -} - -function findConstruct(stack: cdk.Stack, id: string) { - const child = stack.node.tryFindChild(id); - if (!child) { - throw new Error(`Construct with ID ${id} not found (it must be defined before it is referenced)`); - } - return child; -} - -function processReferences(stack: cdk.Stack) { - const include = stack.node.findChild('Include') as cdk.CfnInclude; - if (!include) { - throw new Error('Unexpected'); - } - - process(include.template as any); - - function process(value: any): any { - if (typeof(value) === 'object' && Object.keys(value).length === 1 && Object.keys(value)[0] === 'Fn::GetAtt') { - const [ id, attribute ] = value['Fn::GetAtt']; - return deconstructGetAtt(stack, id, attribute); - } - - if (Array.isArray(value)) { - return value.map(x => process(x)); - } - - if (typeof(value) === 'object') { - for (const [ k, v ] of Object.entries(value)) { - value[k] = process(v); - } - return value; - } - - return value; - } -} - -function isCfnResourceType(resourceType: string) { - return resourceType.includes('::'); -} - -class ValidationError extends Error { } - -function _cwd(workDir: string | undefined, cb: () => T): T { - if (!workDir) { return cb(); } - const prevWd = process.cwd(); - try { - process.chdir(workDir); - return cb(); - } finally { - process.chdir(prevWd); - } -} diff --git a/packages/decdk/lib/index.ts b/packages/decdk/lib/index.ts deleted file mode 100644 index f095ba5e406a8..0000000000000 --- a/packages/decdk/lib/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './declarative-stack'; -export * from './jsii2schema'; -export * from './util'; \ No newline at end of file diff --git a/packages/decdk/lib/jsii2schema.ts b/packages/decdk/lib/jsii2schema.ts deleted file mode 100644 index 2b490d7df2125..0000000000000 --- a/packages/decdk/lib/jsii2schema.ts +++ /dev/null @@ -1,593 +0,0 @@ -import * as jsiiReflect from 'jsii-reflect'; -import * as util from 'util'; - -/* eslint-disable no-console */ - -export class SchemaContext { - public static root(definitions?: { [fqn: string]: any }): SchemaContext { - return new SchemaContext(undefined, undefined, definitions); - } - - public readonly definitions: { [fqn: string]: any }; - public readonly path: string; - public readonly children = new Array(); - public readonly name: string; - public readonly root: boolean; - public readonly warnings = new Array(); - public readonly errors = new Array(); - - private readonly definitionStack: string[]; - - private constructor(name?: string, parent?: SchemaContext, definitions?: { [fqn: string]: any }) { - this.name = name || ''; - if (parent) { - this.root = false; - parent.children.push(this); - this.definitions = parent.definitions; - this.path = parent.path + '/' + this.name; - this.definitionStack = parent.definitionStack; - } else { - this.root = true; - this.definitions = definitions || { }; - this.path = this.name || ''; - this.definitionStack = new Array(); - } - } - - public child(type: string, name: string): SchemaContext { - return new SchemaContext(`[${type} "${name}"]`, this); - } - - public get hasWarningsOrErrors(): boolean { - return this.warnings.length > 0 || this.errors.length > 0 || this.children.some(child => child.hasWarningsOrErrors); - } - - public warning(format: any, ...args: any[]) { - this.warnings.push(util.format(format, ...args)); - } - - public error(format: any, ...args: any[]) { - this.errors.push(util.format(format, ...args)); - } - - public findDefinition(ref: string) { - const [ , , id ] = ref.split('/'); - return this.definitions[id]; - } - - public define(fqn: string, schema: () => any) { - const originalFqn = fqn; - fqn = fqn.replace('/', '.'); - - if (!(fqn in this.definitions)) { - if (this.definitionStack.includes(fqn)) { - this.error(`cyclic definition of ${fqn}`); - return undefined; - } - - this.definitionStack.push(fqn); - - try { - const s = schema(); - if (!s) { - this.error('cannot schematize'); - return undefined; - } - - s.comment = originalFqn; - - this.definitions[fqn] = s; - } finally { - this.definitionStack.pop(); - } - } - - return { $ref: `#/definitions/${fqn}` }; - } -} - -export function schemaForTypeReference(type: jsiiReflect.TypeReference, ctx: SchemaContext): any { - - const prim = schemaForPrimitive(type); - if (prim) { - return prim; - } - - const arr = schemaForArray(type, ctx); - if (arr) { - return arr; - } - - const map = schemaForMap(type, ctx); - if (map) { - return map; - } - - const union = schemaForUnion(type, ctx); - if (union) { - return union; - } - - const constructRef = schemaForConstructRef(type); - if (constructRef) { - return constructRef; - } - - const iface = schemaForInterface(type.type, ctx); - if (iface) { - return iface; - } - - const enm = schemaForEnum(type.type); - if (enm) { - return enm; - } - - const enumLike = schemaForEnumLikeClass(type.type, ctx); - if (enumLike) { - return enumLike; - } - - const cls = schemaForPolymorphic(type.type, ctx); - if (cls) { - return cls; - } - - if (!ctx.hasWarningsOrErrors) { - ctx.error(`didn't match any schematizable shape`); - } - - return undefined; -} - -export function schemaForPolymorphic(type: jsiiReflect.Type | undefined, ctx: SchemaContext) { - if (!type) { - return undefined; - } - - ctx = ctx.child('polymorphic', type.fqn); - - const anyOf = new Array(); - - const parentctx = ctx; - - for (const x of allImplementationsOfType(type)) { - - ctx = parentctx.child('impl', x.fqn); - - const enumLike = schemaForEnumLikeClass(x, ctx); - if (enumLike) { - anyOf.push(enumLike); - } - - if (x.initializer) { - const methd = methodSchema(x.initializer, ctx); - if (methd) { - anyOf.push({ - type: 'object', - additionalProperties: false, - properties: { - [x.fqn]: methd - } - }); - } - } - } - - if (anyOf.length === 0) { - return undefined; - } - - return ctx.define(type.fqn, () => { - return { anyOf }; - }); -} - -function schemaForEnum(type: jsiiReflect.Type | undefined) { - if (!type || !(type instanceof jsiiReflect.EnumType)) { - return undefined; - } - - return { - enum: type.members.map(m => m.name) - }; -} - -function schemaForMap(type: jsiiReflect.TypeReference, ctx: SchemaContext) { - ctx = ctx.child('map', type.toString()); - - if (!type.mapOfType) { - return undefined; - } - - const s = schemaForTypeReference(type.mapOfType, ctx); - if (!s) { - return undefined; - } - - return { - type: 'object', - additionalProperties: s - }; -} - -function schemaForArray(type: jsiiReflect.TypeReference, ctx: SchemaContext) { - ctx = ctx.child('array', type.toString()); - - if (!type.arrayOfType) { - return undefined; - } - - const s = schemaForTypeReference(type.arrayOfType, ctx); - if (!s) { - return undefined; - } - - return { - type: 'array', - items: schemaForTypeReference(type.arrayOfType, ctx) - }; -} - -function schemaForPrimitive(type: jsiiReflect.TypeReference): any { - if (!type.primitive) { - return undefined; - } - - switch (type.primitive) { - case 'date': return { type: 'string', format: 'date-time' }; - case 'json': return { type: 'object' }; - case 'any': return { }; // this means "any" - default: return { type: type.primitive }; - } -} - -function schemaForUnion(type: jsiiReflect.TypeReference, ctx: SchemaContext): any { - ctx = ctx.child('union', type.toString()); - - if (!type.unionOfTypes) { - return undefined; - } - - const anyOf = type.unionOfTypes - .map(x => schemaForTypeReference(x, ctx)) - .filter(x => x); // filter failed schemas - - if (anyOf.length === 0) { - return undefined; - } - - return { anyOf }; -} - -function schemaForConstructRef(type: jsiiReflect.TypeReference) { - if (!isConstruct(type)) { - return undefined; - } - - return { - type: 'object', - properties: { - Ref: { type: 'string' } - } - }; -} - -export function schemaForInterface(type: jsiiReflect.Type | undefined, ctx: SchemaContext) { - if (!type || !(type instanceof jsiiReflect.InterfaceType)) { - return undefined; // skip - } - - if (type.allMethods.length > 0) { - return undefined; - } - - ctx = ctx.child('interface', type.fqn); - - const ifctx = ctx; - - return ctx.define(type.fqn, () => { - const properties: any = {}; - const required = new Array(); - - for (const prop of type.allProperties) { - - ctx = ifctx.child(prop.optional ? 'optional' : 'required' + ' property', prop.name); - - const schema = schemaForTypeReference(prop.type, ctx); - if (!schema) { - // if prop is not serializable but optional, we can still serialize - // but without this property. - if (prop.optional) { - ctx.warning(`optional proprety omitted because it cannot be schematized`); - continue; - } - - // error - ctx.error('property cannot be schematized'); - return undefined; - } - - properties[prop.name] = schema; - - const docstring = prop.docs.toString(); - if (docstring) { - properties[prop.name].description = docstring; - } - - if (!prop.optional) { - required.push(prop.name); - } - } - - return { - type: 'object', - title: type.name, - additionalProperties: false, - properties, - required: required.length > 0 ? required : undefined, - }; - }); -} - -function schemaForEnumLikeClass(type: jsiiReflect.Type | undefined, ctx: SchemaContext) { - if (type) { - ctx = ctx.child('enum-like', type.toString()); - } - - if (!type || !(type instanceof jsiiReflect.ClassType)) { - return undefined; - } - - const enumLikeProps = enumLikeClassProperties(type); - const enumLikeMethods = enumLikeClassMethods(type); - - if (enumLikeProps.length === 0 && enumLikeMethods.length === 0) { - return undefined; - } - - const anyOf = new Array(); - - if (enumLikeProps.length > 0) { - anyOf.push({ enum: enumLikeProps.map(m => m.name) }); - } - - for (const method of enumLikeMethods) { - const s = methodSchema(method, ctx); - if (!s) { - continue; - } - - anyOf.push({ - type: 'object', - additionalProperties: false, - properties: { - [method.name]: methodSchema(method, ctx) - } - }); - } - - if (anyOf.length === 0) { - return undefined; - } - - return ctx.define(type.fqn, () => { - return { anyOf }; - }); -} - -function methodSchema(method: jsiiReflect.Callable, ctx: SchemaContext) { - ctx = ctx.child('method', method.name); - - const fqn = `${method.parentType.fqn}.${method.name}`; - - const methodctx = ctx; - - return ctx.define(fqn, () => { - const properties: any = { }; - const required = new Array(); - - const addProperty = (prop: jsiiReflect.Property | jsiiReflect.Parameter): void => { - const param = schemaForTypeReference(prop.type, ctx); - - // bail out - can't serialize a required parameter, so we can't serialize the method - if (!param && !prop.optional) { - ctx.error(`cannot schematize method because parameter cannot be schematized`); - return undefined; - } - - properties[prop.name] = param; - - if (!prop.optional) { - required.push(prop.name); - } - }; - - for (let i = 0; i < method.parameters.length; ++i) { - const p = method.parameters[i]; - methodctx.child('param', p.name); - - // if this is the last parameter and it's a data type, treat as keyword arguments - if (i === method.parameters.length - 1 && isDataType(p.type.type)) { - const kwargs = schemaForInterface(p.type.type, ctx); - if (kwargs) { - for (const prop of p.type.type.allProperties) { - addProperty(prop); - } - } - } else { - addProperty(p); - } - } - - return { - type: 'object', - properties, - additionalProperties: false, - required: required.length > 0 ? required : undefined - }; - }); -} - -export function isDataType(t: jsiiReflect.Type | undefined): t is jsiiReflect.InterfaceType { - if (!t) { - return false; - } - return t instanceof jsiiReflect.InterfaceType && (t as any).spec.datatype; -} - -// Must only have properties, all of which are scalars, -// lists or isSerializableInterface types. -export function isSerializableTypeReference(type: jsiiReflect.TypeReference, errorPrefix?: string): boolean { - - if (type.primitive) { - return true; - } - - if (type.arrayOfType) { - return isSerializableTypeReference(type.arrayOfType, errorPrefix); - } - - if (type.mapOfType) { - return isSerializableTypeReference(type.mapOfType, errorPrefix); - } - - if (type.type) { - return isSerializableType(type.type, errorPrefix); - } - - if (type.unionOfTypes) { - return type.unionOfTypes.some(x => isSerializableTypeReference(x, errorPrefix)); - } - - return false; -} - -function isSerializableType(type: jsiiReflect.Type, errorPrefix?: string): boolean { - // if this is a cosntruct class, we can represent it as a "Ref" - if (isConstruct(type)) { - return true; - } - - if (isEnum(type)) { - return true; - } - - if (isSerializableInterface(type)) { - return true; - } - - // if this is a class that looks like an enum, we can represent it - if (isEnumLikeClass(type)) { - return true; - } - - if (allImplementationsOfType(type).length > 0) { - return true; - } - - if (errorPrefix) { - console.error(errorPrefix, `${type} is not serializable`); - } - - return false; -} - -export function isSerializableInterface(type: jsiiReflect.Type | undefined, errorPrefix?: string): type is jsiiReflect.InterfaceType { - if (!type || !(type instanceof jsiiReflect.InterfaceType)) { - return false; - } - - if (type.allMethods.length > 0) { - return false; - } - - return type.allProperties.every(p => - isSerializableTypeReference(p.type, errorPrefix) - || isConstruct(p.type) - || p.optional); -} - -function isEnum(type: jsiiReflect.Type): type is jsiiReflect.EnumType { - return type instanceof jsiiReflect.EnumType; -} - -export function isEnumLikeClass(cls: jsiiReflect.Type | undefined): cls is jsiiReflect.ClassType { - if (!cls) { - return false; - } - - if (!(cls instanceof jsiiReflect.ClassType)) { - return false; - } - return enumLikeClassMethods(cls).length > 0 - || enumLikeClassProperties(cls).length > 0; -} - -export function enumLikeClassMethods(cls: jsiiReflect.ClassType) { - return cls.allMethods.filter(m => m.static && m.returns && m.returns.type.type && m.returns.type.type.extends(cls)); -} - -export function enumLikeClassProperties(cls: jsiiReflect.ClassType) { - return cls.allProperties.filter(p => p.static && p.type.type && p.type.type.extends(cls)); -} - -export function isConstruct(typeOrTypeRef: jsiiReflect.TypeReference | jsiiReflect.Type): boolean { - let type: jsiiReflect.Type; - - if (typeOrTypeRef instanceof jsiiReflect.Type) { - type = typeOrTypeRef; - } else { - if (typeOrTypeRef.arrayOfType) { - return isConstruct(typeOrTypeRef.arrayOfType); - } - - if (typeOrTypeRef.mapOfType) { - return isConstruct(typeOrTypeRef.mapOfType); - } - - if (typeOrTypeRef.unionOfTypes) { - return typeOrTypeRef.unionOfTypes.some(x => isConstruct(x)); - } - - if (typeOrTypeRef.type) { - type = typeOrTypeRef.type; - } else { - return false; - } - } - - // if it is an interface, it should extend constructs.IConstruct - if (type instanceof jsiiReflect.InterfaceType) { - const constructIface = type.system.findFqn('constructs.IConstruct'); - return type.extends(constructIface); - } - - // if it is a class, it should extend constructs.Construct - if (type instanceof jsiiReflect.ClassType) { - const constructClass = type.system.findFqn('constructs.Construct'); - return type.extends(constructClass); - } - - return false; -} - -function allImplementationsOfType(type: jsiiReflect.Type) { - if (type instanceof jsiiReflect.ClassType) { - return allSubclasses(type).filter(x => !x.abstract); - } - - if (type instanceof jsiiReflect.InterfaceType) { - return allImplementations(type).filter(x => !x.abstract); - } - - throw new Error(`Must either be a class or an interface`); -} - -function allSubclasses(base: jsiiReflect.ClassType) { - return base.system.classes.filter(x => x.extends(base)); -} - -function allImplementations(base: jsiiReflect.InterfaceType) { - return base.system.classes.filter(x => x.getInterfaces(true).some(i => i.extends(base))); -} diff --git a/packages/decdk/lib/util.ts b/packages/decdk/lib/util.ts deleted file mode 100644 index 4378ba01c8223..0000000000000 --- a/packages/decdk/lib/util.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as fs from 'fs-extra'; -import * as jsiiReflect from 'jsii-reflect'; -import * as path from 'path'; -import * as YAML from 'yaml'; - -/** - * Reads a YAML/JSON template file. - */ -export async function readTemplate(templateFile: string) { - const str = await fs.readFile(templateFile, { encoding: 'utf-8' }); - const template = YAML.parse(str, { schema: 'yaml-1.1' }); - return template; -} - -export async function loadTypeSystem(validate = true) { - const typeSystem = new jsiiReflect.TypeSystem(); - await typeSystem.loadNpmDependencies(path.resolve(__dirname, '..'), { validate }); - return typeSystem; -} - -export function stackNameFromFileName(fileName: string) { - return path.parse(fileName).name.replace('.', '-'); -} diff --git a/packages/decdk/package.json b/packages/decdk/package.json deleted file mode 100644 index d53367fd2dfec..0000000000000 --- a/packages/decdk/package.json +++ /dev/null @@ -1,282 +0,0 @@ -{ - "name": "decdk", - "version": "0.0.0", - "description": "Declarative CDK: a CloudFormation-like syntax for defining CDK stacks", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "repository": { - "type": "git", - "url": "https://github.com/aws/aws-cdk.git" - }, - "bin": { - "decdk": "bin/decdk", - "decdk-schema": "bin/decdk-schema" - }, - "scripts": { - "build": "node ./deps.js && tsc -b && chmod +x bin/decdk && chmod +x bin/decdk-schema && bin/decdk-schema > cdk.schema.json", - "watch": "tsc -b -w", - "test": "jest", - "package": "mkdir -p dist/js && cd dist/js && npm pack ../../", - "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package", - "build+test+extract": "npm run build+test", - "build+extract": "npm run build" - }, - "author": { - "name": "Amazon Web Services", - "url": "https://aws.amazon.com", - "organization": true - }, - "license": "Apache-2.0", - "dependencies": { - "@aws-cdk/alexa-ask": "0.0.0", - "@aws-cdk/assertions": "0.0.0", - "@aws-cdk/assets": "0.0.0", - "@aws-cdk/aws-accessanalyzer": "0.0.0", - "@aws-cdk/aws-acmpca": "0.0.0", - "@aws-cdk/aws-amazonmq": "0.0.0", - "@aws-cdk/aws-amplify": "0.0.0", - "@aws-cdk/aws-amplifyuibuilder": "0.0.0", - "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", - "@aws-cdk/aws-apigatewayv2-authorizers": "0.0.0", - "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", - "@aws-cdk/aws-appconfig": "0.0.0", - "@aws-cdk/aws-appflow": "0.0.0", - "@aws-cdk/aws-appintegrations": "0.0.0", - "@aws-cdk/aws-applicationautoscaling": "0.0.0", - "@aws-cdk/aws-applicationinsights": "0.0.0", - "@aws-cdk/aws-appmesh": "0.0.0", - "@aws-cdk/aws-apprunner": "0.0.0", - "@aws-cdk/aws-appstream": "0.0.0", - "@aws-cdk/aws-appsync": "0.0.0", - "@aws-cdk/aws-aps": "0.0.0", - "@aws-cdk/aws-athena": "0.0.0", - "@aws-cdk/aws-auditmanager": "0.0.0", - "@aws-cdk/aws-autoscaling": "0.0.0", - "@aws-cdk/aws-autoscaling-common": "0.0.0", - "@aws-cdk/aws-autoscaling-hooktargets": "0.0.0", - "@aws-cdk/aws-autoscalingplans": "0.0.0", - "@aws-cdk/aws-backup": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", - "@aws-cdk/aws-budgets": "0.0.0", - "@aws-cdk/aws-cassandra": "0.0.0", - "@aws-cdk/aws-ce": "0.0.0", - "@aws-cdk/aws-certificatemanager": "0.0.0", - "@aws-cdk/aws-chatbot": "0.0.0", - "@aws-cdk/aws-cloud9": "0.0.0", - "@aws-cdk/aws-cloudformation": "0.0.0", - "@aws-cdk/aws-cloudfront": "0.0.0", - "@aws-cdk/aws-cloudfront-origins": "0.0.0", - "@aws-cdk/aws-cloudtrail": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/aws-cloudwatch-actions": "0.0.0", - "@aws-cdk/aws-codeartifact": "0.0.0", - "@aws-cdk/aws-codebuild": "0.0.0", - "@aws-cdk/aws-codecommit": "0.0.0", - "@aws-cdk/aws-codedeploy": "0.0.0", - "@aws-cdk/aws-codeguruprofiler": "0.0.0", - "@aws-cdk/aws-codegurureviewer": "0.0.0", - "@aws-cdk/aws-codepipeline": "0.0.0", - "@aws-cdk/aws-codepipeline-actions": "0.0.0", - "@aws-cdk/aws-codestar": "0.0.0", - "@aws-cdk/aws-codestarconnections": "0.0.0", - "@aws-cdk/aws-codestarnotifications": "0.0.0", - "@aws-cdk/aws-cognito": "0.0.0", - "@aws-cdk/aws-cognito-identitypool": "0.0.0", - "@aws-cdk/aws-config": "0.0.0", - "@aws-cdk/aws-connect": "0.0.0", - "@aws-cdk/aws-cur": "0.0.0", - "@aws-cdk/aws-customerprofiles": "0.0.0", - "@aws-cdk/aws-databrew": "0.0.0", - "@aws-cdk/aws-datapipeline": "0.0.0", - "@aws-cdk/aws-datasync": "0.0.0", - "@aws-cdk/aws-dax": "0.0.0", - "@aws-cdk/aws-detective": "0.0.0", - "@aws-cdk/aws-devopsguru": "0.0.0", - "@aws-cdk/aws-directoryservice": "0.0.0", - "@aws-cdk/aws-dlm": "0.0.0", - "@aws-cdk/aws-dms": "0.0.0", - "@aws-cdk/aws-docdb": "0.0.0", - "@aws-cdk/aws-dynamodb": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", - "@aws-cdk/aws-ecr": "0.0.0", - "@aws-cdk/aws-ecr-assets": "0.0.0", - "@aws-cdk/aws-ecs": "0.0.0", - "@aws-cdk/aws-ecs-patterns": "0.0.0", - "@aws-cdk/aws-efs": "0.0.0", - "@aws-cdk/aws-eks": "0.0.0", - "@aws-cdk/aws-elasticache": "0.0.0", - "@aws-cdk/aws-elasticbeanstalk": "0.0.0", - "@aws-cdk/aws-elasticloadbalancing": "0.0.0", - "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "@aws-cdk/aws-elasticloadbalancingv2-actions": "0.0.0", - "@aws-cdk/aws-elasticloadbalancingv2-targets": "0.0.0", - "@aws-cdk/aws-elasticsearch": "0.0.0", - "@aws-cdk/aws-emr": "0.0.0", - "@aws-cdk/aws-emrcontainers": "0.0.0", - "@aws-cdk/aws-events": "0.0.0", - "@aws-cdk/aws-events-targets": "0.0.0", - "@aws-cdk/aws-eventschemas": "0.0.0", - "@aws-cdk/aws-evidently": "0.0.0", - "@aws-cdk/aws-finspace": "0.0.0", - "@aws-cdk/aws-fis": "0.0.0", - "@aws-cdk/aws-fms": "0.0.0", - "@aws-cdk/aws-forecast": "0.0.0", - "@aws-cdk/aws-frauddetector": "0.0.0", - "@aws-cdk/aws-fsx": "0.0.0", - "@aws-cdk/aws-gamelift": "0.0.0", - "@aws-cdk/aws-globalaccelerator": "0.0.0", - "@aws-cdk/aws-globalaccelerator-endpoints": "0.0.0", - "@aws-cdk/aws-glue": "0.0.0", - "@aws-cdk/aws-greengrass": "0.0.0", - "@aws-cdk/aws-greengrassv2": "0.0.0", - "@aws-cdk/aws-groundstation": "0.0.0", - "@aws-cdk/aws-guardduty": "0.0.0", - "@aws-cdk/aws-healthlake": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-imagebuilder": "0.0.0", - "@aws-cdk/aws-inspector": "0.0.0", - "@aws-cdk/aws-inspectorv2": "0.0.0", - "@aws-cdk/aws-iot": "0.0.0", - "@aws-cdk/aws-iot-actions": "0.0.0", - "@aws-cdk/aws-iot1click": "0.0.0", - "@aws-cdk/aws-iotanalytics": "0.0.0", - "@aws-cdk/aws-iotcoredeviceadvisor": "0.0.0", - "@aws-cdk/aws-iotevents": "0.0.0", - "@aws-cdk/aws-iotfleethub": "0.0.0", - "@aws-cdk/aws-iotsitewise": "0.0.0", - "@aws-cdk/aws-iotthingsgraph": "0.0.0", - "@aws-cdk/aws-iotwireless": "0.0.0", - "@aws-cdk/aws-ivs": "0.0.0", - "@aws-cdk/aws-kendra": "0.0.0", - "@aws-cdk/aws-kinesis": "0.0.0", - "@aws-cdk/aws-kinesisanalytics": "0.0.0", - "@aws-cdk/aws-kinesisanalytics-flink": "0.0.0", - "@aws-cdk/aws-kinesisanalyticsv2": "0.0.0", - "@aws-cdk/aws-kinesisfirehose": "0.0.0", - "@aws-cdk/aws-kinesisfirehose-destinations": "0.0.0", - "@aws-cdk/aws-kinesisvideo": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/aws-lakeformation": "0.0.0", - "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-lambda-destinations": "0.0.0", - "@aws-cdk/aws-lambda-event-sources": "0.0.0", - "@aws-cdk/aws-lambda-go": "0.0.0", - "@aws-cdk/aws-lambda-nodejs": "0.0.0", - "@aws-cdk/aws-lambda-python": "0.0.0", - "@aws-cdk/aws-lex": "0.0.0", - "@aws-cdk/aws-licensemanager": "0.0.0", - "@aws-cdk/aws-lightsail": "0.0.0", - "@aws-cdk/aws-location": "0.0.0", - "@aws-cdk/aws-logs": "0.0.0", - "@aws-cdk/aws-logs-destinations": "0.0.0", - "@aws-cdk/aws-lookoutequipment": "0.0.0", - "@aws-cdk/aws-lookoutmetrics": "0.0.0", - "@aws-cdk/aws-lookoutvision": "0.0.0", - "@aws-cdk/aws-macie": "0.0.0", - "@aws-cdk/aws-managedblockchain": "0.0.0", - "@aws-cdk/aws-mediaconnect": "0.0.0", - "@aws-cdk/aws-mediaconvert": "0.0.0", - "@aws-cdk/aws-medialive": "0.0.0", - "@aws-cdk/aws-mediapackage": "0.0.0", - "@aws-cdk/aws-mediastore": "0.0.0", - "@aws-cdk/aws-memorydb": "0.0.0", - "@aws-cdk/aws-msk": "0.0.0", - "@aws-cdk/aws-mwaa": "0.0.0", - "@aws-cdk/aws-neptune": "0.0.0", - "@aws-cdk/aws-networkfirewall": "0.0.0", - "@aws-cdk/aws-networkmanager": "0.0.0", - "@aws-cdk/aws-nimblestudio": "0.0.0", - "@aws-cdk/aws-opensearchservice": "0.0.0", - "@aws-cdk/aws-opsworks": "0.0.0", - "@aws-cdk/aws-opsworkscm": "0.0.0", - "@aws-cdk/aws-panorama": "0.0.0", - "@aws-cdk/aws-pinpoint": "0.0.0", - "@aws-cdk/aws-pinpointemail": "0.0.0", - "@aws-cdk/aws-qldb": "0.0.0", - "@aws-cdk/aws-quicksight": "0.0.0", - "@aws-cdk/aws-ram": "0.0.0", - "@aws-cdk/aws-rds": "0.0.0", - "@aws-cdk/aws-redshift": "0.0.0", - "@aws-cdk/aws-refactorspaces": "0.0.0", - "@aws-cdk/aws-rekognition": "0.0.0", - "@aws-cdk/aws-resiliencehub": "0.0.0", - "@aws-cdk/aws-resourcegroups": "0.0.0", - "@aws-cdk/aws-robomaker": "0.0.0", - "@aws-cdk/aws-route53": "0.0.0", - "@aws-cdk/aws-route53-patterns": "0.0.0", - "@aws-cdk/aws-route53-targets": "0.0.0", - "@aws-cdk/aws-route53recoverycontrol": "0.0.0", - "@aws-cdk/aws-route53recoveryreadiness": "0.0.0", - "@aws-cdk/aws-route53resolver": "0.0.0", - "@aws-cdk/aws-rum": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/aws-s3-deployment": "0.0.0", - "@aws-cdk/aws-s3-notifications": "0.0.0", - "@aws-cdk/aws-s3objectlambda": "0.0.0", - "@aws-cdk/aws-s3outposts": "0.0.0", - "@aws-cdk/aws-sagemaker": "0.0.0", - "@aws-cdk/aws-sam": "0.0.0", - "@aws-cdk/aws-sdb": "0.0.0", - "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/aws-securityhub": "0.0.0", - "@aws-cdk/aws-servicecatalog": "0.0.0", - "@aws-cdk/aws-servicecatalogappregistry": "0.0.0", - "@aws-cdk/aws-servicediscovery": "0.0.0", - "@aws-cdk/aws-ses": "0.0.0", - "@aws-cdk/aws-ses-actions": "0.0.0", - "@aws-cdk/aws-signer": "0.0.0", - "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-sns-subscriptions": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", - "@aws-cdk/aws-ssm": "0.0.0", - "@aws-cdk/aws-ssmcontacts": "0.0.0", - "@aws-cdk/aws-ssmincidents": "0.0.0", - "@aws-cdk/aws-sso": "0.0.0", - "@aws-cdk/aws-stepfunctions": "0.0.0", - "@aws-cdk/aws-stepfunctions-tasks": "0.0.0", - "@aws-cdk/aws-synthetics": "0.0.0", - "@aws-cdk/aws-timestream": "0.0.0", - "@aws-cdk/aws-transfer": "0.0.0", - "@aws-cdk/aws-waf": "0.0.0", - "@aws-cdk/aws-wafregional": "0.0.0", - "@aws-cdk/aws-wafv2": "0.0.0", - "@aws-cdk/aws-wisdom": "0.0.0", - "@aws-cdk/aws-workspaces": "0.0.0", - "@aws-cdk/aws-xray": "0.0.0", - "@aws-cdk/cfnspec": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/core": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/lambda-layer-awscli": "0.0.0", - "@aws-cdk/lambda-layer-kubectl": "0.0.0", - "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", - "@aws-cdk/pipelines": "0.0.0", - "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.3.69", - "fs-extra": "^9.1.0", - "jsii-reflect": "^1.52.1", - "jsonschema": "^1.4.0", - "yaml": "1.10.2", - "yargs": "^16.2.0" - }, - "devDependencies": { - "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.4.0", - "@types/yaml": "1.9.7", - "@types/yargs": "^15.0.14", - "jest": "^27.4.7", - "jsii": "^1.52.1" - }, - "keywords": [ - "aws", - "cdk" - ], - "homepage": "https://github.com/aws/aws-cdk", - "engines": { - "node": ">= 8.10.0" - } -} diff --git a/packages/decdk/test/__snapshots__/synth.test.js.snap b/packages/decdk/test/__snapshots__/synth.test.js.snap deleted file mode 100644 index 93c4dfdf336c4..0000000000000 --- a/packages/decdk/test/__snapshots__/synth.test.js.snap +++ /dev/null @@ -1,3254 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`apigw.json: apigw 1`] = ` -Object { - "Outputs": Object { - "MyApiEndpoint869ABE96": Object { - "Value": Object { - "Fn::Join": Array [ - "", - Array [ - "https://", - Object { - "Ref": "MyApi49610EDF", - }, - ".execute-api.", - Object { - "Ref": "AWS::Region", - }, - ".", - Object { - "Ref": "AWS::URLSuffix", - }, - "/", - Object { - "Ref": "MyApiDeploymentStageprodE1054AF0", - }, - "/", - ], - ], - }, - }, - }, - "Parameters": Object { - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cArtifactHash47CFB54E": Object { - "Description": "Artifact hash for asset \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3Bucket0D05C9AA": Object { - "Description": "S3 bucket for asset \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3": Object { - "Description": "S3 key for asset version \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - }, - "Resources": Object { - "GetRootA9424890": Object { - "Properties": Object { - "AuthorizationType": "NONE", - "HttpMethod": "GET", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", - Object { - "Ref": "AWS::Region", - }, - ":lambda:path/2015-03-31/functions/", - Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "/invocations", - ], - ], - }, - }, - "ResourceId": Object { - "Fn::GetAtt": Array [ - "MyApi49610EDF", - "RootResourceId", - ], - }, - "RestApiId": Object { - "Ref": "MyApi49610EDF", - }, - }, - "Type": "AWS::ApiGateway::Method", - }, - "GetRootApiPermissionTestapigwMyApiCBFBC5B0GET5B244F0C": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "MyApi49610EDF", - }, - "/test-invoke-stage/GET/", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "GetRootApiPermissionapigwMyApiCBFBC5B0GETC314E626": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "MyApi49610EDF", - }, - "/", - Object { - "Ref": "MyApiDeploymentStageprodE1054AF0", - }, - "/GET/", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "HelloLambda3D9C82D6": Object { - "DependsOn": Array [ - "HelloLambdaServiceRoleE071F162", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3Bucket0D05C9AA", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "HelloLambdaServiceRoleE071F162", - "Arn", - ], - }, - "Runtime": "python3.6", - }, - "Type": "AWS::Lambda::Function", - }, - "HelloLambdaServiceRoleE071F162": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "MyApi49610EDF": Object { - "Properties": Object { - "Name": "MyApi", - }, - "Type": "AWS::ApiGateway::RestApi", - }, - "MyApiANYApiPermissionTestapigwMyApiCBFBC5B0ANYAD86D377": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "MyApi49610EDF", - }, - "/test-invoke-stage/*/", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "MyApiANYApiPermissionapigwMyApiCBFBC5B0ANY5BBED348": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "MyApi49610EDF", - }, - "/", - Object { - "Ref": "MyApiDeploymentStageprodE1054AF0", - }, - "/*/", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "MyApiANYEC3618D9": Object { - "Properties": Object { - "AuthorizationType": "NONE", - "HttpMethod": "ANY", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", - Object { - "Ref": "AWS::Region", - }, - ":lambda:path/2015-03-31/functions/", - Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "/invocations", - ], - ], - }, - }, - "ResourceId": Object { - "Fn::GetAtt": Array [ - "MyApi49610EDF", - "RootResourceId", - ], - }, - "RestApiId": Object { - "Ref": "MyApi49610EDF", - }, - }, - "Type": "AWS::ApiGateway::Method", - }, - "MyApiAccount13882D84": Object { - "DependsOn": Array [ - "MyApi49610EDF", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "MyApiCloudWatchRole2BEC1A9C", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "MyApiCloudWatchRole2BEC1A9C": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "MyApiDeploymentECB0D05E0597cc4592870e54c401cccc6090bd86": Object { - "DependsOn": Array [ - "GetRootA9424890", - "MyApiproxyANYFCF46C66", - "MyApiproxyE14DBEA4", - "MyApiANYEC3618D9", - ], - "Properties": Object { - "Description": "Automatically created by the RestApi construct", - "RestApiId": Object { - "Ref": "MyApi49610EDF", - }, - }, - "Type": "AWS::ApiGateway::Deployment", - }, - "MyApiDeploymentStageprodE1054AF0": Object { - "DependsOn": Array [ - "MyApiAccount13882D84", - ], - "Properties": Object { - "DeploymentId": Object { - "Ref": "MyApiDeploymentECB0D05E0597cc4592870e54c401cccc6090bd86", - }, - "RestApiId": Object { - "Ref": "MyApi49610EDF", - }, - "StageName": "prod", - }, - "Type": "AWS::ApiGateway::Stage", - }, - "MyApiproxyANYApiPermissionTestapigwMyApiCBFBC5B0ANYproxy6DC68FBB": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "MyApi49610EDF", - }, - "/test-invoke-stage/*/*", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "MyApiproxyANYApiPermissionapigwMyApiCBFBC5B0ANYproxyB3375D73": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "MyApi49610EDF", - }, - "/", - Object { - "Ref": "MyApiDeploymentStageprodE1054AF0", - }, - "/*/*", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "MyApiproxyANYFCF46C66": Object { - "Properties": Object { - "AuthorizationType": "NONE", - "HttpMethod": "ANY", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", - Object { - "Ref": "AWS::Region", - }, - ":lambda:path/2015-03-31/functions/", - Object { - "Fn::GetAtt": Array [ - "HelloLambda3D9C82D6", - "Arn", - ], - }, - "/invocations", - ], - ], - }, - }, - "ResourceId": Object { - "Ref": "MyApiproxyE14DBEA4", - }, - "RestApiId": Object { - "Ref": "MyApi49610EDF", - }, - }, - "Type": "AWS::ApiGateway::Method", - }, - "MyApiproxyE14DBEA4": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "MyApi49610EDF", - "RootResourceId", - ], - }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "MyApi49610EDF", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, - }, -} -`; - -exports[`ecs.json: ecs 1`] = ` -Object { - "Resources": Object { - "ClusterEB0386A7": Object { - "Type": "AWS::ECS::Cluster", - }, - "MyTaskDef01F0D39B": Object { - "Properties": Object { - "ContainerDefinitions": Array [ - Object { - "Essential": true, - "Image": "redis", - "Memory": 1024, - "Name": "ContainerDef", - }, - ], - "Cpu": "1024", - "Family": "redis", - "Memory": "1GB", - "NetworkMode": "awsvpc", - "RequiresCompatibilities": Array [ - "FARGATE", - ], - "TaskRoleArn": Object { - "Fn::GetAtt": Array [ - "MyTaskDefTaskRole727F9D3B", - "Arn", - ], - }, - }, - "Type": "AWS::ECS::TaskDefinition", - }, - "MyTaskDefTaskRole727F9D3B": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "ecs-tasks.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "ServiceD69D759B": Object { - "Properties": Object { - "Cluster": Object { - "Ref": "ClusterEB0386A7", - }, - "DeploymentConfiguration": Object { - "MaximumPercent": 200, - "MinimumHealthyPercent": 50, - }, - "EnableECSManagedTags": false, - "LaunchType": "FARGATE", - "NetworkConfiguration": Object { - "AwsvpcConfiguration": Object { - "AssignPublicIp": "DISABLED", - "SecurityGroups": Array [ - Object { - "Fn::GetAtt": Array [ - "ServiceSecurityGroupC96ED6A7", - "GroupId", - ], - }, - ], - "Subnets": Array [ - Object { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0", - }, - ], - }, - }, - "TaskDefinition": Object { - "Ref": "MyTaskDef01F0D39B", - }, - }, - "Type": "AWS::ECS::Service", - }, - "ServiceSecurityGroupC96ED6A7": Object { - "Properties": Object { - "GroupDescription": "ecs/Service/SecurityGroup", - "SecurityGroupEgress": Array [ - Object { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::SecurityGroup", - }, - "VPCB9E5F0B4": Object { - "Properties": Object { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": Array [ - Object { - "Key": "Name", - "Value": "ecs/VPC", - }, - ], - }, - "Type": "AWS::EC2::VPC", - }, - "VPCIGWB7E252D3": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "ecs/VPC", - }, - ], - }, - "Type": "AWS::EC2::InternetGateway", - }, - "VPCPrivateSubnet1DefaultRouteAE1D6490": Object { - "Properties": Object { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": Object { - "Ref": "VPCPublicSubnet1NATGatewayE0556630", - }, - "RouteTableId": Object { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027", - }, - }, - "Type": "AWS::EC2::Route", - }, - "VPCPrivateSubnet1RouteTableAssociation347902D1": Object { - "Properties": Object { - "RouteTableId": Object { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027", - }, - "SubnetId": Object { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0", - }, - }, - "Type": "AWS::EC2::SubnetRouteTableAssociation", - }, - "VPCPrivateSubnet1RouteTableBE8A6027": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "ecs/VPC/PrivateSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::RouteTable", - }, - "VPCPrivateSubnet1Subnet8BCA10E0": Object { - "Properties": Object { - "AvailabilityZone": Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::GetAZs": "", - }, - ], - }, - "CidrBlock": "10.0.128.0/17", - "MapPublicIpOnLaunch": false, - "Tags": Array [ - Object { - "Key": "aws-cdk:subnet-name", - "Value": "Private", - }, - Object { - "Key": "aws-cdk:subnet-type", - "Value": "Private", - }, - Object { - "Key": "Name", - "Value": "ecs/VPC/PrivateSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::Subnet", - }, - "VPCPublicSubnet1DefaultRoute91CEF279": Object { - "DependsOn": Array [ - "VPCVPCGW99B986DC", - ], - "Properties": Object { - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": Object { - "Ref": "VPCIGWB7E252D3", - }, - "RouteTableId": Object { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781", - }, - }, - "Type": "AWS::EC2::Route", - }, - "VPCPublicSubnet1EIP6AD938E8": Object { - "Properties": Object { - "Domain": "vpc", - "Tags": Array [ - Object { - "Key": "Name", - "Value": "ecs/VPC/PublicSubnet1", - }, - ], - }, - "Type": "AWS::EC2::EIP", - }, - "VPCPublicSubnet1NATGatewayE0556630": Object { - "Properties": Object { - "AllocationId": Object { - "Fn::GetAtt": Array [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId", - ], - }, - "SubnetId": Object { - "Ref": "VPCPublicSubnet1SubnetB4246D30", - }, - "Tags": Array [ - Object { - "Key": "Name", - "Value": "ecs/VPC/PublicSubnet1", - }, - ], - }, - "Type": "AWS::EC2::NatGateway", - }, - "VPCPublicSubnet1RouteTableAssociation0B0896DC": Object { - "Properties": Object { - "RouteTableId": Object { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781", - }, - "SubnetId": Object { - "Ref": "VPCPublicSubnet1SubnetB4246D30", - }, - }, - "Type": "AWS::EC2::SubnetRouteTableAssociation", - }, - "VPCPublicSubnet1RouteTableFEE4B781": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "ecs/VPC/PublicSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::RouteTable", - }, - "VPCPublicSubnet1SubnetB4246D30": Object { - "Properties": Object { - "AvailabilityZone": Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::GetAZs": "", - }, - ], - }, - "CidrBlock": "10.0.0.0/17", - "MapPublicIpOnLaunch": true, - "Tags": Array [ - Object { - "Key": "aws-cdk:subnet-name", - "Value": "Public", - }, - Object { - "Key": "aws-cdk:subnet-type", - "Value": "Public", - }, - Object { - "Key": "Name", - "Value": "ecs/VPC/PublicSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::Subnet", - }, - "VPCVPCGW99B986DC": Object { - "Properties": Object { - "InternetGatewayId": Object { - "Ref": "VPCIGWB7E252D3", - }, - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::VPCGatewayAttachment", - }, - }, -} -`; - -exports[`lambda-events.json: lambda-events 1`] = ` -Object { - "Outputs": Object { - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FEndpointC6202FF3": Object { - "Value": Object { - "Fn::Join": Array [ - "", - Array [ - "https://", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - ".execute-api.", - Object { - "Ref": "AWS::Region", - }, - ".", - Object { - "Ref": "AWS::URLSuffix", - }, - "/", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FDeploymentStageprod6A86C016", - }, - "/", - ], - ], - }, - }, - }, - "Parameters": Object { - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cArtifactHash47CFB54E": Object { - "Description": "Artifact hash for asset \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3Bucket0D05C9AA": Object { - "Description": "S3 bucket for asset \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3": Object { - "Description": "S3 key for asset version \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - }, - "Resources": Object { - "HelloWorldFunctionAllowInvokelambdaeventsMyTopic988FAB3E43035740": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "Principal": "sns.amazonaws.com", - "SourceArn": Object { - "Ref": "MyTopic86869434", - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "HelloWorldFunctionB2AB6E79": Object { - "DependsOn": Array [ - "HelloWorldFunctionServiceRoleDefaultPolicy6CCD7798", - "HelloWorldFunctionServiceRole8E0BD458", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3Bucket0D05C9AA", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Environment": Object { - "Variables": Object { - "Param": "f", - }, - }, - "Handler": "app.hello_handler", - "Role": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionServiceRole8E0BD458", - "Arn", - ], - }, - "Runtime": "python3.6", - }, - "Type": "AWS::Lambda::Function", - }, - "HelloWorldFunctionDynamoDBEventSourcelambdaeventsTableF97C65E3DE5C745C": Object { - "Properties": Object { - "BatchSize": 100, - "EventSourceArn": Object { - "Fn::GetAtt": Array [ - "TableCD117FA1", - "StreamArn", - ], - }, - "FunctionName": Object { - "Ref": "HelloWorldFunctionB2AB6E79", - }, - "StartingPosition": "TRIM_HORIZON", - }, - "Type": "AWS::Lambda::EventSourceMapping", - }, - "HelloWorldFunctionMyTopic90F6E0EF": Object { - "Properties": Object { - "Endpoint": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "Protocol": "lambda", - "TopicArn": Object { - "Ref": "MyTopic86869434", - }, - }, - "Type": "AWS::SNS::Subscription", - }, - "HelloWorldFunctionServiceRole8E0BD458": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "HelloWorldFunctionServiceRoleDefaultPolicy6CCD7798": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "dynamodb:ListStreams", - "Effect": "Allow", - "Resource": "*", - }, - Object { - "Action": Array [ - "dynamodb:DescribeStream", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "TableCD117FA1", - "StreamArn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "HelloWorldFunctionServiceRoleDefaultPolicy6CCD7798", - "Roles": Array [ - Object { - "Ref": "HelloWorldFunctionServiceRole8E0BD458", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "MyTopic86869434": Object { - "Type": "AWS::SNS::Topic", - }, - "TableCD117FA1": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "ID", - "AttributeType": "S", - }, - ], - "KeySchema": Array [ - Object { - "AttributeName": "ID", - "KeyType": "HASH", - }, - ], - "ProvisionedThroughput": Object { - "ReadCapacityUnits": 5, - "WriteCapacityUnits": 5, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Retain", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F": Object { - "Properties": Object { - "Name": "lambdaeventsHelloWorldFunctionAB27BB65:ApiEventSourceA7A86A4F", - }, - "Type": "AWS::ApiGateway::RestApi", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FAccountF7734F1E": Object { - "DependsOn": Array [ - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FCloudWatchRole495FDB9D", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FCloudWatchRole495FDB9D": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FDeploymentFF3F4A1Ac00dde791d2719be3e8ea69f9a61a5cd": Object { - "DependsOn": Array [ - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloGET04FBC7F6", - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloPOST53F177B1", - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloC30B3CD9", - ], - "Properties": Object { - "Description": "Automatically created by the RestApi construct", - "RestApiId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - }, - "Type": "AWS::ApiGateway::Deployment", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FDeploymentStageprod6A86C016": Object { - "DependsOn": Array [ - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FAccountF7734F1E", - ], - "Properties": Object { - "DeploymentId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FDeploymentFF3F4A1Ac00dde791d2719be3e8ea69f9a61a5cd", - }, - "RestApiId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - "StageName": "prod", - }, - "Type": "AWS::ApiGateway::Stage", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloC30B3CD9": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - "RootResourceId", - ], - }, - "PathPart": "hello", - "RestApiId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloGET04FBC7F6": Object { - "Properties": Object { - "AuthorizationType": "NONE", - "HttpMethod": "GET", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", - Object { - "Ref": "AWS::Region", - }, - ":lambda:path/2015-03-31/functions/", - Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "/invocations", - ], - ], - }, - }, - "ResourceId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloC30B3CD9", - }, - "RestApiId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - }, - "Type": "AWS::ApiGateway::Method", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloGETApiPermissionTestlambdaeventslambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F0AAEF724GEThello5EA12CF5": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - "/test-invoke-stage/GET/hello", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloGETApiPermissionlambdaeventslambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F0AAEF724GEThelloAC4AB5E4": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - "/", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FDeploymentStageprod6A86C016", - }, - "/GET/hello", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloPOST53F177B1": Object { - "Properties": Object { - "AuthorizationType": "NONE", - "HttpMethod": "POST", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", - Object { - "Ref": "AWS::Region", - }, - ":lambda:path/2015-03-31/functions/", - Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "/invocations", - ], - ], - }, - }, - "ResourceId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloC30B3CD9", - }, - "RestApiId": Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - }, - "Type": "AWS::ApiGateway::Method", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloPOSTApiPermissionTestlambdaeventslambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F0AAEF724POSThello991892DD": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - "/test-invoke-stage/POST/hello", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FhelloPOSTApiPermissionlambdaeventslambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F0AAEF724POSThello3501FACF": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "HelloWorldFunctionB2AB6E79", - "Arn", - ], - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4F12449C5F", - }, - "/", - Object { - "Ref": "lambdaeventsHelloWorldFunctionAB27BB65ApiEventSourceA7A86A4FDeploymentStageprod6A86C016", - }, - "/POST/hello", - ], - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - }, -} -`; - -exports[`lambda-topic.json: lambda-topic 1`] = ` -Object { - "Parameters": Object { - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cArtifactHash47CFB54E": Object { - "Description": "Artifact hash for asset \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3Bucket0D05C9AA": Object { - "Description": "S3 bucket for asset \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3": Object { - "Description": "S3 key for asset version \\"a6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30c\\"", - "Type": "String", - }, - }, - "Resources": Object { - "LambdaAllowInvokelambdatopicTopic702108A3CE1309A3": Object { - "Properties": Object { - "Action": "lambda:InvokeFunction", - "FunctionName": Object { - "Fn::GetAtt": Array [ - "LambdaD247545B", - "Arn", - ], - }, - "Principal": "sns.amazonaws.com", - "SourceArn": Object { - "Ref": "TopicBFC7AF6E", - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "LambdaD247545B": Object { - "DependsOn": Array [ - "LambdaServiceRoleA8ED4D3B", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3Bucket0D05C9AA", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersa6017def6c75b1a9adc95dfc1b2d7bb3dc0dad8ef9e71da67cc1b7c3826fe30cS3VersionKeyDC0BC7B3", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "LambdaServiceRoleA8ED4D3B", - "Arn", - ], - }, - "Runtime": "nodejs", - }, - "Type": "AWS::Lambda::Function", - }, - "LambdaServiceRoleA8ED4D3B": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "LambdaTopicCCB0C2A3": Object { - "Properties": Object { - "Endpoint": Object { - "Fn::GetAtt": Array [ - "LambdaD247545B", - "Arn", - ], - }, - "Protocol": "lambda", - "TopicArn": Object { - "Ref": "TopicBFC7AF6E", - }, - }, - "Type": "AWS::SNS::Subscription", - }, - "TopicBFC7AF6E": Object { - "Type": "AWS::SNS::Topic", - }, - }, -} -`; - -exports[`pipeline.json: pipeline 1`] = ` -Object { - "Resources": Object { - "BuildProject097C5DB7": Object { - "Properties": Object { - "Artifacts": Object { - "Type": "CODEPIPELINE", - }, - "Cache": Object { - "Type": "NO_CACHE", - }, - "EncryptionKey": Object { - "Fn::GetAtt": Array [ - "Key961B73FD", - "Arn", - ], - }, - "Environment": Object { - "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", - "ImagePullCredentialsType": "CODEBUILD", - "PrivilegedMode": false, - "Type": "LINUX_CONTAINER", - }, - "ServiceRole": Object { - "Fn::GetAtt": Array [ - "BuildProjectRoleAA92C755", - "Arn", - ], - }, - "Source": Object { - "Type": "CODEPIPELINE", - }, - }, - "Type": "AWS::CodeBuild::Project", - }, - "BuildProjectRoleAA92C755": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "codebuild.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "BuildProjectRoleDefaultPolicy3E9F248C": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/codebuild/", - Object { - "Ref": "BuildProject097C5DB7", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/codebuild/", - Object { - "Ref": "BuildProject097C5DB7", - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", - "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":codebuild:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":report-group/", - Object { - "Ref": "BuildProject097C5DB7", - }, - "-*", - ], - ], - }, - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "Key961B73FD", - "Arn", - ], - }, - }, - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "BuildProjectRoleDefaultPolicy3E9F248C", - "Roles": Array [ - Object { - "Ref": "BuildProjectRoleAA92C755", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "Key961B73FD": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "KeyPolicy": Object { - "Statement": Array [ - Object { - "Action": "kms:*", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::KMS::Key", - "UpdateReplacePolicy": "Retain", - }, - "PipelineArtifactsBucket22248F97": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "BucketEncryption": Object { - "ServerSideEncryptionConfiguration": Array [ - Object { - "ServerSideEncryptionByDefault": Object { - "KMSMasterKeyID": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - "SSEAlgorithm": "aws:kms", - }, - }, - ], - }, - "PublicAccessBlockConfiguration": Object { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true, - }, - }, - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Retain", - }, - "PipelineArtifactsBucketEncryptionKey01D58D69": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "KeyPolicy": Object { - "Statement": Array [ - Object { - "Action": "kms:*", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::KMS::Key", - "UpdateReplacePolicy": "Delete", - }, - "PipelineArtifactsBucketEncryptionKeyAlias5C510EEE": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "AliasName": "alias/codepipeline-pipelinepipeline22f2a91d", - "TargetKeyId": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - }, - "Type": "AWS::KMS::Alias", - "UpdateReplacePolicy": "Delete", - }, - "PipelineArtifactsBucketPolicyD4F9712A": Object { - "Properties": Object { - "Bucket": Object { - "Ref": "PipelineArtifactsBucket22248F97", - }, - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "s3:*", - "Condition": Object { - "Bool": Object { - "aws:SecureTransport": "false", - }, - }, - "Effect": "Deny", - "Principal": Object { - "AWS": "*", - }, - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::S3::BucketPolicy", - }, - "PipelineBuildCodePipelineActionRoleD77A08E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "PipelineBuildCodePipelineActionRoleDefaultPolicyC9CB73F8": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "codebuild:BatchGetBuilds", - "codebuild:StartBuild", - "codebuild:StopBuild", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "BuildProject097C5DB7", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PipelineBuildCodePipelineActionRoleDefaultPolicyC9CB73F8", - "Roles": Array [ - Object { - "Ref": "PipelineBuildCodePipelineActionRoleD77A08E6", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PipelineC660917D": Object { - "DependsOn": Array [ - "PipelineRoleDefaultPolicyC7A05455", - "PipelineRoleD68726F7", - ], - "Properties": Object { - "ArtifactStore": Object { - "EncryptionKey": Object { - "Id": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - "Type": "KMS", - }, - "Location": Object { - "Ref": "PipelineArtifactsBucket22248F97", - }, - "Type": "S3", - }, - "RoleArn": Object { - "Fn::GetAtt": Array [ - "PipelineRoleD68726F7", - "Arn", - ], - }, - "Stages": Array [ - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Source", - "Owner": "AWS", - "Provider": "CodeCommit", - "Version": "1", - }, - "Configuration": Object { - "BranchName": "master", - "PollForSourceChanges": false, - "RepositoryName": Object { - "Fn::GetAtt": Array [ - "Repo02AC86CF", - "Name", - ], - }, - }, - "Name": "Source", - "OutputArtifacts": Array [ - Object { - "Name": "Source", - }, - ], - "RoleArn": Object { - "Fn::GetAtt": Array [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Source", - }, - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Build", - "Owner": "AWS", - "Provider": "CodeBuild", - "Version": "1", - }, - "Configuration": Object { - "ProjectName": Object { - "Ref": "BuildProject097C5DB7", - }, - }, - "InputArtifacts": Array [ - Object { - "Name": "Source", - }, - ], - "Name": "Build", - "OutputArtifacts": Array [ - Object { - "Name": "Build", - }, - ], - "RoleArn": Object { - "Fn::GetAtt": Array [ - "PipelineBuildCodePipelineActionRoleD77A08E6", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Build", - }, - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Deploy", - "Owner": "AWS", - "Provider": "CloudFormation", - "Version": "1", - }, - "Configuration": Object { - "ActionMode": "CREATE_UPDATE", - "Capabilities": "CAPABILITY_NAMED_IAM", - "RoleArn": Object { - "Fn::GetAtt": Array [ - "PipelineDeployRole97597E3E", - "Arn", - ], - }, - "StackName": "MyStack", - "TemplatePath": "Build::template.yaml", - }, - "InputArtifacts": Array [ - Object { - "Name": "Build", - }, - ], - "Name": "Deploy", - "RoleArn": Object { - "Fn::GetAtt": Array [ - "PipelineDeployCodePipelineActionRole8B83082E", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Deploy", - }, - ], - }, - "Type": "AWS::CodePipeline::Pipeline", - }, - "PipelineDeployCodePipelineActionRole8B83082E": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "PipelineDeployCodePipelineActionRoleDefaultPolicyEE6D615B": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "iam:PassRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineDeployRole97597E3E", - "Arn", - ], - }, - }, - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - }, - Object { - "Action": Array [ - "cloudformation:CreateStack", - "cloudformation:DescribeStack*", - "cloudformation:GetStackPolicy", - "cloudformation:GetTemplate*", - "cloudformation:SetStackPolicy", - "cloudformation:UpdateStack", - "cloudformation:ValidateTemplate", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":cloudformation:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":stack/MyStack/*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PipelineDeployCodePipelineActionRoleDefaultPolicyEE6D615B", - "Roles": Array [ - Object { - "Ref": "PipelineDeployCodePipelineActionRole8B83082E", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PipelineDeployRole97597E3E": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "cloudformation.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "PipelineDeployRoleDefaultPolicy90429F22": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - }, - Object { - "Action": "*", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PipelineDeployRoleDefaultPolicy90429F22", - "Roles": Array [ - Object { - "Ref": "PipelineDeployRole97597E3E", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PipelineEventsRole46BEEA7C": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "events.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "PipelineEventsRoleDefaultPolicyFF4FCCE0": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "codepipeline:StartPipelineExecution", - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":codepipeline:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "PipelineC660917D", - }, - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PipelineEventsRoleDefaultPolicyFF4FCCE0", - "Roles": Array [ - Object { - "Ref": "PipelineEventsRole46BEEA7C", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PipelineRoleD68726F7": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "codepipeline.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "PipelineRoleDefaultPolicyC7A05455": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn", - ], - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineBuildCodePipelineActionRoleD77A08E6", - "Arn", - ], - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineDeployCodePipelineActionRole8B83082E", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PipelineRoleDefaultPolicyC7A05455", - "Roles": Array [ - Object { - "Ref": "PipelineRoleD68726F7", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PipelineSourceCodePipelineActionRoleC6F9E7F5": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucket22248F97", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "PipelineArtifactsBucketEncryptionKey01D58D69", - "Arn", - ], - }, - }, - Object { - "Action": Array [ - "codecommit:GetBranch", - "codecommit:GetCommit", - "codecommit:UploadArchive", - "codecommit:GetUploadArchiveStatus", - "codecommit:CancelUploadArchive", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "Repo02AC86CF", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925", - "Roles": Array [ - Object { - "Ref": "PipelineSourceCodePipelineActionRoleC6F9E7F5", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "Repo02AC86CF": Object { - "Properties": Object { - "RepositoryName": "my-first-decdk-repo", - }, - "Type": "AWS::CodeCommit::Repository", - }, - "RepopipelinePipeline22F2A91DEventRuleF314EE14": Object { - "Properties": Object { - "EventPattern": Object { - "detail": Object { - "event": Array [ - "referenceCreated", - "referenceUpdated", - ], - "referenceName": Array [ - "master", - ], - }, - "detail-type": Array [ - "CodeCommit Repository State Change", - ], - "resources": Array [ - Object { - "Fn::GetAtt": Array [ - "Repo02AC86CF", - "Arn", - ], - }, - ], - "source": Array [ - "aws.codecommit", - ], - }, - "State": "ENABLED", - "Targets": Array [ - Object { - "Arn": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":codepipeline:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "PipelineC660917D", - }, - ], - ], - }, - "Id": "Target0", - "RoleArn": Object { - "Fn::GetAtt": Array [ - "PipelineEventsRole46BEEA7C", - "Arn", - ], - }, - }, - ], - }, - "Type": "AWS::Events::Rule", - }, - }, -} -`; - -exports[`pure-cfn.json: pure-cfn 1`] = ` -Object { - "Resources": Object { - "Hello4A628BD4": Object { - "DeletionPolicy": "Delete", - "Type": "AWS::SQS::Queue", - "UpdateReplacePolicy": "Delete", - }, - "MyLogGroup": Object { - "Properties": Object { - "LogGroupName": Object { - "Ref": "AWS::AccountId", - }, - }, - "Type": "AWS::Logs::LogGroup", - }, - }, -} -`; - -exports[`queue-kms.json: queue-kms 1`] = ` -Object { - "Resources": Object { - "MyQueueE6CA6235": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "KmsMasterKeyId": Object { - "Fn::GetAtt": Array [ - "MyQueueKey6C31ABF3", - "Arn", - ], - }, - }, - "Type": "AWS::SQS::Queue", - "UpdateReplacePolicy": "Delete", - }, - "MyQueueKey6C31ABF3": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "Description": "Created by queue-kms/MyQueue", - "KeyPolicy": Object { - "Statement": Array [ - Object { - "Action": "kms:*", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::KMS::Key", - "UpdateReplacePolicy": "Retain", - }, - }, -} -`; - -exports[`vpc.json: vpc 1`] = ` -Object { - "Resources": Object { - "VPCB9E5F0B4": Object { - "Properties": Object { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC", - }, - ], - }, - "Type": "AWS::EC2::VPC", - }, - "VPCIGWB7E252D3": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC", - }, - ], - }, - "Type": "AWS::EC2::InternetGateway", - }, - "VPCPrivateSubnet1DefaultRouteAE1D6490": Object { - "Properties": Object { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": Object { - "Ref": "VPCPublicSubnet1NATGatewayE0556630", - }, - "RouteTableId": Object { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027", - }, - }, - "Type": "AWS::EC2::Route", - }, - "VPCPrivateSubnet1RouteTableAssociation347902D1": Object { - "Properties": Object { - "RouteTableId": Object { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027", - }, - "SubnetId": Object { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0", - }, - }, - "Type": "AWS::EC2::SubnetRouteTableAssociation", - }, - "VPCPrivateSubnet1RouteTableBE8A6027": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PrivateSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::RouteTable", - }, - "VPCPrivateSubnet1Subnet8BCA10E0": Object { - "Properties": Object { - "AvailabilityZone": Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::GetAZs": "", - }, - ], - }, - "CidrBlock": "10.0.128.0/18", - "MapPublicIpOnLaunch": false, - "Tags": Array [ - Object { - "Key": "aws-cdk:subnet-name", - "Value": "Private", - }, - Object { - "Key": "aws-cdk:subnet-type", - "Value": "Private", - }, - Object { - "Key": "Name", - "Value": "vpc/VPC/PrivateSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::Subnet", - }, - "VPCPrivateSubnet2DefaultRouteF4F5CFD2": Object { - "Properties": Object { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": Object { - "Ref": "VPCPublicSubnet2NATGateway3C070193", - }, - "RouteTableId": Object { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E", - }, - }, - "Type": "AWS::EC2::Route", - }, - "VPCPrivateSubnet2RouteTable0A19E10E": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PrivateSubnet2", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::RouteTable", - }, - "VPCPrivateSubnet2RouteTableAssociation0C73D413": Object { - "Properties": Object { - "RouteTableId": Object { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E", - }, - "SubnetId": Object { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A", - }, - }, - "Type": "AWS::EC2::SubnetRouteTableAssociation", - }, - "VPCPrivateSubnet2SubnetCFCDAA7A": Object { - "Properties": Object { - "AvailabilityZone": Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::GetAZs": "", - }, - ], - }, - "CidrBlock": "10.0.192.0/18", - "MapPublicIpOnLaunch": false, - "Tags": Array [ - Object { - "Key": "aws-cdk:subnet-name", - "Value": "Private", - }, - Object { - "Key": "aws-cdk:subnet-type", - "Value": "Private", - }, - Object { - "Key": "Name", - "Value": "vpc/VPC/PrivateSubnet2", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::Subnet", - }, - "VPCPublicSubnet1DefaultRoute91CEF279": Object { - "DependsOn": Array [ - "VPCVPCGW99B986DC", - ], - "Properties": Object { - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": Object { - "Ref": "VPCIGWB7E252D3", - }, - "RouteTableId": Object { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781", - }, - }, - "Type": "AWS::EC2::Route", - }, - "VPCPublicSubnet1EIP6AD938E8": Object { - "Properties": Object { - "Domain": "vpc", - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet1", - }, - ], - }, - "Type": "AWS::EC2::EIP", - }, - "VPCPublicSubnet1NATGatewayE0556630": Object { - "Properties": Object { - "AllocationId": Object { - "Fn::GetAtt": Array [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId", - ], - }, - "SubnetId": Object { - "Ref": "VPCPublicSubnet1SubnetB4246D30", - }, - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet1", - }, - ], - }, - "Type": "AWS::EC2::NatGateway", - }, - "VPCPublicSubnet1RouteTableAssociation0B0896DC": Object { - "Properties": Object { - "RouteTableId": Object { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781", - }, - "SubnetId": Object { - "Ref": "VPCPublicSubnet1SubnetB4246D30", - }, - }, - "Type": "AWS::EC2::SubnetRouteTableAssociation", - }, - "VPCPublicSubnet1RouteTableFEE4B781": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::RouteTable", - }, - "VPCPublicSubnet1SubnetB4246D30": Object { - "Properties": Object { - "AvailabilityZone": Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::GetAZs": "", - }, - ], - }, - "CidrBlock": "10.0.0.0/18", - "MapPublicIpOnLaunch": true, - "Tags": Array [ - Object { - "Key": "aws-cdk:subnet-name", - "Value": "Public", - }, - Object { - "Key": "aws-cdk:subnet-type", - "Value": "Public", - }, - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet1", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::Subnet", - }, - "VPCPublicSubnet2DefaultRouteB7481BBA": Object { - "DependsOn": Array [ - "VPCVPCGW99B986DC", - ], - "Properties": Object { - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": Object { - "Ref": "VPCIGWB7E252D3", - }, - "RouteTableId": Object { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1", - }, - }, - "Type": "AWS::EC2::Route", - }, - "VPCPublicSubnet2EIP4947BC00": Object { - "Properties": Object { - "Domain": "vpc", - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet2", - }, - ], - }, - "Type": "AWS::EC2::EIP", - }, - "VPCPublicSubnet2NATGateway3C070193": Object { - "Properties": Object { - "AllocationId": Object { - "Fn::GetAtt": Array [ - "VPCPublicSubnet2EIP4947BC00", - "AllocationId", - ], - }, - "SubnetId": Object { - "Ref": "VPCPublicSubnet2Subnet74179F39", - }, - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet2", - }, - ], - }, - "Type": "AWS::EC2::NatGateway", - }, - "VPCPublicSubnet2RouteTable6F1A15F1": Object { - "Properties": Object { - "Tags": Array [ - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet2", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::RouteTable", - }, - "VPCPublicSubnet2RouteTableAssociation5A808732": Object { - "Properties": Object { - "RouteTableId": Object { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1", - }, - "SubnetId": Object { - "Ref": "VPCPublicSubnet2Subnet74179F39", - }, - }, - "Type": "AWS::EC2::SubnetRouteTableAssociation", - }, - "VPCPublicSubnet2Subnet74179F39": Object { - "Properties": Object { - "AvailabilityZone": Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::GetAZs": "", - }, - ], - }, - "CidrBlock": "10.0.64.0/18", - "MapPublicIpOnLaunch": true, - "Tags": Array [ - Object { - "Key": "aws-cdk:subnet-name", - "Value": "Public", - }, - Object { - "Key": "aws-cdk:subnet-type", - "Value": "Public", - }, - Object { - "Key": "Name", - "Value": "vpc/VPC/PublicSubnet2", - }, - ], - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::Subnet", - }, - "VPCVPCGW99B986DC": Object { - "Properties": Object { - "InternetGatewayId": Object { - "Ref": "VPCIGWB7E252D3", - }, - "VpcId": Object { - "Ref": "VPCB9E5F0B4", - }, - }, - "Type": "AWS::EC2::VPCGatewayAttachment", - }, - }, -} -`; diff --git a/packages/decdk/test/fixture/index.ts b/packages/decdk/test/fixture/index.ts deleted file mode 100644 index 04750a5ff654b..0000000000000 --- a/packages/decdk/test/fixture/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Tests how an array with a bunch of primitives is represented in JSON schema. - */ -export interface InterfaceWithPrimitives { - /** - * A property of type number. - */ - readonly numberProperty: number; - - /** - * A property of type string. - */ - readonly stringProperty: string; - - /** - * Array of strings. - */ - readonly arrayOfStrings: string[]; - - /** - * Optional boolean - */ - readonly optionalBoolean?: boolean; - - // - // intentionally left blank (to check that description is omitted) - // - readonly mapOfNumbers: { [key: string]: number } -} - -export enum MyNormalEnum { - ENUM_MEMBER_1, - ENUM_MEMBER_2, - ENUM_MEMBER_3 -} diff --git a/packages/decdk/test/fixture/package.json b/packages/decdk/test/fixture/package.json deleted file mode 100644 index 37ba6d2665de7..0000000000000 --- a/packages/decdk/test/fixture/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "fixture", - "version": "0.0.0", - "description": "test fixtures for deCDK", - "main": "index.js", - "types": "index.d.ts", - "jsii": { - "outdir": "dist" - }, - "repository": { - "url": "https://github.com/aws/aws-cdk", - "type": "git" - }, - "author": { - "name": "Amazon Web Services", - "url": "https://aws.amazon.com" - }, - "license": "Apache-2.0" -} \ No newline at end of file diff --git a/packages/decdk/test/fixture/tsconfig.json b/packages/decdk/test/fixture/tsconfig.json deleted file mode 100644 index 7ca946aa3a374..0000000000000 --- a/packages/decdk/test/fixture/tsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - "alwaysStrict": true, - "charset": "utf8", - "declaration": true, - "experimentalDecorators": true, - "incremental": true, - "inlineSourceMap": true, - "inlineSources": true, - "lib": [ - "es2019" - ], - "module": "CommonJS", - "newLine": "lf", - "noEmitOnError": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitReturns": true, - "noImplicitThis": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "resolveJsonModule": true, - "strict": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "stripInternal": false, - "target": "ES2019", - "composite": false, - "tsBuildInfoFile": "tsconfig.tsbuildinfo" - }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "node_modules" - ], - "_generated_by_jsii_": "Generated by jsii - safe to delete, and ideally should be in .gitignore" -} diff --git a/packages/decdk/test/sanity.test.ts b/packages/decdk/test/sanity.test.ts deleted file mode 100644 index fe765d04f6b9e..0000000000000 --- a/packages/decdk/test/sanity.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as path from 'path'; - -test('path.resolve is sane', async () => { - // Reasons why this might not be true: - // graceful-fs, which is used by Jest, hooks into process.cwd() and - // process.chdir() and caches the values. Because... profit? - - const targetDir = path.join(__dirname, 'fixture'); - - const cwd = process.cwd(); - - try { - process.chdir(targetDir); - expect(process.cwd()).toEqual(targetDir); - - const resolved = path.resolve('.'); - expect(resolved).toEqual(targetDir); - - } finally { - process.chdir(cwd); - } -}); \ No newline at end of file diff --git a/packages/decdk/test/schema.test.ts b/packages/decdk/test/schema.test.ts deleted file mode 100644 index 7b097dcc9fcbe..0000000000000 --- a/packages/decdk/test/schema.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { spawn as spawnAsync, SpawnOptions } from 'child_process'; -import * as reflect from 'jsii-reflect'; -import * as path from 'path'; -import { SchemaContext, schemaForInterface } from '../lib/jsii2schema'; - -const fixturedir = path.join(__dirname, 'fixture'); - -/* eslint-disable no-console */ - -// building the decdk schema often does not complete in the default 5 second Jest timeout -jest.setTimeout(60_000); - -let typesys: reflect.TypeSystem; - -beforeAll(async () => { - typesys = new reflect.TypeSystem(); - - // jsii-compile the fixtures module - await spawn(require.resolve('jsii/bin/jsii'), { cwd: fixturedir, }); - - // load the resulting file system - await typesys.loadFile(path.join(fixturedir, '.jsii')); - await typesys.load(path.dirname(require.resolve('@aws-cdk/core/.jsii'))); -}); - -test('schemaForInterface: interface with primitives', async () => { - // GIVEN - const defs = { }; - const ctx = SchemaContext.root(defs); - - // WHEN - const ref = schemaForInterface(typesys.findFqn('fixture.InterfaceWithPrimitives'), ctx); - - // THEN - expect(ref).toStrictEqual({ $ref: '#/definitions/fixture.InterfaceWithPrimitives' }); - expect(ctx.definitions).toStrictEqual({ - 'fixture.InterfaceWithPrimitives': { - type: 'object', - title: 'InterfaceWithPrimitives', - additionalProperties: false, - properties: { - arrayOfStrings: { - type: 'array', - items: { type: 'string' }, - description: 'Array of strings.' - }, - mapOfNumbers: { - type: 'object', - additionalProperties: { type: 'number' } - }, - numberProperty: { - type: 'number', - description: 'A property of type number.' - }, - stringProperty: { - type: 'string', - description: 'A property of type string.' - }, - optionalBoolean: { - type: 'boolean', - description: 'Optional boolean.' - } - }, - required: [ - 'arrayOfStrings', - 'mapOfNumbers', - 'numberProperty', - 'stringProperty' - ], - comment: 'fixture.InterfaceWithPrimitives' - } - }); -}); - -/** - * Version of spawn() that returns a promise - * - * Need spawn() so that we can set stdio to inherit so that any jsii errors - * are propagated outwards. - */ -function spawn(command: string, options: SpawnOptions | undefined) { - return new Promise((resolve, reject) => { - const cp = spawnAsync(command, [], { stdio: 'inherit', ...options }); - - cp.on('error', reject); - cp.on('exit', (code, signal) => { - if (code === 0) { resolve(); } - reject(new Error(`Subprocess exited with ${code || signal}`)); - }); - }); -} diff --git a/packages/decdk/test/synth.test.ts b/packages/decdk/test/synth.test.ts deleted file mode 100644 index 8952a9aa11fd8..0000000000000 --- a/packages/decdk/test/synth.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as cdk from '@aws-cdk/core'; -import * as fs from 'fs'; -import * as reflect from 'jsii-reflect'; -import * as path from 'path'; -import { FUTURE_FLAGS } from '@aws-cdk/cx-api'; -import { DeclarativeStack, loadTypeSystem, readTemplate, stackNameFromFileName } from '../lib'; - -const VALIDATE_ASSEMBLIES = true; - -const dir = path.join(__dirname, '..', 'examples'); - -if (VALIDATE_ASSEMBLIES) { - // With validation loading all assemblies takes 10s on my machine. - // Without validation it's 600ms. - // - // Add a big margin for slower machines in case validation is enabled. - jest.setTimeout(60 * 1000); -} - -let _cachedTS: reflect.TypeSystem; -async function obtainTypeSystem() { - // Load the typesystem only once, it's quite expensive - if (!_cachedTS) { - _cachedTS = await loadTypeSystem(VALIDATE_ASSEMBLIES); - } - return _cachedTS; -} - -for (const templateFile of fs.readdirSync(dir)) { - test(templateFile, async () => { - const workingDirectory = dir; - const template = await readTemplate(path.resolve(dir, templateFile)); - const typeSystem = await obtainTypeSystem(); - - const app = new cdk.App({ - context: { - ...FUTURE_FLAGS, - } - }); - const stackName = stackNameFromFileName(templateFile); - - new DeclarativeStack(app, stackName, { - workingDirectory, - template, - typeSystem - }); - - const output = app.synth().getStackByName(stackName); - expect(output.template).toMatchSnapshot(stackName); - }); -} diff --git a/packages/decdk/tsconfig.json b/packages/decdk/tsconfig.json deleted file mode 100644 index 60a2dda5d1b9b..0000000000000 --- a/packages/decdk/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2018", - "module": "commonjs", - "lib": ["es2018"], - "strict": true, - "alwaysStrict": true, - "declaration": true, - "inlineSourceMap": true, - "inlineSources": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "resolveJsonModule": true, - "composite": true, - "incremental": true - }, - "exclude": [ - "test/enrichments/**" - ], - "references": [ - { "path": "../@aws-cdk/core" }, - { "path": "../@aws-cdk/cx-api" } - ] -} diff --git a/tools/@aws-cdk/cdk-build-tools/package.json b/tools/@aws-cdk/cdk-build-tools/package.json index ae33d288d14df..203d7142e47f3 100644 --- a/tools/@aws-cdk/cdk-build-tools/package.json +++ b/tools/@aws-cdk/cdk-build-tools/package.json @@ -62,7 +62,7 @@ "markdownlint-cli": "^0.30.0", "nyc": "^15.1.0", "semver": "^7.3.5", - "ts-jest": "^27.1.2", + "ts-jest": "^27.1.3", "typescript": "~3.9.10", "yargs": "^16.2.0" }, diff --git a/version.v1.json b/version.v1.json index 3c3dca292b0e2..b2dc0b4c0995b 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.139.0" + "version": "1.140.0" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bf3c0213efaee..da1eded3a0af7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1582,10 +1582,10 @@ dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.89": - version "8.10.89" - resolved "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.89.tgz#22617ecc1eef9571abebb50c947553362da6051b" - integrity sha512-jwtSuEZj4rY4R2pAEOXi+RutS8RWbwMzoGlRVukdyOpnfqA/XPkAf8QoGWmg4o/UaNpQ8Mj0Xhkp5SZ1t/Zq4Q== +"@types/aws-lambda@^8.10.90": + version "8.10.90" + resolved "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.90.tgz#d9995deb8925afb78b8c6179fc58fa9316925102" + integrity sha512-B08uyjXQuOh/Kyj9NZ0BEJjkfqqj4tsAYpbBgUMRydtYAs1Fs5WL5KiYFtu+OoG5mI64pnsvW8ohFgpJYWdWIg== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.1.18" @@ -1694,7 +1694,7 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/jest@^27.0.3", "@types/jest@^27.4.0": +"@types/jest@^27.4.0": version "27.4.0" resolved "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed" integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ== @@ -1752,9 +1752,9 @@ integrity sha512-uv53RrNdhbkV/3VmVCtfImfYCWC3GTTRn3R11Whni3EJ+gb178tkZBVNj2edLY5CMrB749dQi+SJkg87jsN8UQ== "@types/node@*", "@types/node@>= 8": - version "17.0.8" - resolved "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" - integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== + version "17.0.10" + resolved "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz#616f16e9d3a2a3d618136b1be244315d95bd7cab" + integrity sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog== "@types/node@^10.17.60": version "10.17.60" @@ -1762,9 +1762,9 @@ integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== "@types/node@^16.9.2": - version "16.11.19" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.19.tgz#1afa165146997b8286b6eabcb1c2d50729055169" - integrity sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng== + version "16.11.21" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.21.tgz#474d7589a30afcf5291f59bd49cca9ad171ffde4" + integrity sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2053,9 +2053,9 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.8.2" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" - integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== + version "8.9.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" + integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -2301,9 +2301,9 @@ aws-sdk-mock@^5.5.1: traverse "^0.6.6" aws-sdk@^2.596.0, aws-sdk@^2.848.0, aws-sdk@^2.928.0, aws-sdk@^2.979.0: - version "2.1055.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1055.0.tgz#07beb86650d5a313f7c899807c51b12b5e2f4117" - integrity sha512-99drH3mvXakw9we8Rs2cDQmi2pS7PVAC9pvTlB7lHPUwLYftMlko5cFMceZxvTHeyLkdvg98iNIHI3hbnzitoQ== + version "2.1059.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1059.0.tgz#8ce3fa0652ef2836665d0c3566bc56a3d5cfc929" + integrity sha512-Q+6T9kpO6aobUNboTOk9MVAmWbs/KK0pxgCNFK0M8YO+7EWUFkNOLHM9tdYOP5vsJK5pLz6D2t2w3lHQjKzGlg== dependencies: buffer "4.9.2" events "1.1.1" @@ -2598,9 +2598,9 @@ camelcase@^6.2.0, camelcase@^6.2.1, camelcase@^6.3.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001286: - version "1.0.30001299" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz#d753bf6444ed401eb503cbbe17aa3e1451b5a68c" - integrity sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw== + version "1.0.30001300" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz#11ab6c57d3eb6f964cba950401fd00a146786468" + integrity sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA== case@1.6.3, case@^1.6.3: version "1.6.3" @@ -2612,10 +2612,10 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -cdk-generate-synthetic-examples@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/cdk-generate-synthetic-examples/-/cdk-generate-synthetic-examples-0.1.2.tgz#356e9a96c8f5f681245847d15407b6fc48038cd7" - integrity sha512-vHM+U/JIBU/xiC0/Joo8UOkcqPdN3vBMsToib/ekD3nraDgeFeKZ2I0DAxetjk+9Ned34NBA+u8malVxwVuiTw== +cdk-generate-synthetic-examples@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/cdk-generate-synthetic-examples/-/cdk-generate-synthetic-examples-0.1.3.tgz#ec31aa901e364e279c2ca1d081edc94c9c801f54" + integrity sha512-745IaTttxe1TZtiLBPiFvplQX1+4hIGs3DS0etzod6fNL3Kf5Ht/+2b/Aqpvldv29vyUIHg5Zozo1gHdeNudgA== dependencies: "@jsii/spec" "^1.52.1" fs-extra "^10.0.0" @@ -2624,17 +2624,17 @@ cdk-generate-synthetic-examples@^0.1.2: jsii-rosetta "^1.52.1" yargs "^17.3.1" -cdk8s-plus-21@^1.0.0-beta.73: - version "1.0.0-beta.73" - resolved "https://registry.npmjs.org/cdk8s-plus-21/-/cdk8s-plus-21-1.0.0-beta.73.tgz#72e611ad1d8a168e7b62b07e6cc979b4e73dddc8" - integrity sha512-a7RtYlNZwiSzknvhC2+9LHpLUxCMIrfgsRaIjLgxDPgNImCdpPgvlVCdMXuntvXWHgTeTSh+PwSau0mO2qphnQ== +cdk8s-plus-21@^1.0.0-beta.77: + version "1.0.0-beta.77" + resolved "https://registry.npmjs.org/cdk8s-plus-21/-/cdk8s-plus-21-1.0.0-beta.77.tgz#3ac09d3612cfd7a64e3ff94e9a1016b29eefcfbf" + integrity sha512-W/wqEqFeh7x6hVwaiqFnxilMrjNDbyfpM3Yfh7SytDVFjPdQmzISAVe/kpnP8Om07A8mUHE/synGSvDwRjoVdA== dependencies: minimatch "^3.0.4" -cdk8s@^1.3.32: - version "1.3.32" - resolved "https://registry.npmjs.org/cdk8s/-/cdk8s-1.3.32.tgz#bbb21a249827ba48b0521f25121d47fd8ec1a548" - integrity sha512-E1BM3DFEdkrwHaiBXBoil7fVN882PXwE12RLr/Czou18wUdcjb770VS3+MhJuRrqS4RDCY6bmsGr4GYLyjM7CA== +cdk8s@^1.4.6: + version "1.4.6" + resolved "https://registry.npmjs.org/cdk8s/-/cdk8s-1.4.6.tgz#7d38d5a2ac4de11a48e9e1ddf1375b66b826a355" + integrity sha512-LAUIvbIVq8qNVHn5CEnUpFlbpvgsUrXW1fj7BDgBu0FGODdUjab5iUYZjMT/3Cao8I+mQj4xLfvkhzl5uYXIAA== dependencies: fast-json-patch "^2.2.1" follow-redirects "^1.14.7" @@ -2680,10 +2680,10 @@ charenc@0.0.2: resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= -chokidar@^3.5.2: - version "3.5.2" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== +chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -2922,9 +2922,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constructs@^3.3.69: - version "3.3.186" - resolved "https://registry.npmjs.org/constructs/-/constructs-3.3.186.tgz#8a2deca58191d4a47ce564d82800c78221a0d064" - integrity sha512-QgX306tEq7aUo2CnJlhlYyHgBbuwHdmSxFFg42qR2AvOr8f9tHZA4326OlfsiPrTu0I5JmcER7fGsT2K9vIhVw== + version "3.3.193" + resolved "https://registry.npmjs.org/constructs/-/constructs-3.3.193.tgz#6fe4ff6495127337cff10f70a81d546e61cab530" + integrity sha512-85lCvrPlrlTnKS/rpl/jiB9y5t4GGWHhubRP3hlQbKiGAeQ2VIqcjODsU5oorrDi5JzDxcdZ83vfPtP1RtELWA== conventional-changelog-angular@^5.0.12: version "5.0.13" @@ -3569,9 +3569,9 @@ ecc-jsbn@~0.1.1: safer-buffer "^2.1.0" electron-to-chromium@^1.4.17: - version "1.4.43" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.43.tgz#665c0cd8d5e7cce0ba78d90a514c8c813ca3bdbe" - integrity sha512-PO3kEfcxPrti/4STbXvCkNIF4fgWvCKl2508e6UI7KomCDffpIfeBZLXsh5DK/XGsjUw3kwq6WEsi0MJTlGAdg== + version "1.4.48" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.48.tgz#1948b5227aa0ca1ed690945eae1adbe9e7904575" + integrity sha512-RT3SEmpv7XUA+tKXrZGudAWLDpa7f8qmhjcLaM6OD/ERxjQ/zAojT8/Vvo0BSzbArkElFZ1WyZ9FuwAYbkdBNA== emittery@^0.8.1: version "0.8.1" @@ -4213,9 +4213,9 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.2.9: - version "3.2.10" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz#2734f83baa7f43b7fd41e13bc34438f4ffe284ee" - integrity sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A== + version "3.2.11" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -5802,7 +5802,7 @@ jest-worker@^27.4.6: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^27.3.1, jest@^27.4.5, jest@^27.4.7: +jest@^27.3.1, jest@^27.4.7: version "27.4.7" resolved "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz#87f74b9026a1592f2da05b4d258e57505f28eca4" integrity sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg== @@ -6855,9 +6855,9 @@ nock@^13.2.2: propagate "^2.0.0" node-fetch@^2.6.1: - version "2.6.6" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + version "2.6.7" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" @@ -7967,9 +7967,9 @@ redent@^3.0.0: strip-indent "^3.0.0" regexp.prototype.flags@^1.3.0: - version "1.3.1" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + version "1.4.1" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" + integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" @@ -8876,10 +8876,10 @@ trim-newlines@^3.0.0: resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-jest@^27.1.2: - version "27.1.2" - resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.2.tgz#5991d6eb3fd8e1a8d4b8f6de3ec0a3cc567f3151" - integrity sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA== +ts-jest@^27.1.3: + version "27.1.3" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz#1f723e7e74027c4da92c0ffbd73287e8af2b2957" + integrity sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA== dependencies: bs-logger "0.x" fast-json-stable-stringify "2.x" @@ -9388,9 +9388,9 @@ wordwrap@>=0.0.2, wordwrap@^1.0.0: integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= workerpool@^6.1.5: - version "6.1.5" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" - integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== + version "6.2.0" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== wrap-ansi@^6.2.0: version "6.2.0"