diff --git a/CHANGELOG.v2.alpha.md b/CHANGELOG.v2.alpha.md index a0690279f7076..243bfd95bb4fe 100644 --- a/CHANGELOG.v2.alpha.md +++ b/CHANGELOG.v2.alpha.md @@ -2,7 +2,12 @@ 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. -## [2.19.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.18.0-alpha.0...v2.19.0-alpha.0) (2022-03-30) +## [2.19.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.18.0-alpha.0...v2.19.0-alpha.0) (2022-03-31) + + +### Features + +* **kinesisanalytics-flink:** Add metrics to Flink applications ([#19599](https://github.com/aws/aws-cdk/issues/19599)) ([dab6aca](https://github.com/aws/aws-cdk/commit/dab6aca5005c8d6d180aada699a4cebc2ef5aefa)) ## [2.18.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.17.0-alpha.0...v2.18.0-alpha.0) (2022-03-28) diff --git a/CHANGELOG.v2.md b/CHANGELOG.v2.md index b11138c494c8d..601f5858c8705 100644 --- a/CHANGELOG.v2.md +++ b/CHANGELOG.v2.md @@ -2,19 +2,28 @@ 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. -## [2.19.0](https://github.com/aws/aws-cdk/compare/v2.18.0...v2.19.0) (2022-03-30) +## [2.19.0](https://github.com/aws/aws-cdk/compare/v2.18.0...v2.19.0) (2022-03-31) ### Features -* add new integration test runner ([#19529](https://github.com/aws/aws-cdk/issues/19529)) ([e7f43d1](https://github.com/aws/aws-cdk/commit/e7f43d1a3bb52bbf589d7472c9a9b89e3c1cc8c1)) * **aws-ec2:** Enable/disable EC2 "Detailed Monitoring" ([#19437](https://github.com/aws/aws-cdk/issues/19437)) ([94f9d27](https://github.com/aws/aws-cdk/commit/94f9d27e626bced5fc68a6ebbd653fea21c6e21e)) +* **core:** add size.isUnresolved ([#19569](https://github.com/aws/aws-cdk/issues/19569)) ([ed26731](https://github.com/aws/aws-cdk/commit/ed26731a0a6263482d76441fc06e9607963ac838)) +* **ecs-patterns:** PlacementStrategy and PlacementConstraint for many patterns ([#19612](https://github.com/aws/aws-cdk/issues/19612)) ([0096e67](https://github.com/aws/aws-cdk/commit/0096e672e02123a2ae4e094ba9bb11af3aef20b2)) +* **elbv2:** use `addAction()` on an imported application listener ([#19293](https://github.com/aws/aws-cdk/issues/19293)) ([18a6b0c](https://github.com/aws/aws-cdk/commit/18a6b0cecb5e8a419d09a1456953cb2f422a6d76)), closes [#10902](https://github.com/aws/aws-cdk/issues/10902) +* **lambda:** warn if you use `function.grantInvoke` while also using `currentVersion` ([#19464](https://github.com/aws/aws-cdk/issues/19464)) ([fd1fff9](https://github.com/aws/aws-cdk/commit/fd1fff904a70d18dc9c7863aefc03b3ee44c2863)), closes [#19273](https://github.com/aws/aws-cdk/issues/19273) [#19318](https://github.com/aws/aws-cdk/issues/19318) ### Bug Fixes -* **aws-cdk:** include nested stacks when building changesets ([#19494](https://github.com/aws/aws-cdk/issues/19494)) ([97cc8e2](https://github.com/aws/aws-cdk/commit/97cc8e29e155b222d553b1fe955a0302036feed5)), closes [#5722](https://github.com/aws/aws-cdk/issues/5722) [#17396](https://github.com/aws/aws-cdk/issues/17396) [#19224](https://github.com/aws/aws-cdk/issues/19224) +* **apigateway:** allow using GENERATE_IF_NEEDED for the physical name in LambdaRestApi ([#19638](https://github.com/aws/aws-cdk/issues/19638)) ([e817381](https://github.com/aws/aws-cdk/commit/e8173812aad5f482b1bfcc6737f63cfef0c4841c)), closes [#9374](https://github.com/aws/aws-cdk/issues/9374) +* **apigateway:** id in schema model maps to $id ([#15113](https://github.com/aws/aws-cdk/issues/15113)) ([ac5a345](https://github.com/aws/aws-cdk/commit/ac5a3458fe3687014166b20aefe30442867d162a)), closes [#14585](https://github.com/aws/aws-cdk/issues/14585) +* **aws-cognito:** Lambda::Permission of lambdaTrigger should have a SourceArn ([#19622](https://github.com/aws/aws-cdk/issues/19622)) ([c62eeb7](https://github.com/aws/aws-cdk/commit/c62eeb7162d85c8cb162f8c0ad4b93fb5bccf981)), closes [#19604](https://github.com/aws/aws-cdk/issues/19604) * **docdb:** DB Instance ARN uses 'docdb' as the service component instead of 'rds' ([#19555](https://github.com/aws/aws-cdk/issues/19555)) ([6a63924](https://github.com/aws/aws-cdk/commit/6a63924c0b184342befd92903b8867e45b158252)), closes [#19554](https://github.com/aws/aws-cdk/issues/19554) +* **eks:** incorrect version of aws-node-termination-handler ([#19510](https://github.com/aws/aws-cdk/issues/19510)) ([9c712cc](https://github.com/aws/aws-cdk/commit/9c712cc457ccb80d7180fee67a101b76fc01d207)) +* **elbv2:** unable to add multiple certificates to NLB ([#19289](https://github.com/aws/aws-cdk/issues/19289)) ([e8142e9](https://github.com/aws/aws-cdk/commit/e8142e944ac5fae9948e5c010fe475806b83c94b)), closes [#13490](https://github.com/aws/aws-cdk/issues/13490) [#8918](https://github.com/aws/aws-cdk/issues/8918) [#15328](https://github.com/aws/aws-cdk/issues/15328) +* **rds:** `SnapshotCredentials.fromSecret()` takes a `Secret`, not `ISecret` ([#19639](https://github.com/aws/aws-cdk/issues/19639)) ([a74d82e](https://github.com/aws/aws-cdk/commit/a74d82e667ba3cfbb3341392f7c641b0e29d47f0)), closes [#19409](https://github.com/aws/aws-cdk/issues/19409) + ## [2.18.0](https://github.com/aws/aws-cdk/compare/v2.17.0...v2.18.0) (2022-03-28) diff --git a/allowed-breaking-changes.txt b/allowed-breaking-changes.txt index 864ea5178512b..6069472407d94 100644 --- a/allowed-breaking-changes.txt +++ b/allowed-breaking-changes.txt @@ -75,7 +75,7 @@ strengthened:@aws-cdk/aws-stepfunctions-tasks.BatchSubmitJobProps removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.cluster strengthened:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps -# Remove IO2 from autoscaling EbsDeviceVolumeType. This value is not supported +# Remove IO2 from autoscaling EbsDeviceVolumeType. This value is not supported # at the moment and was not supported in the past. removed:@aws-cdk/aws-autoscaling.EbsDeviceVolumeType.IO2 @@ -83,12 +83,12 @@ removed:@aws-cdk/aws-autoscaling.EbsDeviceVolumeType.IO2 removed:@aws-cdk/aws-stepfunctions-tasks.EmrCreateCluster.AutoTerminationPolicyProperty removed:@aws-cdk/aws-stepfunctions-tasks.EmrCreateClusterProps.autoTerminationPolicy -# Changed property securityGroupId to optional because either securityGroupId or +# Changed property securityGroupId to optional because either securityGroupId or # securityGroupName is required. Therefore securityGroupId is no longer mandatory. weakened:@aws-cdk/cloud-assembly-schema.SecurityGroupContextQuery # refactor autoscaling lifecycle hook target bind() methods to make role optional by -# having bind() methods create the role if it isn't passed to them +# having bind() methods create the role if it isn't passed to them incompatible-argument:@aws-cdk/aws-autoscaling-hooktargets.FunctionHook.bind incompatible-argument:@aws-cdk/aws-autoscaling-hooktargets.QueueHook.bind incompatible-argument:@aws-cdk/aws-autoscaling-hooktargets.TopicHook.bind @@ -106,7 +106,7 @@ removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.maxRecord removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.parallelizationFactor removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.reportBatchItemFailures removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.retryAttempts -removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.tumblingWindow +removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.tumblingWindow removed:@aws-cdk/aws-lambda-event-sources.SelfManagedKafkaEventSourceProps.bisectBatchOnError removed:@aws-cdk/aws-lambda-event-sources.SelfManagedKafkaEventSourceProps.maxRecordAge removed:@aws-cdk/aws-lambda-event-sources.SelfManagedKafkaEventSourceProps.parallelizationFactor @@ -125,4 +125,8 @@ changed-type:@aws-cdk/aws-elasticloadbalancingv2.NetworkLoadBalancer.vpc # removed methods and properties related to event bridge notifications for S3 buckets as they are not yet supported (19 Jan 2022) removed:@aws-cdk/aws-s3.Bucket.enableEventBridgeNotification removed:@aws-cdk/aws-s3.BucketBase.enableEventBridgeNotification -removed:@aws-cdk/aws-s3.BucketProps.eventBridgeEnabled \ No newline at end of file +removed:@aws-cdk/aws-s3.BucketProps.eventBridgeEnabled + +# changed the type of RDS's SnapshotCredentials.secret from Secret to ISecret, +# shouldn't matter +changed-type:@aws-cdk/aws-rds.SnapshotCredentials.secret diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index ca8ffec507a81..a48a9c90588ac 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -322,8 +322,11 @@ export abstract class RestApiBase extends Resource implements IRestApi { protected cloudWatchAccount?: CfnAccount; constructor(scope: Construct, id: string, props: RestApiBaseProps = { }) { - super(scope, id); - this.restApiName = props.restApiName ?? id; + const restApiName = props.restApiName ?? id; + super(scope, id, { + physicalName: restApiName, + }); + this.restApiName = restApiName; Object.defineProperty(this, RESTAPI_SYMBOL, { value: true }); } @@ -736,7 +739,7 @@ export class RestApi extends RestApiBase { super(scope, id, props); const resource = new CfnRestApi(this, 'Resource', { - name: this.restApiName, + name: this.physicalName, description: props.description, policy: props.policy, failOnWarnings: props.failOnWarnings, diff --git a/packages/@aws-cdk/aws-apigateway/lib/util.ts b/packages/@aws-cdk/aws-apigateway/lib/util.ts index 550250edcd432..a97f89882fe04 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/util.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/util.ts @@ -101,7 +101,6 @@ export class JsonSchemaMapper { private static readonly SchemaPropsWithPrefix: { [key: string]: string } = { schema: '$schema', ref: '$ref', - id: '$id', }; // The value indicates whether direct children should be key-mapped. private static readonly SchemaPropsWithUserDefinedChildren: { [key: string]: boolean } = { diff --git a/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts b/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts index 314225d3afe34..f7c47afe85d2b 100644 --- a/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts @@ -242,4 +242,24 @@ describe('lambda api', () => { ], }); }); + + test('LambdaRestApi allows passing GENERATE_IF_NEEDED as the physical name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new apigw.LambdaRestApi(stack, 'lambda-rest-api', { + handler: new lambda.Function(stack, 'handler', { + handler: 'index.handler', + code: lambda.Code.fromInline('boom'), + runtime: lambda.Runtime.NODEJS_10_X, + }), + restApiName: cdk.PhysicalName.GENERATE_IF_NEEDED, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::RestApi', { + Name: Match.absent(), + }); + }); }); diff --git a/packages/@aws-cdk/aws-apigateway/test/util.test.ts b/packages/@aws-cdk/aws-apigateway/test/util.test.ts index 30861de05dad1..79ea5c60e9682 100644 --- a/packages/@aws-cdk/aws-apigateway/test/util.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/util.test.ts @@ -1,4 +1,4 @@ -import { JsonSchema, JsonSchemaType } from '../lib'; +import { JsonSchema, JsonSchemaType, JsonSchemaVersion } from '../lib'; import { JsonSchemaMapper, parseAwsApiCall, parseMethodOptionsPath } from '../lib/util'; describe('util', () => { @@ -136,5 +136,18 @@ describe('util', () => { default: 'blue', }); }); + + test('"id" maps to "id" when using DRAFT-04', () => { + const schema: JsonSchema = { + schema: JsonSchemaVersion.DRAFT4, + id: 'http://json-schema.org/draft-04/schema#', + }; + + const actual = JsonSchemaMapper.toCfnJsonSchema(schema); + expect(actual).toEqual({ + $schema: 'http://json-schema.org/draft-04/schema#', + id: 'http://json-schema.org/draft-04/schema#', + }); + }); }); }); diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index a4157d629307d..21a41f4c8721c 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -936,7 +936,7 @@ export class UserPool extends UserPoolBase { const capitalize = name.charAt(0).toUpperCase() + name.slice(1); fn.addPermission(`${capitalize}Cognito`, { principal: new ServicePrincipal('cognito-idp.amazonaws.com'), - sourceArn: this.userPoolArn, + sourceArn: Lazy.string({ produce: () => this.userPoolArn }), }); } diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json index c28251be02c92..8bc2a5deae13f 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json @@ -60,7 +60,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "pool056F3F7E", + "Arn" + ] + } } }, "keyFEDD6EC0": { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json index 0811dc3173db4..bf01ef9d1faaf 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json @@ -61,7 +61,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "customMessageServiceRoleB4AE7F17": { @@ -125,7 +131,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "defineAuthChallengeServiceRole9E2D15DF": { @@ -189,7 +201,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "postAuthenticationServiceRole5B3B242A": { @@ -253,7 +271,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "postConfirmationServiceRole864BE5F9": { @@ -317,7 +341,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "preAuthenticationServiceRole9712F4D8": { @@ -381,7 +411,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "preSignUpServiceRole0A7E91EB": { @@ -445,7 +481,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "preTokenGenerationServiceRole430C3D14": { @@ -509,7 +551,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "userMigrationServiceRole091766B0": { @@ -573,7 +621,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "verifyAuthChallengeResponseServiceRole7077884C": { @@ -637,7 +691,13 @@ "Arn" ] }, - "Principal": "cognito-idp.amazonaws.com" + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "myuserpool01998219", + "Arn" + ] + } } }, "myuserpoolsmsRole0E16FDD9": { diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index b482d244ea6fa..25be5288800cf 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -335,7 +335,7 @@ describe('User Pool', () => { const fn = fooFunction(stack, 'preSignUp'); // WHEN - new UserPool(stack, 'Pool', { + const pool = new UserPool(stack, 'Pool', { lambdaTriggers: { preSignUp: fn, }, @@ -351,6 +351,7 @@ describe('User Pool', () => { Action: 'lambda:InvokeFunction', FunctionName: stack.resolve(fn.functionArn), Principal: 'cognito-idp.amazonaws.com', + SourceArn: stack.resolve(pool.userPoolArn), }); }); @@ -362,7 +363,7 @@ describe('User Pool', () => { const smsFn = fooFunction(stack, 'customSmsSender'); // WHEN - new UserPool(stack, 'Pool', { + const pool = new UserPool(stack, 'Pool', { customSenderKmsKey: kmsKey, lambdaTriggers: { customEmailSender: emailFn, @@ -387,11 +388,13 @@ describe('User Pool', () => { Action: 'lambda:InvokeFunction', FunctionName: stack.resolve(emailFn.functionArn), Principal: 'cognito-idp.amazonaws.com', + SourceArn: stack.resolve(pool.userPoolArn), }); Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: stack.resolve(smsFn.functionArn), Principal: 'cognito-idp.amazonaws.com', + SourceArn: stack.resolve(pool.userPoolArn), }); }); @@ -479,6 +482,7 @@ describe('User Pool', () => { Action: 'lambda:InvokeFunction', FunctionName: stack.resolve(fn.functionArn), Principal: 'cognito-idp.amazonaws.com', + SourceArn: stack.resolve(pool.userPoolArn), }); }); }); @@ -1760,4 +1764,4 @@ function fooFunction(scope: Construct, name: string): lambda.IFunction { function fooKey(scope: Construct, name: string): kms.Key { return new kms.Key(scope, name); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts index 352bdf6dcd874..9bb2bcf607caa 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts @@ -1,4 +1,4 @@ -import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { Ec2Service, Ec2TaskDefinition, PlacementConstraint, PlacementStrategy } from '@aws-cdk/aws-ecs'; import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -64,6 +64,22 @@ export interface ApplicationLoadBalancedEc2ServiceProps extends ApplicationLoadB * @default - No memory reserved. */ readonly memoryReservationMiB?: number; + + /** + * The placement constraints to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Constraints](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-constraints.html). + * + * @default - No constraints. + */ + readonly placementConstraints?: PlacementConstraint[]; + + /** + * The placement strategies to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Strategies](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html). + * + * @default - No strategies. + */ + readonly placementStrategies?: PlacementStrategy[]; } /** @@ -136,6 +152,8 @@ export class ApplicationLoadBalancedEc2Service extends ApplicationLoadBalancedSe cloudMapOptions: props.cloudMapOptions, deploymentController: props.deploymentController, circuitBreaker: props.circuitBreaker, + placementConstraints: props.placementConstraints, + placementStrategies: props.placementStrategies, }); this.addServiceAsTarget(this.service); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts index c84518094662a..6c00f2074ac85 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts @@ -1,4 +1,4 @@ -import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { Ec2Service, Ec2TaskDefinition, PlacementConstraint, PlacementStrategy } from '@aws-cdk/aws-ecs'; import { ApplicationTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; @@ -59,6 +59,22 @@ export interface ApplicationMultipleTargetGroupsEc2ServiceProps extends Applicat * @default - No memory reserved. */ readonly memoryReservationMiB?: number; + + /** + * The placement constraints to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Constraints](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-constraints.html). + * + * @default - No constraints. + */ + readonly placementConstraints?: PlacementConstraint[]; + + /** + * The placement strategies to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Strategies](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html). + * + * @default - No strategies. + */ + readonly placementStrategies?: PlacementStrategy[]; } /** @@ -151,6 +167,8 @@ export class ApplicationMultipleTargetGroupsEc2Service extends ApplicationMultip propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, cloudMapOptions: props.cloudMapOptions, + placementConstraints: props.placementConstraints, + placementStrategies: props.placementStrategies, }); } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts index 451731dadc626..6372fd6d7806e 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts @@ -1,4 +1,4 @@ -import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { Ec2Service, Ec2TaskDefinition, PlacementConstraint, PlacementStrategy } from '@aws-cdk/aws-ecs'; import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -62,6 +62,22 @@ export interface NetworkLoadBalancedEc2ServiceProps extends NetworkLoadBalancedS * @default - No memory reserved. */ readonly memoryReservationMiB?: number; + + /** + * The placement constraints to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Constraints](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-constraints.html). + * + * @default - No constraints. + */ + readonly placementConstraints?: PlacementConstraint[]; + + /** + * The placement strategies to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Strategies](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html). + * + * @default - No strategies. + */ + readonly placementStrategies?: PlacementStrategy[]; } /** @@ -134,6 +150,8 @@ export class NetworkLoadBalancedEc2Service extends NetworkLoadBalancedServiceBas cloudMapOptions: props.cloudMapOptions, deploymentController: props.deploymentController, circuitBreaker: props.circuitBreaker, + placementConstraints: props.placementConstraints, + placementStrategies: props.placementStrategies, }); this.addServiceAsTarget(this.service); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts index 331cd40490517..1ecaba043c990 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts @@ -1,4 +1,4 @@ -import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { Ec2Service, Ec2TaskDefinition, PlacementConstraint, PlacementStrategy } from '@aws-cdk/aws-ecs'; import { NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; @@ -58,6 +58,22 @@ export interface NetworkMultipleTargetGroupsEc2ServiceProps extends NetworkMulti * @default - No memory reserved. */ readonly memoryReservationMiB?: number; + + /** + * The placement constraints to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Constraints](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-constraints.html). + * + * @default - No constraints. + */ + readonly placementConstraints?: PlacementConstraint[]; + + /** + * The placement strategies to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Strategies](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html). + * + * @default - No strategies. + */ + readonly placementStrategies?: PlacementStrategy[]; } /** @@ -151,6 +167,8 @@ export class NetworkMultipleTargetGroupsEc2Service extends NetworkMultipleTarget propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, cloudMapOptions: props.cloudMapOptions, + placementConstraints: props.placementConstraints, + placementStrategies: props.placementStrategies, }); } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts index e6042a66ea112..93db9d384a39f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts @@ -1,4 +1,4 @@ -import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { Ec2Service, Ec2TaskDefinition, PlacementConstraint, PlacementStrategy } from '@aws-cdk/aws-ecs'; import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -68,6 +68,22 @@ export interface QueueProcessingEc2ServiceProps extends QueueProcessingServiceBa * @default - QueueProcessingContainer */ readonly containerName?: string; + + /** + * The placement constraints to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Constraints](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-constraints.html). + * + * @default - No constraints. + */ + readonly placementConstraints?: PlacementConstraint[]; + + /** + * The placement strategies to use for tasks in the service. For more information, see + * [Amazon ECS Task Placement Strategies](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html). + * + * @default - No strategies. + */ + readonly placementStrategies?: PlacementStrategy[]; } /** @@ -125,6 +141,8 @@ export class QueueProcessingEc2Service extends QueueProcessingServiceBase { deploymentController: props.deploymentController, circuitBreaker: props.circuitBreaker, capacityProviderStrategies: props.capacityProviderStrategies, + placementConstraints: props.placementConstraints, + placementStrategies: props.placementStrategies, }); this.configureAutoscalingForService(this.service); 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 aea8f337b02d0..03975b2cebec3 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 @@ -11,6 +11,8 @@ import { Ec2TaskDefinition, PropagatedTagSource, Protocol, + PlacementStrategy, + PlacementConstraint, } from '@aws-cdk/aws-ecs'; import { ApplicationProtocol, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; @@ -162,6 +164,8 @@ describe('When Application Load Balancer', () => { protocol: Protocol.TCP, }, ], + placementStrategies: [PlacementStrategy.spreadAcrossInstances(), PlacementStrategy.packedByCpu(), PlacementStrategy.randomly()], + placementConstraints: [PlacementConstraint.memberOf('attribute:ecs.instance-type =~ m5a.*')], }); // THEN @@ -188,6 +192,8 @@ describe('When Application Load Balancer', () => { ], PropagateTags: 'SERVICE', ServiceName: 'myService', + PlacementConstraints: [{ Type: 'memberOf', Expression: 'attribute:ecs.instance-type =~ m5a.*' }], + PlacementStrategies: [{ Field: 'instanceId', Type: 'spread' }, { Field: 'cpu', Type: 'binpack' }, { Type: 'random' }], }); Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { @@ -1039,6 +1045,8 @@ describe('When Network Load Balancer', () => { listener: 'listener2', }, ], + placementStrategies: [PlacementStrategy.spreadAcrossInstances(), PlacementStrategy.packedByCpu(), PlacementStrategy.randomly()], + placementConstraints: [PlacementConstraint.memberOf('attribute:ecs.instance-type =~ m5a.*')], }); // THEN @@ -1066,6 +1074,8 @@ describe('When Network Load Balancer', () => { PropagateTags: 'SERVICE', SchedulingStrategy: 'REPLICA', ServiceName: 'myService', + PlacementConstraints: [{ Type: 'memberOf', Expression: 'attribute:ecs.instance-type =~ m5a.*' }], + PlacementStrategies: [{ Field: 'instanceId', Type: 'spread' }, { Field: 'cpu', Type: 'binpack' }, { Type: 'random' }], }); Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { 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 db6e480a8a823..7ae4aa4109cdd 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 @@ -231,6 +231,8 @@ testDeprecated('test ECS queue worker service construct - with optional props', family: 'ecs-task-family', circuitBreaker: { rollback: true }, gpuCount: 256, + placementStrategies: [ecs.PlacementStrategy.spreadAcrossInstances(), ecs.PlacementStrategy.packedByCpu(), ecs.PlacementStrategy.randomly()], + placementConstraints: [ecs.PlacementConstraint.memberOf('attribute:ecs.instance-type =~ m5a.*')], }); // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. @@ -248,6 +250,8 @@ testDeprecated('test ECS queue worker service construct - with optional props', DeploymentController: { Type: 'ECS', }, + PlacementConstraints: [{ Type: 'memberOf', Expression: 'attribute:ecs.instance-type =~ m5a.*' }], + PlacementStrategies: [{ Field: 'instanceId', Type: 'spread' }, { Field: 'cpu', Type: 'binpack' }, { Type: 'random' }], }); Template.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 1a3c3dd742407..e9c93f82712eb 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -942,7 +942,7 @@ abstract class ClusterBase extends Resource implements ICluster { if (!this._spotInterruptHandler) { this._spotInterruptHandler = this.addHelmChart('spot-interrupt-handler', { chart: 'aws-node-termination-handler', - version: '1.14.1', + version: '0.18.0', repository: 'https://aws.github.io/eks-charts', namespace: 'kube-system', values: { diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 02dc4f65277ba..519b5c7ee8f03 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -2690,7 +2690,7 @@ }, "Release": "ksclustertestclusterchartspotinterrupthandlerf41ba997", "Chart": "aws-node-termination-handler", - "Version": "1.14.1", + "Version": "0.18.0", "Values": "{\"nodeSelector\":{\"lifecycle\":\"Ec2Spot\"}}", "Namespace": "kube-system", "Repository": "https://aws.github.io/eks-charts", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 38d9b19153cd0..adb2c6f580c98 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -530,6 +530,21 @@ export interface IApplicationListener extends IResource, ec2.IConnectable { * Don't call this directly. It is called by ApplicationTargetGroup. */ registerConnectable(connectable: ec2.IConnectable, portRange: ec2.Port): void; + + /** + * Perform the given action on incoming requests + * + * This allows full control of the default action of the load balancer, + * including Action chaining, fixed responses and redirect responses. See + * the `ListenerAction` class for all options. + * + * It's possible to add routing conditions to the Action added in this way. + * + * It is not possible to add a default action to an imported IApplicationListener. + * In order to add actions to an imported IApplicationListener a `priority` + * must be provided. + */ + addAction(id: string, props: AddApplicationActionProps): void; } /** @@ -649,6 +664,36 @@ abstract class ExternalApplicationListener extends Resource implements IApplicat // eslint-disable-next-line max-len throw new Error('Can only call addTargets() when using a constructed ApplicationListener; construct a new TargetGroup and use addTargetGroup.'); } + + /** + * Perform the given action on incoming requests + * + * This allows full control of the default action of the load balancer, + * including Action chaining, fixed responses and redirect responses. See + * the `ListenerAction` class for all options. + * + * It's possible to add routing conditions to the Action added in this way. + * + * It is not possible to add a default action to an imported IApplicationListener. + * In order to add actions to an imported IApplicationListener a `priority` + * must be provided. + */ + public addAction(id: string, props: AddApplicationActionProps): void { + checkAddRuleProps(props); + + if (props.priority !== undefined) { + // New rule + // + // TargetGroup.registerListener is called inside ApplicationListenerRule. + new ApplicationListenerRule(this, id + 'Rule', { + listener: this, + priority: props.priority, + ...props, + }); + } else { + throw new Error('priority must be set for actions added to an imported listener'); + } + } } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener-certificate.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener-certificate.ts new file mode 100644 index 0000000000000..f42b50e43e6e5 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener-certificate.ts @@ -0,0 +1,39 @@ +import { Construct } from 'constructs'; +import { CfnListenerCertificate } from '../elasticloadbalancingv2.generated'; +import { IListenerCertificate } from '../shared/listener-certificate'; +import { INetworkListener } from './network-listener'; + +/** + * Properties for adding a set of certificates to a listener + */ +export interface NetworkListenerCertificateProps { + /** + * The listener to attach the rule to + */ + readonly listener: INetworkListener; + + /** + * Certificates to attach + * + * Duplicates are not allowed. + */ + readonly certificates: IListenerCertificate[]; +} + +/** + * Add certificates to a listener + */ +export class NetworkListenerCertificate extends Construct { + constructor(scope: Construct, id: string, props: NetworkListenerCertificateProps) { + super(scope, id); + + const certificates = [ + ...(props.certificates || []).map(c => ({ certificateArn: c.certificateArn })), + ]; + + new CfnListenerCertificate(this, 'Resource', { + listenerArn: props.listener.listenerArn, + certificates, + }); + } +} diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts index d48dbafc8202a..df043d06282b7 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts @@ -1,5 +1,5 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; -import { Duration, IResource, Resource } from '@aws-cdk/core'; +import { Duration, IResource, Resource, Lazy } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { BaseListener, BaseListenerLookupOptions } from '../shared/base-listener'; import { HealthCheck } from '../shared/base-target-group'; @@ -7,6 +7,7 @@ import { AlpnPolicy, Protocol, SslPolicy } from '../shared/enums'; import { IListenerCertificate } from '../shared/listener-certificate'; import { validateNetworkProtocol } from '../shared/util'; import { NetworkListenerAction } from './network-listener-action'; +import { NetworkListenerCertificate } from './network-listener-certificate'; import { INetworkLoadBalancer } from './network-load-balancer'; import { INetworkLoadBalancerTarget, INetworkTargetGroup, NetworkTargetGroup } from './network-target-group'; @@ -160,6 +161,11 @@ export class NetworkListener extends BaseListener implements INetworkListener { */ public readonly loadBalancer: INetworkLoadBalancer; + /** + * ARNs of certificates added to this listener + */ + private readonly certificateArns: string[]; + /** * the protocol of the listener */ @@ -188,13 +194,17 @@ export class NetworkListener extends BaseListener implements INetworkListener { protocol: proto, port: props.port, sslPolicy: props.sslPolicy, - certificates: props.certificates, + certificates: Lazy.any({ produce: () => this.certificateArns.map(certificateArn => ({ certificateArn })) }, { omitEmptyArray: true }), alpnPolicy: props.alpnPolicy ? [props.alpnPolicy] : undefined, }); + this.certificateArns = []; this.loadBalancer = props.loadBalancer; this.protocol = proto; + if (certs.length > 0) { + this.addCertificates('DefaultCertificates', certs); + } if (props.defaultAction && props.defaultTargetGroups) { throw new Error('Specify at most one of \'defaultAction\' and \'defaultTargetGroups\''); } @@ -208,6 +218,29 @@ export class NetworkListener extends BaseListener implements INetworkListener { } } + /** + * Add one or more certificates to this listener. + * + * After the first certificate, this creates NetworkListenerCertificates + * resources since cloudformation requires the certificates array on the + * listener resource to have a length of 1. + */ + public addCertificates(id: string, certificates: IListenerCertificate[]): void { + const additionalCerts = [...certificates]; + if (this.certificateArns.length === 0 && additionalCerts.length > 0) { + const first = additionalCerts.splice(0, 1)[0]; + this.certificateArns.push(first.certificateArn); + } + // Only one certificate can be specified per resource, even though + // `certificates` is of type Array + for (let i = 0; i < additionalCerts.length; i++) { + new NetworkListenerCertificate(this, `${id}${i + 1}`, { + listener: this, + certificates: [additionalCerts[i]], + }); + } + } + /** * Load balance incoming requests to the given target groups. * 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 3db3b7d9495bf..d4095c93c5525 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts @@ -707,6 +707,85 @@ describe('tests', () => { }); }); + test('Can add actions to an imported listener', () => { + // GIVEN + const stack = new cdk.Stack(); + const stack2 = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const lb = new elbv2.ApplicationLoadBalancer(stack, 'LoadBalancer', { + vpc, + }); + const listener = lb.addListener('Listener', { + port: 80, + }); + + // WHEN + listener.addAction('Default', { + action: elbv2.ListenerAction.fixedResponse(404, { + contentType: 'text/plain', + messageBody: 'Not Found', + }), + }); + + const importedListener = elbv2.ApplicationListener.fromApplicationListenerAttributes(stack2, 'listener', { + listenerArn: 'listener-arn', + defaultPort: 443, + securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack2, 'SG', 'security-group-id', { + allowAllOutbound: false, + }), + }); + importedListener.addAction('Hello', { + action: elbv2.ListenerAction.fixedResponse(503), + conditions: [elbv2.ListenerCondition.pathPatterns(['/hello'])], + priority: 10, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + FixedResponseConfig: { + ContentType: 'text/plain', + MessageBody: 'Not Found', + StatusCode: '404', + }, + Type: 'fixed-response', + }, + ], + }); + + Template.fromStack(stack2).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerRule', { + ListenerArn: 'listener-arn', + Priority: 10, + Actions: [ + { + FixedResponseConfig: { + StatusCode: '503', + }, + Type: 'fixed-response', + }, + ], + }); + }); + + test('actions added to an imported listener must have a priority', () => { + // GIVEN + const stack = new cdk.Stack(); + + const importedListener = elbv2.ApplicationListener.fromApplicationListenerAttributes(stack, 'listener', { + listenerArn: 'listener-arn', + defaultPort: 443, + securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'security-group-id', { + allowAllOutbound: false, + }), + }); + expect(() => { + importedListener.addAction('Hello', { + action: elbv2.ListenerAction.fixedResponse(503), + }); + }).toThrow(/priority must be set for actions added to an imported listener/); + }); + testDeprecated('Can add redirect responses', () => { // GIVEN const stack = new cdk.Stack(); 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 d5628fb5ef3fe..f6c10da596916 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts @@ -416,6 +416,62 @@ describe('tests', () => { })).toThrow(/Protocol must be TLS when certificates have been specified/); }); + test('Can pass multiple certificates to network listener constructor', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const lb = new elbv2.NetworkLoadBalancer(stack, 'LB', { vpc }); + + // WHEN + lb.addListener('Listener', { + port: 443, + certificates: [ + importedCertificate(stack, 'cert1'), + importedCertificate(stack, 'cert2'), + ], + defaultTargetGroups: [new elbv2.NetworkTargetGroup(stack, 'Group', { vpc, port: 80 })], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { + Protocol: 'TLS', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Certificates: [{ CertificateArn: 'cert2' }], + }); + }); + + test('Can add multiple certificates to network listener after construction', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const lb = new elbv2.NetworkLoadBalancer(stack, 'LB', { vpc }); + + // WHEN + const listener = lb.addListener('Listener', { + port: 443, + certificates: [ + importedCertificate(stack, 'cert1'), + ], + defaultTargetGroups: [new elbv2.NetworkTargetGroup(stack, 'Group', { vpc, port: 80 })], + }); + + listener.addCertificates('extra', [ + importedCertificate(stack, 'cert2'), + ]); + + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { + Protocol: 'TLS', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::ListenerCertificate', { + Certificates: [{ CertificateArn: 'cert2' }], + }); + }); + test('not allowed to specify defaultTargetGroups and defaultAction together', () => { // GIVEN const stack = new cdk.Stack(); @@ -462,3 +518,8 @@ class ResourceWithLBDependency extends cdk.CfnResource { this.node.addDependency(targetGroup.loadBalancerAttached); } } + +function importedCertificate(stack: cdk.Stack, + certificateArn = 'arn:aws:certificatemanager:123456789012:testregion:certificate/fd0b8392-3c0e-4704-81b6-8edf8612c852') { + return acm.Certificate.fromCertificateArn(stack, certificateArn, certificateArn); +} diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md b/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md index 2882cc60afc54..8e91fcd78b6ac 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md @@ -18,7 +18,7 @@ This package provides constructs for creating Kinesis Analytics Flink applications. To learn more about using using managed Flink applications, see the [AWS developer -guide](https://docs.aws.amazon.com/kinesisanalytics/latest/java/what-is.html). +guide](https://docs.aws.amazon.com/kinesisanalytics/latest/java/). ## Creating Flink Applications diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts index 4a0f3bfc36138..f0fe1f659c035 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts @@ -1,3 +1,4 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import { CfnApplicationCloudWatchLoggingOptionV2, CfnApplicationV2 } from '@aws-cdk/aws-kinesisanalytics'; import * as logs from '@aws-cdk/aws-logs'; @@ -37,6 +38,305 @@ export interface IApplication extends core.IResource, iam.IGrantable { * Convenience method for adding a policy statement to the application role. */ addToRolePolicy(policyStatement: iam.PolicyStatement): boolean; + + /** + * Return a CloudWatch metric associated with this Flink application. + * + * @param metricName The name of the metric + * @param props Customization properties + */ + metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of Kinesis Processing Units that are used to run your stream + * processing application. The average number of KPUs used each hour + * determines the billing for your application. + * + * Units: Count + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricKpus(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time elapsed during an outage for failing/recovering jobs. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricDowntime(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time that the job has been running without interruption. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default sample count over 5 minutes + */ + metricUptime(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of times this job has fully restarted since it was + * submitted. This metric does not measure fine-grained restarts. + * + * Units: Count + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricFullRestarts(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of times checkpointing has failed. + * + * Units: Count + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricNumberOfFailedCheckpoints(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time it took to complete the last checkpoint. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default maximum over 5 minutes + */ + metricLastCheckpointDuration(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total size of the last checkpoint. + * + * Units: Bytes + * + * Reporting Level: Application + * + * @default maximum over 5 minutes + */ + metricLastCheckpointSize(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The overall percentage of CPU utilization across task managers. For + * example, if there are five task managers, Kinesis Data Analytics publishes + * five samples of this metric per reporting interval. + * + * Units: Percentage + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricCpuUtilization(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Overall heap memory utilization across task managers. For example, if there + * are five task managers, Kinesis Data Analytics publishes five samples of + * this metric per reporting interval. + * + * Units: Percentage + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricHeapMemoryUtilization(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total time spent performing old garbage collection operations. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricOldGenerationGCTime(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of old garbage collection operations that have occurred + * across all task managers. + * + * Units: Count + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricOldGenerationGCCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of live threads used by the application. + * + * Units: Count + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricThreadsCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of records this application, operator, or task has + * received. + * + * Units: Count + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsIn(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of records this application, operator or task has + * received per second. + * + * Units: Count/Second + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsInPerSecond(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of records this application, operator or task has emitted. + * + * Units: Count + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsOut(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of records this application, operator or task has emitted + * per second. + * + * Units: Count/Second + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsOutPerSecond(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records this operator or task has dropped due to arriving late. + * + * Units: Count + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default sum over 5 minutes + */ + metricNumLateRecordsDropped(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The last watermark this application/operator/task/thread has received. + * + * Units: Milliseconds + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default maximum over 5 minutes + */ + metricCurrentInputWatermark(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The last watermark this application/operator/task/thread has received. + * + * Units: Milliseconds + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default maximum over 5 minutes + */ + metricCurrentOutputWatermark(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The amount of managed memory currently used. + * + * Units: Bytes + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricManagedMemoryUsed(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total amount of managed memory. + * + * Units: Bytes + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricManagedMemoryTotal(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Derived from managedMemoryUsed/managedMemoryTotal. + * + * Units: Percentage + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricManagedMemoryUtilization(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time (in milliseconds) this task or operator is idle (has no data to + * process) per second. Idle time excludes back pressured time, so if the task + * is back pressured it is not idle. + * + * Units: Milliseconds + * + * Reporting Level: Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricIdleTimeMsPerSecond(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time (in milliseconds) this task or operator is back pressured per + * second. + * + * Units: Milliseconds + * + * Reporting Level: Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricBackPressuredTimeMsPerSecond(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time (in milliseconds) this task or operator is busy (neither idle nor + * back pressured) per second. Can be NaN, if the value could not be + * calculated. + * + * Units: Milliseconds + * + * Reporting Level: Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricBusyTimePerMsPerSecond(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } /** @@ -60,6 +360,364 @@ abstract class ApplicationBase extends core.Resource implements IApplication { return false; } + + /** + * Return a CloudWatch metric associated with this Flink application. + * + * @param metricName The name of the metric + * @param props Customization properties + */ + metric(metricName: string, props?: cloudwatch.MetricOptions) { + return new cloudwatch.Metric({ + namespace: 'AWS/KinesisAnalytics', + metricName, + dimensionsMap: { Application: this.applicationName }, + ...props, + }).attachTo(this); + } + + /** + * The number of Kinesis Processing Units that are used to run your stream + * processing application. The average number of KPUs used each hour + * determines the billing for your application. + * + * Units: Count + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricKpus(props?: cloudwatch.MetricOptions) { + return this.metric('KPUs', { statistic: 'Average', ...props }); + } + + + /** + * The time elapsed during an outage for failing/recovering jobs. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricDowntime(props?: cloudwatch.MetricOptions) { + return this.metric('downtime', { statistic: 'Average', ...props }); + } + + /** + * The time that the job has been running without interruption. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricUptime(props?: cloudwatch.MetricOptions) { + return this.metric('uptime', { statistic: 'Average', ...props }); + } + + /** + * The total number of times this job has fully restarted since it was + * submitted. This metric does not measure fine-grained restarts. + * + * Units: Count + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricFullRestarts(props?: cloudwatch.MetricOptions) { + return this.metric('fullRestarts', { statistic: 'Sum', ...props }); + } + + /** + * The number of times checkpointing has failed. + * + * Units: Count + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricNumberOfFailedCheckpoints(props?: cloudwatch.MetricOptions) { + return this.metric('numberOfFailedCheckpoints', { statistic: 'Sum', ...props }); + } + + /** + * The time it took to complete the last checkpoint. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default maximum over 5 minutes + */ + metricLastCheckpointDuration(props?: cloudwatch.MetricOptions) { + return this.metric('lastCheckpointDuration', { statistic: 'Maximum', ...props }); + } + + /** + * The total size of the last checkpoint. + * + * Units: Bytes + * + * Reporting Level: Application + * + * @default maximum over 5 minutes + */ + metricLastCheckpointSize(props?: cloudwatch.MetricOptions) { + return this.metric('lastCheckpointSize', { statistic: 'Maximum', ...props }); + } + + /** + * The overall percentage of CPU utilization across task managers. For + * example, if there are five task managers, Kinesis Data Analytics publishes + * five samples of this metric per reporting interval. + * + * Units: Percentage + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricCpuUtilization(props?: cloudwatch.MetricOptions) { + return this.metric('cpuUtilization', { statistic: 'Average', ...props }); + } + + /** + * Overall heap memory utilization across task managers. For example, if there + * are five task managers, Kinesis Data Analytics publishes five samples of + * this metric per reporting interval. + * + * Units: Percentage + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricHeapMemoryUtilization(props?: cloudwatch.MetricOptions) { + return this.metric('heapMemoryUtilization', { statistic: 'Average', ...props }); + } + + /** + * The total time spent performing old garbage collection operations. + * + * Units: Milliseconds + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricOldGenerationGCTime(props?: cloudwatch.MetricOptions) { + return this.metric('oldGenerationGCTime', { statistic: 'Sum', ...props }); + } + + /** + * The total number of old garbage collection operations that have occurred + * across all task managers. + * + * Units: Count + * + * Reporting Level: Application + * + * @default sum over 5 minutes + */ + metricOldGenerationGCCount(props?: cloudwatch.MetricOptions) { + return this.metric('oldGenerationGCCount', { statistic: 'Sum', ...props }); + } + + /** + * The total number of live threads used by the application. + * + * Units: Count + * + * Reporting Level: Application + * + * @default average over 5 minutes + */ + metricThreadsCount(props?: cloudwatch.MetricOptions) { + return this.metric('threadsCount', { statistic: 'Average', ...props }); + } + + /** + * The total number of records this application, operator, or task has + * received. + * + * Units: Count + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsIn(props?: cloudwatch.MetricOptions) { + return this.metric('numRecordsIn', { statistic: 'Average', ...props }); + } + + /** + * The total number of records this application, operator or task has received + * per second. + * + * Units: Count/Second + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsInPerSecond(props?: cloudwatch.MetricOptions) { + return this.metric('numRecordsInPerSecond', { statistic: 'Average', ...props }); + } + + /** + * The total number of records this application, operator or task has emitted. + * + * Units: Count + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsOut(props?: cloudwatch.MetricOptions) { + return this.metric('numRecordsOut', { statistic: 'Average', ...props }); + } + + /** + * The total number of records this application, operator or task has emitted + * per second. + * + * Units: Count/Second + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricNumRecordsOutPerSecond(props?: cloudwatch.MetricOptions) { + return this.metric('numRecordsOutPerSecond', { statistic: 'Average', ...props }); + } + + /** + * The number of records this operator or task has dropped due to arriving + * late. + * + * Units: Count + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default sum over 5 minutes + */ + metricNumLateRecordsDropped(props?: cloudwatch.MetricOptions) { + return this.metric('numLateRecordsDropped', { statistic: 'Sum', ...props }); + } + + /** + * The last watermark this application/operator/task/thread has received. + * + * Units: Milliseconds + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default maximum over 5 minutes + */ + metricCurrentInputWatermark(props?: cloudwatch.MetricOptions) { + return this.metric('currentInputWatermark', { statistic: 'Maximum', ...props }); + } + + /** + * The last watermark this application/operator/task/thread has received. + * + * Units: Milliseconds + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default maximum over 5 minutes + */ + metricCurrentOutputWatermark(props?: cloudwatch.MetricOptions) { + return this.metric('currentOutputWatermark', { statistic: 'Maximum', ...props }); + } + + /** + * The amount of managed memory currently used. + * + * Units: Bytes + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricManagedMemoryUsed(props?: cloudwatch.MetricOptions) { + return this.metric('managedMemoryUsed', { statistic: 'Average', ...props }); + } + + /** + * The total amount of managed memory. + * + * Units: Bytes + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricManagedMemoryTotal(props?: cloudwatch.MetricOptions) { + return this.metric('managedMemoryTotal', { statistic: 'Average', ...props }); + } + + /** + * Derived from managedMemoryUsed/managedMemoryTotal. + * + * Units: Percentage + * + * Reporting Level: Application, Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricManagedMemoryUtilization(props?: cloudwatch.MetricOptions) { + return this.metric('managedMemoryUtilization', { statistic: 'Average', ...props }); + } + + /** + * The time (in milliseconds) this task or operator is idle (has no data to + * process) per second. Idle time excludes back pressured time, so if the task + * is back pressured it is not idle. + * + * Units: Milliseconds + * + * Reporting Level: Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricIdleTimeMsPerSecond(props?: cloudwatch.MetricOptions) { + return this.metric('idleTimeMsPerSecond', { statistic: 'Average', ...props }); + } + + /** + * The time (in milliseconds) this task or operator is back pressured per + * second. + * + * Units: Milliseconds + * + * Reporting Level: Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricBackPressuredTimeMsPerSecond(props?: cloudwatch.MetricOptions) { + return this.metric('backPressuredTimeMsPerSecond', { statistic: 'Average', ...props }); + } + + /** + * The time (in milliseconds) this task or operator is busy (neither idle nor + * back pressured) per second. Can be NaN, if the value could not be + * calculated. + * + * Units: Milliseconds + * + * Reporting Level: Operator, Task, Parallelism + * + * @default average over 5 minutes + */ + metricBusyTimePerMsPerSecond(props?: cloudwatch.MetricOptions) { + return this.metric('busyTimePerMsPerSecond', { statistic: 'Average', ...props }); + } } /** diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index beb642b6943c7..945c8f6900a71 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -82,6 +82,7 @@ }, "dependencies": { "@aws-cdk/assets": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -95,6 +96,7 @@ "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/assets": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts index 109a07693ce04..f663c2b4cc0e7 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts @@ -1,5 +1,6 @@ import * as path from 'path'; 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'; import * as s3 from '@aws-cdk/aws-s3'; @@ -610,4 +611,66 @@ describe('Application', () => { expect(flinkApp.applicationArn).toEqual(arn); expect(flinkApp.addToRolePolicy(new iam.PolicyStatement())).toBe(false); }); + + test('get metric', () => { + const flinkApp = new flink.Application(stack, 'Application', { ...requiredProps }); + expect(flinkApp.metric('KPUs', { statistic: 'Sum' })) + .toMatchObject({ + namespace: 'AWS/KinesisAnalytics', + metricName: 'KPUs', + dimensions: { Application: flinkApp.applicationName }, + statistic: 'Sum', + }); + }); + + test('canned metrics', () => { + const flinkApp = new flink.Application(stack, 'Application', { ...requiredProps }); + + // Table driven test with: [method, metricName, default statistic] + const assertions: Array<[(options?: cloudwatch.MetricOptions) => cloudwatch.Metric, string, string]> = [ + [flinkApp.metricKpus, 'KPUs', 'Average'], + [flinkApp.metricDowntime, 'downtime', 'Average'], + [flinkApp.metricUptime, 'uptime', 'Average'], + [flinkApp.metricFullRestarts, 'fullRestarts', 'Sum'], + [flinkApp.metricNumberOfFailedCheckpoints, 'numberOfFailedCheckpoints', 'Sum'], + [flinkApp.metricLastCheckpointDuration, 'lastCheckpointDuration', 'Maximum'], + [flinkApp.metricLastCheckpointSize, 'lastCheckpointSize', 'Maximum'], + [flinkApp.metricCpuUtilization, 'cpuUtilization', 'Average'], + [flinkApp.metricHeapMemoryUtilization, 'heapMemoryUtilization', 'Average'], + [flinkApp.metricOldGenerationGCTime, 'oldGenerationGCTime', 'Sum'], + [flinkApp.metricOldGenerationGCCount, 'oldGenerationGCCount', 'Sum'], + [flinkApp.metricThreadsCount, 'threadsCount', 'Average'], + [flinkApp.metricNumRecordsIn, 'numRecordsIn', 'Average'], + [flinkApp.metricNumRecordsInPerSecond, 'numRecordsInPerSecond', 'Average'], + [flinkApp.metricNumRecordsOut, 'numRecordsOut', 'Average'], + [flinkApp.metricNumRecordsOutPerSecond, 'numRecordsOutPerSecond', 'Average'], + [flinkApp.metricNumLateRecordsDropped, 'numLateRecordsDropped', 'Sum'], + [flinkApp.metricCurrentInputWatermark, 'currentInputWatermark', 'Maximum'], + [flinkApp.metricCurrentOutputWatermark, 'currentOutputWatermark', 'Maximum'], + [flinkApp.metricManagedMemoryUsed, 'managedMemoryUsed', 'Average'], + [flinkApp.metricManagedMemoryTotal, 'managedMemoryTotal', 'Average'], + [flinkApp.metricManagedMemoryUtilization, 'managedMemoryUtilization', 'Average'], + [flinkApp.metricIdleTimeMsPerSecond, 'idleTimeMsPerSecond', 'Average'], + [flinkApp.metricBackPressuredTimeMsPerSecond, 'backPressuredTimeMsPerSecond', 'Average'], + [flinkApp.metricBusyTimePerMsPerSecond, 'busyTimePerMsPerSecond', 'Average'], + ]; + + assertions.forEach(([method, metricName, defaultStatistic]) => { + // Test metrics with no options provided + expect(method.call(flinkApp)).toMatchObject({ + metricName, + statistic: defaultStatistic, + namespace: 'AWS/KinesisAnalytics', + dimensions: { + Application: flinkApp.applicationName, + }, + }); + + // Make sure we can override the default statistic and add other options + expect(method.call(flinkApp, { statistic: 'special', color: '#00ff00' })).toMatchObject({ + statistic: 'special', + color: '#00ff00', + }); + }); + }); }); diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json index 5ab3c94353f04..60f2f92a97420 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.expected.json @@ -276,6 +276,26 @@ } } } + }, + "Alarm7103F465": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "Dimensions": [ + { + "Name": "Application", + "Value": { + "Ref": "AppF1B96344" + } + } + ], + "MetricName": "fullRestarts", + "Namespace": "AWS/KinesisAnalytics", + "Period": 300, + "Statistic": "Sum", + "Threshold": 3 + } } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.ts index 02a6a9949dcfa..11c8b5bda36f4 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/integ.application.lit.ts @@ -2,14 +2,21 @@ import * as path from 'path'; import * as core from '@aws-cdk/core'; import * as flink from '../lib'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; const app = new core.App(); const stack = new core.Stack(app, 'FlinkAppTest'); -new flink.Application(stack, 'App', { +const flinkApp = new flink.Application(stack, 'App', { code: flink.ApplicationCode.fromAsset(path.join(__dirname, 'code-asset')), runtime: flink.Runtime.FLINK_1_11, }); + +new cloudwatch.Alarm(stack, 'Alarm', { + metric: flinkApp.metricFullRestarts(), + evaluationPeriods: 1, + threshold: 3, +}); ///! hide app.synth(); diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index ab45011f3559b..147d433a30479 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -1,7 +1,7 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; -import { ArnFormat, IResource, Resource, Token } from '@aws-cdk/core'; +import { Annotations, ArnFormat, IResource, Resource, Token } from '@aws-cdk/core'; import { Node } from 'constructs'; import { AliasOptions } from './alias'; import { Architecture } from './architecture'; @@ -13,6 +13,10 @@ import { CfnPermission } from './lambda.generated'; import { Permission } from './permission'; import { addAlias, flatMap } from './util'; +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from 'constructs'; + export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { /** @@ -275,12 +279,45 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC private _latestVersion?: LatestVersion; + /** + * Flag to delay adding a warning message until current version is invoked. + * @internal + */ + protected _warnIfCurrentVersionCalled: boolean = false; + /** * Mapping of invocation principals to grants. Used to de-dupe `grantInvoke()` calls. * @internal */ protected _invocationGrants: Record = {}; + /** + * A warning will be added to functions under the following conditions: + * - permissions that include `lambda:InvokeFunction` are added to the unqualified function. + * - function.currentVersion is invoked before or after the permission is created. + * + * This applies only to permissions on Lambda functions, not versions or aliases. + * This function is overridden as a noOp for QualifiedFunctionBase. + */ + public considerWarningOnInvokeFunctionPermissions(scope: Construct, action: string) { + const affectedPermissions = ['lambda:InvokeFunction', 'lambda:*', 'lambda:Invoke*']; + if (affectedPermissions.includes(action)) { + if (scope.node.tryFindChild('CurrentVersion')) { + this.warnInvokeFunctionPermissions(scope); + } else { + this._warnIfCurrentVersionCalled = true; + } + } + } + + protected warnInvokeFunctionPermissions(scope: Construct): void { + Annotations.of(scope).addWarning([ + "AWS Lambda has changed their authorization strategy, which may cause client invocations using the 'Qualifier' parameter of the lambda function to fail with Access Denied errors.", + "If you are using a lambda Version or Alias, make sure to call 'grantInvoke' or 'addPermission' on the Version or Alias, not the underlying Function", + 'See: https://github.com/aws/aws-cdk/issues/19273', + ].join('\n')); + } + /** * Adds a permission to the Lambda resource policy. * @param id The id for the permission construct @@ -297,6 +334,8 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC const action = permission.action ?? 'lambda:InvokeFunction'; const scope = permission.scope ?? this; + this.considerWarningOnInvokeFunctionPermissions(scope, action); + new CfnPermission(scope, id, { action, principal, @@ -555,6 +594,11 @@ export abstract class QualifiedFunctionBase extends FunctionBase { ...options, }); } + + public considerWarningOnInvokeFunctionPermissions(_scope: Construct, _action: string): void { + // noOp + return; + } } /** diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 3e2c778be2891..6bc89845edf3b 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -399,6 +399,10 @@ export class Function extends FunctionBase { return this._currentVersion; } + if (this._warnIfCurrentVersionCalled) { + this.warnInvokeFunctionPermissions(this); + }; + this._currentVersion = new Version(this, 'CurrentVersion', { lambda: this, ...this.currentVersionOptions, diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index fc52bae379bde..886d7c754feb8 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { Match, Template } from '@aws-cdk/assertions'; +import { Annotations, 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'; @@ -436,6 +436,154 @@ describe('function', () => { // THEN Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 0); }); + + describe('annotations on different IFunctions', () => { + let stack: cdk.Stack; + let fn: lambda.Function; + let warningMessage: string; + beforeEach(() => { + warningMessage = 'AWS Lambda has changed their authorization strategy'; + stack = new cdk.Stack(); + fn = new lambda.Function(stack, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_6, + }); + }); + + describe('permissions on functions', () => { + test('without lambda:InvokeFunction', () => { + // WHEN + fn.addPermission('MyPermission', { + action: 'lambda.GetFunction', + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // Simulate a workflow where a user has created a currentVersion with the intent to invoke it later. + fn.currentVersion; + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default/MyLambda', Match.stringLikeRegexp(warningMessage)); + }); + + describe('with lambda:InvokeFunction', () => { + test('without invoking currentVersion', () => { + // WHEN + fn.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default/MyLambda', Match.stringLikeRegexp(warningMessage)); + }); + + test('with currentVersion invoked first', () => { + // GIVEN + // Simulate a workflow where a user has created a currentVersion with the intent to invoke it later. + fn.currentVersion; + + // WHEN + fn.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // THEN + Annotations.fromStack(stack).hasWarning('/Default/MyLambda', Match.stringLikeRegexp(warningMessage)); + }); + + test('with currentVersion invoked after permissions created', () => { + // WHEN + fn.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // Simulate a workflow where a user has created a currentVersion after adding permissions to the function. + fn.currentVersion; + + // THEN + Annotations.fromStack(stack).hasWarning('/Default/MyLambda', Match.stringLikeRegexp(warningMessage)); + }); + + test('multiple currentVersion calls does not result in multiple warnings', () => { + // WHEN + fn.currentVersion; + + fn.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + fn.currentVersion; + + // THEN + const warns = Annotations.fromStack(stack).findWarning('/Default/MyLambda', Match.stringLikeRegexp(warningMessage)); + expect(warns).toHaveLength(1); + }); + }); + }); + + test('permission on versions', () => { + // GIVEN + const version = new lambda.Version(stack, 'MyVersion', { + lambda: fn.currentVersion, + }); + + // WHEN + version.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default/MyVersion', Match.stringLikeRegexp(warningMessage)); + }); + + test('permission on latest version', () => { + // WHEN + fn.latestVersion.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // THEN + // cannot add permissions on latest version, so no warning necessary + Annotations.fromStack(stack).hasNoWarning('/Default/MyLambda/$LATEST', Match.stringLikeRegexp(warningMessage)); + }); + + describe('permission on alias', () => { + test('of current version', () => { + // GIVEN + const version = new lambda.Version(stack, 'MyVersion', { + lambda: fn.currentVersion, + }); + const alias = new lambda.Alias(stack, 'MyAlias', { + aliasName: 'alias', + version, + }); + + // WHEN + alias.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default/MyAlias', Match.stringLikeRegexp(warningMessage)); + }); + + test('of latest version', () => { + // GIVEN + const alias = new lambda.Alias(stack, 'MyAlias', { + aliasName: 'alias', + version: fn.latestVersion, + }); + + // WHEN + alias.addPermission('MyPermission', { + principal: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // THEN + Annotations.fromStack(stack).hasNoWarning('/Default/MyAlias', Match.stringLikeRegexp(warningMessage)); + }); + }); + }); }); test('Lambda code can be read from a local directory via an asset', () => { diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index 6338fa0368849..8f61088997d96 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -384,7 +384,7 @@ export abstract class SnapshotCredentials { * } * ``` */ - public static fromSecret(secret: secretsmanager.Secret): SnapshotCredentials { + public static fromSecret(secret: secretsmanager.ISecret): SnapshotCredentials { return { generatePassword: false, password: secret.secretValueFromJson('password'), @@ -435,7 +435,7 @@ export abstract class SnapshotCredentials { * * @default - none */ - public abstract readonly secret?: secretsmanager.Secret; + public abstract readonly secret?: secretsmanager.ISecret; /** * The characters to exclude from the generated password. diff --git a/packages/@aws-cdk/aws-s3-assets/test/alpine-markdown/Dockerfile b/packages/@aws-cdk/aws-s3-assets/test/alpine-markdown/Dockerfile index fa7a67678bae9..d0ec147b4a786 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/alpine-markdown/Dockerfile +++ b/packages/@aws-cdk/aws-s3-assets/test/alpine-markdown/Dockerfile @@ -1,3 +1,3 @@ -FROM alpine +FROM public.ecr.aws/docker/library/alpine:latest RUN apk add markdown diff --git a/packages/@aws-cdk/aws-ssm/README.md b/packages/@aws-cdk/aws-ssm/README.md index 23fea31765525..880cc6b7b3322 100644 --- a/packages/@aws-cdk/aws-ssm/README.md +++ b/packages/@aws-cdk/aws-ssm/README.md @@ -30,7 +30,7 @@ import * as ssm from '@aws-cdk/aws-ssm'; ## Using existing SSM Parameters in your CDK app You can reference existing SSM Parameter Store values that you want to use in -your CDK app by using `ssm.ParameterStoreString`: +your CDK app by using `ssm.StringParameter.fromStringParameterAttributes`: [using SSM parameter](test/integ.parameter-store-string.lit.ts) 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 51903ee940094..7cd626e41dad8 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 @@ -33361,7 +33361,7 @@ "AllowMajorVersionUpgrade": "A value that indicates whether major version upgrades are allowed. Changing this parameter doesn't result in an outage and the change is asynchronously applied as soon as possible.\n\nConstraints: Major version upgrades must be allowed when specifying a value for the `EngineVersion` parameter that is a different major version than the DB instance's current version.", "AssociatedRoles": "The AWS Identity and Access Management (IAM) roles associated with the DB instance.", "AutoMinorVersionUpgrade": "A value that indicates whether minor engine upgrades are applied automatically to the DB instance during the maintenance window. By default, minor engine upgrades are applied automatically.", - "AvailabilityZone": "The Availability Zone (AZ) where the database will be created. For information on AWS Regions and Availability Zones, see [Regions and Availability Zones](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) .\n\n*Amazon Aurora*\n\nNot applicable. Availability Zones are managed by the DB cluster.\n\nDefault: A random, system-chosen Availability Zone in the endpoint's AWS Region .\n\nExample: `us-east-1d`\n\nConstraint: The `AvailabilityZone` parameter can't be specified if the DB instance is a Multi-AZ deployment. The specified Availability Zone must be in the same AWS Region as the current endpoint.\n\n> If you're creating a DB instance in an RDS on VMware environment, specify the identifier of the custom Availability Zone to create the DB instance in.\n> \n> For more information about RDS on VMware, see the [RDS on VMware User Guide.](https://docs.aws.amazon.com/AmazonRDS/latest/RDSonVMwareUserGuide/rds-on-vmware.html)", + "AvailabilityZone": "The Availability Zone that the database instance will be created in.\n\nDefault: A random, system-chosen Availability Zone in the endpoint's region.\n\nExample: `us-east-1d`\n\nConstraint: The AvailabilityZone parameter cannot be specified if the MultiAZ parameter is set to `true` . The specified Availability Zone must be in the same region as the current endpoint.", "BackupRetentionPeriod": "The number of days for which automated backups are retained. Setting this parameter to a positive number enables backups. Setting this parameter to 0 disables automated backups.\n\n*Amazon Aurora*\n\nNot applicable. The retention period for automated backups is managed by the DB cluster.\n\nDefault: 1\n\nConstraints:\n\n- Must be a value from 0 to 35\n- Can't be set to 0 if the DB instance is a source to read replicas", "CACertificateIdentifier": "The identifier of the CA certificate for this DB instance.\n\n> Specifying or updating this property triggers a reboot. \n\nFor more information about CA certificate identifiers for RDS DB engines, see [Rotating Your SSL/TLS Certificate](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL-certificate-rotation.html) in the *Amazon RDS User Guide* .\n\nFor more information about CA certificate identifiers for Aurora DB engines, see [Rotating Your SSL/TLS Certificate](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.SSL-certificate-rotation.html) in the *Amazon Aurora User Guide* .", "CharacterSetName": "For supported engines, indicates that the DB instance should be associated with the specified character set.\n\n*Amazon Aurora*\n\nNot applicable. The character set is managed by the DB cluster. For more information, see [AWS::RDS::DBCluster](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbcluster.html) .", @@ -33433,7 +33433,7 @@ }, "description": "The `AWS::RDS::DBParameterGroup` resource creates a custom parameter group for an RDS database family.\n\nThis type can be declared in a template and referenced in the `DBParameterGroupName` property of an `[AWS::RDS::DBInstance](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html)` resource.\n\nFor information about configuring parameters for Amazon RDS DB instances, see [Working with DB parameter groups](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html) in the *Amazon RDS User Guide* .\n\nFor information about configuring parameters for Amazon Aurora DB instances, see [Working with DB parameter groups and DB cluster parameter groups](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_WorkingWithParamGroups.html) in the *Amazon Aurora User Guide* .\n\n> Applying a parameter group to a DB instance may require the DB instance to reboot, resulting in a database outage for the duration of the reboot.", "properties": { - "Description": "Provides the customer-specified description for this DB Parameter Group.", + "Description": "Provides the customer-specified description for this DB parameter group.", "Family": "The DB parameter group family name. A DB parameter group can be associated with one and only one DB parameter group family, and can be applied only to a DB instance running a DB engine and engine version compatible with that DB parameter group family.\n\n> The DB parameter group family can't be changed when updating a DB parameter group. \n\nTo list all of the available parameter group families, use the following command:\n\n`aws rds describe-db-engine-versions --query \"DBEngineVersions[].DBParameterGroupFamily\"`\n\nThe output contains duplicates.\n\nFor more information, see `[CreateDBParameterGroup](https://docs.aws.amazon.com//AmazonRDS/latest/APIReference/API_CreateDBParameterGroup.html)` .", "Parameters": "An array of parameter names and values for the parameter update. At least one parameter name and value must be supplied. Subsequent arguments are optional.\n\nFor more information about DB parameters and DB parameter groups for Amazon RDS DB engines, see [Working with DB Parameter Groups](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html) in the *Amazon RDS User Guide* .\n\nFor more information about DB cluster and DB instance parameters and parameter groups for Amazon Aurora DB engines, see [Working with DB Parameter Groups and DB Cluster Parameter Groups](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_WorkingWithParamGroups.html) in the *Amazon Aurora User Guide* .\n\n> AWS CloudFormation doesn't support specifying an apply method for each individual parameter. The default apply method for each parameter is used.", "Tags": "Tags to assign to the DB parameter group." @@ -33537,7 +33537,7 @@ "properties": { "DBSecurityGroupIngress": "Ingress rules to be applied to the DB security group.", "EC2VpcId": "The identifier of an Amazon VPC. This property indicates the VPC that this DB security group belongs to.\n\n> The `EC2VpcId` property is for backward compatibility with older regions, and is no longer recommended for providing security information to an RDS DB instance.", - "GroupDescription": "Provides the description of the DB Security Group.", + "GroupDescription": "Provides the description of the DB security group.", "Tags": "Tags to assign to the DB security group." } }, @@ -33546,9 +33546,9 @@ "description": "The `Ingress` property type specifies an individual ingress rule within an `AWS::RDS::DBSecurityGroup` resource.", "properties": { "CIDRIP": "The IP range to authorize.", - "EC2SecurityGroupId": "Id of the EC2 security group to authorize. For VPC DB security groups, `EC2SecurityGroupId` must be provided. Otherwise, `EC2SecurityGroupOwnerId` and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", - "EC2SecurityGroupName": "Name of the EC2 security group to authorize. For VPC DB security groups, `EC2SecurityGroupId` must be provided. Otherwise, `EC2SecurityGroupOwnerId` and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", - "EC2SecurityGroupOwnerId": "AWS account number of the owner of the EC2 security group specified in the `EC2SecurityGroupName` parameter. The AWS access key ID isn't an acceptable value. For VPC DB security groups, `EC2SecurityGroupId` must be provided. Otherwise, `EC2SecurityGroupOwnerId` and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided." + "EC2SecurityGroupId": "Id of the EC2 Security Group to authorize. For VPC DB Security Groups, `EC2SecurityGroupId` must be provided. Otherwise, EC2SecurityGroupOwnerId and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", + "EC2SecurityGroupName": "Name of the EC2 Security Group to authorize. For VPC DB Security Groups, `EC2SecurityGroupId` must be provided. Otherwise, EC2SecurityGroupOwnerId and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", + "EC2SecurityGroupOwnerId": "AWS Account Number of the owner of the EC2 Security Group specified in the EC2SecurityGroupName parameter. The AWS Access Key ID is not an acceptable value. For VPC DB Security Groups, `EC2SecurityGroupId` must be provided. Otherwise, EC2SecurityGroupOwnerId and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided." } }, "AWS::RDS::DBSecurityGroupIngress": { @@ -33558,10 +33558,10 @@ "description": "The `AWS::RDS::DBSecurityGroupIngress` resource enables ingress to a DB security group using one of two forms of authorization. First, you can add EC2 or VPC security groups to the DB security group if the application using the database is running on EC2 or VPC instances. Second, IP ranges are available if the application accessing your database is running on the Internet.\n\nThis type supports updates. For more information about updating stacks, see [AWS CloudFormation Stacks Updates](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks.html) .\n\nFor details about the settings for DB security group ingress, see [AuthorizeDBSecurityGroupIngress](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_AuthorizeDBSecurityGroupIngress.html) .", "properties": { "CIDRIP": "The IP range to authorize.", - "DBSecurityGroupName": "The name of the DB security group to add authorization to.", - "EC2SecurityGroupId": "Id of the EC2 security group to authorize. For VPC DB security groups, `EC2SecurityGroupId` must be provided. Otherwise, `EC2SecurityGroupOwnerId` and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", - "EC2SecurityGroupName": "Name of the EC2 security group to authorize. For VPC DB security groups, `EC2SecurityGroupId` must be provided. Otherwise, `EC2SecurityGroupOwnerId` and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", - "EC2SecurityGroupOwnerId": "AWS account number of the owner of the EC2 security group specified in the `EC2SecurityGroupName` parameter. The AWS access key ID isn't an acceptable value. For VPC DB security groups, `EC2SecurityGroupId` must be provided. Otherwise, `EC2SecurityGroupOwnerId` and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided." + "DBSecurityGroupName": "The name of the DB Security Group to add authorization to.", + "EC2SecurityGroupId": "Id of the EC2 Security Group to authorize. For VPC DB Security Groups, `EC2SecurityGroupId` must be provided. Otherwise, EC2SecurityGroupOwnerId and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", + "EC2SecurityGroupName": "Name of the EC2 Security Group to authorize. For VPC DB Security Groups, `EC2SecurityGroupId` must be provided. Otherwise, EC2SecurityGroupOwnerId and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided.", + "EC2SecurityGroupOwnerId": "AWS Account Number of the owner of the EC2 Security Group specified in the EC2SecurityGroupName parameter. The AWS Access Key ID is not an acceptable value. For VPC DB Security Groups, `EC2SecurityGroupId` must be provided. Otherwise, EC2SecurityGroupOwnerId and either `EC2SecurityGroupName` or `EC2SecurityGroupId` must be provided." } }, "AWS::RDS::DBSubnetGroup": { @@ -33570,9 +33570,9 @@ }, "description": "The `AWS::RDS::DBSubnetGroup` resource creates a database subnet group. Subnet groups must contain at least two subnets in two different Availability Zones in the same region.\n\nFor more information, see [Working with DB subnet groups](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Subnets) in the *Amazon RDS User Guide* .", "properties": { - "DBSubnetGroupDescription": "The description for the DB subnet group.", + "DBSubnetGroupDescription": "The description for the DB Subnet Group.", "DBSubnetGroupName": "The name for the DB subnet group. This value is stored as a lowercase string.\n\nConstraints: Must contain no more than 255 lowercase alphanumeric characters or hyphens. Must not be \"Default\".\n\nExample: `mysubnetgroup`", - "SubnetIds": "The EC2 Subnet IDs for the DB subnet group.", + "SubnetIds": "The EC2 Subnet IDs for the DB Subnet Group.", "Tags": "Tags to assign to the DB subnet group." } }, @@ -33582,8 +33582,8 @@ }, "description": "The `AWS::RDS::EventSubscription` resource allows you to receive notifications for Amazon Relational Database Service events through the Amazon Simple Notification Service (Amazon SNS). For more information, see [Using Amazon RDS Event Notification](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html) in the *Amazon RDS User Guide* .", "properties": { - "Enabled": "A value that indicates whether to activate the subscription. If the event notification subscription isn't activated, the subscription is created but not active.", - "EventCategories": "A list of event categories for a particular source type ( `SourceType` ) that you want to subscribe to. You can see a list of the categories for a given source type in the \"Amazon RDS event categories and event messages\" section of the [*Amazon RDS User Guide*](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.Messages.html) or the [*Amazon Aurora User Guide*](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_Events.Messages.html) . You can also see this list by using the `DescribeEventCategories` operation.", + "Enabled": "A Boolean value; set to *true* to activate the subscription, set to *false* to create the subscription but not active it.", + "EventCategories": "A list of event categories for a SourceType that you want to subscribe to. You can see a list of the categories for a given SourceType in the [Events](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html) topic in the Amazon RDS User Guide or by using the *DescribeEventCategories* action.", "SnsTopicArn": "The Amazon Resource Name (ARN) of the SNS topic created for event notification. The ARN is created by Amazon SNS when you create a topic and subscribe to it.", "SourceIds": "The list of identifiers of the event sources for which events are returned. If not specified, then all sources are included in the response. An identifier must begin with a letter and must contain only ASCII letters, digits, and hyphens. It can't end with a hyphen or contain two consecutive hyphens.\n\nConstraints:\n\n- If a `SourceIds` value is supplied, `SourceType` must also be provided.\n- If the source type is a DB instance, a `DBInstanceIdentifier` value must be supplied.\n- If the source type is a DB cluster, a `DBClusterIdentifier` value must be supplied.\n- If the source type is a DB parameter group, a `DBParameterGroupName` value must be supplied.\n- If the source type is a DB security group, a `DBSecurityGroupName` value must be supplied.\n- If the source type is a DB snapshot, a `DBSnapshotIdentifier` value must be supplied.\n- If the source type is a DB cluster snapshot, a `DBClusterSnapshotIdentifier` value must be supplied.", "SourceType": "The type of source that is generating the events. For example, if you want to be notified of events generated by a DB instance, set this parameter to `db-instance` . If this value isn't specified, all events are returned.\n\nValid values: `db-instance` | `db-cluster` | `db-parameter-group` | `db-security-group` | `db-snapshot` | `db-cluster-snapshot`" diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts index 5fd6eb6ceda07..50c2dc35a5eab 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts @@ -1,4 +1,3 @@ export * from './cloud-assembly'; export * from './assets'; export * from './manifest'; -export * from './integ-tests'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/common.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/common.ts deleted file mode 100644 index 01ab969b63098..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/common.ts +++ /dev/null @@ -1,202 +0,0 @@ -/** - * In what scenarios should the CLI ask for approval - */ -export enum RequireApproval { - /** - * Never ask for approval - */ - NEVER = 'never', - - /** - * Prompt for approval for any type of change to the stack - */ - ANYCHANGE = 'any-change', - - /** - * Only prompt for approval if there are security related changes - */ - BROADENING = 'broadening' -} - -/** - * Default CDK CLI options that apply to all commands - */ -export interface DefaultCdkOptions { - /** - * List of stacks to deploy - * - * Requried if `all` is not set - * - * @default - [] - */ - readonly stacks?: string[]; - - /** - * Deploy all stacks - * - * Requried if `stacks` is not set - * - * @default - false - */ - readonly all?: boolean; - - /** - * command-line for executing your app or a cloud assembly directory - * e.g. "node bin/my-app.js" - * or - * "cdk.out" - * - * @default - read from cdk.json - */ - readonly app?: string; - - - /** - * Role to pass to CloudFormation for deployment - * - * @default - use the bootstrap cfn-exec role - */ - readonly roleArn?: string; - - /** - * Additional context - * - * @default - no additional context - */ - readonly context?: { [name: string]: string }; - - /** - * Print trace for stack warnings - * - * @default false - */ - readonly trace?: boolean; - - /** - * Do not construct stacks with warnings - * - * @default false - */ - readonly strict?: boolean; - - /** - * Perform context lookups. - * - * Synthesis fails if this is disabled and context lookups need - * to be performed - * - * @default true - */ - readonly lookups?: boolean; - - /** - * Ignores synthesis errors, which will likely produce an invalid output - * - * @default false - */ - readonly ignoreErrors?: boolean; - - /** - * Use JSON output instead of YAML when templates are printed - * to STDOUT - * - * @default false - */ - readonly json?: boolean; - - /** - * show debug logs - * - * @default false - */ - readonly verbose?: boolean; - - /** - * enable emission of additional debugging information, such as creation stack - * traces of tokens - * - * @default false - */ - readonly debug?: boolean; - - /** - * Use the indicated AWS profile as the default environment - * - * @default - no profile is used - */ - readonly profile?: string; - - /** - * Use the indicated proxy. Will read from - * HTTPS_PROXY environment if specified - * - * @default - no proxy - */ - readonly proxy?: string; - - /** - * Path to CA certificate to use when validating HTTPS - * requests. - * - * @default - read from AWS_CA_BUNDLE environment variable - */ - readonly caBundlePath?: string; - - /** - * Force trying to fetch EC2 instance credentials - * - * @default - guess EC2 instance status - */ - readonly ec2Creds?: boolean; - - /** - * Include "AWS::CDK::Metadata" resource in synthesized templates - * - * @default true - */ - readonly versionReporting?: boolean; - - /** - * Include "aws:cdk:path" CloudFormation metadata for each resource - * - * @default true - */ - readonly pathMetadata?: boolean; - - /** - * Include "aws:asset:*" CloudFormation metadata for resources that use assets - * - * @default true - */ - readonly assetMetadata?: boolean; - - /** - * Copy assets to the output directory - * - * Needed for local debugging the source files with SAM CLI - * - * @default false - */ - readonly staging?: boolean; - - /** - * Emits the synthesized cloud assembly into a directory - * - * @default cdk.out - */ - readonly output?: string; - - /** - * Show relevant notices - * - * @default true - */ - readonly notices?: boolean; - - /** - * Show colors and other style from console output - * - * @default true - */ - readonly color?: boolean; -} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/deploy.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/deploy.ts deleted file mode 100644 index 09a20c610f12d..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/deploy.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { DefaultCdkOptions, RequireApproval } from './common'; - -/** - * Options to use with cdk deploy - */ -export interface DeployOptions extends DefaultCdkOptions { - /** - * Only perform action on the given stack - * - * @default false - */ - readonly exclusively?: boolean; - - /** - * Name of the toolkit stack to use/deploy - * - * @default CDKToolkit - */ - readonly toolkitStackName?: string; - - /** - * Reuse the assets with the given asset IDs - * - * @default - do not reuse assets - */ - readonly reuseAssets?: string[]; - - /** - * Optional name to use for the CloudFormation change set. - * If not provided, a name will be generated automatically. - * - * @default - auto generate a name - */ - readonly changeSetName?: string; - - /** - * Always deploy, even if templates are identical. - * @default false - */ - readonly force?: boolean; - - /** - * Rollback failed deployments - * - * @default true - */ - readonly rollback?: boolean; - - /** - * ARNs of SNS topics that CloudFormation will notify with stack related events - * - * @default - no notifications - */ - readonly notificationArns?: string[]; - - /** - * What kind of security changes require approval - * - * @default RequireApproval.Never - */ - readonly requireApproval?: RequireApproval; - - /** - * Whether to execute the ChangeSet - * Not providing `execute` parameter will result in execution of ChangeSet - * @default true - */ - readonly execute?: boolean; - - /** - * Additional parameters for CloudFormation at deploy time - * @default {} - */ - readonly parameters?: { [name: string]: string }; - - /** - * Use previous values for unspecified parameters - * - * If not set, all parameters must be specified for every deployment. - * - * @default true - */ - readonly usePreviousParameters?: boolean; - - /** - * Path to file where stack outputs will be written after a successful deploy as JSON - * @default - Outputs are not written to any file - */ - readonly outputsFile?: string; - - /** - * Whether we are on a CI system - * - * @default false - */ - readonly ci?: boolean; -} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/destroy.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/destroy.ts deleted file mode 100644 index 9dfe8f267c6db..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/destroy.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { DefaultCdkOptions } from './common'; - -/** - * Options to use with cdk destroy - */ -export interface DestroyOptions extends DefaultCdkOptions { - /** - * Do not ask for permission before destroying stacks - * - * @default false - */ - readonly force?: boolean; - - /** - * Only destroy the given stack - * - * @default false - */ - readonly exclusively?: boolean; -} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/index.ts deleted file mode 100644 index 528980446938b..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/commands/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './common'; -export * from './deploy'; -export * from './destroy'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/index.ts deleted file mode 100644 index 5a08e62a47958..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './schema'; -export * from './commands'; -export * from './test-case'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts deleted file mode 100644 index 4eccc8a6422b4..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TestCase } from './test-case'; -/** - * Definitions for the integration testing manifest - */ -export interface IntegManifest { - /** - * Version of the manifest - */ - readonly version: string; - - /** - * Enable lookups for this test. If lookups are enabled - * then `stackUpdateWorkflow` must be set to false. - * Lookups should only be enabled when you are explicitely testing - * lookups. - * - * @default false - */ - readonly enableLookups?: boolean; - - /** - * test cases - */ - readonly testCases: { [testName: string]: TestCase }; -} - diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/test-case.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/test-case.ts deleted file mode 100644 index 6d3ecc05c626e..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/integ-tests/test-case.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { DeployOptions, DestroyOptions } from './commands'; - -/** - * Represents an integration test test case - */ -export interface TestCase { - /** - * Stacks that should be tested as part of this test case - * The stackNames will be passed as args to the cdk commands - * so dependent stacks will be automatically deployed unless - * `exclusively` is passed - */ - readonly stacks: string[]; - - /** - * Run update workflow on this test case - * This should only be set to false to test scenarios - * that are not possible to test as part of the update workflow - * - * @default true - */ - readonly stackUpdateWorkflow?: boolean; - - /** - * Additional options to use for each CDK command - * - * @default - runner default options - */ - readonly cdkCommandOptions?: CdkCommands; - - /** - * Additional commands to run at predefined points in the test workflow - * - * e.g. { postDeploy: ['yarn', 'test'] } - * - * @default - no hooks - */ - readonly hooks?: Hooks; - - /** - * Whether or not to include asset hashes in the diff - * Asset hashes can introduces a lot of unneccessary noise into tests, - * but there are some cases where asset hashes _should_ be included. For example - * any tests involving custom resources or bundling - * - * @default false - */ - readonly diffAssets?: boolean; - - /** - * List of CloudFormation resource types in this stack that can - * be destroyed as part of an update without failing the test. - * - * This list should only include resources that for this specific - * integration test we are sure will not cause errors or an outage if - * destroyed. For example, maybe we know that a new resource will be created - * first before the old resource is destroyed which prevents any outage. - * - * e.g. ['AWS::IAM::Role'] - * - * @default - do not allow destruction of any resources on update - */ - readonly allowDestroy?: string[]; - - /** - * Limit deployment to these regions - * - * @default - can run in any region - */ - readonly regions?: string[]; -} - -/** - * Commands to run at predefined points during the - * integration test workflow - */ -export interface Hooks { - /** - * Commands to run prior to deploying the cdk stacks - * in the integration test - * - * @default - no commands - */ - readonly preDeploy?: string[]; - - /** - * Commands to run prior after deploying the cdk stacks - * in the integration test - * - * @default - no commands - */ - readonly postDeploy?: string[]; - - /** - * Commands to run prior to destroying the cdk stacks - * in the integration test - * - * @default - no commands - */ - readonly preDestroy?: string[]; - - /** - * Commands to run after destroying the cdk stacks - * in the integration test - * - * @default - no commands - */ - readonly postDestroy?: string[]; -} - -/** - * Represents a cdk command - * i.e. `synth`, `deploy`, & `destroy` - */ -export interface CdkCommand { - /** - * Whether or not to run this command as part of the workflow - * This can be used if you only want to test some of the workflow - * for example enable `synth` and disable `deploy` & `destroy` in order - * to limit the test to synthesis - * - * @default true - */ - readonly enabled?: boolean; - - /** - * If the runner should expect this command to fail - * - * @default false - */ - readonly expectError?: boolean; - - /** - * This can be used in combination with `expectedError` - * to validate that a specific message is returned. - * - * @default - do not validate message - */ - readonly expectedMessage?: string; -} - -/** - * Represents a cdk deploy command - */ -export interface DeployCommand extends CdkCommand { - /** - * Additional arguments to pass to the command - * This can be used to test specific CLI functionality - * - * @default - only default args are used - */ - readonly args?: DeployOptions; -} - -/** - * Represents a cdk destroy command - */ -export interface DestroyCommand extends CdkCommand { - /** - * Additional arguments to pass to the command - * This can be used to test specific CLI functionality - * - * @default - only default args are used - */ - readonly args?: DestroyOptions; -} - -/** - * Options for specific cdk commands that are run - * as part of the integration test workflow - */ -export interface CdkCommands { - /** - * Options to for the cdk deploy command - * - * @default - default deploy options - */ - readonly deploy?: DeployCommand; - - /** - * Options to for the cdk destroy command - * - * @default - default destroy options - */ - readonly destroy?: DestroyCommand; -} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts index 62f7894a54dd3..d2ceb45685678 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts @@ -3,7 +3,6 @@ import * as jsonschema from 'jsonschema'; import * as semver from 'semver'; import * as assets from './assets'; import * as assembly from './cloud-assembly'; -import * as integ from './integ-tests'; /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-require-imports */ @@ -22,8 +21,6 @@ const ASSEMBLY_SCHEMA = require('../schema/cloud-assembly.schema.json'); */ const SCHEMA_VERSION = require('../schema/cloud-assembly.version.json').version; -const INTEG_SCHEMA = require('../schema/integ.schema.json'); - /** * Options for the loadManifest operation */ @@ -92,25 +89,6 @@ export class Manifest { return this.loadManifest(filePath, ASSETS_SCHEMA); } - /** - * Validates and saves the integ manifest to file. - * - * @param manifest - manifest. - * @param filePath - output file path. - */ - public static saveIntegManifest(manifest: integ.IntegManifest, filePath: string) { - Manifest.saveManifest(manifest, filePath, INTEG_SCHEMA); - } - - /** - * Load and validates the integ manifest from file. - * - * @param filePath - path to the manifest file. - */ - public static loadIntegManifest(filePath: string): integ.IntegManifest { - return this.loadManifest(filePath, INTEG_SCHEMA); - } - /** * Fetch the current schema version number. */ @@ -273,4 +251,4 @@ function noUndefined(xs: A): A { function stripEnumErrors(errors: jsonschema.ValidationError[]) { return errors.filter(e => typeof e.schema ==='string' || !('enum' in e.schema)); -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json index 90bef2e09ad39..ae7a33e962d0b 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json @@ -1 +1 @@ -{"version":"17.0.0"} \ No newline at end of file +{"version":"16.0.0"} diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/integ.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/integ.schema.json deleted file mode 100644 index 676c1bdab91dd..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/integ.schema.json +++ /dev/null @@ -1,474 +0,0 @@ -{ - "$ref": "#/definitions/IntegManifest", - "definitions": { - "IntegManifest": { - "description": "Definitions for the integration testing manifest", - "type": "object", - "properties": { - "version": { - "description": "Version of the manifest", - "type": "string" - }, - "enableLookups": { - "description": "Enable lookups for this test. If lookups are enabled\nthen `stackUpdateWorkflow` must be set to false.\nLookups should only be enabled when you are explicitely testing\nlookups.", - "default": false, - "type": "boolean" - }, - "testCases": { - "description": "test cases", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/TestCase" - } - } - }, - "required": [ - "testCases", - "version" - ] - }, - "TestCase": { - "description": "Represents an integration test test case", - "type": "object", - "properties": { - "stacks": { - "description": "Stacks that should be tested as part of this test case\nThe stackNames will be passed as args to the cdk commands\nso dependent stacks will be automatically deployed unless\n`exclusively` is passed", - "type": "array", - "items": { - "type": "string" - } - }, - "stackUpdateWorkflow": { - "description": "Run update workflow on this test case\nThis should only be set to false to test scenarios\nthat are not possible to test as part of the update workflow (Default true)", - "type": "boolean" - }, - "cdkCommandOptions": { - "description": "Additional options to use for each CDK command (Default - runner default options)", - "$ref": "#/definitions/CdkCommands" - }, - "hooks": { - "description": "Additional commands to run at predefined points in the test workflow\n\ne.g. { postDeploy: ['yarn', 'test'] } (Default - no hooks)", - "$ref": "#/definitions/Hooks" - }, - "diffAssets": { - "description": "Whether or not to include asset hashes in the diff\nAsset hashes can introduces a lot of unneccessary noise into tests,\nbut there are some cases where asset hashes _should_ be included. For example\nany tests involving custom resources or bundling", - "default": false, - "type": "boolean" - }, - "allowDestroy": { - "description": "List of CloudFormation resource types in this stack that can\nbe destroyed as part of an update without failing the test.\n\nThis list should only include resources that for this specific\nintegration test we are sure will not cause errors or an outage if\ndestroyed. For example, maybe we know that a new resource will be created\nfirst before the old resource is destroyed which prevents any outage.\n\ne.g. ['AWS::IAM::Role'] (Default - do not allow destruction of any resources on update)", - "type": "array", - "items": { - "type": "string" - } - }, - "regions": { - "description": "Limit deployment to these regions (Default - can run in any region)", - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "stacks" - ] - }, - "CdkCommands": { - "description": "Options for specific cdk commands that are run\nas part of the integration test workflow", - "type": "object", - "properties": { - "deploy": { - "description": "Options to for the cdk deploy command (Default - default deploy options)", - "$ref": "#/definitions/DeployCommand" - }, - "destroy": { - "description": "Options to for the cdk destroy command (Default - default destroy options)", - "$ref": "#/definitions/DestroyCommand" - } - } - }, - "DeployCommand": { - "description": "Represents a cdk deploy command", - "type": "object", - "properties": { - "args": { - "description": "Additional arguments to pass to the command\nThis can be used to test specific CLI functionality (Default - only default args are used)", - "$ref": "#/definitions/DeployOptions" - }, - "enabled": { - "description": "Whether or not to run this command as part of the workflow\nThis can be used if you only want to test some of the workflow\nfor example enable `synth` and disable `deploy` & `destroy` in order\nto limit the test to synthesis (Default true)", - "type": "boolean" - }, - "expectError": { - "description": "If the runner should expect this command to fail", - "default": false, - "type": "boolean" - }, - "expectedMessage": { - "description": "This can be used in combination with `expectedError`\nto validate that a specific message is returned. (Default - do not validate message)", - "type": "string" - } - } - }, - "DeployOptions": { - "description": "Options to use with cdk deploy", - "type": "object", - "properties": { - "exclusively": { - "description": "Only perform action on the given stack", - "default": false, - "type": "boolean" - }, - "toolkitStackName": { - "description": "Name of the toolkit stack to use/deploy (Default CDKToolkit)", - "type": "string" - }, - "reuseAssets": { - "description": "Reuse the assets with the given asset IDs (Default - do not reuse assets)", - "type": "array", - "items": { - "type": "string" - } - }, - "changeSetName": { - "description": "Optional name to use for the CloudFormation change set.\nIf not provided, a name will be generated automatically. (Default - auto generate a name)", - "type": "string" - }, - "force": { - "description": "Always deploy, even if templates are identical.", - "default": false, - "type": "boolean" - }, - "rollback": { - "description": "Rollback failed deployments (Default true)", - "type": "boolean" - }, - "notificationArns": { - "description": "ARNs of SNS topics that CloudFormation will notify with stack related events (Default - no notifications)", - "type": "array", - "items": { - "type": "string" - } - }, - "requireApproval": { - "description": "What kind of security changes require approval (Default RequireApproval.Never)", - "enum": [ - "any-change", - "broadening", - "never" - ], - "type": "string" - }, - "execute": { - "description": "Whether to execute the ChangeSet\nNot providing `execute` parameter will result in execution of ChangeSet (Default true)", - "type": "boolean" - }, - "parameters": { - "description": "Additional parameters for CloudFormation at deploy time (Default [object Object])", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "usePreviousParameters": { - "description": "Use previous values for unspecified parameters\n\nIf not set, all parameters must be specified for every deployment. (Default true)", - "type": "boolean" - }, - "outputsFile": { - "description": "Path to file where stack outputs will be written after a successful deploy as JSON (Default - Outputs are not written to any file)", - "type": "string" - }, - "ci": { - "description": "Whether we are on a CI system", - "default": false, - "type": "boolean" - }, - "stacks": { - "description": "List of stacks to deploy\n\nRequried if `all` is not set (Default - [])", - "type": "array", - "items": { - "type": "string" - } - }, - "all": { - "description": "Deploy all stacks\n\nRequried if `stacks` is not set (Default - false)", - "type": "boolean" - }, - "app": { - "description": "command-line for executing your app or a cloud assembly directory\ne.g. \"node bin/my-app.js\"\nor\n\"cdk.out\" (Default - read from cdk.json)", - "type": "string" - }, - "roleArn": { - "description": "Role to pass to CloudFormation for deployment (Default - use the bootstrap cfn-exec role)", - "type": "string" - }, - "context": { - "description": "Additional context (Default - no additional context)", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "trace": { - "description": "Print trace for stack warnings", - "default": false, - "type": "boolean" - }, - "strict": { - "description": "Do not construct stacks with warnings", - "default": false, - "type": "boolean" - }, - "lookups": { - "description": "Perform context lookups.\n\nSynthesis fails if this is disabled and context lookups need\nto be performed (Default true)", - "type": "boolean" - }, - "ignoreErrors": { - "description": "Ignores synthesis errors, which will likely produce an invalid output", - "default": false, - "type": "boolean" - }, - "json": { - "description": "Use JSON output instead of YAML when templates are printed\nto STDOUT", - "default": false, - "type": "boolean" - }, - "verbose": { - "description": "show debug logs", - "default": false, - "type": "boolean" - }, - "debug": { - "description": "enable emission of additional debugging information, such as creation stack\ntraces of tokens", - "default": false, - "type": "boolean" - }, - "profile": { - "description": "Use the indicated AWS profile as the default environment (Default - no profile is used)", - "type": "string" - }, - "proxy": { - "description": "Use the indicated proxy. Will read from\nHTTPS_PROXY environment if specified (Default - no proxy)", - "type": "string" - }, - "caBundlePath": { - "description": "Path to CA certificate to use when validating HTTPS\nrequests. (Default - read from AWS_CA_BUNDLE environment variable)", - "type": "string" - }, - "ec2Creds": { - "description": "Force trying to fetch EC2 instance credentials (Default - guess EC2 instance status)", - "type": "boolean" - }, - "versionReporting": { - "description": "Include \"AWS::CDK::Metadata\" resource in synthesized templates (Default true)", - "type": "boolean" - }, - "pathMetadata": { - "description": "Include \"aws:cdk:path\" CloudFormation metadata for each resource (Default true)", - "type": "boolean" - }, - "assetMetadata": { - "description": "Include \"aws:asset:*\" CloudFormation metadata for resources that use assets (Default true)", - "type": "boolean" - }, - "staging": { - "description": "Copy assets to the output directory\n\nNeeded for local debugging the source files with SAM CLI", - "default": false, - "type": "boolean" - }, - "output": { - "description": "Emits the synthesized cloud assembly into a directory (Default cdk.out)", - "type": "string" - }, - "notices": { - "description": "Show relevant notices (Default true)", - "type": "boolean" - }, - "color": { - "description": "Show colors and other style from console output (Default true)", - "type": "boolean" - } - } - }, - "DestroyCommand": { - "description": "Represents a cdk destroy command", - "type": "object", - "properties": { - "args": { - "description": "Additional arguments to pass to the command\nThis can be used to test specific CLI functionality (Default - only default args are used)", - "$ref": "#/definitions/DestroyOptions" - }, - "enabled": { - "description": "Whether or not to run this command as part of the workflow\nThis can be used if you only want to test some of the workflow\nfor example enable `synth` and disable `deploy` & `destroy` in order\nto limit the test to synthesis (Default true)", - "type": "boolean" - }, - "expectError": { - "description": "If the runner should expect this command to fail", - "default": false, - "type": "boolean" - }, - "expectedMessage": { - "description": "This can be used in combination with `expectedError`\nto validate that a specific message is returned. (Default - do not validate message)", - "type": "string" - } - } - }, - "DestroyOptions": { - "description": "Options to use with cdk destroy", - "type": "object", - "properties": { - "force": { - "description": "Do not ask for permission before destroying stacks", - "default": false, - "type": "boolean" - }, - "exclusively": { - "description": "Only destroy the given stack", - "default": false, - "type": "boolean" - }, - "stacks": { - "description": "List of stacks to deploy\n\nRequried if `all` is not set (Default - [])", - "type": "array", - "items": { - "type": "string" - } - }, - "all": { - "description": "Deploy all stacks\n\nRequried if `stacks` is not set (Default - false)", - "type": "boolean" - }, - "app": { - "description": "command-line for executing your app or a cloud assembly directory\ne.g. \"node bin/my-app.js\"\nor\n\"cdk.out\" (Default - read from cdk.json)", - "type": "string" - }, - "roleArn": { - "description": "Role to pass to CloudFormation for deployment (Default - use the bootstrap cfn-exec role)", - "type": "string" - }, - "context": { - "description": "Additional context (Default - no additional context)", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "trace": { - "description": "Print trace for stack warnings", - "default": false, - "type": "boolean" - }, - "strict": { - "description": "Do not construct stacks with warnings", - "default": false, - "type": "boolean" - }, - "lookups": { - "description": "Perform context lookups.\n\nSynthesis fails if this is disabled and context lookups need\nto be performed (Default true)", - "type": "boolean" - }, - "ignoreErrors": { - "description": "Ignores synthesis errors, which will likely produce an invalid output", - "default": false, - "type": "boolean" - }, - "json": { - "description": "Use JSON output instead of YAML when templates are printed\nto STDOUT", - "default": false, - "type": "boolean" - }, - "verbose": { - "description": "show debug logs", - "default": false, - "type": "boolean" - }, - "debug": { - "description": "enable emission of additional debugging information, such as creation stack\ntraces of tokens", - "default": false, - "type": "boolean" - }, - "profile": { - "description": "Use the indicated AWS profile as the default environment (Default - no profile is used)", - "type": "string" - }, - "proxy": { - "description": "Use the indicated proxy. Will read from\nHTTPS_PROXY environment if specified (Default - no proxy)", - "type": "string" - }, - "caBundlePath": { - "description": "Path to CA certificate to use when validating HTTPS\nrequests. (Default - read from AWS_CA_BUNDLE environment variable)", - "type": "string" - }, - "ec2Creds": { - "description": "Force trying to fetch EC2 instance credentials (Default - guess EC2 instance status)", - "type": "boolean" - }, - "versionReporting": { - "description": "Include \"AWS::CDK::Metadata\" resource in synthesized templates (Default true)", - "type": "boolean" - }, - "pathMetadata": { - "description": "Include \"aws:cdk:path\" CloudFormation metadata for each resource (Default true)", - "type": "boolean" - }, - "assetMetadata": { - "description": "Include \"aws:asset:*\" CloudFormation metadata for resources that use assets (Default true)", - "type": "boolean" - }, - "staging": { - "description": "Copy assets to the output directory\n\nNeeded for local debugging the source files with SAM CLI", - "default": false, - "type": "boolean" - }, - "output": { - "description": "Emits the synthesized cloud assembly into a directory (Default cdk.out)", - "type": "string" - }, - "notices": { - "description": "Show relevant notices (Default true)", - "type": "boolean" - }, - "color": { - "description": "Show colors and other style from console output (Default true)", - "type": "boolean" - } - } - }, - "Hooks": { - "description": "Commands to run at predefined points during the\nintegration test workflow", - "type": "object", - "properties": { - "preDeploy": { - "description": "Commands to run prior to deploying the cdk stacks\nin the integration test (Default - no commands)", - "type": "array", - "items": { - "type": "string" - } - }, - "postDeploy": { - "description": "Commands to run prior after deploying the cdk stacks\nin the integration test (Default - no commands)", - "type": "array", - "items": { - "type": "string" - } - }, - "preDestroy": { - "description": "Commands to run prior to destroying the cdk stacks\nin the integration test (Default - no commands)", - "type": "array", - "items": { - "type": "string" - } - }, - "postDestroy": { - "description": "Commands to run after destroying the cdk stacks\nin the integration test (Default - no commands)", - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts b/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts index 13a410cd4a36f..e92083d34b0a6 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/scripts/update-schema.ts @@ -17,7 +17,6 @@ const SCHEMA_DIR = path.resolve(__dirname, '../schema'); const SCHEMA_DEFINITIONS: { [schemaName: string]: { rootTypeName: string } } = { 'assets': { rootTypeName: 'AssetManifest' }, 'cloud-assembly': { rootTypeName: 'AssemblyManifest' }, - 'integ': { rootTypeName: 'IntegManifest' }, }; export const SCHEMAS = Object.keys(SCHEMA_DEFINITIONS); diff --git a/packages/@aws-cdk/cloud-assembly-schema/test/integ-tests.test.ts b/packages/@aws-cdk/cloud-assembly-schema/test/integ-tests.test.ts deleted file mode 100644 index 3baefc89d750f..0000000000000 --- a/packages/@aws-cdk/cloud-assembly-schema/test/integ-tests.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import { Manifest } from '../lib'; - -describe('Integration test', () => { - test('valid input', () => { - expect(() => { - validate({ - version: Manifest.version(), - testCases: { - testCase1: { - stacks: ['stack1', 'stack2'], - stackUpdateWorkflow: true, - cdkCommandOptions: { - deploy: { - enabled: true, - expectError: false, - expectedMessage: 'some message', - args: { - exclusively: true, - toolkitStackName: 'Stack', - reuseAssets: ['asset1', 'asset2'], - changeSetName: 'changeset', - force: true, - rollback: false, - notificationArns: ['arn1', 'arn2'], - execute: true, - parameters: { - 'MYPARAM': 'Value', - 'Stack1:OtherParam': 'OtherValue', - }, - usePreviousParameters: true, - outputsFile: 'outputs.json', - ci: true, - requireApproval: 'never', - app: 'node bin/my-app.js', - roleArn: 'roleArn', - context: { - KEY: 'value', - }, - trace: true, - strict: true, - lookups: true, - ignoreErrors: true, - json: true, - verbose: true, - debug: true, - profile: 'profile', - proxy: 'https://proxy', - caBundlePath: 'path/to/bundle', - ec2Creds: true, - versionReporting: false, - pathMetadata: false, - assetMetadata: true, - staging: false, - output: true, - notices: true, - color: false, - }, - }, - synth: { - enabled: true, - expectError: false, - expectedMessage: 'some message', - args: { - quiet: true, - exclusively: true, - validation: true, - }, - }, - destroy: { - enabled: true, - expectError: false, - expectedMessage: 'some message', - args: { - force: true, - exclusively: true, - }, - }, - }, - hooks: { - preDeploy: ['yarn test'], - postDeploy: ['some other command'], - preDestroy: ['command1', 'command2'], - postDestroy: ['command3', 'command4'], - }, - diffAssets: true, - allowDestroy: ['AWS::IAM::Role'], - region: ['us-east-1', 'us-east-2'], - }, - }, - }); - }); - }); - - test('invalid input', () => { - expect(() => { - validate({ - version: Manifest.version(), - testCases: { - stacks: true, - }, - }); - }).toThrow(/instance\.testCases\.stacks is not of a type\(s\) object/); - }); - - test('without command options', () => { - expect(() => { - validate({ - version: Manifest.version(), - testCases: { - testCase1: { - stacks: ['stack1', 'stack2'], - stackUpdateWorkflow: true, - hooks: { - preDeploy: ['yarn test'], - }, - diffAssets: true, - }, - }, - }); - }); - }); -}); - -function validate(manifest: any) { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'integ.test.')); - const filePath = path.join(dir, 'manifest.json'); - fs.writeFileSync(filePath, JSON.stringify(manifest, undefined, 2)); - try { - Manifest.loadIntegManifest(filePath); - } finally { - fs.unlinkSync(filePath); - fs.rmdirSync(dir); - } -} diff --git a/packages/@aws-cdk/core/lib/duration.ts b/packages/@aws-cdk/core/lib/duration.ts index ebb5e60a19a67..29cafc4f8b189 100644 --- a/packages/@aws-cdk/core/lib/duration.ts +++ b/packages/@aws-cdk/core/lib/duration.ts @@ -316,7 +316,7 @@ function convert(amount: number, fromUnit: TimeUnit, toUnit: TimeUnit, { integra if (fromUnit.inMillis === toUnit.inMillis) { return amount; } if (Token.isUnresolved(amount)) { - throw new Error(`Unable to perform time unit conversion on un-resolved token ${amount}.`); + throw new Error(`Duration must be specified as 'Duration.${toUnit}()' here since its value comes from a token and cannot be converted (got Duration.${fromUnit})`); } const value = (amount * fromUnit.inMillis) / toUnit.inMillis; if (!Number.isInteger(value) && integral) { diff --git a/packages/@aws-cdk/core/lib/size.ts b/packages/@aws-cdk/core/lib/size.ts index e8b9c66e35b72..fa938c5939271 100644 --- a/packages/@aws-cdk/core/lib/size.ts +++ b/packages/@aws-cdk/core/lib/size.ts @@ -144,6 +144,13 @@ export class Size { public toPebibytes(opts: SizeConversionOptions = {}): number { return convert(this.amount, this.unit, StorageUnit.Pebibytes, opts); } + + /** + * Checks if size is a token or a resolvable object + */ + public isUnresolved() { + return Token.isUnresolved(this.amount); + } } /** @@ -190,7 +197,7 @@ function convert(amount: number, fromUnit: StorageUnit, toUnit: StorageUnit, opt const rounding = options.rounding ?? SizeRoundingBehavior.FAIL; if (fromUnit.inKibiBytes === toUnit.inKibiBytes) { return amount; } if (Token.isUnresolved(amount)) { - throw new Error(`Unable to perform time unit conversion on un-resolved token ${amount}.`); + throw new Error(`Size must be specified as 'Size.${toUnit}()' here since its value comes from a token and cannot be converted (got Size.${fromUnit})`); } const multiplier = fromUnit.inKibiBytes / toUnit.inKibiBytes; diff --git a/packages/@aws-cdk/core/test/duration.test.ts b/packages/@aws-cdk/core/test/duration.test.ts index 99d54d15f0905..466369be3f4f8 100644 --- a/packages/@aws-cdk/core/test/duration.test.ts +++ b/packages/@aws-cdk/core/test/duration.test.ts @@ -16,10 +16,8 @@ describe('duration', () => { expect(stack.resolve(lazyDuration.toSeconds())).toEqual(1337); expect( () => stack.resolve(lazyDuration.toMinutes())).toThrow( - /Unable to perform time unit conversion on un-resolved token/, + /Duration must be specified as 'Duration.minutes\(\)' here/, ); - - }); test('Duration in seconds', () => { @@ -31,8 +29,6 @@ describe('duration', () => { floatEqual(duration.toDays({ integral: false }), 300 / 86_400); expect(Duration.seconds(60 * 60 * 24).toDays()).toEqual(1); - - }); test('Duration in minutes', () => { @@ -44,8 +40,6 @@ describe('duration', () => { floatEqual(duration.toDays({ integral: false }), 300 / 86_400); expect(Duration.minutes(60 * 24).toDays()).toEqual(1); - - }); test('Duration in hours', () => { @@ -57,16 +51,12 @@ describe('duration', () => { floatEqual(duration.toDays({ integral: false }), 5 / 24); expect(Duration.hours(24).toDays()).toEqual(1); - - }); test('seconds to milliseconds', () => { const duration = Duration.seconds(5); expect(duration.toMilliseconds()).toEqual(5_000); - - }); test('Duration in days', () => { @@ -75,8 +65,6 @@ describe('duration', () => { expect(duration.toSeconds()).toEqual(86_400); expect(duration.toMinutes()).toEqual(1_440); expect(duration.toDays()).toEqual(1); - - }); testDeprecated('toISOString', () => { @@ -93,8 +81,6 @@ describe('duration', () => { expect(Duration.days(5).toISOString()).toEqual('P5D'); expect(Duration.seconds(1 + 60 * (1 + 60 * (1 + 24))).toISOString()).toEqual('P1DT1H1M1S'); - - }); test('toIsoString', () => { @@ -112,8 +98,6 @@ describe('duration', () => { expect(Duration.seconds(65).toIsoString()).toEqual('PT1M5S'); expect(Duration.seconds(1 + 60 * (1 + 60 * (1 + 24))).toIsoString()).toEqual('P1DT1H1M1S'); - - }); test('parse', () => { @@ -128,8 +112,6 @@ describe('duration', () => { expect(Duration.parse('P5D').toSeconds()).toEqual(432_000); expect(Duration.parse('P1DT1H1M1S').toSeconds()).toEqual(1 + 60 * (1 + 60 * (1 + 24))); - - }); test('reject illegal parses', () => { @@ -141,8 +123,6 @@ describe('duration', () => { expect(() => { Duration.parse('P5S'); }).toThrow(err); - - }); test('to human string', () => { @@ -165,8 +145,6 @@ describe('duration', () => { expect(Duration.millis(3666).toHumanString()).toEqual('3 seconds 666 millis'); expect(Duration.millis(3.6).toHumanString()).toEqual('3.6 millis'); - - }); test('add two durations', () => { @@ -188,7 +166,6 @@ describe('duration', () => { expect(Duration.millis(1).unitLabel()).toEqual('millis'); expect(Duration.hours(1000).unitLabel()).toEqual('hours'); expect(Duration.days(2).unitLabel()).toEqual('days'); - }); test('format number token to number', () => { @@ -197,14 +174,12 @@ describe('duration', () => { expect(stack.resolve(lazyDuration.formatTokenToNumber())).toEqual('10 minutes'); expect(Duration.hours(10).formatTokenToNumber()).toEqual('10 hours'); expect(Duration.days(5).formatTokenToNumber()).toEqual('5 days'); - }); test('duration is unresolved', () => { const lazyDuration = Duration.minutes(Lazy.number({ produce: () => 10 })); expect(lazyDuration.isUnresolved()).toEqual(true); expect(Duration.hours(10).isUnresolved()).toEqual(false); - }); }); diff --git a/packages/@aws-cdk/core/test/size.test.ts b/packages/@aws-cdk/core/test/size.test.ts index 9801fc8f53acf..a7c9c93a1a5bb 100644 --- a/packages/@aws-cdk/core/test/size.test.ts +++ b/packages/@aws-cdk/core/test/size.test.ts @@ -1,10 +1,8 @@ -import { Size, SizeRoundingBehavior, Stack, Token } from '../lib'; +import { Size, SizeRoundingBehavior, Stack, Token, Lazy } from '../lib'; describe('size', () => { test('negative amount', () => { expect(() => Size.kibibytes(-1)).toThrow(/negative/); - - }); test('unresolved amount', () => { @@ -13,10 +11,8 @@ describe('size', () => { expect(stack.resolve(lazySize.toKibibytes())).toEqual(1337); expect( () => stack.resolve(lazySize.toMebibytes())).toThrow( - /Unable to perform time unit conversion on un-resolved token/, + /Size must be specified as 'Size.mebibytes\(\)' here/, ); - - }); test('Size in kibibytes', () => { @@ -30,8 +26,6 @@ describe('size', () => { floatEqual(size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 4_294_967_296 / (1024 * 1024 * 1024 * 1024)); expect(Size.kibibytes(4 * 1024 * 1024).toGibibytes()).toEqual(4); - - }); test('Size in mebibytes', () => { @@ -45,8 +39,6 @@ describe('size', () => { floatEqual(size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 4_194_304 / (1024 * 1024 * 1024)); expect(Size.mebibytes(4 * 1024).toGibibytes()).toEqual(4); - - }); test('Size in gibibyte', () => { @@ -61,8 +53,6 @@ describe('size', () => { floatEqual(size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 5 / (1024 * 1024)); expect(Size.gibibytes(4096).toTebibytes()).toEqual(4); - - }); test('Size in tebibyte', () => { @@ -76,8 +66,6 @@ describe('size', () => { floatEqual(size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 5 / 1024); expect(Size.tebibytes(4096).toPebibytes()).toEqual(4); - - }); test('Size in pebibytes', () => { @@ -88,8 +76,6 @@ describe('size', () => { expect(size.toGibibytes()).toEqual(5_242_880); expect(size.toTebibytes()).toEqual(5_120); expect(size.toPebibytes()).toEqual(5); - - }); test('rounding behavior', () => { @@ -105,8 +91,12 @@ describe('size', () => { expect(size.toGibibytes({ rounding: SizeRoundingBehavior.NONE })).toEqual(5.078125); expect(size.toTebibytes({ rounding: SizeRoundingBehavior.NONE })).toEqual(5200 / (1024 * 1024)); expect(size.toKibibytes({ rounding: SizeRoundingBehavior.NONE })).toEqual(5_324_800); + }); - + test('size is unresolved', () => { + const lazySize = Size.pebibytes(Lazy.number({ produce: () => 10 })); + expect(lazySize.isUnresolved()).toEqual(true); + expect(Size.mebibytes(10).isUnresolved()).toEqual(false); }); }); diff --git a/packages/@aws-cdk/integ-runner/.eslintrc.js b/packages/@aws-cdk/integ-runner/.eslintrc.js deleted file mode 100644 index 2658ee8727166..0000000000000 --- a/packages/@aws-cdk/integ-runner/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); -baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; diff --git a/packages/@aws-cdk/integ-runner/.gitignore b/packages/@aws-cdk/integ-runner/.gitignore deleted file mode 100644 index d24092a6feda2..0000000000000 --- a/packages/@aws-cdk/integ-runner/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -*.js -*.js.map -*.d.ts -!lib/init-templates/**/javascript/**/* -node_modules -dist - -# Generated by generate.sh -build-info.json - -.LAST_BUILD -.nyc_output -coverage -nyc.config.js -.LAST_PACKAGE -*.snk - -!test/integ/run-wrappers/dist -!test/integ/cli/**/* -assets.json -npm-shrinkwrap.json -!.eslintrc.js -!jest.config.js - -junit.xml - -# Ignore this symlink, we recreate it at test time -test/test-archive-follow/data/linked diff --git a/packages/@aws-cdk/integ-runner/.npmignore b/packages/@aws-cdk/integ-runner/.npmignore deleted file mode 100644 index 45b8808bdd7ac..0000000000000 --- a/packages/@aws-cdk/integ-runner/.npmignore +++ /dev/null @@ -1,30 +0,0 @@ -# Don't include original .ts files when doing `npm pack` -*.ts -!*.template.ts -!*.d.ts -coverage -.nyc_output -*.tgz - -dist -.LAST_PACKAGE -.LAST_BUILD -*.snk - -!lib/init-templates/*/*/tsconfig.json -!test/integ/cli/**/*.js -!test/integ/run-wrappers/dist - -*.tsbuildinfo - -tsconfig.json - -# init templates include default tsconfig.json files which we need -!lib/init-templates/**/tsconfig.json -.eslintrc.js -jest.config.js - -# exclude cdk artifacts -**/cdk.out -junit.xml -test/ \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/LICENSE b/packages/@aws-cdk/integ-runner/LICENSE deleted file mode 100644 index 82ad00bb02d0b..0000000000000 --- a/packages/@aws-cdk/integ-runner/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/@aws-cdk/integ-runner/NOTICE b/packages/@aws-cdk/integ-runner/NOTICE deleted file mode 100644 index 1b7adbb891265..0000000000000 --- a/packages/@aws-cdk/integ-runner/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/integ-runner/README.md b/packages/@aws-cdk/integ-runner/README.md deleted file mode 100644 index e67a64282a42b..0000000000000 --- a/packages/@aws-cdk/integ-runner/README.md +++ /dev/null @@ -1,161 +0,0 @@ -# integ-runner - - - ---- - -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) - -> The APIs of higher level constructs in this module are experimental and under active development. -> They are subject to non-backward compatible changes or removal in any future version. These are -> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be -> announced in the release notes. This means that while you may use them, you may need to update -> your source code when upgrading to a newer version of this package. - ---- - - - - -## Overview - - -## Usage - -- Run all integration tests in `test` directory - -```bash -integ-runner [ARGS] [TEST...] -``` - -This will look for all files that match the naming convention of `/integ.*.ts$/`. Each of these files will be expected -to be a self contained CDK app. The runner will execute the following for each file (app): - -1. Check if a snapshot file exists (i.e. `/integ.*.expected.snapshot$/`) -2. If the snapshot does not exist - 2a. Synth the integ app which will produce the `integ.json` file -3. Read the `integ.json` file which contains instructions on what the runner should do. -4. Execute instructions - -### Options - -- `--update-on-failed` (default=false) - Rerun integration tests if snapshot fails -- `--clean` (default=`true`) - Destroy stacks after deploy (use `--no-clean` for debugging) -- `--verbose` (default=`false`) - verbose logging -- `--parallel` (default=`false`) - Run tests in parallel across default regions -- `--parallel-regions` - List of regions to run tests in. If this is provided then all tests will - be run in parallel across these regions -- `--directory` (default=`test`) - Search for integration tests recursively from this starting directory -- `--force` (default=`false`) - Rerun integration test even if the test passes -- `--file` - Read the list of tests from this file - -Example: - -```bash -integ-runner --update --parallel --parallel-regions us-east-1 --parallel-regions us-east-2 --parallel-regions us-west-2 --directory ./ -``` - -This will search for integration tests recursively from the current directory and then execute them in parallel across `us-east-1`, `us-east-2`, & `us-west-2`. - -### integ.json schema - -See [@aws-cdk/cloud-assembly-schema/lib/integ-tests/schema.ts](../cloud-assembly-schema/lib/integ-tests/schema.ts) - -### defining an integration test - -In most cases an integration test will be an instance of a stack - -```ts -import { Function, FunctionOptions } from '../lib'; - -interface MyIntegTestProps extends StackOptions { - functionProps?: FunctionOptions; -} -class MyIntegTest extends Stack { - constructor(scope: Construct, id: string, props: MyIntegTestProps) { - super(scope, id, props); - - new Function(this, 'Handler', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), - ...props.functionProps, - }); - } -} -``` - -You would then use the `IntegTest` construct to create your test cases - -```ts -new IntegTeset(app, 'ArmTest', { - stacks: [ - new MyIntegTest(app, 'Stack1', { - functionProps: { - architecture: lambda.Architecture.ARM_64, - }, - }), - ], - diffAssets: true, - update: true, - cdkCommandOptions: { - deploy: { - args: { - requireApproval: RequireApproval.NEVER, - json: true, - }, - }, - destroy: { - args: { - force: true, - }, - }, - }, -}); - -new IntegTeset(app, 'AmdTest', { - stacks: [ - new MyIntegTest(app, 'Stack2', { - functionProps: { - architecture: lambda.Architecture.X86_64, - }, - }), - ], -}); -``` - -This will synthesize an `integ.json` file with the following contents - -```json -{ - "ArmTest": { - "stacks": ["Stack1"], - "diffAssets": true, - "update": true, - "cdkCommands": { - "deploy": { - "args": { - "requireApproval": "never", - "json": true - } - }, - "destroy": { - "args": { - "force": true - } - } - } - }, - "AmdTest": { - "stacks": ["Stack2"] - } -} -``` diff --git a/packages/@aws-cdk/integ-runner/bin/integ-runner b/packages/@aws-cdk/integ-runner/bin/integ-runner deleted file mode 100755 index 20ace56b80449..0000000000000 --- a/packages/@aws-cdk/integ-runner/bin/integ-runner +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('./integ-runner.js'); diff --git a/packages/@aws-cdk/integ-runner/bin/integ-runner.ts b/packages/@aws-cdk/integ-runner/bin/integ-runner.ts deleted file mode 100644 index ca343920f91cb..0000000000000 --- a/packages/@aws-cdk/integ-runner/bin/integ-runner.ts +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env node -// Exercise all integ stacks and if they deploy, update the expected synth files -import * as os from 'os'; -import * as path from 'path'; -import * as chalk from 'chalk'; -import * as workerpool from 'workerpool'; -import * as yargs from 'yargs'; -import { IntegrationTests, IntegTestConfig } from '../lib/runner/integ-tests'; -import * as logger from '../lib/runner/private/logger'; -import { IntegBatchResponse, printResults } from '../lib/workers/common'; -import { SnapshotBatchRequest } from '../lib/workers/extract_worker'; -import { runIntegrationTestsInParallel, IntegTestRunOptions } from '../lib/workers/integ-test-worker'; - - -/** - * Split a list of snapshot tests into batches that can be run using a workerpool. - */ -function batchTests(tests: IntegTestConfig[]): SnapshotBatchRequest[] { - let batchSize = 3; - const ret: SnapshotBatchRequest[] = []; - for (let i = 0; i < tests.length; i += batchSize) { - ret.push({ - tests: tests.slice(i, i + batchSize), - }); - } - return ret; -} - -export function printSummary(total: number, failed: number): void { - if (failed > 0) { - logger.print('%s: %s %s, %s total', chalk.bold('Tests'), chalk.red(failed), chalk.red('failed'), total); - } else { - logger.print('%s: %s %s, %s total', chalk.bold('Tests'), chalk.green(total), chalk.green('passed'), total); - } -} - -/** - * Run Integration tests. - */ -async function runIntegrationTests(options: IntegTestRunOptions): Promise { - logger.highlight('\nRunning integration tests for failed tests...\n'); - logger.print('Running in parallel across: %s', options.regions.join(', ')); - const totalTests = options.tests.length; - const failedTests: IntegTestConfig[] = []; - - const responses = await runIntegrationTestsInParallel(options); - for (const response of responses) { - failedTests.push(...response.failedTests); - } - logger.highlight('\nTest Results: \n'); - printSummary(totalTests, failedTests.length); -} - -/** - * Run Snapshot tests - * First batch up the tests. By default there will be 3 tests per batch. - * Use a workerpool to run the batches in parallel. - */ -async function runSnapshotTests(pool: workerpool.WorkerPool, tests: IntegTestConfig[]): Promise { - const testsToRun: IntegTestConfig[] = []; - const requests = batchTests(tests); - logger.highlight('\nVerifying integration test snapshots...\n'); - const responses: IntegBatchResponse[] = await Promise.all( - requests.map((request) => pool.exec('snapshotTestBatch', [request], { - on: printResults, - })), - ); - for (const response of responses) { - testsToRun.push(...response.failedTests); - } - - logger.highlight('\nSnapshot Results: \n'); - printSummary(tests.length, testsToRun.length); - return testsToRun; -} - -async function main() { - const argv = yargs - .usage('Usage: integ-runner [TEST...]') - .option('list', { type: 'boolean', default: false, desc: 'List tests instead of running them' }) - .option('clean', { type: 'boolean', default: true, desc: 'Skips stack clean up after test is completed (use --no-clean to negate)' }) - .option('verbose', { type: 'boolean', default: false, alias: 'v', desc: 'Verbose logs' }) - .option('dry-run', { type: 'boolean', default: false, desc: 'do not actually deploy the stack. just update the snapshot (not recommended!)' }) - .option('update-on-failed', { type: 'boolean', default: false, desc: 'rerun integration tests and update snapshots for failed tests.' }) - .option('force', { type: 'boolean', default: false, desc: 'Rerun all integration tests even if tests are passing' }) - .option('parallel', { type: 'boolean', default: false, desc: 'run integration tests in parallel' }) - .option('parallel-regions', { type: 'array', desc: 'if --parallel is used then these regions are used to run tests in parallel', nargs: 1, default: [] }) - .options('directory', { type: 'string', default: 'test', desc: 'starting directory to discover integration tests' }) - .argv; - - // Cap to a reasonable top-level limit to prevent thrash on machines with many, many cores. - const maxWorkers = parseInt(process.env.CDK_INTEG_MAX_WORKER_COUNT ?? '16'); - const N = Math.min(maxWorkers, Math.max(1, Math.ceil(os.cpus().length / 2))); - const pool = workerpool.pool(path.join(__dirname, '../lib/workers/extract_worker.js'), { - maxWorkers: N, - }); - - // list of integration tests that will be executed - const testsToRun: IntegTestConfig[] = []; - const testsFromArgs: IntegTestConfig[] = []; - const parallelRegions = arrayFromYargs(argv['parallel-regions']); - const testRegions: string[] = parallelRegions ?? ['us-east-1', 'us-east-2', 'us-west-2']; - const runUpdateOnFailed = argv['update-on-failed'] ?? false; - - - try { - if (argv.list) { - const tests = await new IntegrationTests(argv.directory).fromCliArgs(); - process.stdout.write(tests.map(t => t.fileName).join('\n') + '\n'); - return; - } - - if (argv._.length === 0) { - testsFromArgs.push(...(await new IntegrationTests(argv.directory).fromCliArgs())); - } else { - testsFromArgs.push(...(await new IntegrationTests(argv.directory).fromCliArgs(argv._.map(x => x.toString())))); - } - - // If `--force` is not used then first validate the snapshots and gather - // the failed snapshot tests. If `--force` is used then we will skip snapshot - // tests and run integration tests for all tests - if (!argv.force) { - const failedSnapshots = await runSnapshotTests(pool, testsFromArgs); - testsToRun.push(...failedSnapshots); - } else { - testsToRun.push(...testsFromArgs); - } - - - // run integration tests if `--update-on-failed` OR `--force` is used - if (runUpdateOnFailed || argv.force) { - await runIntegrationTests({ - pool, - tests: testsToRun, - regions: testRegions, - clean: argv.clean, - dryRun: argv['dry-run'], - verbose: argv.verbose, - }); - - if (argv.clean === false) { - logger.warning('Not cleaning up stacks since "--no-clean" was used'); - } - } - - } finally { - void pool.terminate(); - } -} - -/** - * Translate a Yargs input array to something that makes more sense in a programming language - * model (telling the difference between absence and an empty array) - * - * - An empty array is the default case, meaning the user didn't pass any arguments. We return - * undefined. - * - If the user passed a single empty string, they did something like `--array=`, which we'll - * take to mean they passed an empty array. - */ -function arrayFromYargs(xs: string[]): string[] | undefined { - if (xs.length === 0) { return undefined; } - return xs.filter(x => x !== ''); -} - -main().catch(e => { - // eslint-disable-next-line no-console - console.error(e); - process.exit(1); -}); diff --git a/packages/@aws-cdk/integ-runner/jest.config.js b/packages/@aws-cdk/integ-runner/jest.config.js deleted file mode 100644 index d052cbb29f05d..0000000000000 --- a/packages/@aws-cdk/integ-runner/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); -module.exports = { - ...baseConfig, - coverageThreshold: { - global: { - ...baseConfig.coverageThreshold.global, - branches: 60, - }, - }, -}; diff --git a/packages/@aws-cdk/integ-runner/lib/runner/integ-tests.ts b/packages/@aws-cdk/integ-runner/lib/runner/integ-tests.ts deleted file mode 100644 index 0fd648c31c5d1..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/runner/integ-tests.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; - -/** - * Represents a single integration test - */ -export interface IntegTestConfig { - readonly directory: string; - readonly fileName: string; -} - -/** - * Discover integration tests - */ -export class IntegrationTests { - constructor(private readonly directory: string) { - } - - /** - * Takes an optional list of tests to look for, otherwise - * it will look for all tests from the directory - */ - public async fromCliArgs(tests?: string[]): Promise { - let allTests = await this.discover(); - const all = allTests.map(x => x.fileName); - let foundAll = true; - - if (tests && tests.length > 0) { - // Pare down found tests to filter - allTests = allTests.filter(t => { - const parts = path.parse(t.fileName); - return (tests.includes(t.fileName) || tests.includes(parts.base)); - }); - - const selectedNames = allTests.map(t => path.parse(t.fileName).base); - for (const unmatched of tests.filter(t => !selectedNames.includes(t))) { - process.stderr.write(`No such integ test: ${unmatched}\n`); - foundAll = false; - } - } - - if (!foundAll) { - process.stderr.write(`Available tests: ${all.join(' ')}\n`); - return []; - } - - return allTests; - } - - private async discover(): Promise { - const files = await this.readTree(); - const integs = files.filter(fileName => path.basename(fileName).startsWith('integ.') && path.basename(fileName).endsWith('.js')); - return this.request(integs); - } - - private request(files: string[]): IntegTestConfig[] { - return files.map(fileName => { return { directory: this.directory, fileName }; }); - } - - private async readTree(): Promise { - const ret = new Array(); - - async function recurse(dir: string) { - const files = await fs.readdir(dir); - for (const file of files) { - const fullPath = path.join(dir, file); - const statf = await fs.stat(fullPath); - if (statf.isFile()) { ret.push(fullPath); } - if (statf.isDirectory()) { await recurse(path.join(fullPath)); } - } - } - - await recurse(this.directory); - return ret; - } -} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/canonicalize-assets.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/canonicalize-assets.ts deleted file mode 100644 index 9cee3d4742b3c..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/runner/private/canonicalize-assets.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Reduce template to a normal form where asset references have been normalized - * - * This makes it possible to compare templates if all that's different between - * them is the hashes of the asset values. - * - * Currently only handles parameterized assets, but can (and should) - * be adapted to handle convention-mode assets as well when we start using - * more of those. - */ -export function canonicalizeTemplate(template: any): any { - // For the weird case where we have an array of templates... - if (Array.isArray(template)) { - return template.map(canonicalizeTemplate); - } - - // Find assets via parameters - const stringSubstitutions = new Array<[RegExp, string]>(); - const paramRe = /^AssetParameters([a-zA-Z0-9]{64})(S3Bucket|S3VersionKey|ArtifactHash)([a-zA-Z0-9]{8})$/; - - const assetsSeen = new Set(); - for (const paramName of Object.keys(template?.Parameters || {})) { - const m = paramRe.exec(paramName); - if (!m) { continue; } - if (assetsSeen.has(m[1])) { continue; } - - assetsSeen.add(m[1]); - const ix = assetsSeen.size; - - // Full parameter reference - stringSubstitutions.push([ - new RegExp(`AssetParameters${m[1]}(S3Bucket|S3VersionKey|ArtifactHash)([a-zA-Z0-9]{8})`), - `Asset${ix}$1`, - ]); - // Substring asset hash reference - stringSubstitutions.push([ - new RegExp(`${m[1]}`), - `Asset${ix}Hash`, - ]); - } - - // Substitute them out - return substitute(template); - - function substitute(what: any): any { - if (Array.isArray(what)) { - return what.map(substitute); - } - - if (typeof what === 'object' && what !== null) { - const ret: any = {}; - for (const [k, v] of Object.entries(what)) { - ret[stringSub(k)] = substitute(v); - } - return ret; - } - - if (typeof what === 'string') { - return stringSub(what); - } - - return what; - } - - function stringSub(x: string) { - for (const [re, replacement] of stringSubstitutions) { - x = x.replace(re, replacement); - } - return x; - } -} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts deleted file mode 100644 index 99626ea53bdb2..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts +++ /dev/null @@ -1,66 +0,0 @@ -import * as path from 'path'; -import { AssemblyManifest, Manifest, ArtifactType, AwsCloudFormationStackProperties } from '@aws-cdk/cloud-assembly-schema'; -import * as fs from 'fs-extra'; - -/** - * Reads a Cloud Assembly manifest - */ -export class AssemblyManifestReader { - public static readonly DEFAULT_FILENAME = 'manifest.json'; - - /** - * Reads a Cloud Assembly manifest from a file - */ - public static fromFile(fileName: string): AssemblyManifestReader { - try { - const obj = Manifest.loadAssemblyManifest(fileName); - return new AssemblyManifestReader(path.dirname(fileName), obj); - - } catch (e) { - throw new Error(`Cannot read integ manifest '${fileName}': ${e.message}`); - } - } - - /** - * Reads a Cloud Assembly manifest from a file or a directory - * If the given filePath is a directory then it will look for - * a file within the directory with the DEFAULT_FILENAME - */ - public static fromPath(filePath: string): AssemblyManifestReader { - let st; - try { - st = fs.statSync(filePath); - } catch (e) { - throw new Error(`Cannot read integ manifest at '${filePath}': ${e.message}`); - } - if (st.isDirectory()) { - return AssemblyManifestReader.fromFile(path.join(filePath, AssemblyManifestReader.DEFAULT_FILENAME)); - } - return AssemblyManifestReader.fromFile(filePath); - } - - /** - * The directory where the manifest was found - */ - public readonly directory: string; - - constructor(directory: string, private readonly manifest: AssemblyManifest) { - this.directory = directory; - } - - /** - * Get the stacks from the manifest - * returns a map of artifactId to CloudFormation template - */ - public get stacks(): Record { - const stacks: Record = {}; - for (const [artifactId, artifact] of Object.entries(this.manifest.artifacts ?? {})) { - if (artifact.type !== ArtifactType.AWS_CLOUDFORMATION_STACK) { continue; } - const props = artifact.properties as AwsCloudFormationStackProperties; - - const template = fs.readJSONSync(path.resolve(this.directory, props.templateFile)); - stacks[artifactId] = template; - } - return stacks; - } -} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts deleted file mode 100644 index 80b567dbb69ce..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as path from 'path'; -import { IntegManifest, Manifest, TestCase } from '@aws-cdk/cloud-assembly-schema'; -import * as fs from 'fs-extra'; - -/** - * Test case configuration read from the integ manifest - */ -export interface IntegTestConfig { - /** - * Test cases contained in this integration test - */ - readonly testCases: { [testCaseName: string]: TestCase }; - - /** - * Whether to enable lookups for this test - * - * @default false - */ - readonly enableLookups: boolean; -} - -/** - * Reads an integration tests manifest - */ -export class IntegManifestReader { - public static readonly DEFAULT_FILENAME = 'integ.json'; - - /** - * Reads an integration test manifest from the specified file - */ - public static fromFile(fileName: string): IntegManifestReader { - try { - const obj = Manifest.loadIntegManifest(fileName); - return new IntegManifestReader(path.dirname(fileName), obj); - - } catch (e) { - throw new Error(`Cannot read integ manifest '${fileName}': ${e.message}`); - } - } - - /** - * Reads a Integration test manifest from a file or a directory - * If the given filePath is a directory then it will look for - * a file within the directory with the DEFAULT_FILENAME - */ - public static fromPath(filePath: string): IntegManifestReader { - let st; - try { - st = fs.statSync(filePath); - } catch (e) { - throw new Error(`Cannot read integ manifest at '${filePath}': ${e.message}`); - } - if (st.isDirectory()) { - return IntegManifestReader.fromFile(path.join(filePath, IntegManifestReader.DEFAULT_FILENAME)); - } - return IntegManifestReader.fromFile(filePath); - } - - /** - * The directory where the manifest was found - */ - public readonly directory: string; - constructor(directory: string, private readonly manifest: IntegManifest) { - this.directory = directory; - } - - /** - * List of integration tests in the manifest - */ - public get tests(): IntegTestConfig { - return { - testCases: this.manifest.testCases, - enableLookups: this.manifest.enableLookups ?? false, - }; - } -} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/logger.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/logger.ts deleted file mode 100644 index 55c7f80b24365..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/runner/private/logger.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Writable } from 'stream'; -import * as util from 'util'; -import * as chalk from 'chalk'; - -type StyleFn = (str: string) => string; -const { stderr } = process; - -const logger = (stream: Writable, styles?: StyleFn[]) => (fmt: string, ...args: any[]) => { - let str = util.format(fmt, ...args); - if (styles && styles.length) { - str = styles.reduce((a, style) => style(a), str); - } - stream.write(str + '\n'); -}; - -export const print = logger(stderr); -export const error = logger(stderr, [chalk.red]); -export const warning = logger(stderr, [chalk.yellow]); -export const success = logger(stderr, [chalk.green]); -export const highlight = logger(stderr, [chalk.bold]); diff --git a/packages/@aws-cdk/integ-runner/lib/runner/runners.ts b/packages/@aws-cdk/integ-runner/lib/runner/runners.ts deleted file mode 100644 index 747d240c8f04d..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/runner/runners.ts +++ /dev/null @@ -1,606 +0,0 @@ -import * as path from 'path'; -import { Writable, WritableOptions } from 'stream'; -import { StringDecoder, NodeStringDecoder } from 'string_decoder'; -import { TestCase, RequireApproval, DefaultCdkOptions } from '@aws-cdk/cloud-assembly-schema'; -import { diffTemplate, formatDifferences } from '@aws-cdk/cloudformation-diff'; -import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS, TARGET_PARTITIONS } from '@aws-cdk/cx-api'; -import { CdkCliWrapper, ICdk } from 'cdk-cli-wrapper'; -import * as fs from 'fs-extra'; -import { Diagnostic, DiagnosticReason } from '../workers/common'; -import { canonicalizeTemplate } from './private/canonicalize-assets'; -import { AssemblyManifestReader } from './private/cloud-assembly'; -import { IntegManifestReader } from './private/integ-manifest'; - -const CDK_OUTDIR_PREFIX = 'cdk-integ.out'; -const CDK_INTEG_STACK_PRAGMA = '/// !cdk-integ'; -const PRAGMA_PREFIX = 'pragma:'; -const SET_CONTEXT_PRAGMA_PREFIX = 'pragma:set-context:'; -const VERIFY_ASSET_HASHES = 'pragma:include-assets-hashes'; -const ENABLE_LOOKUPS_PRAGMA = 'pragma:enable-lookups'; - -/** - * Options for creating an integration test runner - */ -export interface IntegRunnerOptions { - /** - * The name of the file that contains the integration test - * This should be a JavaScript file - */ - readonly fileName: string, - - /** - * Additional environment variables that will be available - * to the CDK CLI - * - * @default - no additional environment variables - */ - readonly env?: { [name: string]: string }, - - /** - * tmp cdk.out directory - * - * @default - directory will be `cdk-integ.out.${testName}` - */ - readonly integOutDir?: string, - - /** - * Instance of the CDK CLI to use - * - * @default - CdkCliWrapper - */ - readonly cdk?: ICdk; -} - -/** - * Represents an Integration test runner - */ -export abstract class IntegRunner { - /** - * The directory where the snapshot will be stored - */ - public readonly snapshotDir: string; - - /** - * An instance of the CDK CLI - */ - public readonly cdk: ICdk; - - /** - * Pretty name of the test - */ - public readonly testName: string; - - /** - * The path to the integration test file - */ - protected readonly sourceFilePath: string; - - /** - * The value used in the '--app' CLI parameter - */ - protected readonly cdkApp: string; - - /** - * The path where the `cdk.context.json` file - * will be created - */ - protected readonly cdkContextPath: string; - - /** - * The relative path from the cwd to the snapshot directory - */ - protected readonly relativeSnapshotDir: string; - - /** - * The integration tests that this runner will execute - */ - protected _tests?: { [testName: string]: TestCase }; - - /** - * The working directory that the integration tests will be - * executed from - */ - protected readonly directory: string; - - /** - * Default options to pass to the CDK CLI - */ - protected readonly defaultArgs: DefaultCdkOptions = { - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - } - - private _enableLookups?: boolean; - - /** - * The directory where the CDK will be synthed to - */ - protected readonly cdkOutDir: string; - - constructor(options: IntegRunnerOptions) { - const parsed = path.parse(options.fileName); - this.directory = parsed.dir; - this.testName = parsed.name.slice(6); - this.snapshotDir = path.join(this.directory, `${this.testName}.integ.snapshot`); - this.relativeSnapshotDir = `${this.testName}.integ.snapshot`; - this.sourceFilePath = path.join(this.directory, parsed.base); - this.cdkContextPath = path.join(this.directory, 'cdk.context.json'); - this.cdk = options.cdk ?? new CdkCliWrapper({ - directory: this.directory, - env: options.env, - }); - this.cdkOutDir = options.integOutDir ?? `${CDK_OUTDIR_PREFIX}.${this.testName}`; - this.cdkApp = `node ${parsed.base}`; - if (this.hasSnapshot()) { - this.loadManifest(); - } - } - - /** - * Whether or not lookups are enabled for a given test case - */ - protected get enableLookups(): boolean { - return this._enableLookups ?? false; - } - - /** - * Return this list of test cases for this integration test - */ - public get tests(): { [testName: string]: TestCase } | undefined { - return this._tests; - } - - /** - * Returns true if a snapshot already exists for this test - */ - public hasSnapshot(): boolean { - if (fs.existsSync(this.snapshotDir)) { - return true; - } else { - return false; - } - } - - protected loadManifest(dir?: string): void { - try { - const reader = IntegManifestReader.fromPath(dir ?? this.snapshotDir); - this._tests = reader.tests.testCases; - this._enableLookups = reader.tests.enableLookups; - } catch (e) { - this._tests = this.renderTestCasesForLegacyTests(); - this._enableLookups = this.pragmas().includes(ENABLE_LOOKUPS_PRAGMA); - } - } - - protected cleanup(): void { - const cdkOutPath = path.join(this.directory, this.cdkOutDir); - if (fs.existsSync(cdkOutPath)) { - fs.removeSync(cdkOutPath); - } - } - - protected createSnapshot(): void { - if (fs.existsSync(this.snapshotDir)) { - fs.removeSync(this.snapshotDir); - } - - // if lookups are enabled then we need to synth again - // using dummy context and save that as the snapshot - if (this.enableLookups) { - this.writeContext(); - this.cdk.synth({ - ...this.defaultArgs, - all: true, - app: this.cdkApp, - output: this.relativeSnapshotDir, - // TODO: figure out if we need this... - // env: { - // ...DEFAULT_SYNTH_OPTIONS.env, - // }, - }); - this.cleanupContextFile(); - } else { - fs.moveSync(path.join(this.directory, this.cdkOutDir), this.snapshotDir, { overwrite: true }); - } - } - - /** - * Returns the single test stack to use. - * - * If the test has a single stack, it will be chosen. Otherwise a pragma is expected within the - * test file the name of the stack: - * - * @example - * - * /// !cdk-integ - * - */ - private renderTestCasesForLegacyTests(): { [testName: string]: TestCase } { - const tests: TestCase = { - stacks: [], - }; - const pragma = this.readStackPragma(); - if (pragma.length > 0) { - tests.stacks.push(...pragma); - } else { - const stacks = (this.cdk.list({ - ...this.defaultArgs, - all: true, - app: this.cdkApp, - output: this.cdkOutDir, - })).split('\n'); - if (stacks.length !== 1) { - throw new Error('"cdk-integ" can only operate on apps with a single stack.\n\n' + - ' If your app has multiple stacks, specify which stack to select by adding this to your test source:\n\n' + - ` ${CDK_INTEG_STACK_PRAGMA} STACK ...\n\n` + - ` Available stacks: ${stacks.join(' ')} (wildcards are also supported)\n`); - } - tests.stacks.push(...stacks); - } - - return { - [this.testName]: tests, - }; - } - - /** - * Reads stack names from the "!cdk-integ" pragma. - * - * Every word that's NOT prefixed by "pragma:" is considered a stack name. - * - * @example - * - * /// !cdk-integ - */ - private readStackPragma(): string[] { - return (this.readIntegPragma()).filter(p => !p.startsWith(PRAGMA_PREFIX)); - } - - /** - * Read arbitrary cdk-integ pragma directives - * - * Reads the test source file and looks for the "!cdk-integ" pragma. If it exists, returns it's - * contents. This allows integ tests to supply custom command line arguments to "cdk deploy" and "cdk synth". - * - * @example - * - * /// !cdk-integ [...] - */ - private readIntegPragma(): string[] { - const source = fs.readFileSync(this.sourceFilePath, { encoding: 'utf-8' }); - const pragmaLine = source.split('\n').find(x => x.startsWith(CDK_INTEG_STACK_PRAGMA + ' ')); - if (!pragmaLine) { - return []; - } - - const args = pragmaLine.substring(CDK_INTEG_STACK_PRAGMA.length).trim().split(' '); - if (args.length === 0) { - throw new Error(`Invalid syntax for cdk-integ pragma. Usage: "${CDK_INTEG_STACK_PRAGMA} [STACK] [pragma:PRAGMA] [...]"`); - } - return args; - } - - /** - * Return the non-stack pragmas - * - * These are all pragmas that start with "pragma:". - * - * For backwards compatibility reasons, all pragmas that DON'T start with this - * string are considered to be stack names. - */ - protected pragmas(): string[] { - return (this.readIntegPragma()).filter(p => p.startsWith(PRAGMA_PREFIX)); - } - - /** - * There is not currently a way to pass structured context to the CLI - * so to workaround this we write the context to a file - */ - protected writeContext(additionalContext?: Record): void { - const ctxPragmaContext: Record = {}; - - // apply context from set-context pragma - // usage: pragma:set-context:key=value - const ctxPragmas = (this.pragmas()).filter(p => p.startsWith(SET_CONTEXT_PRAGMA_PREFIX)); - for (const p of ctxPragmas) { - const instruction = p.substring(SET_CONTEXT_PRAGMA_PREFIX.length); - const [key, value] = instruction.split('='); - if (key == null || value == null) { - throw new Error(`invalid "set-context" pragma syntax. example: "pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true" got: ${p}`); - } - - ctxPragmaContext[key] = value; - } - const context: Record = { - ...DEFAULT_SYNTH_OPTIONS.context, - ...ctxPragmaContext, - ...additionalContext, - }; - fs.writeFileSync(this.cdkContextPath, JSON.stringify(context, undefined, 2), { encoding: 'utf-8' }); - } - - protected cleanupContextFile() { - if (fs.existsSync(this.cdkContextPath)) { - fs.unlinkSync(this.cdkContextPath); - } - } -} - -/** - * Options for the integration test runner - */ -export interface IntegTestRunOptions { - /** - * The test case to execute - */ - readonly testCase: TestCase; - - /** - * Whether or not to run `cdk destroy` and cleanup the - * integration test stacks. - * - * Set this to false if you need to perform any validation - * or troubleshooting after deployment. - * - * @default true - */ - readonly clean?: boolean; - - /** - * If set to true, the integration test will not deploy - * anything and will simply update the snapshot. - * - * You should NOT use this method since you are essentially - * bypassing the integration test. - * - * @default false - */ - readonly dryRun?: boolean; -} - -/** - * An integration test runner that orchestrates executing - * integration tests - */ -export class IntegTestRunner extends IntegRunner { - constructor(options: IntegRunnerOptions) { - super(options); - } - - /** - * Orchestrates running integration tests. Currently this includes - * - * 1. Deploying the integration test stacks - * 2. Saving the snapshot - * 3. Destroying the integration test stacks - */ - public runIntegTestCase(options: IntegTestRunOptions): void { - const clean = options.clean ?? true; - try { - if (!options.dryRun) { - this.cdk.deploy({ - ...this.defaultArgs, - stacks: options.testCase.stacks, - requireApproval: RequireApproval.NEVER, - output: this.cdkOutDir, - app: this.cdkApp, - lookups: this.enableLookups, - }); - } else { - this.cdk.synth({ - ...this.defaultArgs, - stacks: options.testCase.stacks, - output: this.cdkOutDir, - app: this.cdkApp, - lookups: this.enableLookups, - }); - } - this.createSnapshot(); - } catch (e) { - throw e; - } finally { - if (!options.dryRun) { - if (clean) { - this.cdk.destroy({ - ...this.defaultArgs, - stacks: options.testCase.stacks, - force: true, - app: this.cdkApp, - output: this.cdkOutDir, - }); - } - } - this.cleanup(); - } - } - - /** - * Generate a snapshot if one does not exist - * This will synth and then load the integration test manifest - */ - public generateSnapshot(): void { - if (this.hasSnapshot()) { - throw new Error(`${this.testName} already has a snapshot: ${this.snapshotDir}`); - } - - this.cdk.synth({ - ...this.defaultArgs, - all: true, - app: this.cdkApp, - output: this.cdkOutDir, - }); - this.loadManifest(this.cdkOutDir); - } -} - -/** - * Runner for snapshot tests. This handles orchestrating - * the validation of the integration test snapshots - */ -export class IntegSnapshotRunner extends IntegRunner { - constructor(options: IntegRunnerOptions) { - super(options); - } - - /** - * Synth the integration tests and compare the templates - * to the existing snapshot. - */ - public testSnapshot(): Diagnostic[] { - try { - // read the existing snapshot - const expectedStacks = this.readAssembly(this.snapshotDir); - - // if lookups are enabled then write the dummy context file - if (this.enableLookups) { - this.writeContext(); - } - // synth the integration test - this.cdk.synth({ - ...this.defaultArgs, - all: true, - app: this.cdkApp, - output: this.cdkOutDir, - lookups: this.enableLookups, - }); - const actualStacks = this.readAssembly(path.join(this.directory, this.cdkOutDir)); - - // diff the existing snapshot (expected) with the integration test (actual) - const diagnostics = this.diffAssembly(expectedStacks, actualStacks); - return diagnostics; - } catch (e) { - throw e; - } finally { - this.cleanupContextFile(); - this.cleanup(); - } - } - - private diffAssembly(existing: Record, actual: Record): Diagnostic[] { - const verifyHashes = this.pragmas().includes(VERIFY_ASSET_HASHES); - const failures: Diagnostic[] = []; - for (const templateId of Object.keys(existing)) { - if (!actual.hasOwnProperty(templateId)) { - failures.push({ - testName: this.testName, - reason: DiagnosticReason.SNAPSHOT_FAILED, - message: `${templateId} exists in snapshot, but not in actual`, - }); - } - } - - for (const templateId of Object.keys(actual)) { - if (!existing.hasOwnProperty(templateId)) { - failures.push({ - testName: this.testName, - reason: DiagnosticReason.SNAPSHOT_FAILED, - message: `${templateId} does not exist in snapshot, but does in actual`, - }); - } else { - let actualTemplate = actual[templateId]; - let expectedTemplate = existing[templateId]; - - if (!verifyHashes) { - actualTemplate = canonicalizeTemplate(actualTemplate); - expectedTemplate = canonicalizeTemplate(expectedTemplate); - } - const diff = diffTemplate(expectedTemplate, actualTemplate); - if (!diff.isEmpty) { - const writable = new StringWritable({}); - formatDifferences(writable, diff); - failures.push({ - reason: DiagnosticReason.SNAPSHOT_FAILED, - message: writable.data, - testName: this.testName, - }); - } - } - } - - return failures; - } - - private readAssembly(dir: string): Record { - const assembly = AssemblyManifestReader.fromPath(dir); - const stacks = assembly.stacks; - - return stacks; - } -} - -class StringWritable extends Writable { - public data: string; - private _decoder: NodeStringDecoder; - constructor(options: WritableOptions) { - super(options); - this._decoder = new StringDecoder(); - this.data = ''; - } - - _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void { - if (encoding === 'buffer') { - chunk = this._decoder.write(chunk); - } - - this.data += chunk; - callback(); - } - - _final(callback: (error?: Error | null) => void): void { - this.data += this._decoder.end(); - callback(); - } -} - -// Default context we run all integ tests with, so they don't depend on the -// account of the exercising user. -const DEFAULT_SYNTH_OPTIONS = { - context: { - [AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY]: ['test-region-1a', 'test-region-1b', 'test-region-1c'], - 'availability-zones:account=12345678:region=test-region': ['test-region-1a', 'test-region-1b', 'test-region-1c'], - 'ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2:region=test-region': 'ami-1234', - 'ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2:region=test-region': 'ami-1234', - 'ssm:account=12345678:parameterName=/aws/service/ecs/optimized-ami/amazon-linux/recommended:region=test-region': '{"image_id": "ami-1234"}', - // eslint-disable-next-line max-len - 'ami:account=12345678:filters.image-type.0=machine:filters.name.0=amzn-ami-vpc-nat-*:filters.state.0=available:owners.0=amazon:region=test-region': 'ami-1234', - 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': { - vpcId: 'vpc-60900905', - subnetGroups: [ - { - type: 'Public', - name: 'Public', - subnets: [ - { - subnetId: 'subnet-e19455ca', - availabilityZone: 'us-east-1a', - routeTableId: 'rtb-e19455ca', - }, - { - subnetId: 'subnet-e0c24797', - availabilityZone: 'us-east-1b', - routeTableId: 'rtb-e0c24797', - }, - { - subnetId: 'subnet-ccd77395', - availabilityZone: 'us-east-1c', - routeTableId: 'rtb-ccd77395', - }, - ], - }, - ], - }, - // Enable feature flags for all integ tests - ...FUTURE_FLAGS, - - // Restricting to these target partitions makes most service principals synthesize to - // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` - // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what - // most existing integ tests contain, and we want to disturb as few as possible. - [TARGET_PARTITIONS]: ['aws', 'aws-cn'], - }, - env: { - CDK_INTEG_ACCOUNT: '12345678', - CDK_INTEG_REGION: 'test-region', - }, -}; diff --git a/packages/@aws-cdk/integ-runner/lib/workers/common.ts b/packages/@aws-cdk/integ-runner/lib/workers/common.ts deleted file mode 100644 index db196cc809937..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/workers/common.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { IntegTestConfig } from '../runner/integ-tests'; -import * as logger from '../runner/private/logger'; - -/** - * Integration test results - */ -export interface IntegBatchResponse { - failedTests: IntegTestConfig[]; -} - -/** - * Common options for running integration tests - */ -export interface IntegTestOptions { - /** - * A list of integration tests to run - * in this batch - */ - readonly tests: IntegTestConfig[]; - - /** - * Whether or not to destroy the stacks at the - * end of the test - * - * @default true - */ - readonly clean?: boolean; - - /** - * When this is set to `true` the snapshot will - * be created _without_ running the integration test - * The resulting snapshot SHOULD NOT be checked in - * - * @default false - */ - readonly dryRun?: boolean; - - /** - * Whether to enable verbose logging - * - * @default false - */ - readonly verbose?: boolean; -} - -/** - * Represents possible reasons for a diagnostic - */ -export enum DiagnosticReason { - /** - * The integration test failed because there - * is not existing snapshot - */ - NO_SNAPSHOT = 'NO_SNAPSHOT', - - /** - * The integration test failed - */ - TEST_FAILED = 'TEST_FAILED', - - /** - * The snapshot test failed because the actual - * snapshot was different than the expected snapshot - */ - SNAPSHOT_FAILED = 'SNAPSHOT_FAILED', - - /** - * The snapshot test succeeded - */ - SNAPSHOT_SUCCESS = 'SNAPSHOT_SUCCESS', - - /** - * The integration test succeeded - */ - TEST_SUCCESS = 'TEST_SUCCESS', -} - -/** - * Integration test diagnostics - * This is used to report back the status of each test - */ -export interface Diagnostic { - /** - * The name of the test - */ - readonly testName: string; - - /** - * The diagnostic message - */ - readonly message: string; - - /** - * The reason for the diagnostic - */ - readonly reason: DiagnosticReason; -} - -/** - * Print out the results from tests - */ -export function printResults(diagnostic: Diagnostic): void { - switch (diagnostic.reason) { - case DiagnosticReason.SNAPSHOT_SUCCESS: - logger.success(' %s No Change!', diagnostic.testName); - break; - case DiagnosticReason.TEST_SUCCESS: - logger.success(' %s Test Succeeded!', diagnostic.testName); - break; - case DiagnosticReason.NO_SNAPSHOT: - logger.error(' %s - No Snapshot!', diagnostic.testName); - break; - case DiagnosticReason.SNAPSHOT_FAILED: - logger.error(' %s - Snapshot changed!\n%s', diagnostic.testName, diagnostic.message); - break; - case DiagnosticReason.TEST_FAILED: - logger.error(' %s - Failed!\n%s', diagnostic.testName, diagnostic.message); - } -} diff --git a/packages/@aws-cdk/integ-runner/lib/workers/extract_worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/extract_worker.ts deleted file mode 100644 index 42b0e63b1f9af..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/workers/extract_worker.ts +++ /dev/null @@ -1,35 +0,0 @@ -import * as workerpool from 'workerpool'; -import { IntegTestConfig } from '../runner/integ-tests'; -import { Diagnostic, IntegBatchResponse } from './common'; -import { singleThreadedSnapshotRunner } from './integ-snapshot-worker'; -import { singleThreadedTestRunner, IntegTestBatchRequest } from './integ-test-worker'; - -/** - * Options for running snapshot tests - */ -export interface SnapshotBatchRequest { - readonly tests: IntegTestConfig[]; -} - -/** - * Snapshot test results - */ -export interface SnapshotBatchResponse { - diagnostics: Diagnostic[]; - failedTests: IntegTestConfig[]; -} - -function integTestBatch(request: IntegTestBatchRequest): IntegBatchResponse { - const result = singleThreadedTestRunner(request); - return result; -} - -function snapshotTestBatch(request: SnapshotBatchRequest): IntegBatchResponse { - const result = singleThreadedSnapshotRunner(request.tests); - return result; -} - -workerpool.worker({ - snapshotTestBatch, - integTestBatch, -}); diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts deleted file mode 100644 index f92efe543746a..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as workerpool from 'workerpool'; -import { IntegTestConfig } from '../runner/integ-tests'; -import { IntegSnapshotRunner } from '../runner/runners'; -import { DiagnosticReason, IntegBatchResponse } from './common'; - -/** - * Runs a single snapshot test batch request. - * For each integration test this will check to see - * if there is an existing snapshot, and if there is will - * check if there are any changes - */ -export function singleThreadedSnapshotRunner(tests: IntegTestConfig[]): IntegBatchResponse { - const failedTests = new Array(); - for (const test of tests) { - const runner = new IntegSnapshotRunner({ fileName: test.fileName }); - try { - if (!runner.hasSnapshot()) { - workerpool.workerEmit({ - reason: DiagnosticReason.NO_SNAPSHOT, - testName: runner.testName, - message: 'No Snapshot', - }); - failedTests.push(test); - } else { - const snapshotDiagnostics = runner.testSnapshot(); - if (snapshotDiagnostics.length > 0) { - snapshotDiagnostics.forEach(diagnostic => workerpool.workerEmit(diagnostic)); - failedTests.push(test); - } else { - workerpool.workerEmit({ - reason: DiagnosticReason.SNAPSHOT_SUCCESS, - testName: runner.testName, - message: 'Success', - }); - } - } - } catch (e) { - failedTests.push(test); - workerpool.workerEmit({ - message: e.message, - testName: runner.testName, - reason: DiagnosticReason.SNAPSHOT_FAILED, - }); - } - } - - return { - failedTests, - }; -} - diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts deleted file mode 100644 index def9915d91c35..0000000000000 --- a/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts +++ /dev/null @@ -1,124 +0,0 @@ -import * as workerpool from 'workerpool'; -import { IntegTestConfig } from '../runner/integ-tests'; -import * as logger from '../runner/private/logger'; -import { IntegTestRunner } from '../runner/runners'; -import { printResults, IntegBatchResponse, IntegTestOptions, DiagnosticReason } from './common'; - -/** - * Options for an integration test batch - */ -export interface IntegTestBatchRequest extends IntegTestOptions { - /** - * The AWS region to run this batch in - */ - readonly region: string; -} - -/** - * Options for running all integration tests - */ -export interface IntegTestRunOptions extends IntegTestOptions { - /** - * The regions to run the integration tests across. - * This allows the runner to run integration tests in parallel - */ - readonly regions: string[]; - - /** - * The workerpool to use - */ - readonly pool: workerpool.WorkerPool; -} - - -/** - * Runs a set of integration tests in parallel across a list of AWS regions. - * Only a single test can be run at a time in a given region. Once a region - * is done running a test, the next test will be pulled from the queue - */ -export async function runIntegrationTestsInParallel( - options: IntegTestRunOptions, -): Promise { - - const queue = options.tests; - const results: IntegBatchResponse[] = []; - - async function runTest(region: string): Promise { - do { - const test = queue.pop(); - if (!test) break; - logger.highlight(`Running test ${test.fileName} in ${region}`); - const response: IntegBatchResponse = await options.pool.exec('integTestBatch', [{ - region, - tests: [test], - clean: options.clean, - dryRun: options.dryRun, - verbose: options.verbose, - }], { - on: printResults, - }); - - results.push(response); - } while (queue.length > 0); - } - - const workers = options.regions.map((region) => runTest(region)); - await Promise.all(workers); - return results; -} - -/** - * Runs a single integration test batch request. - * If the test does not have an existing snapshot, - * this will first generate a snapshot and then execute - * the integration tests. - * - * If the tests succeed it will then save the snapshot - */ -export function singleThreadedTestRunner(request: IntegTestBatchRequest): IntegBatchResponse { - const failures: IntegTestConfig[] = []; - for (const test of request.tests) { - const runner = new IntegTestRunner({ - fileName: test.fileName, - env: { - AWS_REGION: request.region, - }, - }); - try { - if (!runner.hasSnapshot()) { - runner.generateSnapshot(); - } - - if (!runner.tests) { - throw new Error(`No tests defined for ${runner.testName}`); - } - for (const [testName, testCase] of Object.entries(runner.tests)) { - try { - runner.runIntegTestCase({ - testCase: testCase, - clean: request.clean, - dryRun: request.dryRun, - }); - workerpool.workerEmit({ - reason: DiagnosticReason.TEST_SUCCESS, - testName: testName, - message: 'Success', - }); - } catch (e) { - failures.push(test); - workerpool.workerEmit({ - reason: DiagnosticReason.TEST_FAILED, - testName: testName, - message: `Integration test failed: ${e}`, - }); - } - } - } catch (e) { - logger.error(`Errors running test cases: ${e}`); - } - } - - return { - failedTests: failures, - }; -} diff --git a/packages/@aws-cdk/integ-runner/package.json b/packages/@aws-cdk/integ-runner/package.json deleted file mode 100644 index 20fae96cdfbb6..0000000000000 --- a/packages/@aws-cdk/integ-runner/package.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "name": "@aws-cdk/integ-runner", - "description": "CDK Integration Testing Tool", - "version": "0.0.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "bin": { - "integ-runner": "bin/integ-runner" - }, - "scripts": { - "build": "cdk-build", - "lint": "cdk-lint", - "package": "cdk-package", - "awslint": "cdk-awslint", - "pkglint": "pkglint -f", - "test": "cdk-test", - "watch": "cdk-watch", - "build+test": "yarn build && yarn test", - "build+test+package": "yarn build+test && yarn package", - "compat": "cdk-compat", - "build+extract": "yarn build", - "build+test+extract": "yarn build+test" - }, - "author": { - "name": "Amazon Web Services", - "url": "https://aws.amazon.com", - "organization": true - }, - "license": "Apache-2.0", - "devDependencies": { - "@aws-cdk/cdk-build-tools": "0.0.0", - "@aws-cdk/pkglint": "0.0.0", - "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.4.1", - "@types/node": "^10.17.60", - "@types/workerpool": "^6.1.0", - "@types/yargs": "^15.0.14", - "jest": "^27.5.1" - }, - "dependencies": { - "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/cloudformation-diff": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", - "aws-cdk": "0.0.0", - "cdk-cli-wrapper": "0.0.0", - "chalk": "^4", - "fs-extra": "^9.1.0", - "workerpool": "^6.2.0", - "yargs": "^16.2.0" - }, - "repository": { - "url": "https://github.com/aws/aws-cdk.git", - "type": "git", - "directory": "packages/@aws-cdk/integ-runner" - }, - "keywords": [ - "aws", - "cdk" - ], - "homepage": "https://github.com/aws/aws-cdk", - "engines": { - "node": ">= 14.15.0" - }, - "cdk-package": { - "shrinkWrap": true - }, - "nozem": { - "ostools": [ - "unzip", - "diff", - "rm" - ] - }, - "stability": "experimental", - "maturity": "experimental", - "publishConfig": { - "tag": "latest" - }, - "private": true -} diff --git a/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts b/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts deleted file mode 100644 index 878f5bf5d2489..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as path from 'path'; -import { IntegrationTests } from '../../lib/runner/integ-tests'; - -const directory = path.join(__dirname, '../test-data'); - -describe('IntegrationTests', () => { - test('from cli args', async () => { - const tests = new IntegrationTests(directory); - - const integTests = await tests.fromCliArgs(['integ.integ-test1.js']); - - expect(integTests.length).toEqual(1); - expect(integTests[0].fileName).toEqual(expect.stringMatching(/integ.integ-test1.js$/)); - }); -}); diff --git a/packages/@aws-cdk/integ-runner/test/runner/runners.test.ts b/packages/@aws-cdk/integ-runner/test/runner/runners.test.ts deleted file mode 100644 index 8894f5ba92843..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/runner/runners.test.ts +++ /dev/null @@ -1,324 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { IntegTestRunner, IntegSnapshotRunner } from '../../lib/runner/runners'; -import { DiagnosticReason } from '../../lib/workers/common'; - -describe('IntegTest runSnapshotTests', () => { - let synthMock: jest.SpyInstance; - beforeEach(() => { - jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); - jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); - }); - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - }); - test('with defaults no diff', () => { - // WHEN - const integTest = new IntegSnapshotRunner({ - fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot.js'), - integOutDir: 'test-with-snapshot.integ.snapshot', - }); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - integTest.testSnapshot(); - - // THEN - expect(synthMock).toHaveBeenCalledTimes(1); - expect(synthMock.mock.calls[0][0]).toEqual({ - all: true, - app: 'node integ.test-with-snapshot.js', - output: 'test-with-snapshot.integ.snapshot', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - lookups: false, - }); - }); - - test('with defaults and diff', () => { - // WHEN - const integTest = new IntegSnapshotRunner({ - fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot.js'), - integOutDir: 'test-with-snapshot-diff.integ.snapshot', - }); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - const diagnostics = integTest.testSnapshot(); - - // THEN - expect(synthMock).toHaveBeenCalledTimes(1); - expect(synthMock.mock.calls[0][0]).toEqual({ - all: true, - app: 'node integ.test-with-snapshot.js', - output: 'test-with-snapshot-diff.integ.snapshot', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - lookups: false, - }); - expect(diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ - reason: DiagnosticReason.SNAPSHOT_FAILED, - testName: integTest.testName, - message: expect.stringContaining('foobar'), - })])); - }); - - test('dont diff asset hashes', () => { - // WHEN - const integTest = new IntegSnapshotRunner({ - fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot-assets-diff.js'), - integOutDir: 'test-with-snapshot-assets.integ.snapshot', - }); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - expect(() => { - integTest.testSnapshot(); - }).not.toThrow(); - - // THEN - expect(synthMock).toHaveBeenCalledTimes(1); - expect(synthMock.mock.calls[0][0]).toEqual({ - all: true, - app: 'node integ.test-with-snapshot-assets-diff.js', - output: 'test-with-snapshot-assets.integ.snapshot', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - lookups: true, - }); - }); - - test('diff asset hashes', () => { - // WHEN - const integTest = new IntegSnapshotRunner({ - fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot-assets.js'), - integOutDir: 'test-with-snapshot-assets-diff.integ.snapshot', - }); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - const diagnostics = integTest.testSnapshot(); - - // THEN - expect(synthMock).toHaveBeenCalledTimes(1); - expect(synthMock.mock.calls[0][0]).toEqual({ - all: true, - app: 'node integ.test-with-snapshot-assets.js', - output: 'test-with-snapshot-assets-diff.integ.snapshot', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - lookups: false, - }); - expect(diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ - reason: DiagnosticReason.SNAPSHOT_FAILED, - testName: integTest.testName, - message: expect.stringContaining('Parameters'), - })])); - }); -}); - -describe('IntegTest runIntegTests', () => { - let integTest: IntegTestRunner; - let deployMock: jest.SpyInstance; - let destroyMock: jest.SpyInstance; - let synthMock: jest.SpyInstance; - let listMock: jest.SpyInstance; - // let stderrMock: jest.SpyInstance; - beforeEach(() => { - integTest = new IntegTestRunner({ fileName: path.join(__dirname, '../test-data/integ.integ-test1.js') }); - deployMock = jest.spyOn(integTest.cdk, 'deploy').mockImplementation(); - destroyMock = jest.spyOn(integTest.cdk, 'destroy').mockImplementation(); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - listMock = jest.spyOn(integTest.cdk, 'list').mockImplementation(); - jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); - }); - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - }); - test('with defaults', () => { - // WHEN - integTest.runIntegTestCase({ - testCase: { - stacks: ['stack1'], - }, - }); - - // THEN - expect(deployMock).toHaveBeenCalledTimes(1); - expect(destroyMock).toHaveBeenCalledTimes(1); - expect(synthMock).toHaveBeenCalledTimes(0); - expect(deployMock.mock.calls[0][0]).toEqual({ - app: 'node integ.integ-test1.js', - requireApproval: 'never', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - lookups: false, - stacks: ['stack1'], - output: 'cdk-integ.out.integ-test1', - }); - expect(destroyMock.mock.calls[0][0]).toEqual({ - app: 'node integ.integ-test1.js', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - force: true, - stacks: ['stack1'], - output: 'cdk-integ.out.integ-test1', - }); - }); - - test('with lookups', () => { - // WHEN - integTest = new IntegTestRunner({ fileName: path.join(__dirname, '../test-data/integ.test-with-snapshot-assets-diff.js') }); - deployMock = jest.spyOn(integTest.cdk, 'deploy').mockImplementation(); - destroyMock = jest.spyOn(integTest.cdk, 'destroy').mockImplementation(); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - listMock = jest.spyOn(integTest.cdk, 'list').mockImplementation(); - integTest.runIntegTestCase({ - testCase: { - stacks: ['test-stack'], - }, - }); - - // THEN - expect(deployMock).toHaveBeenCalledTimes(1); - expect(destroyMock).toHaveBeenCalledTimes(1); - expect(synthMock).toHaveBeenCalledTimes(1); - expect(deployMock.mock.calls[0][0]).toEqual({ - app: 'node integ.test-with-snapshot-assets-diff.js', - requireApproval: 'never', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - lookups: true, - stacks: ['test-stack'], - output: 'cdk-integ.out.test-with-snapshot-assets-diff', - }); - expect(synthMock.mock.calls[0][0]).toEqual({ - app: 'node integ.test-with-snapshot-assets-diff.js', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - all: true, - output: 'test-with-snapshot-assets-diff.integ.snapshot', - }); - expect(destroyMock.mock.calls[0][0]).toEqual({ - app: 'node integ.test-with-snapshot-assets-diff.js', - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - force: true, - stacks: ['test-stack'], - output: 'cdk-integ.out.test-with-snapshot-assets-diff', - }); - }); - - test('no clean', () => { - // WHEN - integTest.runIntegTestCase({ - clean: false, - testCase: { - stacks: ['stack1'], - }, - }); - - // THEN - expect(deployMock).toHaveBeenCalledTimes(1); - expect(destroyMock).toHaveBeenCalledTimes(0); - expect(synthMock).toHaveBeenCalledTimes(0); - }); - - test('dryrun', () => { - // WHEN - integTest.runIntegTestCase({ - dryRun: true, - testCase: { - stacks: ['stack1'], - }, - }); - - // THEN - expect(deployMock).toHaveBeenCalledTimes(0); - expect(destroyMock).toHaveBeenCalledTimes(0); - expect(synthMock).toHaveBeenCalledTimes(1); - }); - - test('determine test stack via pragma', () => { - // WHEN - integTest.generateSnapshot(); - - // THEN - expect(integTest.tests).toEqual(expect.objectContaining({ - 'integ-test1': { - stacks: ['stack1'], - }, - })); - expect(listMock).toHaveBeenCalledTimes(0); - }); - - test('generate snapshot', () => { - // WHEN - integTest.generateSnapshot(); - - // THEN - expect(synthMock).toHaveBeenCalledTimes(1); - expect(synthMock.mock.calls[0][0]).toEqual({ - all: true, - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - app: 'node integ.integ-test1.js', - output: 'cdk-integ.out.integ-test1', - }); - }); -}); - -describe('IntegTest no pragma', () => { - let integTest: IntegTestRunner; - let synthMock: jest.SpyInstance; - beforeEach(() => { - integTest = new IntegTestRunner({ fileName: path.join(__dirname, '../test-data/integ.integ-test2.js') }); - jest.spyOn(integTest.cdk, 'deploy').mockImplementation(); - jest.spyOn(integTest.cdk, 'destroy').mockImplementation(); - synthMock = jest.spyOn(integTest.cdk, 'synth').mockImplementation(); - jest.spyOn(integTest.cdk, 'list').mockImplementation(() => { - return 'stackabc'; - }); - jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); - }); - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - }); - test('get stacks from list', async () => { - // WHEN - integTest.generateSnapshot(); - - // THEN - expect(integTest.tests).toEqual(expect.objectContaining({ - 'integ-test2': { - stacks: ['stackabc'], - }, - })); - expect(synthMock).toHaveBeenCalledTimes(1); - expect(synthMock.mock.calls[0][0]).toEqual({ - app: 'node integ.integ-test2.js', - all: true, - pathMetadata: false, - assetMetadata: false, - versionReporting: false, - output: 'cdk-integ.out.integ-test2', - }); - }); -}); diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/test-stack.template.json deleted file mode 100644 index 40f4c8238c04f..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/test-stack.template.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foo" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets-diff/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/test-stack.template.json deleted file mode 100644 index 40f4c8238c04f..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/test-stack.template.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foo" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot-assets/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/test-stack.template.json deleted file mode 100644 index 40f4c8238c04f..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/test-stack.template.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foo" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.test-with-snapshot/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test1.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test1.ts deleted file mode 100644 index 26679b49d93bc..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test1.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// !cdk-integ stack1 pragma:ignore-assets -/// !cdk-integ pragma:ignore-assets diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test2.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test2.ts deleted file mode 100644 index bb0eb24f2756d..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/integ.integ-test2.ts +++ /dev/null @@ -1 +0,0 @@ -/// !cdk-integ pragma:enable-lookups diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets-diff.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets-diff.ts deleted file mode 100644 index bcdc92fbcdcf2..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets-diff.ts +++ /dev/null @@ -1 +0,0 @@ -/// !cdk-integ test-stack pragma:enable-lookups diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets.ts deleted file mode 100644 index ff230f9f7e58e..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot-assets.ts +++ /dev/null @@ -1 +0,0 @@ -/// !cdk-integ test-stack pragma:include-assets-hashes diff --git a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot.ts b/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot.ts deleted file mode 100644 index c3548a8acffcc..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/integ.test-with-snapshot.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// !cdk-integ test-stack pragma:ignore-assets -/// !cdk-integ pragma:ignore-assets diff --git a/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.ts b/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.ts deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/test-stack.template.json deleted file mode 100644 index 969780cdf33e5..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/test-stack.template.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foo" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - }, - "Parameters": { - "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { - "Type": "String", - "Description": "S3 bucket for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" - }, - "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { - "Type": "String", - "Description": "S3 key for asset version \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" - }, - "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { - "Type": "String", - "Description": "Artifact hash for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets-diff.integ.snapshot/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/test-stack.template.json deleted file mode 100644 index ed2a09b94be23..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/test-stack.template.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foo" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - }, - "Parameters": { - "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { - "Type": "String", - "Description": "S3 bucket for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" - }, - "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { - "Type": "String", - "Description": "S3 key for asset version \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" - }, - "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { - "Type": "String", - "Description": "Artifact hash for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-assets.integ.snapshot/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/test-stack.template.json deleted file mode 100644 index 3d62830b46139..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/test-stack.template.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foobar" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot-diff.integ.snapshot/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/cdk.out deleted file mode 100644 index 2efc89439fab8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/manifest.json deleted file mode 100644 index c0da3afe14484..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/manifest.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "version": "17.0.0", - "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "test-stack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "test-stack.template.json", - "validateOnSynth": false - }, - "metadata": { - "/test-stack/MyFunction1/ServiceRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction1ServiceRole9852B06B", - "trace": [ - "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ], - "/test-stack/MyFunction1/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyFunction12A744C2E", - "trace": [ - "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", - "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", - "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", - "Module._compile (node:internal/modules/cjs/loader:1103:14)", - "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", - "Module.load (node:internal/modules/cjs/loader:981:32)", - "Function.Module._load (node:internal/modules/cjs/loader:822:12)", - "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", - "node:internal/main/run_main_module:17:47" - ] - } - ] - }, - "displayName": "test-stack" - } - } -} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/test-stack.template.json deleted file mode 100644 index 40f4c8238c04f..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/test-stack.template.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Resources": { - "MyFunction1ServiceRole9852B06B": { - "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" - ] - ] - } - ] - } - }, - "MyFunction12A744C2E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "foo" - }, - "Role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs14.x" - }, - "DependsOn": [ - "MyFunction1ServiceRole9852B06B" - ] - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/tree.json deleted file mode 100644 index b664bec74b37c..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/test-data/test-with-snapshot.integ.snapshot/tree.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "@aws-cdk/core.Construct", - "version": "0.0.0" - } - }, - "test-stack": { - "id": "test-stack", - "path": "test-stack", - "children": { - "MyFunction1": { - "id": "MyFunction1", - "path": "test-stack/MyFunction1", - "children": { - "ServiceRole": { - "id": "ServiceRole", - "path": "test-stack/MyFunction1/ServiceRole", - "children": { - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/ServiceRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "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" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "test-stack/MyFunction1/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Lambda::Function", - "aws:cdk:cloudformation:props": { - "code": { - "zipFile": "foo" - }, - "role": { - "Fn::GetAtt": [ - "MyFunction1ServiceRole9852B06B", - "Arn" - ] - }, - "handler": "index.handler", - "runtime": "nodejs14.x" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts b/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts deleted file mode 100644 index 7479d229302b8..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as workerpool from 'workerpool'; -import { IntegBatchResponse } from '../../lib/workers/common'; -import { IntegTestBatchRequest } from '../../lib/workers/integ-test-worker'; - - -function integTestBatch(request: IntegTestBatchRequest): IntegBatchResponse { - return { - failedTests: request.tests, - }; -} - -workerpool.worker({ - integTestBatch, -}); - diff --git a/packages/@aws-cdk/integ-runner/test/workers/workers.test.ts b/packages/@aws-cdk/integ-runner/test/workers/workers.test.ts deleted file mode 100644 index cc0be1ec8a9b0..0000000000000 --- a/packages/@aws-cdk/integ-runner/test/workers/workers.test.ts +++ /dev/null @@ -1,266 +0,0 @@ -import * as child_process from 'child_process'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as workerpool from 'workerpool'; -import { singleThreadedSnapshotRunner } from '../../lib/workers/integ-snapshot-worker'; -import { singleThreadedTestRunner, runIntegrationTestsInParallel } from '../../lib/workers/integ-test-worker'; - -const directory = path.join(__dirname, '../test-data'); -describe('Snapshot tests', () => { - beforeEach(() => { - jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); - jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); - }); - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - }); - test('no snapshot', () => { - // WHEN - const test = { - fileName: path.join(directory, 'integ.integ-test1.js'), - directory: directory, - }; - const result = singleThreadedSnapshotRunner([test]); - - // THEN - expect(result.failedTests.length).toEqual(1); - expect(result.failedTests[0]).toEqual(test); - }); - - test('has snapshot', () => { - // WHEN - jest.spyOn(child_process, 'spawnSync').mockResolvedValue; - const test = { - fileName: path.join(directory, 'integ.test-with-snapshot.js'), - directory: directory, - }; - const result = singleThreadedSnapshotRunner([test]); - - // THEN - expect(result.failedTests.length).toEqual(0); - }); - - test('failed snapshot', () => { - // WHEN - jest.spyOn(child_process, 'spawnSync').mockRejectedValue; - const test = { - fileName: path.join(directory, 'integ.test-with-snapshot-assets.js'), - directory: directory, - }; - const result = singleThreadedSnapshotRunner([test]); - - // THEN - expect(result.failedTests.length).toEqual(1); - expect(result.failedTests[0]).toEqual(test); - }); -}); - -describe('test runner', () => { - beforeEach(() => { - jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); - jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); - }); - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - }); - - test('no snapshot', () => { - // WHEN - const test = { - fileName: path.join(directory, 'integ.integ-test1.js'), - directory: directory, - }; - const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockImplementation(); - singleThreadedTestRunner({ - tests: [test], - region: 'us-east-1', - }); - - expect(spawnSyncMock).toHaveBeenCalledWith( - expect.stringMatching(/cdk/), - ['synth', '--app', 'node integ.integ-test1.js', '--no-version-reporting', '--no-path-metadata', '--no-asset-metadata', '--output', 'cdk-integ.out.integ-test1', '--all'], - expect.anything(), - ); - }); -}); - -describe('parallel worker', () => { - let pool: workerpool.WorkerPool; - let stderrMock: jest.SpyInstance; - beforeEach(() => { - pool = workerpool.pool(path.join(__dirname, './mock-extract_worker.js')); - stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); - jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'moveSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'removeSync').mockImplementation(() => { return true; }); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { return true; }); - }); - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - void pool.terminate(); - }); - test('run tests', async () => { - const tests = [{ - fileName: 'integ.test-with-snapshot.js', - directory, - }]; - const results = await runIntegrationTestsInParallel({ - tests, - pool, - regions: ['us-east-1'], - }); - - expect(stderrMock.mock.calls[0][0]).toContain( - 'Running test integ.test-with-snapshot.js in us-east-1', - ); - expect(results).toEqual([ - { - failedTests: [{ - fileName: 'integ.test-with-snapshot.js', - directory, - }], - }, - ]); - }); - - test('run multiple tests', async () => { - const tests = [ - { - fileName: 'integ.test-with-snapshot.js', - directory, - }, - { - fileName: 'integ.another-test-with-snapshot.js', - directory, - }, - ]; - const results = await runIntegrationTestsInParallel({ - tests, - pool, - regions: ['us-east-1', 'us-east-2'], - }); - - expect(stderrMock.mock.calls[1][0]).toContain( - 'Running test integ.test-with-snapshot.js in us-east-2', - ); - expect(stderrMock.mock.calls[0][0]).toContain( - 'Running test integ.another-test-with-snapshot.js in us-east-1', - ); - expect(results).toEqual(expect.arrayContaining([ - { - failedTests: [ - { - fileName: 'integ.test-with-snapshot.js', - directory, - }, - ], - }, - { - failedTests: [ - { - fileName: 'integ.another-test-with-snapshot.js', - directory, - }, - ], - }, - ])); - }); - - test('more tests than regions', async () => { - const tests = [ - { - fileName: 'integ.test-with-snapshot.js', - directory, - }, - { - fileName: 'integ.another-test-with-snapshot.js', - directory, - }, - ]; - const results = await runIntegrationTestsInParallel({ - tests, - pool, - regions: ['us-east-1'], - }); - - expect(stderrMock.mock.calls[1][0]).toContain( - 'Running test integ.test-with-snapshot.js in us-east-1', - ); - expect(stderrMock.mock.calls[0][0]).toContain( - 'Running test integ.another-test-with-snapshot.js in us-east-1', - ); - expect(results).toEqual([ - { - failedTests: [ - { - fileName: 'integ.another-test-with-snapshot.js', - directory, - }, - ], - }, - { - failedTests: [ - { - fileName: 'integ.test-with-snapshot.js', - directory, - }, - ], - }, - ]); - }); - - test('more regions than tests', async () => { - const tests = [ - { - fileName: 'integ.test-with-snapshot.js', - directory, - }, - { - fileName: 'integ.another-test-with-snapshot.js', - directory, - }, - ]; - const results = await runIntegrationTestsInParallel({ - tests, - pool, - regions: ['us-east-1', 'us-east-2', 'us-west-2'], - }); - - expect(stderrMock.mock.calls[1][0]).toContain( - 'Running test integ.test-with-snapshot.js in us-east-2', - ); - expect(stderrMock.mock.calls[0][0]).toContain( - 'Running test integ.another-test-with-snapshot.js in us-east-1', - ); - expect(results).toEqual(expect.arrayContaining([ - { - failedTests: [ - { - fileName: 'integ.another-test-with-snapshot.js', - directory, - }, - ], - }, - { - failedTests: [ - { - fileName: 'integ.test-with-snapshot.js', - directory, - }, - ], - }, - ])); - }); -}); diff --git a/packages/@aws-cdk/integ-runner/tsconfig.json b/packages/@aws-cdk/integ-runner/tsconfig.json deleted file mode 100644 index 04e0404f04442..0000000000000 --- a/packages/@aws-cdk/integ-runner/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2018", - "module": "commonjs", - "lib": ["es2018", "dom"], - "strict": true, - "alwaysStrict": true, - "declaration": true, - "inlineSourceMap": true, - "inlineSources": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "resolveJsonModule": true, - "composite": true, - "incremental": true - }, - "include": [ - "**/*.ts", - "**/*.d.ts", - "lib/init-templates/*/*/add-project.hook.ts" - ], - "exclude": [ - "lib/init-templates/*/typescript/**/*.ts" - ] -} - diff --git a/packages/cdk-cli-wrapper/lib/cdk-wrapper.ts b/packages/cdk-cli-wrapper/lib/cdk-wrapper.ts index bfcd4983f776d..80bc2f407555a 100644 --- a/packages/cdk-cli-wrapper/lib/cdk-wrapper.ts +++ b/packages/cdk-cli-wrapper/lib/cdk-wrapper.ts @@ -110,16 +110,11 @@ export class CdkCliWrapper implements ICdk { } } - private validateArgs(options: DefaultCdkOptions): void { - if (!options.stacks && !options.all) { - throw new Error('one of "app" or "stacks" must be provided'); - } - } - public list(options: ListOptions): string { const listCommandArgs: string[] = [ - ...renderBooleanArg('long', options.long), ...this.createDefaultArguments(options), + ...renderBooleanArg('long', options.long), + ...options.stacks, ]; return exec([this.cdk, 'ls', ...listCommandArgs], { @@ -133,6 +128,7 @@ export class CdkCliWrapper implements ICdk { */ public deploy(options: DeployOptions): void { const deployCommandArgs: string[] = [ + ...this.createDefaultArguments(options), ...renderBooleanArg('ci', options.ci), ...renderBooleanArg('execute', options.execute), ...renderBooleanArg('exclusively', options.exclusively), @@ -147,7 +143,7 @@ export class CdkCliWrapper implements ICdk { ...options.requireApproval ? ['--require-approval', options.requireApproval] : [], ...options.changeSetName ? ['--change-set-name', options.changeSetName] : [], ...options.toolkitStackName ? ['--toolkit-stack-name', options.toolkitStackName] : [], - ...this.createDefaultArguments(options), + ...options.stacks, ]; exec([this.cdk, 'deploy', ...deployCommandArgs], { @@ -162,9 +158,10 @@ export class CdkCliWrapper implements ICdk { */ public destroy(options: DestroyOptions): void { const destroyCommandArgs: string[] = [ + ...this.createDefaultArguments(options), ...renderBooleanArg('force', options.force), ...renderBooleanArg('exclusively', options.exclusively), - ...this.createDefaultArguments(options), + ...options.stacks, ]; exec([this.cdk, 'destroy', ...destroyCommandArgs], { @@ -179,10 +176,11 @@ export class CdkCliWrapper implements ICdk { */ public synth(options: SynthOptions): void { const synthCommandArgs: string[] = [ + ...this.createDefaultArguments(options), ...renderBooleanArg('validation', options.validation), ...renderBooleanArg('quiet', options.quiet), ...renderBooleanArg('exclusively', options.exclusively), - ...this.createDefaultArguments(options), + ...options.stacks, ]; exec([this.cdk, 'synth', ...synthCommandArgs], { @@ -211,8 +209,6 @@ export class CdkCliWrapper implements ICdk { } private createDefaultArguments(options: DefaultCdkOptions): string[] { - this.validateArgs(options); - const stacks = options.stacks ?? []; return [ ...options.app ? ['--app', options.app] : [], ...renderBooleanArg('strict', options.strict), @@ -234,8 +230,6 @@ export class CdkCliWrapper implements ICdk { ...options.caBundlePath ? ['--ca-bundle-path', options.caBundlePath] : [], ...options.roleArn ? ['--role-arn', options.roleArn] : [], ...options.output ? ['--output', options.output] : [], - ...stacks, - ...options.all ? ['--all'] : [], ]; } } diff --git a/packages/cdk-cli-wrapper/lib/commands/common.ts b/packages/cdk-cli-wrapper/lib/commands/common.ts index 01ab969b63098..78e027cd922ca 100644 --- a/packages/cdk-cli-wrapper/lib/commands/common.ts +++ b/packages/cdk-cli-wrapper/lib/commands/common.ts @@ -24,21 +24,8 @@ export enum RequireApproval { export interface DefaultCdkOptions { /** * List of stacks to deploy - * - * Requried if `all` is not set - * - * @default - [] - */ - readonly stacks?: string[]; - - /** - * Deploy all stacks - * - * Requried if `stacks` is not set - * - * @default - false */ - readonly all?: boolean; + readonly stacks: string[]; /** * command-line for executing your app or a cloud assembly directory diff --git a/packages/cdk-cli-wrapper/test/cdk-wrapper.test.ts b/packages/cdk-cli-wrapper/test/cdk-wrapper.test.ts index 5cc294f3b5b7b..2f25054632cae 100644 --- a/packages/cdk-cli-wrapper/test/cdk-wrapper.test.ts +++ b/packages/cdk-cli-wrapper/test/cdk-wrapper.test.ts @@ -1,6 +1,6 @@ import * as child_process from 'child_process'; import { CdkCliWrapper } from '../lib/cdk-wrapper'; -import { RequireApproval } from '../lib/commands'; +import { RequireApproval } from '../lib/commands/common'; let spawnSyncMock: jest.SpyInstance; beforeEach(() => { @@ -89,6 +89,8 @@ test('deploy with all arguments', () => { expect.stringMatching(/aws-cdk\/bin\/cdk/), expect.arrayContaining([ 'deploy', + '--app', + 'node bin/my-app.js', '--no-strict', '--no-trace', '--no-lookups', @@ -120,8 +122,6 @@ test('deploy with all arguments', () => { '--change-set-name', 'my-change-set', '--toolkit-stack-name', 'Toolkit', '--previous-parameters', - '--app', - 'node bin/my-app.js', 'test-stack1', ]), expect.objectContaining({ @@ -182,10 +182,10 @@ test('can parse parameters', () => { expect.stringMatching(/aws-cdk\/bin\/cdk/), [ 'deploy', - '--parameters', 'myparam=test', - '--parameters', 'test-stack1:myotherparam=test', '--app', 'node bin/my-app.js', + '--parameters', 'myparam=test', + '--parameters', 'test-stack1:myotherparam=test', 'test-stack1', ], expect.objectContaining({ @@ -246,10 +246,10 @@ test('can parse array arguments', () => { expect.stringMatching(/aws-cdk\/bin\/cdk/), [ 'deploy', - '--notification-arns', 'arn:aws:us-east-1:1111111111:some:resource', - '--notification-arns', 'arn:aws:us-east-1:1111111111:some:other-resource', '--app', 'node bin/my-app.js', + '--notification-arns', 'arn:aws:us-east-1:1111111111:some:resource', + '--notification-arns', 'arn:aws:us-east-1:1111111111:some:other-resource', 'test-stack1', ], expect.objectContaining({ @@ -355,7 +355,7 @@ test('destroy arguments', () => { // THEN expect(spawnSyncMock).toHaveBeenCalledWith( expect.stringMatching(/aws-cdk\/bin\/cdk/), - ['destroy', '--force', '--no-exclusively', '--app', 'node bin/my-app.js', 'test-stack1'], + ['destroy', '--app', 'node bin/my-app.js', '--force', '--no-exclusively', 'test-stack1'], expect.objectContaining({ env: expect.objectContaining({ KEY: 'value', @@ -416,7 +416,7 @@ test('ls arguments', () => { // THEN expect(spawnSyncMock).toHaveBeenCalledWith( expect.stringMatching(/aws-cdk\/bin\/cdk/), - ['ls', '--long', '--app', 'node bin/my-app.js', '*'], + ['ls', '--app', 'node bin/my-app.js', '--long', '*'], expect.objectContaining({ env: expect.objectContaining({ KEY: 'value', diff --git a/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts b/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts index 83ca5563887e6..afc76b48bdefd 100644 --- a/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts +++ b/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts @@ -83,7 +83,6 @@ export async function unitTestFiles(): Promise { } export async function hasIntegTests(): Promise { - if (currentPackageJson().name === '@aws-cdk/integ-runner') return false; const files = await listFiles('test', f => f.filename.startsWith('integ.') && f.filename.endsWith('.js')); return files.length > 0; } diff --git a/yarn.lock b/yarn.lock index 134c222bf1113..23ea3b69ba3b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1994,13 +1994,6 @@ resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== -"@types/workerpool@^6.1.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@types/workerpool/-/workerpool-6.1.0.tgz#16c3b9d3c62a8f6e6ad2e4d6212a68130f0cd3b1" - integrity sha512-C+J/c1BHyc351xJuiH2Jbe+V9hjf5mCzRP0UK4KEpF5SpuU+vJ/FC5GLZsCU/PJpp/3I6Uwtfm3DG7Lmrb7LOQ== - dependencies: - "@types/node" "*" - "@types/wrap-ansi@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd"