From 1a15512f17257a763e620a4a26d63531082cef19 Mon Sep 17 00:00:00 2001 From: biffgaut <78155736+biffgaut@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:38:01 -0400 Subject: [PATCH] chore(all): reduce cognitive complexity, distribute prop checking code (#1016) * Finish emptying CheckProps() * Remove CheckProps * Typo * remove stray imports * Distribute and remove input-valdation.test.ts * Remove redundant comments * minor eslint format error --- .../aws-alb-fargate/lib/index.ts | 1 - .../aws-alb-lambda/lib/index.ts | 1 - .../aws-apigateway-dynamodb/lib/index.ts | 2 +- .../test/apigateway-dynamodb.test.ts | 33 +- .../aws-apigateway-iot/lib/index.ts | 1 - .../test/test.apigateway-iot.test.ts | 40 -- .../lib/index.ts | 2 +- .../test/apigateway-kinesisstreams.test.ts | 27 +- .../aws-apigateway-lambda/lib/index.ts | 1 - .../test/test.apigateway-lambda.test.ts | 15 - .../lib/index.ts | 2 +- .../test/apigateway-sagemakerendpoint.test.ts | 6 - .../aws-apigateway-sqs/lib/index.ts | 1 - .../lib/index.ts | 2 +- .../test.cloudfront-apigateway-lambda.test.ts | 31 +- .../aws-cloudfront-apigateway/lib/index.ts | 2 +- .../test/test.cloudfront-apigateway.test.ts | 10 +- .../aws-cloudfront-mediastore/lib/index.ts | 2 +- .../test/cloudfront-mediastore.test.ts | 27 +- .../aws-cloudfront-s3/lib/index.ts | 2 +- .../test/test.cloudfront-s3.test.ts | 35 +- .../lib/index.ts | 1 - .../lib/index.ts | 3 +- .../aws-dynamodbstreams-lambda/lib/index.ts | 1 - .../lib/index.ts | 3 +- .../eventbridge-kinesisfirehose-s3.test.ts | 31 +- .../lib/index.ts | 3 +- .../test/eventbridge-kinesisstreams.test.ts | 35 +- .../aws-eventbridge-lambda/lib/index.ts | 2 +- .../test/eventbridge-lambda.test.ts | 48 +- .../aws-eventbridge-sns/lib/index.ts | 2 +- .../test/eventbridge-sns-topic.test.ts | 4 +- .../aws-eventbridge-sqs/lib/index.ts | 2 +- .../test/eventbridge-sqs-queue.test.ts | 4 +- .../lib/index.ts | 2 +- .../test/eventbridge-stepfunctions.test.ts | 4 +- .../aws-fargate-dynamodb/lib/index.ts | 1 - .../aws-fargate-eventbridge/lib/index.ts | 2 +- .../test/fargate-eventbridge.test.ts | 20 + .../aws-fargate-kinesisfirehose/lib/index.ts | 1 - .../aws-fargate-kinesisstreams/lib/index.ts | 2 +- .../test/fargate-kinesisstreams.test.ts | 27 + .../aws-fargate-opensearch/lib/index.ts | 2 +- .../test/fargate-opensearch.test.ts | 2 +- .../aws-fargate-s3/lib/index.ts | 1 - .../aws-fargate-secretsmanager/lib/index.ts | 2 +- .../test/fargate-secretsmanager.test.ts | 26 + .../aws-fargate-sns/lib/index.ts | 1 - .../aws-fargate-sqs/lib/index.ts | 1 - .../lib/index.ts | 1 - .../aws-fargate-stepfunctions/lib/index.ts | 1 - .../aws-iot-kinesisfirehose-s3/lib/index.ts | 5 +- .../test/test.iot-kinesisfirehose-s3.test.ts | 16 +- .../aws-iot-kinesisstreams/lib/index.ts | 2 +- .../test/test.iot-kinesisstreams.test.ts | 4 +- .../aws-iot-lambda-dynamodb/lib/index.ts | 2 - .../test/iot-lambda-dynamodb.test.ts | 20 +- .../aws-iot-lambda/lib/index.ts | 1 - .../aws-iot-s3/lib/index.ts | 1 - .../aws-iot-sqs/lib/index.ts | 1 - .../aws-iot-sqs/test/iot-sqs.test.ts | 30 - .../lib/index.ts | 2 - .../aws-kinesisfirehose-s3/lib/index.ts | 1 - .../test/kinesisfirehose-s3.test.ts | 12 - .../aws-kinesisstreams-gluejob/lib/index.ts | 2 +- .../test/kinesisstream-gluejob.test.ts | 39 + .../lib/index.ts | 3 +- .../kinesisstreams-kinesisfirehose-s3.test.ts | 16 + .../aws-kinesisstreams-lambda/lib/index.ts | 2 +- .../test/kinesisstreams-lambda.test.ts | 20 + .../aws-lambda-dynamodb/lib/index.ts | 1 - .../lib/index.ts | 1 - .../lib/index.ts | 1 - .../aws-lambda-eventbridge/lib/index.ts | 2 +- .../test/aws-lambda-eventbridge.test.ts | 16 +- .../aws-lambda-kendra/lib/index.ts | 1 - .../aws-lambda-kinesisfirehose/lib/index.ts | 1 - .../aws-lambda-kinesisstreams/lib/index.ts | 2 +- .../test/lambda-kinesisstream.test.ts | 20 + .../aws-lambda-opensearch/lib/index.ts | 2 +- .../test/lambda-opensearch.test.ts | 2 +- .../aws-lambda-s3/lib/index.ts | 1 - .../aws-lambda-sagemakerendpoint/lib/index.ts | 1 - .../aws-lambda-secretsmanager/lib/index.ts | 2 +- .../test/lambda-secretsmanager.test.ts | 26 +- .../aws-lambda-sns/lib/index.ts | 1 - .../aws-lambda-sqs-lambda/lib/index.ts | 2 - .../aws-lambda-sqs/lib/index.ts | 1 - .../lib/index.ts | 1 - .../aws-lambda-stepfunctions/lib/index.ts | 1 - .../aws-route53-alb/lib/index.ts | 2 - .../aws-route53-apigateway/lib/index.ts | 1 - .../aws-s3-lambda/lib/index.ts | 1 - .../aws-s3-sns/lib/index.ts | 1 - .../aws-s3-sqs/lib/index.ts | 1 - .../aws-s3-stepfunctions/lib/index.ts | 1 - .../aws-sns-lambda/lib/index.ts | 1 - .../aws-sns-sqs/lib/index.ts | 1 - .../aws-sqs-lambda/lib/index.ts | 1 - .../aws-wafwebacl-alb/lib/index.ts | 2 +- .../test/test.wafwebacl-alb.test.ts | 7 +- .../aws-wafwebacl-apigateway/lib/index.ts | 2 +- .../test/test.wafwebacl-apigateway.test.ts | 4 +- .../aws-wafwebacl-appsync/lib/index.ts | 2 +- .../test/test.wafwebacl-appsync.test.ts | 7 +- .../aws-wafwebacl-cloudfront/lib/index.ts | 2 +- .../test/test.wafwebacl-cloudfront.test.ts | 4 +- .../@aws-solutions-constructs/core/index.ts | 1 - .../lib/cloudfront-distribution-helper.ts | 19 + .../core/lib/dynamodb-table-helper.ts | 58 +- .../core/lib/eventbridge-helper.ts | 21 +- .../core/lib/glue-table-helper.ts | 46 ++ .../core/lib/input-validation.ts | 375 ---------- .../core/lib/kinesis-streams-helper.ts | 21 +- .../core/lib/lambda-helper.ts | 19 + .../core/lib/mediastore-helper.ts | 21 +- .../core/lib/opensearch-helper.ts | 18 + .../core/lib/s3-bucket-helper.ts | 38 + .../core/lib/sagemaker-helper.ts | 19 + .../core/lib/secretsmanager-helper.ts | 27 +- .../core/lib/sns-helper.ts | 39 + .../core/lib/sqs-helper.ts | 55 +- .../core/lib/utils.ts | 11 + .../core/lib/vpc-helper.ts | 22 +- .../core/lib/waf-helper.ts | 19 + .../cloudfront-distribution-s3-helper.test.ts | 21 + .../core/test/dynamo-table.test.ts | 71 +- .../core/test/eventbridge-helper.test.ts | 22 +- .../core/test/glue-job-helper.test.ts | 101 +++ .../core/test/input-validation.test.ts | 679 ------------------ .../core/test/kinesis-streams-helper.test.ts | 34 +- .../core/test/lambda-helper.test.ts | 29 + .../core/test/mediastore-helper.test.ts | 31 +- .../core/test/s3-bucket.test.ts | 74 +- .../core/test/sagemaker-helper.test.ts | 32 + .../core/test/secretsmanager-helper.test.ts | 26 +- .../core/test/sns-helper.test.ts | 109 +++ .../core/test/sqs-helper.test.ts | 165 +++++ .../core/test/utils.test.ts | 36 + .../core/test/vpc-helper.test.ts | 77 +- .../core/test/waf-helper.test.ts | 57 +- 141 files changed, 1587 insertions(+), 1588 deletions(-) delete mode 100644 source/patterns/@aws-solutions-constructs/core/lib/input-validation.ts delete mode 100644 source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts index c710a9dcb..3b4821b7d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts @@ -164,7 +164,6 @@ export class AlbToFargate extends Construct { constructor(scope: Construct, id: string, props: AlbToFargateProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckAlbProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/lib/index.ts index eaa060887..2dc1315fe 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/lib/index.ts @@ -121,7 +121,6 @@ export class AlbToLambda extends Construct { constructor(scope: Construct, id: string, props: AlbToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckAlbProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts index 4fcd666a5..84cc33e36 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts @@ -203,7 +203,7 @@ export class ApiGatewayToDynamoDB extends Construct { */ constructor(scope: Construct, id: string, props: ApiGatewayToDynamoDBProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckDynamoDBProps(props); if (this.CheckCreateRequestProps(props)) { throw new Error(`The 'allowCreateOperation' property must be set to true when setting any of the following: ` + diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts index af4b249ae..0596aedff 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts @@ -742,4 +742,35 @@ test('Construct throws error when deleteIntegrationResponses is set and allowDel }); expect(app).toThrowError(/The 'allowDeleteOperation' property must be set to true when setting any of the following: 'deleteRequestTemplate', 'additionalDeleteRequestTemplates', 'deleteIntegrationResponses'/); -}); \ No newline at end of file +}); + +test('Test that CheckDynamoDBProps is getting called', () => { + const stack = new Stack(); + const tableName = 'custom-table-name'; + + const existingTable = new ddb.Table(stack, 'MyTablet', { + tableName, + partitionKey: { + name: 'id', + type: ddb.AttributeType.STRING + } + }); + + const props: ApiGatewayToDynamoDBProps = { + existingTableObj: existingTable, + dynamoTableProps: { + tableName, + partitionKey: { + name: 'id', + type: ddb.AttributeType.STRING + }, + }, + }; + + const app = () => { + new ApiGatewayToDynamoDB(stack, 'test-apigateway-dynamodb-stack', props); + }; + + // Assertion + expect(app).toThrowError(/Error - Either provide existingTableObj or dynamoTableProps, but not both.\n/); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts index fa753702f..33fa931ab 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts @@ -82,7 +82,6 @@ export class ApiGatewayToIot extends Construct { */ constructor(scope: Construct, id: string, props: ApiGatewayToIotProps) { super(scope, id); - defaults.CheckProps(props); // Assignment to local member variables to make these available to all member methods of the class. // (Split the string just in case user supplies fully qualified endpoint eg. ab123cdefghij4l-ats.iot.ap-south-1.amazonaws.com) diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts index 0ef55d50f..15fe5f509 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts @@ -18,9 +18,6 @@ import * as api from 'aws-cdk-lib/aws-apigateway'; import * as iam from 'aws-cdk-lib/aws-iam'; import { Template } from "aws-cdk-lib/assertions"; -// -------------------------------------------------------------- -// Check for ApiGateway params -// -------------------------------------------------------------- test('Test for default Params construct props', () => { // Initial Setup const stack = new cdk.Stack(); @@ -35,9 +32,6 @@ test('Test for default Params construct props', () => { expect(construct.apiGatewayRole).not.toBeNull(); }); -// -------------------------------------------------------------- -// Check for Default IAM Role -// -------------------------------------------------------------- test('Test for default IAM Role', () => { // Initial Setup const stack = new cdk.Stack(); @@ -122,9 +116,6 @@ test('Test for default IAM Role', () => { }); }); -// -------------------------------------------------------------- -// Check for Request Validator -// -------------------------------------------------------------- test('Test for default Params request validator', () => { // Initial Setup const stack = new cdk.Stack(); @@ -140,9 +131,6 @@ test('Test for default Params request validator', () => { }); }); -// -------------------------------------------------------------- -// Check for Integ Props and Method Props -// -------------------------------------------------------------- test('Test for default Params Integ Props and Method Props', () => { // Initial Setup const stack = new cdk.Stack(); @@ -234,10 +222,6 @@ test('Test for default Params Integ Props and Method Props', () => { } }); }); - -// -------------------------------------------------------------- -// Check for valid IoT Endpoint -// -------------------------------------------------------------- test('Test for valid iot endpoint', () => { // Initial Setup const stack = new cdk.Stack(); @@ -252,9 +236,6 @@ test('Test for valid iot endpoint', () => { expect(app).toThrowError(); }); -// -------------------------------------------------------------- -// Check for binaryMediaTypes -// -------------------------------------------------------------- test('Test for Binary Media types', () => { // Stack const stack = new cdk.Stack(); @@ -272,9 +253,6 @@ test('Test for Binary Media types', () => { }); }); -// -------------------------------------------------------------- -// Check for Api Name and Desc -// -------------------------------------------------------------- test('Test for Api Name and Desc', () => { // Stack const stack = new cdk.Stack(); @@ -296,9 +274,6 @@ test('Test for Api Name and Desc', () => { }); }); -// -------------------------------------------------------------- -// Check for Overridden IAM Role -// -------------------------------------------------------------- test('Test for overridden IAM Role', () => { // Initial Setup const stack = new cdk.Stack(); @@ -407,9 +382,6 @@ test('Test for overridden IAM Role', () => { }); }); -// -------------------------------------------------------------- -// Check for Api Key Source -// -------------------------------------------------------------- test('Test for APi Key Source', () => { // Stack const stack = new cdk.Stack(); @@ -430,9 +402,6 @@ test('Test for APi Key Source', () => { }); }); -// -------------------------------------------------------------- -// Check for Api Key Creation -// -------------------------------------------------------------- test('Test for Api Key Creation', () => { // Initial Setup const stack = new cdk.Stack(); @@ -467,9 +436,6 @@ test('Test for Api Key Creation', () => { }); }); -// ----------------------------------------------------------------- -// Test deployment for ApiGateway endPointCongiurationOverride -// ----------------------------------------------------------------- test('Test for deployment ApiGateway AuthorizationType override', () => { // Stack const stack = new cdk.Stack(); @@ -491,9 +457,6 @@ test('Test for deployment ApiGateway AuthorizationType override', () => { }); }); -// ----------------------------------------------------------------- -// Test deployment for override ApiGateway AuthorizationType to NONE -// ----------------------------------------------------------------- test('Test for deployment ApiGateway AuthorizationType override', () => { // Stack const stack = new cdk.Stack(); @@ -514,9 +477,6 @@ test('Test for deployment ApiGateway AuthorizationType override', () => { }); }); -// ----------------------------------------------------------------- -// Test deployment for fully qualified iotEndpoint name -// ----------------------------------------------------------------- test('Test for handling fully qualified iotEndpoint', () => { // Stack const stack = new cdk.Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts index 52f389453..767bc37c4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts @@ -137,7 +137,7 @@ export class ApiGatewayToKinesisStreams extends Construct { */ constructor(scope: Construct, id: string, props: ApiGatewayToKinesisStreamsProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckKinesisStreamProps(props); // Setup the Kinesis stream this.kinesisStream = defaults.buildKinesisStream(scope, { diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesisstreams.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesisstreams.test.ts index 90b5c7164..e69db897b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesisstreams.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesisstreams.test.ts @@ -13,13 +13,10 @@ // Imports import { Stack, Duration } from 'aws-cdk-lib'; -import { ApiGatewayToKinesisStreams } from '../lib'; +import { ApiGatewayToKinesisStreams, ApiGatewayToKinesisStreamsProps } from '../lib'; import * as kinesis from 'aws-cdk-lib/aws-kinesis'; import { Template } from 'aws-cdk-lib/assertions'; -// -------------------------------------------------------------- -// Test construct properties -// -------------------------------------------------------------- test('Test construct properties', () => { const stack = new Stack(); const pattern = new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {}); @@ -32,9 +29,6 @@ test('Test construct properties', () => { expect(pattern.cloudwatchAlarms !== null); }); -// -------------------------------------------------------------- -// Test deployment w/ overwritten properties -// -------------------------------------------------------------- test('Test deployment w/ overwritten properties', () => { const stack = new Stack(); @@ -87,9 +81,6 @@ test('Test deployment w/ overwritten properties', () => { template.resourceCountIs('AWS::CloudWatch::Alarm', 2); }); -// -------------------------------------------------------------- -// Test deployment w/ existing stream without default cloudwatch alarms -// -------------------------------------------------------------- test('Test deployment w/ existing stream', () => { const stack = new Stack(); @@ -232,4 +223,18 @@ test('Construct uses custom putRecordsIntegrationResponses property', () => { ] } }); -}); \ No newline at end of file +}); + +test('Confirm that CheckKinesisStreamProps is called', () => { + const stack = new Stack(); + + const props: ApiGatewayToKinesisStreamsProps = { + existingStreamObj: new kinesis.Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + + const app = () => { + new ApiGatewayToKinesisStreams(stack, 'test-eventbridge-kinesisstreams', props); + }; + expect(app).toThrowError(); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts index 0a1590321..570a4f30c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts @@ -69,7 +69,6 @@ export class ApiGatewayToLambda extends Construct { */ constructor(scope: Construct, id: string, props: ApiGatewayToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); // Setup the Lambda function diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts index 4ea4a90b3..119f25b4c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts @@ -19,9 +19,6 @@ import * as api from 'aws-cdk-lib/aws-apigateway'; import { Template } from "aws-cdk-lib/assertions"; import * as defaults from '@aws-solutions-constructs/core'; -// -------------------------------------------------------------- -// Test for error with existingLambdaObj=undefined (not supplied by user). -// -------------------------------------------------------------- test('Error on existingLambdaObj=undefined', () => { // Initial Setup const stack = new Stack(); @@ -63,9 +60,6 @@ test('Test with lambdaFunctionProps', () => { }); }); -// -------------------------------------------------------------- -// Test getter methods -// -------------------------------------------------------------- test('Test properties', () => { // Initial Setup const stack = new Stack(); @@ -85,9 +79,6 @@ test('Test properties', () => { expect(app.apiGatewayLogGroup !== null); }); -// -------------------------------------------------------------- -// Test for error with lambdaFunctionProps=undefined (not supplied by user). -// -------------------------------------------------------------- test('Error on lambdaFunctionProps=undefined', () => { // Initial Setup const stack = new Stack(); @@ -100,9 +91,6 @@ test('Error on lambdaFunctionProps=undefined', () => { expect(app).toThrowError(); }); -// ----------------------------------------------------------------- -// Test deployment for override ApiGateway AuthorizationType to NONE -// ----------------------------------------------------------------- test('Test deployment ApiGateway AuthorizationType override', () => { // Stack const stack = new Stack(); @@ -127,9 +115,6 @@ test('Test deployment ApiGateway AuthorizationType override', () => { }); }); -// ----------------------------------------------------------------- -// Test deployment for override ApiGateway cloudWatchRole = false -// ----------------------------------------------------------------- test('Test deployment ApiGateway override cloudWatchRole = false', () => { // Stack const stack = new Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts index 0ff4b0628..7d2324c18 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts @@ -100,7 +100,7 @@ export class ApiGatewayToSageMakerEndpoint extends Construct { */ constructor(scope: Construct, id: string, props: ApiGatewayToSageMakerEndpointProps) { super(scope, id); - defaults.CheckProps(props); + // CheckSagemakerProps is not called because this construct can't create a Sagemaker resource // Setup the API Gateway const globalRestApiResponse = defaults.GlobalRestApi(this, props.apiGatewayProps, props.logGroupProps); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts index c31b4da3b..b43069523 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts @@ -17,9 +17,6 @@ import { ApiGatewayToSageMakerEndpoint } from '../lib'; import * as iam from 'aws-cdk-lib/aws-iam'; import { Template } from 'aws-cdk-lib/assertions'; -// -------------------------------------------------------------- -// Test construct properties -// -------------------------------------------------------------- test('Test construct properties', () => { const stack = new Stack(); const pattern = new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { @@ -34,9 +31,6 @@ test('Test construct properties', () => { expect(pattern.apiGatewayLogGroup !== null); }); -// -------------------------------------------------------------- -// Test deployment w/ overwritten properties -// -------------------------------------------------------------- test('Test deployment w/ overwritten properties', () => { const stack = new Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts index 40431218f..b97e9198d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts @@ -196,7 +196,6 @@ export class ApiGatewayToSqs extends Construct { */ constructor(scope: Construct, id: string, props: ApiGatewayToSqsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSqsProps(props); if (this.CheckCreateRequestProps(props)) { diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts index db8b3d254..6ef986a5a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts @@ -104,8 +104,8 @@ export class CloudFrontToApiGatewayToLambda extends Construct { */ constructor(scope: Construct, id: string, props: CloudFrontToApiGatewayToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); + // CheckCloudFrontProps() is called by internal aws-cloudfront-apigateway construct this.lambdaFunction = defaults.buildLambdaFunction(this, { existingLambdaObj: props.existingLambdaObj, diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts index aa10fc080..0c657f914 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts @@ -202,9 +202,6 @@ test('override api gateway properties without existingLambdaObj', () => { }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket with destroy removal policy and auto delete objects -// -------------------------------------------------------------- test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => { const stack = new cdk.Stack(); @@ -243,9 +240,6 @@ test('Cloudfront logging bucket with destroy removal policy and auto delete obje }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket error providing existing log bucket and logBucketProps -// -------------------------------------------------------------- test('Cloudfront logging bucket error when providing existing log bucket and logBucketProps', () => { const stack = new cdk.Stack(); const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {}); @@ -296,3 +290,28 @@ test('Confirm CheckLambdaProps is being called', () => { }; expect(app).toThrowError('Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'); }); + +test("Confirm CheckCloudFrontProps is being called", () => { + const stack = new cdk.Stack(); + + expect(() => { + new CloudFrontToApiGatewayToLambda(stack, "test-cloudfront-apigateway-lambda", { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + insertHttpSecurityHeaders: true, + responseHeadersPolicyProps: { + securityHeadersBehavior: { + strictTransportSecurity: { + accessControlMaxAge: cdk.Duration.seconds(63072), + includeSubdomains: true, + override: false, + preload: true + } + } + } + }); + }).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts index 3deb82336..2114518b1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts @@ -79,7 +79,7 @@ export class CloudFrontToApiGateway extends Construct { */ constructor(scope: Construct, id: string, props: CloudFrontToApiGatewayProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckCloudFrontProps(props); this.apiGateway = props.existingApiGatewayObj; diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts index d7ad60d05..4d19561a9 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts @@ -177,9 +177,6 @@ function createApi() { return {stack, api: regionalLambdaRestApiResponse.api}; } -// -------------------------------------------------------------- -// Cloudfront logging bucket with destroy removal policy and auto delete objects -// -------------------------------------------------------------- test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => { const {stack, api} = createApi(); @@ -209,9 +206,6 @@ test('Cloudfront logging bucket with destroy removal policy and auto delete obje }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket error providing existing log bucket and logBucketProps -// -------------------------------------------------------------- test('Cloudfront logging bucket error when providing existing log bucket and logBucketProps', () => { const {stack, api} = createApi(); @@ -275,7 +269,7 @@ test('Test the deployment with securityHeadersBehavior instead of HTTP security expect(cloudFrontToS3.cloudFrontFunction).toEqual(undefined); }); -test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProps are provided", () => { +test("Confirm CheckCloudFrontProps is being called", () => { const {stack, api} = createApi(); expect(() => { @@ -293,5 +287,5 @@ test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProp } } }); - }).toThrowError(); + }).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts index 3adca9492..f8110107f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts @@ -87,8 +87,8 @@ export class CloudFrontToMediaStore extends Construct { */ constructor(scope: Construct, id: string, props: CloudFrontToMediaStoreProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckMediaStoreProps(props); + defaults.CheckCloudFrontProps(props); let cloudFrontDistributionProps = props.cloudFrontDistributionProps; diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts index 5903d9340..7aaddb2ef 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts @@ -20,9 +20,6 @@ import { CloudFrontToMediaStore } from '../lib'; import * as cdk from "aws-cdk-lib"; import { Template } from 'aws-cdk-lib/assertions'; -// -------------------------------------------------------------- -// Test the default deployment pattern variables -// -------------------------------------------------------------- test('Test the default deployment pattern variables', () => { // Initial setup const stack = new Stack(); @@ -37,9 +34,6 @@ test('Test the default deployment pattern variables', () => { expect(cloudFrontToMediaStore.cloudFrontFunction).not.toEqual(undefined); }); -// -------------------------------------------------------------- -// Test the deployment without HTTP security headers -// -------------------------------------------------------------- test('Test the deployment without HTTP security headers', () => { // Initial setup const stack = new Stack(); @@ -170,7 +164,7 @@ test('Test the deployment with securityHeadersBehavior instead of HTTP security expect(cloudFrontToMediaStore.cloudFrontFunction).toEqual(undefined); }); -test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProps are provided", () => { +test("Confirm CheckCloudFrontProps is being called", () => { const stack = new cdk.Stack(); expect(() => { @@ -187,12 +181,9 @@ test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProp } } }); - }).toThrowError(); + }).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'); }); -// -------------------------------------------------------------- -// Test the deployment with existing MediaStore container -// -------------------------------------------------------------- test('Test the deployment with existing MediaStore container', () => { // Initial setup const stack = new Stack(); @@ -325,9 +316,6 @@ test('Test the deployment with existing MediaStore container', () => { expect(cloudFrontToMediaStore.cloudFrontOriginAccessIdentity).toEqual(undefined); }); -// -------------------------------------------------------------- -// Test the deployment with the user provided MediaStore properties -// -------------------------------------------------------------- test('Test the deployment with the user provided MediaStore properties', () => { // Initial setup const stack = new Stack(); @@ -471,9 +459,6 @@ test('Test the deployment with the user provided MediaStore properties', () => { expect(cloudFrontToMediaStore.cloudFrontOriginAccessIdentity).toEqual(undefined); }); -// -------------------------------------------------------------- -// Test the deployment with the user provided CloudFront properties -// -------------------------------------------------------------- test('Test the deployment with the user provided CloudFront properties', () => { // Initial setup const stack = new Stack(); @@ -650,9 +635,6 @@ test('Test the deployment with the user provided CloudFront properties', () => { }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket with destroy removal policy and auto delete objects -// -------------------------------------------------------------- test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => { const stack = new Stack(); @@ -681,9 +663,6 @@ test('Cloudfront logging bucket with destroy removal policy and auto delete obje }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket error providing existing log bucket and logBucketProps -// -------------------------------------------------------------- test('Cloudfront logging bucket error when providing existing log bucket and logBucketProps', () => { const stack = new Stack(); const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {}); @@ -718,4 +697,4 @@ test('Confirm CheckMediaStoreProps is called', () => { }; expect(app).toThrowError('Error - Either provide mediaStoreContainerProps or existingMediaStoreContainerObj, but not both.\n'); -}); \ No newline at end of file +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts index 810c7b827..45776a697 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts @@ -111,8 +111,8 @@ export class CloudFrontToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckS3Props(props); + defaults.CheckCloudFrontProps(props); let bucket: s3.IBucket; diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts index 14889c679..f7c0090d0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts @@ -246,9 +246,6 @@ test('test cloudfront with custom domain names', () => { }); }); -// -------------------------------------------------------------- -// s3 bucket with bucket, loggingBucket, and auto delete objects -// -------------------------------------------------------------- test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { const stack = new cdk.Stack(); @@ -282,9 +279,6 @@ test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket with destroy removal policy and auto delete objects -// -------------------------------------------------------------- test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => { const stack = new cdk.Stack(); @@ -316,9 +310,6 @@ test('Cloudfront logging bucket with destroy removal policy and auto delete obje }); }); -// -------------------------------------------------------------- -// Cloudfront logging bucket error providing existing log bucket and logBucketProps -// -------------------------------------------------------------- test('Cloudfront logging bucket error when providing existing log bucket and logBucketProps', () => { const stack = new cdk.Stack(); const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {}); @@ -338,9 +329,6 @@ test('Cloudfront logging bucket error when providing existing log bucket and log expect(app).toThrowError(); }); -// -------------------------------------------------------------- -// s3 bucket with one content bucket and no logging bucket -// -------------------------------------------------------------- test('s3 bucket with one content bucket and no logging bucket', () => { const stack = new cdk.Stack(); @@ -356,9 +344,6 @@ test('s3 bucket with one content bucket and no logging bucket', () => { expect(construct.s3LoggingBucket).toEqual(undefined); }); -// -------------------------------------------------- -// CloudFront origin path -// -------------------------------------------------- test('CloudFront origin path present when provided', () => { const stack = new cdk.Stack(); @@ -457,3 +442,23 @@ test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProp }); }).toThrowError(); }); + +test("Confirm CheckCloudFrontProps is being called", () => { + const stack = new cdk.Stack(); + + expect(() => { + new CloudFrontToS3(stack, "test-cloudfront-apigateway", { + insertHttpSecurityHeaders: true, + responseHeadersPolicyProps: { + securityHeadersBehavior: { + strictTransportSecurity: { + accessControlMaxAge: Duration.seconds(63072), + includeSubdomains: true, + override: false, + preload: true + } + } + } + }); + }).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts index d0822f308..47a97fec3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts @@ -81,7 +81,6 @@ export class CognitoToApiGatewayToLambda extends Construct { */ constructor(scope: Construct, id: string, props: CognitoToApiGatewayToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); // This Construct requires that the auth type be COGNITO regardless of what is specified in the props diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/lib/index.ts index d2bf5e038..ac6aa517b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/lib/index.ts @@ -24,7 +24,6 @@ import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as sqs from 'aws-cdk-lib/aws-sqs'; // Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate import { Construct } from 'constructs'; -import * as defaults from '@aws-solutions-constructs/core'; /** * @summary The properties for the DynamoDBStreamsToLambdaToElastciSearchAndKibana Construct @@ -140,7 +139,7 @@ export class DynamoDBStreamsToLambdaToElasticSearchAndKibana extends Construct { */ constructor(scope: Construct, id: string, props: DynamoDBStreamsToLambdaToElasticSearchAndKibanaProps) { super(scope, id); - defaults.CheckProps(props); + // CheckLambdaProps() is called by aws-lambda-elasticsearch const lambdaToElasticSearchProps: LambdaToElasticSearchAndKibanaProps = { existingLambdaObj: props.existingLambdaObj, diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts index 362ccc2cf..d51bbb62e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts @@ -82,7 +82,6 @@ export class DynamoDBStreamsToLambda extends Construct { */ constructor(scope: Construct, id: string, props: DynamoDBStreamsToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); this.lambdaFunction = defaults.buildLambdaFunction(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/lib/index.ts index 00e634d20..ed747969a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/lib/index.ts @@ -108,7 +108,8 @@ export class EventbridgeToKinesisFirehoseToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); + defaults.CheckEventBridgeProps(props); + // CheckS3Props is called by internal aws-kinesisfirehose-s3 construct // Set up the Kinesis Firehose using KinesisFirehoseToS3 construct const firehoseToS3 = new KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/test/eventbridge-kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/test/eventbridge-kinesisfirehose-s3.test.ts index 9d9cebb09..46340caa7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/test/eventbridge-kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/test/eventbridge-kinesisfirehose-s3.test.ts @@ -18,9 +18,6 @@ import { Template } from 'aws-cdk-lib/assertions'; import { EventbridgeToKinesisFirehoseToS3, EventbridgeToKinesisFirehoseToS3Props } from '../lib'; import * as defaults from '@aws-solutions-constructs/core'; -// -------------------------------------------------------------- -// Test snapshot match with default parameters -// -------------------------------------------------------------- function deployNewStack(stack: cdk.Stack) { const props: EventbridgeToKinesisFirehoseToS3Props = { eventRuleProps: { @@ -31,9 +28,6 @@ function deployNewStack(stack: cdk.Stack) { return new EventbridgeToKinesisFirehoseToS3(stack, 'test-eventbridge-kinesis-firehose-s3-default-parameters', props); } -// -------------------------------------------------------------- -// Test properties -// -------------------------------------------------------------- test('Test properties', () => { const stack = new cdk.Stack(); const construct: EventbridgeToKinesisFirehoseToS3 = deployNewStack(stack); @@ -48,9 +42,6 @@ test('Test properties', () => { expect(construct.s3LoggingBucket !== null); }); -// -------------------------------------------------------------- -// Test default server side s3 bucket encryption -// -------------------------------------------------------------- test('Test default server side s3 bucket encryption', () => { const stack = new cdk.Stack(); deployNewStack(stack); @@ -70,9 +61,6 @@ test('Test default server side s3 bucket encryption', () => { }); }); -// -------------------------------------------------------------- -// Test property override -// -------------------------------------------------------------- test('Test property override', () => { const stack = new cdk.Stack(); @@ -120,9 +108,6 @@ test('Test property override', () => { }}); }); -// -------------------------------------------------------------- -// Test bad call with existingBucket and bucketProps -// -------------------------------------------------------------- test("Test bad call with existingBucket and bucketProps", () => { // Stack const stack = new cdk.Stack(); @@ -143,7 +128,7 @@ test("Test bad call with existingBucket and bucketProps", () => { }); }; // Assertion - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n'); }); test('check eventbus property, snapshot & eventbus exists', () => { @@ -172,7 +157,7 @@ test('check eventbus property, snapshot & eventbus exists', () => { template.resourceCountIs('AWS::Events::EventBus', 1); }); -test('check exception while passing existingEventBus & eventBusProps', () => { +test('Confirm CheckEventBridgeProps is being called', () => { const stack = new cdk.Stack(); const props: EventbridgeToKinesisFirehoseToS3Props = { @@ -186,9 +171,9 @@ test('check exception while passing existingEventBus & eventBusProps', () => { }; const app = () => { - new EventbridgeToKinesisFirehoseToS3(stack, 'test-eventbridge-firehose', props); + new EventbridgeToKinesisFirehoseToS3(stack, 'test-eventbridge-firehose-s3', props); }; - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); }); test('check custom event bus resource with props when deploy:true', () => { @@ -212,9 +197,6 @@ test('check custom event bus resource with props when deploy:true', () => { }); }); -// -------------------------------------------------------------- -// s3 bucket with bucket, loggingBucket, and auto delete objects -// -------------------------------------------------------------- test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { const stack = new cdk.Stack(); @@ -248,9 +230,6 @@ test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { }); }); -// -------------------------------------------------------------- -// s3 bucket with one content bucket and no logging bucket -// -------------------------------------------------------------- test('s3 bucket with one content bucket and no logging bucket', () => { const stack = new cdk.Stack(); @@ -307,7 +286,7 @@ test('Confirm CheckS3Props is being called', () => { }; const app = () => { - new EventbridgeToKinesisFirehoseToS3(stack, 'test-eventbridge-firehose', props); + new EventbridgeToKinesisFirehoseToS3(stack, 'test-eventbridge-firehose-s3', props); }; expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n'); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/lib/index.ts index 032c40f94..3709a4a76 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/lib/index.ts @@ -78,7 +78,8 @@ export class EventbridgeToKinesisStreams extends Construct { */ constructor(scope: Construct, id: string, props: EventbridgeToKinesisStreamsProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckEventBridgeProps(props); + defaults.CheckKinesisStreamProps(props); // Set up the Kinesis Stream this.kinesisStream = defaults.buildKinesisStream(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/test/eventbridge-kinesisstreams.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/test/eventbridge-kinesisstreams.test.ts index 8ff33ec52..db67a11dc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/test/eventbridge-kinesisstreams.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/test/eventbridge-kinesisstreams.test.ts @@ -17,9 +17,6 @@ import * as kinesis from 'aws-cdk-lib/aws-kinesis'; import { Template } from "aws-cdk-lib/assertions"; import {EventbridgeToKinesisStreams, EventbridgeToKinesisStreamsProps} from '../lib'; -// -------------------------------------------------------------- -// Test snapshot match with default parameters -// -------------------------------------------------------------- function deployNewStack(stack: cdk.Stack) { const props: EventbridgeToKinesisStreamsProps = { eventRuleProps: { @@ -30,9 +27,6 @@ function deployNewStack(stack: cdk.Stack) { return new EventbridgeToKinesisStreams(stack, 'test-eventbridge-kinesis-streams-default-parameters', props); } -// -------------------------------------------------------------- -// Test properties -// -------------------------------------------------------------- test('Test properties', () => { const stack = new cdk.Stack(); const construct: EventbridgeToKinesisStreams = deployNewStack(stack); @@ -43,9 +37,6 @@ test('Test properties', () => { expect(construct.eventsRole !== null); }); -// -------------------------------------------------------------- -// Test default AWS managed encryption key property -// -------------------------------------------------------------- test('Test default AWS managed encryption key property', () => { const stack = new cdk.Stack(); deployNewStack(stack); @@ -60,9 +51,6 @@ test('Test default AWS managed encryption key property', () => { }); }); -// -------------------------------------------------------------- -// Test existing resources -// -------------------------------------------------------------- test('Test existing resources', () => { const stack = new cdk.Stack(); @@ -128,7 +116,7 @@ test('check exception while passing existingEventBus & eventBusProps', () => { const app = () => { new EventbridgeToKinesisStreams(stack, 'test-eventbridge-kinesisstreams', props); }; - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); }); test('check custom event bus resource with props when deploy:true', () => { @@ -150,4 +138,23 @@ test('check custom event bus resource with props when deploy:true', () => { template.hasResourceProperties('AWS::Events::EventBus', { Name: `testeventbus` }); -}); \ No newline at end of file +}); + +test('Confirm that CheckKinesisStreamProps is called', () => { + const stack = new cdk.Stack(); + + const props: EventbridgeToKinesisStreamsProps = { + eventRuleProps: { + eventPattern: { + source: ['solutionsconstructs'] + } + }, + existingStreamObj: new kinesis.Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + + const app = () => { + new EventbridgeToKinesisStreams(stack, 'test-eventbridge-kinesisstreams', props); + }; + expect(app).toThrowError(); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/lib/index.ts index f9f052540..c4b12a8c5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/lib/index.ts @@ -69,8 +69,8 @@ export class EventbridgeToLambda extends Construct { */ constructor(scope: Construct, id: string, props: EventbridgeToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); + defaults.CheckEventBridgeProps(props); this.lambdaFunction = defaults.buildLambdaFunction(this, { existingLambdaObj: props.existingLambdaObj, diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/test/eventbridge-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/test/eventbridge-lambda.test.ts index 12fa1ab48..ecda59f25 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/test/eventbridge-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/test/eventbridge-lambda.test.ts @@ -217,30 +217,6 @@ test('check eventbus property, snapshot & eventbus exists', () => { template.resourceCountIs('AWS::Events::EventBus', 1); }); -test('check exception while passing existingEventBus & eventBusProps', () => { - const stack = new cdk.Stack(); - - const props: EventbridgeToLambdaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_16_X, - handler: 'index.handler' - }, - eventRuleProps: { - eventPattern: { - source: ['solutionsconstructs'] - } - }, - eventBusProps: { eventBusName: 'test' }, - existingEventBusInterface: new events.EventBus(stack, `test-existing-eventbus`, { eventBusName: 'test' }) - }; - - const app = () => { - new EventbridgeToLambda(stack, 'test-eventbridge-lambda', props); - }; - expect(app).toThrowError(); -}); - test('check custom event bus resource with props when deploy:true', () => { const stack = new cdk.Stack(); @@ -295,3 +271,27 @@ test('Confirm call to CheckLambdaProps', () => { // Assertion expect(app).toThrowError('Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'); }); + +test('Confirm CheckEventBridgeProps is being called', () => { + const stack = new cdk.Stack(); + + const props: EventbridgeToLambdaProps = { + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_16_X, + handler: 'index.handler' + }, + eventRuleProps: { + eventPattern: { + source: ['solutionsconstructs'] + } + }, + eventBusProps: { eventBusName: 'test' }, + existingEventBusInterface: new events.EventBus(stack, `test-existing-eventbus`, { eventBusName: 'test' }) + }; + + const app = () => { + new EventbridgeToLambda(stack, 'test-eventbridge-lambda', props); + }; + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts index b9781dd9d..16f117634 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts @@ -87,8 +87,8 @@ export class EventbridgeToSns extends Construct { */ constructor(scope: Construct, id: string, props: EventbridgeToSnsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSnsProps(props); + defaults.CheckEventBridgeProps(props); let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey; if (props.enableEncryptionWithCustomerManagedKey === undefined || diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts index 76045d8e0..7d3c800f5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts @@ -234,7 +234,7 @@ test('check eventbus property, snapshot & eventbus exists', () => { template.resourceCountIs('AWS::Events::EventBus', 1); }); -test('check exception while passing existingEventBus & eventBusProps', () => { +test('Confirm CheckEventBridgeProps is being called', () => { const stack = new cdk.Stack(); const props: EventbridgeToSnsProps = { @@ -250,7 +250,7 @@ test('check exception while passing existingEventBus & eventBusProps', () => { const app = () => { new EventbridgeToSns(stack, 'test-eventbridge-sns', props); }; - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); }); test('check custom event bus resource with props when deploy:true', () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts index ca236a852..835884662 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts @@ -116,8 +116,8 @@ export class EventbridgeToSqs extends Construct { */ constructor(scope: Construct, id: string, props: EventbridgeToSqsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSqsProps(props); + defaults.CheckEventBridgeProps(props); // Setup the dead letter queue, if applicable this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts index 260eb00b2..34836f8cc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts @@ -299,7 +299,7 @@ test('check eventbus property, snapshot & eventbus exists', () => { template.resourceCountIs('AWS::Events::EventBus', 1); }); -test('check exception while passing existingEventBus & eventBusProps', () => { +test('Confirm CheckEventBridgeProps is being called', () => { const stack = new cdk.Stack(); const props: EventbridgeToSqsProps = { @@ -315,7 +315,7 @@ test('check exception while passing existingEventBus & eventBusProps', () => { const app = () => { new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props); }; - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); }); test('check custom event bus resource with props when deploy:true', () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts index 01b91451b..86a4acca8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts @@ -79,7 +79,7 @@ export class EventbridgeToStepfunctions extends Construct { */ constructor(scope: Construct, id: string, props: EventbridgeToStepfunctionsProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckEventBridgeProps(props); const buildStateMachineResponse = defaults.buildStateMachine(this, props.stateMachineProps, props.logGroupProps); diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/test/eventbridge-stepfunctions.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/test/eventbridge-stepfunctions.test.ts index 6c6eb9c2c..0138bde2b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/test/eventbridge-stepfunctions.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/test/eventbridge-stepfunctions.test.ts @@ -150,7 +150,7 @@ test('check eventbus property, snapshot & eventbus exists', () => { template.resourceCountIs('AWS::Events::EventBus', 1); }); -test('check exception while passing existingEventBus & eventBusProps', () => { +test('Confirm CheckEventBridgeProps is being called', () => { const stack = new cdk.Stack(); const startState = new sfn.Pass(stack, 'StartState'); @@ -170,7 +170,7 @@ test('check exception while passing existingEventBus & eventBusProps', () => { const app = () => { new EventbridgeToStepfunctions(stack, 'test-eventbridge-stepfunctions', props); }; - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); }); test('check custom event bus resource with props when deploy:true', () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts index e6d4ec2cd..60ef5c9c4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts @@ -140,7 +140,6 @@ export class FargateToDynamoDB extends Construct { constructor(scope: Construct, id: string, props: FargateToDynamoDBProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckDynamoDBProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts index ebace3548..498b58249 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts @@ -132,9 +132,9 @@ export class FargateToEventbridge extends Construct { constructor(scope: Construct, id: string, props: FargateToEventbridgeProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); + defaults.CheckEventBridgeProps(props); this.vpc = defaults.buildVpc(scope, { existingVpc: props.existingVpc, diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts index 0a8e7f10e..e8789f9d4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts @@ -398,3 +398,23 @@ test('Confirm that CheckVpcProps was called', () => { // Assertion expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); }); + +test('Confirm CheckEventBridgeProps is being called', () => { + const stack = new cdk.Stack(); + + const props: FargateToEventbridgeProps = { + publicApi: true, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + eventBusProps: { eventBusName: 'test' }, + existingEventBusInterface: new events.EventBus(stack, `test-existing-eventbus`, { eventBusName: 'test' }) + }; + + const app = () => { + new FargateToEventbridge(stack, 'test-fargate-eventbridge', props); + }; + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts index c17170209..c1df8bea4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts @@ -125,7 +125,6 @@ export class FargateToKinesisFirehose extends Construct { constructor(scope: Construct, id: string, props: FargateToKinesisFirehoseProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts index 57b95b6e8..a71abdc57 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts @@ -150,9 +150,9 @@ export class FargateToKinesisStreams extends Construct { */ constructor(scope: Construct, id: string, props: FargateToKinesisStreamsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); + defaults.CheckKinesisStreamProps(props); // Setup the VPC this.vpc = defaults.buildVpc(scope, { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts index 15740bc9d..5ae9df5b6 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts @@ -623,3 +623,30 @@ test('Confirm that CheckVpcProps was called', () => { // Assertion expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); }); + +test('Confirm that CheckKinesisStreamsProps was called', () => { + const stack = new cdk.Stack(); + const publicApi = true; + const clusterName = "custom-cluster-name"; + const containerName = "custom-container-name"; + const serviceName = "custom-service-name"; + const familyName = "custom-family-name"; + + const props: FargateToKinesisStreamsProps = { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + vpcProps: { }, + existingStreamObj: new kinesis.Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + + const app = () => { + new FargateToKinesisStreams(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts index 33d8abfdc..439c81380 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts @@ -145,9 +145,9 @@ export class FargateToOpenSearch extends Construct { constructor(scope: Construct, id: string, props: FargateToOpenSearchProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); + defaults.CheckOpenSearchProps(props); this.vpc = defaults.buildVpc(scope, { existingVpc: props.existingVpc, diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts index a102ffc5e..c12f81c9c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts @@ -720,7 +720,7 @@ test('Existing service/new domain, private API, existing VPC', () => { template.resourceCountIs('AWS::OpenSearchService::Domain', 1); }); -test('Check error for using OpenSearch VPC prop parameter', () => { +test('Confirm CheckOpenSearchProps is called', () => { const stack = new cdk.Stack(); const publicApi = false; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts index 02b520da2..d04dbf50d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts @@ -161,7 +161,6 @@ export class FargateToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckS3Props(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts index 721ba5a97..4c03f206e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts @@ -134,9 +134,9 @@ export class FargateToSecretsmanager extends Construct { constructor(scope: Construct, id: string, props: FargateToSecretsmanagerProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); + defaults.CheckSecretsManagerProps(props); // Other permissions for constructs are accepted as arrays, turning grantWriteAccess into // an array to use the same validation function. diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts index ac84bf248..4b5daa9f7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts @@ -16,6 +16,7 @@ import * as defaults from '@aws-solutions-constructs/core'; import * as cdk from "aws-cdk-lib"; import { FargateToSecretsmanager, FargateToSecretsmanagerProps } from "../lib"; import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as secrets from 'aws-cdk-lib/aws-secretsmanager'; import { buildSecretsManagerSecret } from '@aws-solutions-constructs/core'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; @@ -663,3 +664,28 @@ test('Confirm that CheckVpcProps was called', () => { // Assertion expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); }); + +test('Confirm that CheckSecretsManagerProps was called', () => { + const stack = new cdk.Stack(); + const publicApi = true; + + const props: FargateToSecretsmanagerProps = { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + secretProps: { + secretName + }, + existingSecretObj: new secrets.Secret(stack, 'test', {}), + vpcProps: { }, + }; + + const app = () => { + new FargateToSecretsmanager(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide secretProps or existingSecretObj, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts index a694daada..ccae9849c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts @@ -153,7 +153,6 @@ export class FargateToSns extends Construct { constructor(scope: Construct, id: string, props: FargateToSnsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckSnsProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts index de07fe47a..992b91b97 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts @@ -178,7 +178,6 @@ export class FargateToSqs extends Construct { constructor(scope: Construct, id: string, props: FargateToSqsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckSqsProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts index 533be3cea..39a1fe36e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts @@ -133,7 +133,6 @@ export class FargateToSsmstringparameter extends Construct { constructor(scope: Construct, id: string, props: FargateToSsmstringparameterProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts index 64d238471..cbe37a755 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts @@ -138,7 +138,6 @@ export class FargateToStepfunctions extends Construct { constructor(scope: Construct, id: string, props: FargateToStepfunctionsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckFargateProps(props); defaults.CheckVpcProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts index 97431270c..27e288be1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts @@ -19,7 +19,6 @@ import * as logs from 'aws-cdk-lib/aws-logs'; // Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate import { Construct } from 'constructs'; import * as defaults from '@aws-solutions-constructs/core'; -import { overrideProps } from '@aws-solutions-constructs/core'; import { KinesisFirehoseToS3 } from '@aws-solutions-constructs/aws-kinesisfirehose-s3'; /** @@ -96,8 +95,6 @@ export class IotToKinesisFirehoseToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); - const firehoseToS3 = new KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', { kinesisFirehoseProps: props.kinesisFirehoseProps, existingBucketObj: props.existingBucketObj, @@ -134,7 +131,7 @@ export class IotToKinesisFirehoseToS3 extends Construct { roleArn: this.iotActionsRole.roleArn } }]); - const iotTopicProps = overrideProps(defaultIotTopicProps, props.iotTopicRuleProps, true); + const iotTopicProps = defaults.overrideProps(defaultIotTopicProps, props.iotTopicRuleProps, true); // Create the IoT topic rule this.iotTopicRule = new iot.CfnTopicRule(this, 'IotTopic', iotTopicProps); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts index a77015ea2..e74600402 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts @@ -111,8 +111,10 @@ test('check firehose and s3 overrides', () => { IntervalInSeconds: 600, SizeInMBs: 55 } - }}); + } + }); }); + test('check properties', () => { const stack = new cdk.Stack(); @@ -127,9 +129,6 @@ test('check properties', () => { expect(construct.s3LoggingBucket !== null); }); -// -------------------------------------------------------------- -// Test bad call with existingBucket and bucketProps -// -------------------------------------------------------------- test("Confirm CheckS3Props is being called", () => { // Stack const stack = new cdk.Stack(); @@ -157,9 +156,6 @@ test("Confirm CheckS3Props is being called", () => { expect(app).toThrowError("Error - Either provide bucketProps or existingBucketObj, but not both.\n"); }); -// -------------------------------------------------------------- -// s3 bucket with bucket, loggingBucket, and auto delete objects -// -------------------------------------------------------------- test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { const stack = new cdk.Stack(); @@ -197,9 +193,6 @@ test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { }); }); -// -------------------------------------------------------------- -// Test bad call with logS3AccessLogs as false and bucketProps -// -------------------------------------------------------------- test("Test bad call with logS3AccessLogs as false and bucketProps", () => { // Stack const stack = new cdk.Stack(); @@ -225,9 +218,6 @@ test("Test bad call with logS3AccessLogs as false and bucketProps", () => { expect(app).toThrowError('Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'); }); -// -------------------------------------------------------------- -// s3 bucket with one content bucket and no logging bucket -// -------------------------------------------------------------- test('s3 bucket with one content bucket and no logging bucket', () => { const stack = new cdk.Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/lib/index.ts index ffb17e44e..6c27d29fd 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/lib/index.ts @@ -65,7 +65,7 @@ export class IotToKinesisStreams extends Construct { */ constructor(scope: Construct, id: string, props: IotToKinesisStreamsProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckKinesisStreamProps(props); // Set up the Kinesis Stream this.kinesisStream = defaults.buildKinesisStream(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/test/test.iot-kinesisstreams.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/test/test.iot-kinesisstreams.test.ts index 2d295da58..daecaa05b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/test/test.iot-kinesisstreams.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/test/test.iot-kinesisstreams.test.ts @@ -241,7 +241,7 @@ test('check construct chaining', () => { template.resourceCountIs('AWS::Kinesis::Stream', 1); }); -test('check error when stream props and existing stream is supplied', () => { +test('Confirm call to CheckKinesisStreamProps', () => { const stack = new cdk.Stack(); const existingKinesisStream = new kinesis.Stream(stack, `existing-stream`, {}); @@ -254,5 +254,5 @@ test('check error when stream props and existing stream is supplied', () => { const app = () => { new IotToKinesisStreams(stack, 'test-iot-kinesisstreams', props); }; - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/lib/index.ts index 1a9715d69..d35dbe0fa 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/lib/index.ts @@ -94,8 +94,6 @@ export class IotToLambdaToDynamoDB extends Construct { */ constructor(scope: Construct, id: string, props: IotToLambdaToDynamoDBProps) { super(scope, id); - defaults.CheckProps(props); - defaults.CheckSnsProps(props); // Other permissions for constructs are accepted as arrays, turning tablePermissions into // an array to use the same validation function. diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts index e69a46d51..e571342db 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts @@ -366,9 +366,6 @@ test('check lambda function custom environment variable', () => { }); }); -// -------------------------------------------------------------- -// Test minimal deployment that deploys a VPC without vpcProps -// -------------------------------------------------------------- test("Test minimal deployment that deploys a VPC without vpcProps", () => { // Stack const stack = new cdk.Stack(); @@ -425,9 +422,6 @@ test("Test minimal deployment that deploys a VPC without vpcProps", () => { template.resourceCountIs("AWS::EC2::InternetGateway", 0); }); -// -------------------------------------------------------------- -// Test minimal deployment that deploys a VPC w/vpcProps -// -------------------------------------------------------------- test("Test minimal deployment that deploys a VPC w/vpcProps", () => { // Stack const stack = new cdk.Stack(); @@ -490,9 +484,6 @@ test("Test minimal deployment that deploys a VPC w/vpcProps", () => { template.resourceCountIs("AWS::EC2::InternetGateway", 0); }); -// -------------------------------------------------------------- -// Test minimal deployment with an existing VPC -// -------------------------------------------------------------- test("Test minimal deployment with an existing VPC", () => { // Stack const stack = new cdk.Stack(); @@ -544,16 +535,12 @@ test("Test minimal deployment with an existing VPC", () => { }); }); -// -------------------------------------------------------------- -// Test minimal deployment with an existing VPC and existing Lambda function not in a VPC -// -// buildLambdaFunction should throw an error if the Lambda function is not -// attached to a VPC -// -------------------------------------------------------------- test("Test minimal deployment with an existing VPC and existing Lambda function not in a VPC", () => { // Stack const stack = new cdk.Stack(); + // buildLambdaFunction should throw an error if the Lambda function is not + // attached to a VPC const testLambdaFunction = new lambda.Function(stack, 'test-lambda', { runtime: lambda.Runtime.NODEJS_16_X, handler: "index.handler", @@ -584,9 +571,6 @@ test("Test minimal deployment with an existing VPC and existing Lambda function }); -// -------------------------------------------------------------- -// Test bad call with existingVpc and deployVpc -// -------------------------------------------------------------- test("Confirm CheckVpcProps is called", () => { // Stack const stack = new cdk.Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/lib/index.ts index ad0dc64d3..42b2b727d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/lib/index.ts @@ -57,7 +57,6 @@ export class IotToLambda extends Construct { */ constructor(scope: Construct, id: string, props: IotToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); this.lambdaFunction = defaults.buildLambdaFunction(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts index d17c4e809..232e67009 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts @@ -82,7 +82,6 @@ export class IotToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckS3Props(props); // Setup S3 Bucket diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts index c6ed87fdc..e75e16eb9 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts @@ -102,7 +102,6 @@ export class IotToSqs extends Construct { */ constructor(scope: Construct, id: string, props: IotToSqsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSqsProps(props); // Setup the dead letter queue, if applicable diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/test/iot-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/test/iot-sqs.test.ts index bc84424c7..201465b17 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/test/iot-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/test/iot-sqs.test.ts @@ -19,9 +19,6 @@ import * as sqs from 'aws-cdk-lib/aws-sqs'; import * as kms from 'aws-cdk-lib/aws-kms'; import * as defaults from '@aws-solutions-constructs/core'; -// -------------------------------------------------------------- -// Pattern deployment with default props -// -------------------------------------------------------------- test('Pattern deployment with default props', () => { // Initial Setup const stack = new Stack(); @@ -81,9 +78,6 @@ test('Pattern deployment with default props', () => { }); }); -// -------------------------------------------------------------- -// Testing with existing SQS Queue -// -------------------------------------------------------------- test('Pattern deployment with existing queue', () => { // Initial Setup const stack = new Stack(); @@ -112,9 +106,6 @@ test('Pattern deployment with existing queue', () => { }); }); -// -------------------------------------------------------------- -// Testing with passing queue and dead letter queue props -// -------------------------------------------------------------- test('Pattern deployment with queue and dead letter queue props', () => { // Initial Setup const stack = new Stack(); @@ -158,9 +149,6 @@ test('Pattern deployment with queue and dead letter queue props', () => { }); }); -// -------------------------------------------------------------- -// Testing with dead letter queue turned off -// -------------------------------------------------------------- test('Pattern deployment with dead letter queue turned off', () => { // Initial Setup const stack = new Stack(); @@ -193,9 +181,6 @@ test('Pattern deployment with dead letter queue turned off', () => { }); }); -// -------------------------------------------------------------- -// Testing with custom maxReceiveCount -// -------------------------------------------------------------- test('Pattern deployment with custom maxReceiveCount', () => { // Initial Setup const stack = new Stack(); @@ -236,9 +221,6 @@ test('Pattern deployment with custom maxReceiveCount', () => { }); }); -// -------------------------------------------------------------- -// Testing without creating a KMS key -// -------------------------------------------------------------- test('Pattern deployment without creating a KMS key', () => { // Initial Setup const stack = new Stack(); @@ -293,9 +275,6 @@ test('Pattern deployment without creating a KMS key', () => { template.resourceCountIs("AWS::KMS::Key", 0); }); -// -------------------------------------------------------------- -// Testing with existing KMS key -// -------------------------------------------------------------- test('Pattern deployment with existing KMS key', () => { // Initial Setup const stack = new Stack(); @@ -362,9 +341,6 @@ test('Pattern deployment with existing KMS key', () => { }); }); -// --------------------------------------------------------------- -// Testing with existing KMS key on queueProps.encryptionMasterKey -// --------------------------------------------------------------- test('Pattern deployment with existing KMS key', () => { // Initial Setup const stack = new Stack(); @@ -433,9 +409,6 @@ test('Pattern deployment with existing KMS key', () => { }); }); -// -------------------------------------------------------------- -// Testing with passing KMS key props -// -------------------------------------------------------------- test('Pattern deployment passing KMS key props', () => { // Initial Setup const stack = new Stack(); @@ -510,9 +483,6 @@ test('Pattern deployment passing KMS key props', () => { }); }); -// -------------------------------------------------------------- -// Testing with passing a FIFO queue (not supported by IoT) -// -------------------------------------------------------------- test('Pattern deployment with passing a FIFO queue (not supported by IoT)', () => { // Initial Setup const stack = new Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts index 8798c43e8..7c144a724 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts @@ -98,8 +98,6 @@ export class KinesisFirehoseToAnalyticsAndS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); - // Setup the kinesisfirehose-s3 pattern const kinesisFirehoseToS3Props: KinesisFirehoseToS3Props = { kinesisFirehoseProps: props.kinesisFirehoseProps, diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts index ec1c2b1de..0fb36c413 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts @@ -94,7 +94,6 @@ export class KinesisFirehoseToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckS3Props(props); const firehoseId = 'KinesisFirehose'; diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/kinesisfirehose-s3.test.ts index 1671ab5fa..f1eb0b435 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/kinesisfirehose-s3.test.ts @@ -213,9 +213,6 @@ test("Confirm that CheckS3Props is being called", () => { expect(app).toThrowError("Error - Either provide bucketProps or existingBucketObj, but not both.\n"); }); -// -------------------------------------------------------------- -// s3 bucket with bucket, loggingBucket, and auto delete objects -// -------------------------------------------------------------- test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { const stack = new cdk.Stack(); @@ -248,9 +245,6 @@ test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { }); }); -// -------------------------------------------------------------- -// Test bad call with existingLoggingBucketObj and loggingBucketProps -// -------------------------------------------------------------- test("Test bad call with existingLoggingBucketObj and loggingBucketProps", () => { // Stack const stack = new cdk.Stack(); @@ -270,9 +264,6 @@ test("Test bad call with existingLoggingBucketObj and loggingBucketProps", () => expect(app).toThrowError('Error - Either provide existingLoggingBucketObj or loggingBucketProps, but not both.\n'); }); -// -------------------------------------------------------------- -// Test bad call with logS3AccessLogs as false and bucketProps -// -------------------------------------------------------------- test("Test bad call with logS3AccessLogs as false and bucketProps", () => { // Stack const stack = new cdk.Stack(); @@ -290,9 +281,6 @@ test("Test bad call with logS3AccessLogs as false and bucketProps", () => { expect(app).toThrowError('Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'); }); -// -------------------------------------------------------------- -// s3 bucket with one content bucket and no logging bucket -// -------------------------------------------------------------- test('s3 bucket with one content bucket and no logging bucket', () => { const stack = new cdk.Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts index 5568a5937..29cfeaf23 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts @@ -173,8 +173,8 @@ export class KinesisstreamsToGluejob extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckGlueProps(props); + defaults.CheckKinesisStreamProps(props); this.kinesisStream = defaults.buildKinesisStream(this, { existingStreamObj: props.existingStreamObj, diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/kinesisstream-gluejob.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/kinesisstream-gluejob.test.ts index a4a0d75a6..5e0f4a5f4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/kinesisstream-gluejob.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/kinesisstream-gluejob.test.ts @@ -880,3 +880,42 @@ test('Check properties when output bucket is provided', () => { expect(construct.outputBucket![0]).toBeDefined(); expect(construct.outputBucket![1]).not.toBeDefined(); }); + +test('Confirm call to CheckKinesisStreamProps', () => { + // Initial Setup + const stack = new Stack(); + + const props: KinesisstreamsToGluejobProps = { + glueJobProps: { + command: { + name: 'glueetl', + pythonVersion: '3', + scriptLocation: 's3://fakebucket/fakefolder/fakefolder/fakefile.py' + } + }, + fieldSchema: [{ + name: "id", + type: "int", + comment: "Identifier for the record" + }, { + name: "name", + type: "string", + comment: "The name of the record" + }, { + name: "type", + type: "string", + comment: "The type of the record" + }, { + name: "numericvalue", + type: "int", + comment: "Some value associated with the record" + }], + existingStreamObj: new Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + const app = () => { + new KinesisstreamsToGluejob(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts index 9eb56020c..21ce087da 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts @@ -117,7 +117,8 @@ export class KinesisStreamsToKinesisFirehoseToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); + defaults.CheckKinesisStreamProps(props); + // CheckS3Props() is called by the internal aws-kinesisfirehose-s3 construct // Setup the Kinesis Stream this.kinesisStream = defaults.buildKinesisStream(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/kinesisstreams-kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/kinesisstreams-kinesisfirehose-s3.test.ts index 0d435e207..ecd7174ca 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/kinesisstreams-kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/kinesisstreams-kinesisfirehose-s3.test.ts @@ -17,6 +17,7 @@ import { Template } from 'aws-cdk-lib/assertions'; import * as defaults from '@aws-solutions-constructs/core'; import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as kinesis from 'aws-cdk-lib/aws-kinesis'; function deploy(stack: cdk.Stack, props: KinesisStreamsToKinesisFirehoseToS3Props = {}) { return new KinesisStreamsToKinesisFirehoseToS3(stack, 'test-stream-firehose-s3', props); @@ -257,3 +258,18 @@ test("Confirm that CheckS3Props is being called", () => { // Assertion expect(app).toThrowError("Error - Either provide bucketProps or existingBucketObj, but not both.\n"); }); + +test('Confirm call to CheckKinesisStreamProps', () => { + // Initial Setup + const stack = new cdk.Stack(); + + const props: KinesisStreamsToKinesisFirehoseToS3Props = { + existingStreamObj: new kinesis.Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + const app = () => { + new KinesisStreamsToKinesisFirehoseToS3(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts index ecf0e4b7f..e0f68b198 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts @@ -94,8 +94,8 @@ export class KinesisStreamsToLambda extends Construct { */ constructor(scope: Construct, id: string, props: KinesisStreamsToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckLambdaProps(props); + defaults.CheckKinesisStreamProps(props); // Setup the Kinesis Stream this.kinesisStream = defaults.buildKinesisStream(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/kinesisstreams-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/kinesisstreams-lambda.test.ts index 9935241d0..16d4ac1d9 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/kinesisstreams-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/kinesisstreams-lambda.test.ts @@ -138,3 +138,23 @@ test('Confirm call to CheckLambdaProps', () => { // Assertion expect(app).toThrowError('Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'); }); + +test('Confirm call to CheckKinesisStreamProps', () => { + // Initial Setup + const stack = new Stack(); + + const props: KinesisStreamsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_16_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + existingStreamObj: new kinesis.Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + const app = () => { + new KinesisStreamsToLambda(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts index 6f3be85a1..2379fdd58 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts @@ -90,7 +90,6 @@ export class LambdaToDynamoDB extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToDynamoDBProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckDynamoDBProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts index 2ef1a3813..1d8397080 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts @@ -92,7 +92,6 @@ export class LambdaToElasticachememcached extends Construct { props: LambdaToElasticachememcachedProps ) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts index 7f4254c96..742ea3498 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts @@ -107,7 +107,6 @@ export class LambdaToElasticSearchAndKibana extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToElasticSearchAndKibanaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts index 03eb1b584..8a0fbaaa3 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts @@ -86,9 +86,9 @@ export class LambdaToEventbridge extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToEventbridgeProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); + defaults.CheckEventBridgeProps(props); if (props.deployVpc || props.existingVpc) { this.vpc = defaults.buildVpc(scope, { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/test/aws-lambda-eventbridge.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/test/aws-lambda-eventbridge.test.ts index 246b86b0a..ca46ce863 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/test/aws-lambda-eventbridge.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/test/aws-lambda-eventbridge.test.ts @@ -140,7 +140,7 @@ test("Confirm CheckVpcProps is being called", () => { expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); }); -test("Test bad call with existingVpc and deployVpc", () => { +test("Confirm CheckEventBridgeProps is called", () => { // Stack const stack = new Stack(); @@ -157,12 +157,9 @@ test("Test bad call with existingVpc and deployVpc", () => { }); }; // Assertion - expect(app).toThrowError(); + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); }); -// -------------------------------------------------------------- -// Test deployment w/ existing eventbus -// -------------------------------------------------------------- test('Test deployment w/ existing eventbus', () => { // Stack const stack = new Stack(); @@ -268,9 +265,6 @@ test("Test minimal deployment that deploys a VPC w/vpcProps", () => { template.resourceCountIs("AWS::EC2::InternetGateway", 0); }); -// -------------------------------------------------------------- -// Test minimal deployment with an existing VPC -// -------------------------------------------------------------- test("Test minimal deployment with an existing VPC", () => { // Stack const stack = new Stack(); @@ -335,10 +329,6 @@ test("Test minimal deployment with an existing VPC", () => { }); }); -// -------------------------------------------------------------- -// Test minimal deployment with an existing VPC and existing Lambda function not in a VPC -// -// -------------------------------------------------------------- test("Test minimal deployment with an existing VPC and existing Lambda function not in a VPC", () => { // Stack const stack = new Stack(); @@ -362,7 +352,7 @@ test("Test minimal deployment with an existing VPC and existing Lambda function }; // Assertion - expect(app).toThrowError(); + expect(app).toThrowError('A Lambda function must be bound to a VPC upon creation, it cannot be added to a VPC in a subsequent construct'); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-kendra/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-kendra/lib/index.ts index 1f988aa1f..bdccc5944 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-kendra/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-kendra/lib/index.ts @@ -104,7 +104,6 @@ export class LambdaToKendra extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToKendraProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisfirehose/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisfirehose/lib/index.ts index d4562a033..e5a4677e4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisfirehose/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisfirehose/lib/index.ts @@ -82,7 +82,6 @@ export class LambdaToKinesisFirehose extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToKinesisFirehoseProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/lib/index.ts index 895734136..f7451f252 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/lib/index.ts @@ -95,9 +95,9 @@ export class LambdaToKinesisStreams extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToKinesisStreamsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); + defaults.CheckKinesisStreamProps(props); // Setup the VPC if (props.deployVpc || props.existingVpc) { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/test/lambda-kinesisstream.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/test/lambda-kinesisstream.test.ts index 7396c8628..05fd96014 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/test/lambda-kinesisstream.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-kinesisstreams/test/lambda-kinesisstream.test.ts @@ -601,3 +601,23 @@ test('Confirm call to CheckLambdaProps', () => { // Assertion expect(app).toThrowError('Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'); }); + +test('Confirm call to CheckKinesisStreamProps', () => { + // Initial Setup + const stack = new cdk.Stack(); + + const props: LambdaToKinesisStreamsProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_16_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + existingStreamObj: new kinesis.Stream(stack, 'test', {}), + kinesisStreamProps: {} + }; + const app = () => { + new LambdaToKinesisStreams(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts index 212bf4f45..ca1228cd7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts @@ -107,9 +107,9 @@ export class LambdaToOpenSearch extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToOpenSearchProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); + defaults.CheckOpenSearchProps(props); if (props.vpcProps && !props.deployVpc) { throw new Error("Error - deployVpc must be true when defining vpcProps"); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/test/lambda-opensearch.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/test/lambda-opensearch.test.ts index 2533b776a..1c75c121b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/test/lambda-opensearch.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/test/lambda-opensearch.test.ts @@ -567,7 +567,7 @@ test('Test error for Lambda function VPC props', () => { expect(app).toThrowError("Error - Define VPC using construct parameters not Lambda function props"); }); -test('Test error for the OpenSearch domain VPC props', () => { +test('Confirm CheckOpenSearchProps is called', () => { const stack = new cdk.Stack(); const app = () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts index fb223ca81..8985f7ed8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts @@ -114,7 +114,6 @@ export class LambdaToS3 extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckS3Props(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts index 3b27984e9..e5233aaa0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts @@ -105,7 +105,6 @@ export class LambdaToSagemakerEndpoint extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToSagemakerEndpointProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); defaults.CheckSagemakerProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts index 4819539af..966f04f1b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts @@ -92,9 +92,9 @@ export class LambdaToSecretsmanager extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToSecretsmanagerProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); + defaults.CheckSecretsManagerProps(props); if (props.deployVpc || props.existingVpc) { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/test/lambda-secretsmanager.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/test/lambda-secretsmanager.test.ts index 4c752bd7d..ec7ff2c75 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/test/lambda-secretsmanager.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/test/lambda-secretsmanager.test.ts @@ -14,7 +14,7 @@ // Imports import { RemovalPolicy, Stack } from "aws-cdk-lib"; import * as lambda from "aws-cdk-lib/aws-lambda"; -import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; +import * as secrets from 'aws-cdk-lib/aws-secretsmanager'; import * as ec2 from "aws-cdk-lib/aws-ec2"; import { LambdaToSecretsmanager, LambdaToSecretsmanagerProps } from '../lib'; import { Template } from 'aws-cdk-lib/assertions'; @@ -44,7 +44,7 @@ test('Test deployment w/ existing secret', () => { // Stack const stack = new Stack(); // Helper declaration - const existingSecret = new Secret(stack, 'secret', {}); + const existingSecret = new secrets.Secret(stack, 'secret', {}); const pattern = new LambdaToSecretsmanager(stack, 'lambda-to-secretsmanager-stack', { lambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_16_X, @@ -419,3 +419,25 @@ test('Confirm call to CheckLambdaProps', () => { // Assertion expect(app).toThrowError('Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'); }); + +test('Confirm call to CheckSecretsManagerProps', () => { + // Initial Setup + const stack = new Stack(); + + const props: LambdaToSecretsmanagerProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_16_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + secretProps: { + secretName: 'test' + }, + existingSecretObj: new secrets.Secret(stack, 'test', {}), + }; + const app = () => { + new LambdaToSecretsmanager(stack, 'test-construct', props); + }; + // Assertion + expect(app).toThrowError('Error - Either provide secretProps or existingSecretObj, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts index 0f0612790..7996f9638 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts @@ -113,7 +113,6 @@ export class LambdaToSns extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToSnsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSnsProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts index 13eda1f42..b14523652 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts @@ -20,7 +20,6 @@ import { SqsToLambda } from '@aws-solutions-constructs/aws-sqs-lambda'; import { Construct } from 'constructs'; import { SqsEventSourceProps } from 'aws-cdk-lib/aws-lambda-event-sources'; import * as ec2 from "aws-cdk-lib/aws-ec2"; -import * as defaults from '@aws-solutions-constructs/core'; /** * @summary The properties for the LambdaToSqsToLambda class. @@ -131,7 +130,6 @@ export class LambdaToSqsToLambda extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToSqsToLambdaProps) { super(scope, id); - defaults.CheckProps(props); // Setup the aws-lambda-sqs pattern const lambdaToSqs = new LambdaToSqs(this, 'lambda-to-sqs', { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts index 7f8710fcc..5fa88501e 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts @@ -131,7 +131,6 @@ export class LambdaToSqs extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToSqsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSqsProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts index 0ae04d0b5..ef7d0279e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts @@ -94,7 +94,6 @@ export class LambdaToSsmstringparameter extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToSsmstringparameterProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts index e592e85d9..ab1cd7da8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts @@ -97,7 +97,6 @@ export class LambdaToStepfunctions extends Construct { */ constructor(scope: Construct, id: string, props: LambdaToStepfunctionsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckVpcProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-route53-alb/lib/index.ts index 6f4bb3489..2130e99b2 100644 --- a/source/patterns/@aws-solutions-constructs/aws-route53-alb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-route53-alb/lib/index.ts @@ -103,8 +103,6 @@ export class Route53ToAlb extends Construct { */ constructor(scope: Construct, id: string, props: Route53ToAlbProps) { super(scope, id); - defaults.CheckProps(props); - // NOTE: We don't call CheckAlbProps() here, because this construct creates an ALB // with no listener or target, so some of those checks don't apply this.PropsCustomCheck(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/lib/index.ts index d973cd623..1c18e8284 100755 --- a/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/lib/index.ts @@ -84,7 +84,6 @@ export class Route53ToApiGateway extends Construct { */ constructor(scope: Construct, id: string, props: Route53ToApiGatewayProps) { super(scope, id); - defaults.CheckProps(props); this.certificate = props.existingCertificateInterface; diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts index 74b2296f5..b334bcccd 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts @@ -89,7 +89,6 @@ export class S3ToLambda extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckS3Props(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts index 0df5c0718..5c522a454 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts @@ -129,7 +129,6 @@ export class S3ToSns extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckSnsProps(props); defaults.CheckS3Props(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts index 8a69d3e1e..cebd96705 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts @@ -139,7 +139,6 @@ export class S3ToSqs extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckSqsProps(props); defaults.CheckS3Props(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts index 496dea659..83fac8004 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts @@ -106,7 +106,6 @@ export class S3ToStepfunctions extends Construct { // context here rather than assuming the client will set it this.node.setContext("@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy", true); - defaults.CheckProps(props); defaults.CheckS3Props(props); let bucket: s3.IBucket; diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts index d1c959d83..f419afeed 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts @@ -85,7 +85,6 @@ export class SnsToLambda extends Construct { */ constructor(scope: Construct, id: string, props: SnsToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSnsProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts index e298db4c2..155ae4bf7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts @@ -115,7 +115,6 @@ export class SnsToSqs extends Construct { */ constructor(scope: Construct, id: string, props: SnsToSqsProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSnsProps(props); defaults.CheckSqsProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts index f07c49626..880b82c6a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts @@ -111,7 +111,6 @@ export class SqsToLambda extends Construct { */ constructor(scope: Construct, id: string, props: SqsToLambdaProps) { super(scope, id); - defaults.CheckProps(props); defaults.CheckSqsProps(props); defaults.CheckLambdaProps(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/lib/index.ts index b6cee9a87..ca3c4ae00 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/lib/index.ts @@ -53,7 +53,7 @@ export class WafwebaclToAlb extends Construct { */ constructor(scope: Construct, id: string, props: WafwebaclToAlbProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckWafWebAclProps(props); // CheckAlbProps() not called because this only accepts and existing Load Balancer // Build the Web ACL diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/test/test.wafwebacl-alb.test.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/test/test.wafwebacl-alb.test.ts index a8941e2ae..be7a1dadc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/test/test.wafwebacl-alb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/test/test.wafwebacl-alb.test.ts @@ -38,10 +38,7 @@ function deployConstruct(stack: cdk.Stack, webaclProps?: waf.CfnWebACLProps, exi }); } -// -------------------------------------------------------------- -// Test error handling for existing WAF web ACL and user provided web ACL props -// -------------------------------------------------------------- -test('Test error handling for existing WAF web ACL and user provider web ACL props', () => { +test('Confirm CheckWafWebAclProps is called', () => { const stack = new cdk.Stack(); const props: waf.CfnWebACLProps = { defaultAction: { @@ -64,7 +61,7 @@ test('Test error handling for existing WAF web ACL and user provider web ACL pro existingWebaclObj: wafAcl, webaclProps: props }); - }).toThrowError(); + }).toThrowError('Error - Either provide existingWebaclObj or webaclProps, but not both.\n'); }); // -------------------------------------------------------------- diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/lib/index.ts index fd7f4dae5..c7d3130ed 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/lib/index.ts @@ -54,7 +54,7 @@ export class WafwebaclToApiGateway extends Construct { */ constructor(scope: Construct, id: string, props: WafwebaclToApiGatewayProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckWafWebAclProps(props); // Build the Web ACL this.webacl = defaults.buildWebacl(this, 'REGIONAL', { diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/test/test.wafwebacl-apigateway.test.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/test/test.wafwebacl-apigateway.test.ts index cc6da5575..c1941167e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/test/test.wafwebacl-apigateway.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/test/test.wafwebacl-apigateway.test.ts @@ -30,7 +30,7 @@ function deployConstruct(stack: cdk.Stack, constructProps?: waf.CfnWebACLProps | return new WafwebaclToApiGateway(stack, 'test-wafwebacl-apigateway', props); } -test('Test error handling for existing WAF web ACL and user provider web ACL props', () => { +test('Confirm CheckWafWebAclProps is called', () => { const stack = new cdk.Stack(); const props: waf.CfnWebACLProps = { defaultAction: { @@ -53,7 +53,7 @@ test('Test error handling for existing WAF web ACL and user provider web ACL pro existingWebaclObj: wafAcl, webaclProps: props }); - }).toThrowError(); + }).toThrowError('Error - Either provide existingWebaclObj or webaclProps, but not both.\n'); }); test('Test default deployment', () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/lib/index.ts index 2215207ff..2fe981b31 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/lib/index.ts @@ -53,7 +53,7 @@ export class WafwebaclToAppsync extends Construct { */ constructor(scope: Construct, id: string, props: WafwebaclToAppsyncProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckWafWebAclProps(props); // Build the Web ACL this.webacl = defaults.buildWebacl(this, "REGIONAL", { diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/test/test.wafwebacl-appsync.test.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/test/test.wafwebacl-appsync.test.ts index 6b13384b6..bc5826048 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/test/test.wafwebacl-appsync.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-appsync/test/test.wafwebacl-appsync.test.ts @@ -40,10 +40,7 @@ function deployConstruct( }); } -// -------------------------------------------------------------- -// Test error handling for existing WAF web ACL and user provided web ACL props -// -------------------------------------------------------------- -test("Test error handling for existing WAF web ACL and user provider web ACL props", () => { +test('Confirm CheckWafWebAclProps is called', () => { const stack = new cdk.Stack(); const props: waf.CfnWebACLProps = { defaultAction: { @@ -66,7 +63,7 @@ test("Test error handling for existing WAF web ACL and user provider web ACL pro existingWebaclObj: wafAcl, webaclProps: props, }); - }).toThrowError(); + }).toThrowError('Error - Either provide existingWebaclObj or webaclProps, but not both.\n'); }); // -------------------------------------------------------------- diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/lib/index.ts index 757996dd5..457d481a7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/lib/index.ts @@ -57,7 +57,7 @@ export class WafwebaclToCloudFront extends Construct { */ constructor(scope: Construct, id: string, props: WafwebaclToCloudFrontProps) { super(scope, id); - defaults.CheckProps(props); + defaults.CheckWafWebAclProps(props); // Build the Web ACL this.webacl = defaults.buildWebacl(this, 'CLOUDFRONT', { diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/test/test.wafwebacl-cloudfront.test.ts b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/test/test.wafwebacl-cloudfront.test.ts index 77461d1d4..974c8ad18 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/test/test.wafwebacl-cloudfront.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/test/test.wafwebacl-cloudfront.test.ts @@ -37,7 +37,7 @@ function deployConstruct(stack: cdk.Stack, constructProps?: waf.CfnWebACLProps | return new WafwebaclToCloudFront(stack, 'test-wafwebacl-cloudfront', props); } -test('Test error handling for existing WAF web ACL and user provider web ACL props', () => { +test('Confirm CheckWafWebAclProps is called', () => { const stack = new cdk.Stack(); const props: waf.CfnWebACLProps = { defaultAction: { @@ -63,7 +63,7 @@ test('Test error handling for existing WAF web ACL and user provider web ACL pro existingWebaclObj: wafAcl, webaclProps: props }); - }).toThrowError(); + }).toThrowError('Error - Either provide existingWebaclObj or webaclProps, but not both.\n'); }); test('Test default deployment', () => { diff --git a/source/patterns/@aws-solutions-constructs/core/index.ts b/source/patterns/@aws-solutions-constructs/core/index.ts index c35ed2b18..29bc3741f 100644 --- a/source/patterns/@aws-solutions-constructs/core/index.ts +++ b/source/patterns/@aws-solutions-constructs/core/index.ts @@ -64,7 +64,6 @@ export * from './lib/glue-table-defaults'; export * from './lib/glue-table-helper'; export * from './lib/glue-database-defaults'; export * from './lib/glue-database-helper'; -export * from './lib/input-validation'; export * from './test/test-helper'; export * from './lib/ssm-string-parameter-helper'; export * from './lib/eventbridge-helper'; diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts index 0bbff36fe..19f7eec07 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts @@ -264,3 +264,22 @@ function getLoggingBucket( function getCloudfrontFunction(httpSecurityHeaders: boolean, scope: Construct) { return httpSecurityHeaders ? defaultCloudfrontFunction(scope) : undefined; } + +export interface CloudFrontProps { + readonly insertHttpSecurityHeaders?: boolean; + readonly responseHeadersPolicyProps?: cloudfront.ResponseHeadersPolicyProps; +} + +export function CheckCloudFrontProps(propsObject: CloudFrontProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.insertHttpSecurityHeaders !== false && propsObject.responseHeadersPolicyProps?.securityHeadersBehavior) { + errorMessages += 'responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts index 9d28b59b4..cf2cfe68b 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts @@ -70,7 +70,6 @@ export interface BuildDynamoDBTableResponse { * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. */ export function buildDynamoDBTable(scope: Construct, props: BuildDynamoDBTableProps): BuildDynamoDBTableResponse { - checkTableProps(props); // Conditional DynamoDB Table creation if (props.existingTableObj) { @@ -84,33 +83,6 @@ export function buildDynamoDBTable(scope: Construct, props: BuildDynamoDBTablePr } } -/** - * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. - */ -export function checkTableProps(props: BuildDynamoDBTableProps) { - let errorMessages = ''; - let errorFound = false; - - if (props.dynamoTableProps && props.existingTableObj) { - errorMessages += 'Error - Either provide existingTableObj or dynamoTableProps, but not both.\n'; - errorFound = true; - } - - if (props.dynamoTableProps && props.existingTableInterface) { - errorMessages += 'Error - Either provide existingTableInterface or dynamoTableProps, but not both.\n'; - errorFound = true; - } - - if (props.existingTableObj && props.existingTableInterface) { - errorMessages += 'Error - Either provide existingTableInterface or existingTableObj, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - export interface BuildDynamoDBTableWithStreamResponse { readonly tableInterface: dynamodb.ITable, readonly tableObject?: dynamodb.Table, @@ -143,3 +115,33 @@ export function getPartitionKeyNameFromTable(table: dynamodb.Table): string { } return partitionKey.attributeName; } + +export interface DynamoDBProps { + readonly dynamoTableProps?: dynamodb.TableProps, + readonly existingTableObj?: dynamodb.Table, + readonly existingTableInterface?: dynamodb.ITable, +} + +export function CheckDynamoDBProps(propsObject: DynamoDBProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.dynamoTableProps && propsObject.existingTableObj) { + errorMessages += 'Error - Either provide existingTableObj or dynamoTableProps, but not both.\n'; + errorFound = true; + } + + if (propsObject.dynamoTableProps && propsObject.existingTableInterface) { + errorMessages += 'Error - Either provide existingTableInterface or dynamoTableProps, but not both.\n'; + errorFound = true; + } + + if (propsObject.existingTableObj && propsObject.existingTableInterface) { + errorMessages += 'Error - Either provide existingTableInterface or existingTableObj, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/eventbridge-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/eventbridge-helper.ts index 469ca514f..819ec3bfd 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/eventbridge-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/eventbridge-helper.ts @@ -49,4 +49,23 @@ export function buildEventBus(scope: Construct, props: BuildEventBusProps): even } // ESLint requires this return statement, so disabling SonarQube warning return; // NOSONAR -} \ No newline at end of file +} + +export interface EventBridgeProps { + readonly existingEventBusInterface: events.IEventBus, + readonly eventBusProps: events.EventBusProps +} + +export function CheckEventBridgeProps(propsObject: EventBridgeProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingEventBusInterface && propsObject.eventBusProps) { + errorMessages += 'Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/glue-table-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/glue-table-helper.ts index 077dd3768..4939a26be 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/glue-table-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/glue-table-helper.ts @@ -18,6 +18,8 @@ import { CfnTable, CfnTableProps } from "aws-cdk-lib/aws-glue"; import { Construct } from "constructs"; +import * as glue from 'aws-cdk-lib/aws-glue'; +import * as s3assets from 'aws-cdk-lib/aws-s3-assets'; /** * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. @@ -34,3 +36,47 @@ import { Construct } from "constructs"; export function DefaultGlueTable(scope: Construct, tableProps: CfnTableProps): CfnTable { return new CfnTable(scope, 'GlueTable', tableProps); } +export interface GlueProps { + readonly existingGlueJob?: glue.CfnJob, + readonly etlCodeAsset?: s3assets.Asset; + readonly glueJobProps?: glue.CfnJobProps | any; + readonly fieldSchema?: glue.CfnTable.ColumnProperty[]; + readonly existingTable?: glue.CfnTable; + readonly tablePropss?: glue.CfnTableProps; +} + +export function CheckGlueProps(propsObject: GlueProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.glueJobProps && propsObject.existingGlueJob) { + errorMessages += 'Error - Either provide glueJobProps or existingGlueJob, but not both.\n'; + errorFound = true; + } + + if ((!propsObject.existingGlueJob) && (!propsObject.glueJobProps.command.scriptLocation && !propsObject.etlCodeAsset)) { + errorMessages += ('Either one of CfnJob.JobCommandProperty.scriptLocation or etlCodeAsset has ' + + 'to be provided. If the ETL Job code file exists in a local filesystem, please set ' + + 'KinesisstreamsToGluejobProps.etlCodeAsset. If the ETL Job is available in an S3 bucket, set the ' + + 'CfnJob.JobCommandProperty.scriptLocation property\n'); + errorFound = true; + } + + if (propsObject.glueJobProps?.command?.scriptLocation) { + const s3Url: string = propsObject.glueJobProps.command.scriptLocation; + const found = s3Url.match(/^s3:\/\/\S+\/\S+/g); + if (!(found && found.length > 0 && found[0].length === s3Url.length)) { + errorMessages += "Invalid S3 URL for Glue script provided\n"; + errorFound = true; + } + } + + if (propsObject.fieldSchema === undefined && propsObject.existingTable === undefined && propsObject.tableProps === undefined) { + errorMessages += "Either fieldSchema or table property has to be set, both cannot be omitted"; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/input-validation.ts b/source/patterns/@aws-solutions-constructs/core/lib/input-validation.ts deleted file mode 100644 index 654d73ef1..000000000 --- a/source/patterns/@aws-solutions-constructs/core/lib/input-validation.ts +++ /dev/null @@ -1,375 +0,0 @@ -/** - * Copyright 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. A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ - -/* - * The functions found here in the core library are for internal use and can be changed - * or removed outside of a major release. We recommend against calling them directly from client code. - */ - -import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; -import * as kinesis from 'aws-cdk-lib/aws-kinesis'; -import * as lambda from 'aws-cdk-lib/aws-lambda'; -import * as sqs from 'aws-cdk-lib/aws-sqs'; -import * as mediastore from 'aws-cdk-lib/aws-mediastore'; -import * as s3 from 'aws-cdk-lib/aws-s3'; -import * as ec2 from 'aws-cdk-lib/aws-ec2'; -import * as sns from 'aws-cdk-lib/aws-sns'; -import * as glue from 'aws-cdk-lib/aws-glue'; -import * as sagemaker from 'aws-cdk-lib/aws-sagemaker'; -import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; -import * as kms from "aws-cdk-lib/aws-kms"; -import { ResponseHeadersPolicyProps } from "aws-cdk-lib/aws-cloudfront"; -import * as opensearch from "aws-cdk-lib/aws-opensearchservice"; -import * as s3assets from "aws-cdk-lib/aws-s3-assets"; - -export interface VerifiedProps { - readonly existingStreamObj?: kinesis.Stream; - readonly kinesisStreamProps?: kinesis.StreamProps, - - readonly existingSecretObj?: secretsmanager.Secret; - readonly secretProps?: secretsmanager.SecretProps; - - readonly encryptionKey?: kms.Key, - readonly encryptionKeyProps?: kms.KeyProps - - readonly insertHttpSecurityHeaders?: boolean; - readonly responseHeadersPolicyProps?: ResponseHeadersPolicyProps; - readonly openSearchDomainProps?: opensearch.CfnDomainProps; - -} - -/** - * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. - */ -export function CheckProps(propsObject: VerifiedProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.existingStreamObj && propsObject.kinesisStreamProps) { - errorMessages += 'Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'; - errorFound = true; - } - - if (propsObject.existingSecretObj && propsObject.secretProps) { - errorMessages += 'Error - Either provide secretProps or existingSecretObj, but not both.\n'; - errorFound = true; - } - - if (propsObject.encryptionKey && propsObject.encryptionKeyProps) { - errorMessages += 'Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'; - errorFound = true; - } - - if (propsObject.existingEventBusInterface && propsObject.eventBusProps) { - errorMessages += 'Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'; - errorFound = true; - } - - if (propsObject.existingWebaclObj && propsObject.webaclProps) { - errorMessages += 'Error - Either provide existingWebaclObj or webaclProps, but not both.\n'; - errorFound = true; - } - - if (propsObject.insertHttpSecurityHeaders !== false && propsObject.responseHeadersPolicyProps?.securityHeadersBehavior) { - errorMessages += 'responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'; - errorFound = true; - } - - if (propsObject.openSearchDomainProps?.vpcOptions) { - errorMessages += "Error - Define VPC using construct parameters not the OpenSearch Service props\n"; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface GlueProps { - readonly existingGlueJob?: glue.CfnJob, - readonly etlCodeAsset?: s3assets.Asset; - readonly glueJobProps?: glue.CfnJobProps | any; - readonly fieldSchema?: glue.CfnTable.ColumnProperty[]; - readonly existingTable?: glue.CfnTable; - readonly tablePropss?: glue.CfnTableProps; -} - -export function CheckGlueProps(propsObject: GlueProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.glueJobProps && propsObject.existingGlueJob) { - errorMessages += 'Error - Either provide glueJobProps or existingGlueJob, but not both.\n'; - errorFound = true; - } - - if ((!propsObject.existingGlueJob) && (!propsObject.glueJobProps.command.scriptLocation && !propsObject.etlCodeAsset)) { - errorMessages += ('Either one of CfnJob.JobCommandProperty.scriptLocation or etlCodeAsset has ' + - 'to be provided. If the ETL Job code file exists in a local filesystem, please set ' + - 'KinesisstreamsToGluejobProps.etlCodeAsset. If the ETL Job is available in an S3 bucket, set the ' + - 'CfnJob.JobCommandProperty.scriptLocation property\n'); - errorFound = true; - } - - if (propsObject.glueJobProps?.command?.scriptLocation) { - const s3Url: string = propsObject.glueJobProps.command.scriptLocation; - const found = s3Url.match(/^s3:\/\/\S+\/\S+/g); - if (!(found && found.length > 0 && found[0].length === s3Url.length)) { - errorMessages += "Invalid S3 URL for Glue script provided\n"; - errorFound = true; - } - } - - if (propsObject.fieldSchema === undefined && propsObject.existingTable === undefined && propsObject.tableProps === undefined) { - errorMessages += "Either fieldSchema or table property has to be set, both cannot be omitted"; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface DynamoDBProps { - readonly dynamoTableProps?: dynamodb.TableProps, - readonly existingTableObj?: dynamodb.Table, - readonly existingTableInterface?: dynamodb.ITable, -} - -export function CheckDynamoDBProps(propsObject: DynamoDBProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.dynamoTableProps && propsObject.existingTableObj) { - errorMessages += 'Error - Either provide existingTableObj or dynamoTableProps, but not both.\n'; - errorFound = true; - } - - if (propsObject.dynamoTableProps && propsObject.existingTableInterface) { - errorMessages += 'Error - Either provide existingTableInterface or dynamoTableProps, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface SnsProps { - readonly topicProps?: sns.TopicProps, - readonly existingTopicObj?: sns.Topic, - readonly existingTopicObject?: sns.Topic, - readonly encryptionKey?: kms.Key, - readonly encryptionKeyProps?: kms.KeyProps -} - -export function CheckSnsProps(propsObject: SnsProps | any) { - let errorMessages = ''; - let errorFound = false; - - // FargateToSns used TopicObject instead of TopicObj - to fix would be a breaking change, so we - // must look for both here. - if (propsObject.topicProps && (propsObject.existingTopicObj || propsObject.existingTopicObject)) { - errorMessages += 'Error - Either provide topicProps or existingTopicObj, but not both.\n'; - errorFound = true; - } - - if (propsObject.topicProps?.masterKey && propsObject.encryptionKey) { - errorMessages += 'Error - Either provide topicProps.masterKey or encryptionKey, but not both.\n'; - errorFound = true; - } - - if (propsObject.topicProps?.masterKey && propsObject.encryptionKeyProps) { - errorMessages += 'Error - Either provide topicProps.masterKey or encryptionKeyProps, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface SqsProps { - readonly existingQueueObj?: sqs.Queue, - readonly queueProps?: sqs.QueueProps, - readonly deployDeadLetterQueue?: boolean, - readonly deadLetterQueueProps?: sqs.QueueProps, - readonly encryptionKey?: kms.Key, - readonly encryptionKeyProps?: kms.KeyProps -} - -export function CheckSqsProps(propsObject: SqsProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.existingQueueObj && propsObject.queueProps) { - errorMessages += 'Error - Either provide queueProps or existingQueueObj, but not both.\n'; - errorFound = true; - } - - if (propsObject.queueProps?.encryptionMasterKey && propsObject.encryptionKey) { - errorMessages += 'Error - Either provide queueProps.encryptionMasterKey or encryptionKey, but not both.\n'; - errorFound = true; - } - - if (propsObject.queueProps?.encryptionMasterKey && propsObject.encryptionKeyProps) { - errorMessages += 'Error - Either provide queueProps.encryptionMasterKey or encryptionKeyProps, but not both.\n'; - errorFound = true; - } - - if ((propsObject?.deployDeadLetterQueue === false) && propsObject.deadLetterQueueProps) { - errorMessages += 'Error - If deployDeadLetterQueue is false then deadLetterQueueProps cannot be specified.\n'; - errorFound = true; - } - - const isQueueFifo: boolean = propsObject?.queueProps?.fifo; - const isDeadLetterQueueFifo: boolean = propsObject?.deadLetterQueueProps?.fifo; - const deployDeadLetterQueue: boolean = propsObject.deployDeadLetterQueue || propsObject.deployDeadLetterQueue === undefined; - - if (deployDeadLetterQueue && (isQueueFifo !== isDeadLetterQueueFifo)) { - errorMessages += 'Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + - 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface S3Props { - readonly existingBucketObj?: s3.Bucket, - readonly existingBucketInterface?: s3.IBucket, - readonly bucketProps?: s3.BucketProps, - readonly existingLoggingBucketObj?: s3.IBucket; - readonly loggingBucketProps?: s3.BucketProps; - readonly logS3AccessLogs?: boolean; -} - -export function CheckS3Props(propsObject: S3Props | any) { - let errorMessages = ''; - let errorFound = false; - - if ((propsObject.existingBucketObj || propsObject.existingBucketInterface) && propsObject.bucketProps) { - errorMessages += 'Error - Either provide bucketProps or existingBucketObj, but not both.\n'; - errorFound = true; - } - - if (propsObject.existingLoggingBucketObj && propsObject.loggingBucketProps) { - errorMessages += 'Error - Either provide existingLoggingBucketObj or loggingBucketProps, but not both.\n'; - errorFound = true; - } - - if ((propsObject?.logS3AccessLogs === false) && (propsObject.loggingBucketProps || propsObject.existingLoggingBucketObj)) { - errorMessages += 'Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'; - errorFound = true; - } - - if (propsObject.existingBucketObj && (propsObject.loggingBucketProps || propsObject.logS3AccessLogs)) { - errorMessages += 'Error - If existingBucketObj is provided, supplying loggingBucketProps or logS3AccessLogs is an error.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface VpcPropsSet { - readonly existingVpc?: ec2.IVpc; - readonly vpcProps?: ec2.VpcProps; - readonly deployVpc?: boolean; - -} - -export function CheckVpcProps(propsObject: VpcPropsSet | any) { - let errorMessages = ''; - let errorFound = false; - - if ((propsObject.deployVpc || propsObject.vpcProps) && propsObject.existingVpc) { - errorMessages += 'Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface LambdaProps { - readonly existingLambdaObj?: lambda.Function, - readonly lambdaFunctionProps?: lambda.FunctionProps, -} - -export function CheckLambdaProps(propsObject: LambdaProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.existingLambdaObj && propsObject.lambdaFunctionProps) { - errorMessages += 'Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface MediaStoreProps { - readonly existingMediaStoreContainerObj?: mediastore.CfnContainer; - readonly mediaStoreContainerProps?: mediastore.CfnContainerProps; -} - -export function CheckMediaStoreProps(propsObject: MediaStoreProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.existingMediaStoreContainerObj && propsObject.mediaStoreContainerProps) { - errorMessages += 'Error - Either provide mediaStoreContainerProps or existingMediaStoreContainerObj, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -export interface SagemakerProps { - readonly existingSagemakerEndpointObj?: sagemaker.CfnEndpoint, - readonly endpointProps?: sagemaker.CfnEndpointProps, -} - -export function CheckSagemakerProps(propsObject: SagemakerProps | any) { - let errorMessages = ''; - let errorFound = false; - - if (propsObject.existingSagemakerEndpointObj && propsObject.endpointProps) { - errorMessages += 'Error - Either provide endpointProps or existingSagemakerEndpointObj, but not both.\n'; - errorFound = true; - } - - if (errorFound) { - throw new Error(errorMessages); - } -} - -/** - * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. - */ -export function CheckListValues(allowedPermissions: string[], submittedValues: string[], valueType: string) { - submittedValues.forEach((submittedValue) => { - if (!allowedPermissions.includes(submittedValue)) { - throw Error(`Invalid ${valueType} submitted - ${submittedValue}`); - } - }); -} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts index f366dafc8..050fbd956 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts @@ -95,4 +95,23 @@ export function buildKinesisStreamCWAlarms(scope: Construct): cloudwatch.Alarm[] })); return alarms; -} \ No newline at end of file +} + +export interface KinesisStreamProps { + readonly existingStreamObj?: kinesis.Stream; + readonly kinesisStreamProps?: kinesis.StreamProps, +} + +export function CheckKinesisStreamProps(propsObject: KinesisStreamProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingStreamObj && propsObject.kinesisStreamProps) { + errorMessages += 'Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts index ebcb5c859..0a0989c4e 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts @@ -237,3 +237,22 @@ export function getLambdaVpcSecurityGroupIds(lambdaFunction: lambda.Function): s return securityGroupIds; } + +export interface LambdaProps { + readonly existingLambdaObj?: lambda.Function, + readonly lambdaFunctionProps?: lambda.FunctionProps, +} + +export function CheckLambdaProps(propsObject: LambdaProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingLambdaObj && propsObject.lambdaFunctionProps) { + errorMessages += 'Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/mediastore-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/mediastore-helper.ts index b8428283c..4ce2f08d8 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/mediastore-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/mediastore-helper.ts @@ -39,4 +39,23 @@ export function MediaStoreContainer(scope: Construct, mediaStoreContainerProps?: mediaStoreContainer.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.RETAIN; return mediaStoreContainer; -} \ No newline at end of file +} + +export interface MediaStoreProps { + readonly existingMediaStoreContainerObj?: mediastore.CfnContainer; + readonly mediaStoreContainerProps?: mediastore.CfnContainerProps; +} + +export function CheckMediaStoreProps(propsObject: MediaStoreProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingMediaStoreContainerObj && propsObject.mediaStoreContainerProps) { + errorMessages += 'Error - Either provide mediaStoreContainerProps or existingMediaStoreContainerObj, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts index 7393177e3..6aa3124e2 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts @@ -305,3 +305,21 @@ function createDashboardCognitoRole( cognitoDashboardConfigureRolePolicy.attachToRole(cognitoDashboardConfigureRole); return cognitoDashboardConfigureRole; } + +export interface OpenSearchProps { + readonly openSearchDomainProps?: opensearch.CfnDomainProps; +} + +export function CheckOpenSearchProps(propsObject: OpenSearchProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.openSearchDomainProps?.vpcOptions) { + errorMessages += "Error - Define VPC using construct parameters not the OpenSearch Service props\n"; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts index 799ebe876..adcf285f6 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts @@ -238,3 +238,41 @@ export function addCfnNagS3BucketNotificationRulesToSuppress(stackRoot: cdk.Stac } ]); } + +export interface S3Props { + readonly existingBucketObj?: s3.Bucket, + readonly existingBucketInterface?: s3.IBucket, + readonly bucketProps?: s3.BucketProps, + readonly existingLoggingBucketObj?: s3.IBucket; + readonly loggingBucketProps?: s3.BucketProps; + readonly logS3AccessLogs?: boolean; +} + +export function CheckS3Props(propsObject: S3Props | any) { + let errorMessages = ''; + let errorFound = false; + + if ((propsObject.existingBucketObj || propsObject.existingBucketInterface) && propsObject.bucketProps) { + errorMessages += 'Error - Either provide bucketProps or existingBucketObj, but not both.\n'; + errorFound = true; + } + + if (propsObject.existingLoggingBucketObj && propsObject.loggingBucketProps) { + errorMessages += 'Error - Either provide existingLoggingBucketObj or loggingBucketProps, but not both.\n'; + errorFound = true; + } + + if ((propsObject?.logS3AccessLogs === false) && (propsObject.loggingBucketProps || propsObject.existingLoggingBucketObj)) { + errorMessages += 'Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'; + errorFound = true; + } + + if (propsObject.existingBucketObj && (propsObject.loggingBucketProps || propsObject.logS3AccessLogs)) { + errorMessages += 'Error - If existingBucketObj is provided, supplying loggingBucketProps or logS3AccessLogs is an error.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts index e835260fd..24e3b84d4 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts @@ -550,3 +550,22 @@ export function createSagemakerEndpoint( return endpoint; } + +export interface SagemakerProps { + readonly existingSagemakerEndpointObj?: sagemaker.CfnEndpoint, + readonly endpointProps?: sagemaker.CfnEndpointProps, +} + +export function CheckSagemakerProps(propsObject: SagemakerProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingSagemakerEndpointObj && propsObject.endpointProps) { + errorMessages += 'Error - Either provide endpointProps or existingSagemakerEndpointObj, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/secretsmanager-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/secretsmanager-helper.ts index 095c96271..84c0c0d20 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/secretsmanager-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/secretsmanager-helper.ts @@ -16,7 +16,7 @@ * or removed outside of a major release. We recommend against calling them directly from client code. */ -import { Secret, SecretProps } from 'aws-cdk-lib/aws-secretsmanager'; +import * as secrets from 'aws-cdk-lib/aws-secretsmanager'; // Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate import { Construct } from 'constructs'; import { DefaultSecretProps } from './secretsmanager-defaults'; @@ -31,10 +31,10 @@ import { consolidateProps, addCfnSuppressRules } from './utils'; * @param id * @param secretProps */ -export function buildSecretsManagerSecret(scope: Construct, id: string, secretProps?: SecretProps): Secret { - let secret: Secret; +export function buildSecretsManagerSecret(scope: Construct, id: string, secretProps?: secrets.SecretProps): secrets.Secret { + let secret: secrets.Secret; - secret = new Secret(scope, id, consolidateProps(DefaultSecretProps, secretProps)); + secret = new secrets.Secret(scope, id, consolidateProps(DefaultSecretProps, secretProps)); // suppress warning on build addCfnSuppressRules(secret, [ @@ -46,3 +46,22 @@ export function buildSecretsManagerSecret(scope: Construct, id: string, secretPr return secret; } + +export interface SecretsManagerProps { + readonly existingSecretObj?: secrets.Secret; + readonly secretProps?: secrets.SecretProps; +} + +export function CheckSecretsManagerProps(propsObject: SecretsManagerProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingSecretObj && propsObject.secretProps) { + errorMessages += 'Error - Either provide secretProps or existingSecretObj, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts index 883a82b92..b82075a24 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts @@ -172,3 +172,42 @@ export function buildTopic(scope: Construct, props: BuildTopicProps): BuildTopic return { topic: props.existingTopicObj, key: props.existingTopicEncryptionKey }; } } + +export interface SnsProps { + readonly topicProps?: sns.TopicProps, + readonly existingTopicObj?: sns.Topic, + readonly existingTopicObject?: sns.Topic, + readonly encryptionKey?: kms.Key, + readonly encryptionKeyProps?: kms.KeyProps +} + +export function CheckSnsProps(propsObject: SnsProps | any) { + let errorMessages = ''; + let errorFound = false; + + // FargateToSns used TopicObject instead of TopicObj - to fix would be a breaking change, so we + // must look for both here. + if (propsObject.topicProps && (propsObject.existingTopicObj || propsObject.existingTopicObject)) { + errorMessages += 'Error - Either provide topicProps or existingTopicObj, but not both.\n'; + errorFound = true; + } + + if (propsObject.topicProps?.masterKey && propsObject.encryptionKey) { + errorMessages += 'Error - Either provide topicProps.masterKey or encryptionKey, but not both.\n'; + errorFound = true; + } + + if (propsObject.topicProps?.masterKey && propsObject.encryptionKeyProps) { + errorMessages += 'Error - Either provide topicProps.masterKey or encryptionKeyProps, but not both.\n'; + errorFound = true; + } + + if (propsObject.encryptionKey && propsObject.encryptionKeyProps) { + errorMessages += 'Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts index 0d93060ee..4328319a7 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts @@ -227,4 +227,57 @@ function applySecureQueuePolicy(queue: sqs.Queue): void { } }) ); -} \ No newline at end of file +} + +export interface SqsProps { + readonly existingQueueObj?: sqs.Queue, + readonly queueProps?: sqs.QueueProps, + readonly deployDeadLetterQueue?: boolean, + readonly deadLetterQueueProps?: sqs.QueueProps, + readonly encryptionKey?: kms.Key, + readonly encryptionKeyProps?: kms.KeyProps +} + +export function CheckSqsProps(propsObject: SqsProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingQueueObj && propsObject.queueProps) { + errorMessages += 'Error - Either provide queueProps or existingQueueObj, but not both.\n'; + errorFound = true; + } + + if (propsObject.queueProps?.encryptionMasterKey && propsObject.encryptionKey) { + errorMessages += 'Error - Either provide queueProps.encryptionMasterKey or encryptionKey, but not both.\n'; + errorFound = true; + } + + if (propsObject.queueProps?.encryptionMasterKey && propsObject.encryptionKeyProps) { + errorMessages += 'Error - Either provide queueProps.encryptionMasterKey or encryptionKeyProps, but not both.\n'; + errorFound = true; + } + + if (propsObject.encryptionKey && propsObject.encryptionKeyProps) { + errorMessages += 'Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'; + errorFound = true; + } + + if ((propsObject?.deployDeadLetterQueue === false) && propsObject.deadLetterQueueProps) { + errorMessages += 'Error - If deployDeadLetterQueue is false then deadLetterQueueProps cannot be specified.\n'; + errorFound = true; + } + + const isQueueFifo: boolean = propsObject?.queueProps?.fifo; + const isDeadLetterQueueFifo: boolean = propsObject?.deadLetterQueueProps?.fifo; + const deployDeadLetterQueue: boolean = propsObject.deployDeadLetterQueue || propsObject.deployDeadLetterQueue === undefined; + + if (deployDeadLetterQueue && (isQueueFifo !== isDeadLetterQueueFifo)) { + errorMessages += 'Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + + 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/utils.ts b/source/patterns/@aws-solutions-constructs/core/lib/utils.ts index 324bf91ac..5a0e065cd 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/utils.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/utils.ts @@ -256,3 +256,14 @@ export function generateName(scope: Construct, resourceId: string = ""): string } return name; } + +/** + * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. + */ +export function CheckListValues(allowedPermissions: string[], submittedValues: string[], valueType: string) { + submittedValues.forEach((submittedValue) => { + if (!allowedPermissions.includes(submittedValue)) { + throw Error(`Invalid ${valueType} submitted - ${submittedValue}`); + } + }); +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts index 6ca739ca4..f880b9356 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts @@ -270,4 +270,24 @@ export function retrievePrivateSubnetIds(vpc: ec2.IVpc) { }; return vpc.selectSubnets(subnetSelector).subnetIds; -} \ No newline at end of file +} + +export interface VpcPropsSet { + readonly existingVpc?: ec2.IVpc; + readonly vpcProps?: ec2.VpcProps; + readonly deployVpc?: boolean; +} + +export function CheckVpcProps(propsObject: VpcPropsSet | any) { + let errorMessages = ''; + let errorFound = false; + + if ((propsObject.deployVpc || propsObject.vpcProps) && propsObject.existingVpc) { + errorMessages += 'Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} diff --git a/source/patterns/@aws-solutions-constructs/core/lib/waf-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/waf-helper.ts index 3f4b51c97..67a03a9ea 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/waf-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/waf-helper.ts @@ -50,3 +50,22 @@ export function buildWebacl(scope: Construct, webaclScope: string, props: BuildW return webAcl; } + +export interface WafWebAclProps { + readonly existingWebaclObj: waf.CfnWebACL, + readonly webaclProps: waf.CfnWebACLProps, +} + +export function CheckWafWebAclProps(propsObject: WafWebAclProps | any) { + let errorMessages = ''; + let errorFound = false; + + if (propsObject.existingWebaclObj && propsObject.webaclProps) { + errorMessages += 'Error - Either provide existingWebaclObj or webaclProps, but not both.\n'; + errorFound = true; + } + + if (errorFound) { + throw new Error(errorMessages); + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts index 047d61509..71bf22f6f 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts @@ -21,6 +21,7 @@ import { Bucket } from 'aws-cdk-lib/aws-s3'; import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; import { LambdaEdgeEventType } from 'aws-cdk-lib/aws-cloudfront'; import * as acm from 'aws-cdk-lib/aws-certificatemanager'; +import * as defaults from '../'; test('check bucket policy metadata', () => { const stack = new Stack(); @@ -539,3 +540,23 @@ test('test cloudfront override cloudfront custom domain names ', () => { } }); }); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test CloudFront insertHttpHeaders bad props', () => { + + const props: defaults.CloudFrontProps = { + insertHttpSecurityHeaders: true, + responseHeadersPolicyProps: { + securityHeadersBehavior: {} + } + }; + + const app = () => { + defaults.CheckCloudFrontProps(props); + }; + + // Assertion + expect(app).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts b/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts index 70c50ee08..c995e14b7 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts @@ -421,74 +421,37 @@ test('test getPartitionKeyNameFromTable()', () => { expect(testKeyName).toEqual(partitionKeyName); }); -test('Test providing both existingTableInterface and existingTableObj', () => { +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail DynamoDB table check', () => { const stack = new Stack(); - const tableProps: dynamodb.TableProps = { - partitionKey: { - name: 'table_id', - type: dynamodb.AttributeType.STRING - }, - stream: dynamodb.StreamViewType.NEW_IMAGE + const props: defaults.DynamoDBProps = { + existingTableObj: new dynamodb.Table(stack, 'placeholder', defaults.DefaultTableProps), + dynamoTableProps: defaults.DefaultTableProps, }; - const existingTableInterface = new dynamodb.Table(stack, 'DynamoTable', tableProps) - ; - const newProps = { - existingTableInterface, - existingTableObj: existingTableInterface - }; const app = () => { - defaults.buildDynamoDBTable(stack, newProps); + defaults.CheckDynamoDBProps(props); }; - expect(app).toThrowError('Error - Either provide existingTableInterface or existingTableObj, but not both.\n'); + // Assertion + expect(app).toThrowError('Error - Either provide existingTableObj or dynamoTableProps, but not both.\n'); }); -test('Test providing both existingTableInterface and dynamoTableProps', () => { +test('Test fail DynamoDB table check (for interface AND obj)', () => { const stack = new Stack(); - const dynamoTableProps: dynamodb.TableProps = { - partitionKey: { - name: 'table_id', - type: dynamodb.AttributeType.STRING - }, - stream: dynamodb.StreamViewType.NEW_IMAGE + const props: defaults.DynamoDBProps = { + existingTableInterface: new dynamodb.Table(stack, 'placeholder', defaults.DefaultTableProps), + existingTableObj: new dynamodb.Table(stack, 'placeholderobj', defaults.DefaultTableProps), }; - const existingTableInterface = new dynamodb.Table(stack, 'DynamoTable', dynamoTableProps) - ; - const newProps = { - existingTableInterface, - dynamoTableProps - }; const app = () => { - defaults.buildDynamoDBTable(stack, newProps); + defaults.CheckDynamoDBProps(props); }; - expect(app).toThrowError('Error - Either provide existingTableInterface or dynamoTableProps, but not both.\n'); + // Assertion + expect(app).toThrowError('Error - Either provide existingTableInterface or existingTableObj, but not both.\n'); }); - -test('Test providing both existingTableObj and dynamoTableProps', () => { - const stack = new Stack(); - - const dynamoTableProps: dynamodb.TableProps = { - partitionKey: { - name: 'table_id', - type: dynamodb.AttributeType.STRING - }, - stream: dynamodb.StreamViewType.NEW_IMAGE - }; - - const existingTableObj = new dynamodb.Table(stack, 'DynamoTable', dynamoTableProps) - ; - const newProps = { - existingTableObj, - dynamoTableProps - }; - const app = () => { - defaults.buildDynamoDBTable(stack, newProps); - }; - - expect(app).toThrowError('Error - Either provide existingTableObj or dynamoTableProps, but not both.\n'); -}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/eventbridge-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/eventbridge-helper.test.ts index a9b81c64f..c2b4c0b9a 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/eventbridge-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/eventbridge-helper.test.ts @@ -63,4 +63,24 @@ test('Test deployment with new EventBus with props', () => { Template.fromStack(stack).hasResourceProperties('AWS::Events::EventBus', { Name: 'testneweventbus' }); -}); \ No newline at end of file +}); + +// --------------------------- +// Prop Tests +// --------------------------- + +test('Test fail EventBridge bad bus props', () => { + const stack = new Stack(); + + const props: defaults.EventBridgeProps = { + existingEventBusInterface: new events.EventBus(stack, 'test', {}), + eventBusProps: {} + }; + + const app = () => { + defaults.CheckEventBridgeProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide existingEventBusInterface or eventBusProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts index f116c94bc..9a2e159d8 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts @@ -18,6 +18,7 @@ import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; import { Bucket, BucketEncryption } from 'aws-cdk-lib/aws-s3'; import { RemovalPolicy, Stack } from "aws-cdk-lib"; import * as defaults from '..'; +import * as iam from 'aws-cdk-lib/aws-iam'; test('Test deployment with role creation', () => { // Stack @@ -515,3 +516,103 @@ test('Cannot use maxCapacity and WorkerType, so error out', () => { expect(error).toBeInstanceOf(Error); } }); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail Glue job check', () => { + const stack = new Stack(); + + const _jobRole = new iam.Role(stack, 'CustomETLJobRole', { + assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') + }); + + const jobProps: CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { + command: { + name: 'glueetl', + pythonVersion: '3', + scriptLocation: new Bucket(stack, 'ScriptBucket').bucketArn, + }, + role: new iam.Role(stack, 'JobRole', { + assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') + }).roleArn + }, 'testETLJob', {}); + + const job = new CfnJob(stack, 'placeholder', jobProps); + + const props: defaults.GlueProps = { + glueJobProps: jobProps, + existingGlueJob: job + }; + + const app = () => { + defaults.CheckGlueProps(props); + }; + + // Assertion + expect(app).toThrowError("Error - Either provide glueJobProps or existingGlueJob, but not both.\n"); +}); + +test('Test bad Glue script location', () => { + const stack = new Stack(); + + const _jobRole = new iam.Role(stack, 'CustomETLJobRole', { + assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') + }); + + const jobProps: CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { + command: { + name: 'glueetl', + pythonVersion: '3', + scriptLocation: "s://bad/url", + }, + role: new iam.Role(stack, 'JobRole', { + assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') + }).roleArn + }, 'testETLJob', {}); + + const props: defaults.GlueProps = { + glueJobProps: jobProps, + }; + + const app = () => { + defaults.CheckGlueProps(props); + }; + + // Assertion + expect(app).toThrowError('Invalid S3 URL for Glue script provided\n'); +}); + +test('Test missing Glue script location', () => { + const stack = new Stack(); + + const _jobRole = new iam.Role(stack, 'CustomETLJobRole', { + assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') + }); + + const jobProps: CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { + command: { + name: 'glueetl', + pythonVersion: '3', + }, + role: new iam.Role(stack, 'JobRole', { + assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') + }).roleArn + }, 'testETLJob', {}); + + const props: defaults.GlueProps = { + glueJobProps: jobProps, + }; + + const app = () => { + defaults.CheckGlueProps(props); + }; + + const expectedError: string = 'Either one of CfnJob.JobCommandProperty.scriptLocation or etlCodeAsset has ' + + 'to be provided. If the ETL Job code file exists in a local filesystem, please set ' + + 'KinesisstreamsToGluejobProps.etlCodeAsset. If the ETL Job is available in an S3 bucket, set the ' + + 'CfnJob.JobCommandProperty.scriptLocation property\n'; + + // Assertion + expect(app).toThrowError(expectedError); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts b/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts deleted file mode 100644 index f9a7caf2a..000000000 --- a/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts +++ /dev/null @@ -1,679 +0,0 @@ -/** - * Copyright 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. A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ - -// Imports -import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; -import * as glue from 'aws-cdk-lib/aws-glue'; -import * as iam from 'aws-cdk-lib/aws-iam'; -import * as kinesis from 'aws-cdk-lib/aws-kinesis'; -import * as kms from 'aws-cdk-lib/aws-kms'; -import * as lambda from 'aws-cdk-lib/aws-lambda'; -import * as mediastore from 'aws-cdk-lib/aws-mediastore'; -import * as s3 from 'aws-cdk-lib/aws-s3'; -import * as sns from 'aws-cdk-lib/aws-sns'; -import * as sqs from 'aws-cdk-lib/aws-sqs'; -import { Stack } from 'aws-cdk-lib'; -import * as defaults from '../'; -import { MediaStoreContainerProps } from '../lib/mediastore-defaults'; -import { BuildSagemakerEndpoint } from '../lib/sagemaker-helper'; -import { CreateScrapBucket } from './test-helper'; - -test('Test with valid props', () => { - const props: defaults.VerifiedProps = { - }; - - defaults.CheckProps(props); -}); - -// --------------------------- -// DynamoDB Prop Tests -// --------------------------- -test('Test fail DynamoDB table check', () => { - const stack = new Stack(); - - const props: defaults.DynamoDBProps = { - existingTableObj: new dynamodb.Table(stack, 'placeholder', defaults.DefaultTableProps), - dynamoTableProps: defaults.DefaultTableProps, - }; - - const app = () => { - defaults.CheckDynamoDBProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide existingTableObj or dynamoTableProps, but not both.\n'); -}); - -test('Test fail DynamoDB table check (for interface)', () => { - const stack = new Stack(); - - const props: defaults.DynamoDBProps = { - existingTableInterface: new dynamodb.Table(stack, 'placeholder', defaults.DefaultTableProps), - dynamoTableProps: defaults.DefaultTableProps, - }; - - const app = () => { - defaults.CheckDynamoDBProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide existingTableInterface or dynamoTableProps, but not both.\n'); -}); - -// --------------------------- -// Lambda Prop Tests -// --------------------------- -test("Test fail Lambda function check", () => { - const stack = new Stack(); - - const props: defaults.LambdaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_16_X, - handler: "index.handler", - }, - existingLambdaObj: new lambda.Function(stack, "placeholder", { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_16_X, - handler: "index.handler", - }), - }; - - const app = () => { - defaults.CheckLambdaProps(props); - }; - - // Assertion - expect(app).toThrowError( - "Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n" - ); -}); -// --------------------------- - -// --------------------------- -// SQS Prop Tests -// --------------------------- -test("Test fail SQS Queue check", () => { - const stack = new Stack(); - - const props: defaults.SqsProps = { - queueProps: {}, - existingQueueObj: new sqs.Queue(stack, 'placeholder', {}), - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide queueProps or existingQueueObj, but not both.\n'); -}); - -test('Test fail SQS queue check when queueProps.encryptionMasterKey and encryptionKey are both specified', () => { - const stack = new Stack(); - - const props: defaults.SqsProps = { - queueProps: { - encryptionMasterKey: new kms.Key(stack, 'key') - }, - encryptionKey: new kms.Key(stack, 'otherkey') - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - expect(app).toThrowError('Error - Either provide queueProps.encryptionMasterKey or encryptionKey, but not both.\n'); -}); - -test('Test fail SQS queue check when queueProps.encryptionMasterKey and encryptionKeyProps are both specified', () => { - const stack = new Stack(); - - const props: defaults.SqsProps = { - encryptionKeyProps: { - description: 'key description' - }, - queueProps: { - encryptionMasterKey: new kms.Key(stack, 'key') - } - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide queueProps.encryptionMasterKey or encryptionKeyProps, but not both.\n'); -}); - -test('Test fail Dead Letter Queue check', () => { - - const props: defaults.SqsProps = { - deployDeadLetterQueue: false, - deadLetterQueueProps: {}, - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - If deployDeadLetterQueue is false then deadLetterQueueProps cannot be specified.\n'); -}); - -test('Test fail Dead Letter Queue check with queueProps fifo set to true and undefined deadLetterQueueProps', () => { - - const props: defaults.SqsProps = { - queueProps: { fifo: true }, - deadLetterQueueProps: {}, - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + - 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); -}); - -test('Test fail Dead Letter Queue check with queueProps fifo set to true and deadLetterQueueProps fifo set to false', () => { - - const props: defaults.SqsProps = { - queueProps: { fifo: true }, - deadLetterQueueProps: { fifo: false }, - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + - 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); -}); - -test('Test fail Dead Letter Queue check with queueProps fifo set to false and deadLetterQueueProps fifo set to true', () => { - - const props: defaults.SqsProps = { - deadLetterQueueProps: { fifo: true }, - queueProps: { fifo: false }, - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + - 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); -}); - -test('Test fail Dead Letter Queue check with deadLetterQueueProps fifo set to true', () => { - - const props: defaults.SqsProps = { - deadLetterQueueProps: { fifo: true }, - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + - 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); -}); - -test('Test fail Dead Letter Queue check with queueProps fifo set to false', () => { - - const props: defaults.SqsProps = { - queueProps: { fifo: false }, - }; - - const app = () => { - defaults.CheckSqsProps(props); - }; - - expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + - 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); -}); - -test("Test fail MediaStore container check", () => { - const stack = new Stack(); - - const mediaStoreContainer = new mediastore.CfnContainer( - stack, - "placeholder", - MediaStoreContainerProps() - ); - - const props: defaults.MediaStoreProps = { - mediaStoreContainerProps: MediaStoreContainerProps(), - existingMediaStoreContainerObj: mediaStoreContainer, - }; - - const app = () => { - defaults.CheckMediaStoreProps(props); - }; - - // Assertion - expect(app).toThrowError( - "Error - Either provide mediaStoreContainerProps or existingMediaStoreContainerObj, but not both.\n" - ); -}); - -test('Test fail Kinesis stream check', () => { - const stack = new Stack(); - - const stream = new kinesis.Stream(stack, 'placeholder', { - - }); - - const props: defaults.VerifiedProps = { - existingStreamObj: stream, - kinesisStreamProps: {} - }; - - const app = () => { - defaults.CheckProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); -}); - -// --------------------------- -// Sns Prop Tests -// --------------------------- -test('Test fail SNS topic check', () => { - const stack = new Stack(); - - const props: defaults.SnsProps = { - topicProps: {}, - existingTopicObj: new sns.Topic(stack, 'placeholder', {}) - }; - - const app = () => { - defaults.CheckSnsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide topicProps or existingTopicObj, but not both.\n'); -}); - -test('Test fail SNS topic check with bad topic attribute name', () => { - const stack = new Stack(); - - const props: defaults.SnsProps = { - topicProps: {}, - existingTopicObj: new sns.Topic(stack, 'placeholder', {}) - }; - - const app = () => { - defaults.CheckSnsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide topicProps or existingTopicObj, but not both.\n'); -}); - -test('Test fail SNS topic check when both encryptionKey and encryptionKeyProps are specified', () => { - const stack = new Stack(); - - const props: defaults.VerifiedProps = { - encryptionKey: new kms.Key(stack, 'key'), - encryptionKeyProps: { - description: 'a description' - } - }; - - const app = () => { - defaults.CheckProps(props); - }; - - expect(app).toThrowError('Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'); -}); - -test('Test fail SNS topic check when both topicProps.masterKey and encryptionKeyProps are specified', () => { - const stack = new Stack(); - - const props: defaults.SnsProps = { - topicProps: { - masterKey: new kms.Key(stack, 'key') - }, - encryptionKeyProps: { - description: 'a description' - } - }; - - const app = () => { - defaults.CheckSnsProps(props); - }; - - expect(app).toThrowError('Error - Either provide topicProps.masterKey or encryptionKeyProps, but not both.\n'); -}); - -test('Test fail SNS topic check when both encryptionKey and topicProps.masterKey are specified', () => { - const stack = new Stack(); - - const props: defaults.SnsProps = { - encryptionKey: new kms.Key(stack, 'key'), - topicProps: { - masterKey: new kms.Key(stack, 'otherkey') - } - }; - - const app = () => { - defaults.CheckSnsProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide topicProps.masterKey or encryptionKey, but not both.\n'); -}); -// --------------------------- - -// --------------------------- -// Glue Prop Tests -// --------------------------- -test('Test fail Glue job check', () => { - const stack = new Stack(); - - const _jobRole = new iam.Role(stack, 'CustomETLJobRole', { - assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') - }); - - const jobProps: glue.CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { - command: { - name: 'glueetl', - pythonVersion: '3', - scriptLocation: new s3.Bucket(stack, 'ScriptBucket').bucketArn, - }, - role: new iam.Role(stack, 'JobRole', { - assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') - }).roleArn - }, 'testETLJob', {}); - - const job = new glue.CfnJob(stack, 'placeholder', jobProps); - - const props: defaults.GlueProps = { - glueJobProps: jobProps, - existingGlueJob: job - }; - - const app = () => { - defaults.CheckGlueProps(props); - }; - - // Assertion - expect(app).toThrowError("Error - Either provide glueJobProps or existingGlueJob, but not both.\n"); -}); - -test('Test bad Glue script location', () => { - const stack = new Stack(); - - const _jobRole = new iam.Role(stack, 'CustomETLJobRole', { - assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') - }); - - const jobProps: glue.CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { - command: { - name: 'glueetl', - pythonVersion: '3', - scriptLocation: "s://bad/url", - }, - role: new iam.Role(stack, 'JobRole', { - assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') - }).roleArn - }, 'testETLJob', {}); - - const props: defaults.GlueProps = { - glueJobProps: jobProps, - }; - - const app = () => { - defaults.CheckGlueProps(props); - }; - - // Assertion - expect(app).toThrowError('Invalid S3 URL for Glue script provided\n'); -}); - -test('Test missing Glue script location', () => { - const stack = new Stack(); - - const _jobRole = new iam.Role(stack, 'CustomETLJobRole', { - assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') - }); - - const jobProps: glue.CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { - command: { - name: 'glueetl', - pythonVersion: '3', - }, - role: new iam.Role(stack, 'JobRole', { - assumedBy: new iam.ServicePrincipal('glue.amazonaws.com') - }).roleArn - }, 'testETLJob', {}); - - const props: defaults.GlueProps = { - glueJobProps: jobProps, - }; - - const app = () => { - defaults.CheckGlueProps(props); - }; - - const expectedError: string = 'Either one of CfnJob.JobCommandProperty.scriptLocation or etlCodeAsset has ' + - 'to be provided. If the ETL Job code file exists in a local filesystem, please set ' + - 'KinesisstreamsToGluejobProps.etlCodeAsset. If the ETL Job is available in an S3 bucket, set the ' + - 'CfnJob.JobCommandProperty.scriptLocation property\n'; - - // Assertion - expect(app).toThrowError(expectedError); -}); -// --------------------------- - -test('Test fail SageMaker endpoint check', () => { - const stack = new Stack(); - - // Build Sagemaker Inference Endpoint - const modelProps = { - primaryContainer: { - image: ".dkr.ecr..amazonaws.com/linear-learner:latest", - modelDataUrl: "s3:////model.tar.gz", - }, - }; - - const buildSagemakerEndpointResponse = BuildSagemakerEndpoint(stack, { modelProps }); - - const props: defaults.SagemakerProps = { - existingSagemakerEndpointObj: buildSagemakerEndpointResponse.endpoint, - endpointProps: { - endpointConfigName: 'placeholder' - } - }; - - const app = () => { - defaults.CheckSagemakerProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide endpointProps or existingSagemakerEndpointObj, but not both.\n'); -}); - -test('Test fail Secret check', () => { - const stack = new Stack(); - - const props: defaults.VerifiedProps = { - secretProps: {}, - existingSecretObj: defaults.buildSecretsManagerSecret(stack, 'secret', {}), - }; - - const app = () => { - defaults.CheckProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide secretProps or existingSecretObj, but not both.\n'); -}); - -test('Test fail encryption key check', () => { - const stack = new Stack(); - - const key = defaults.buildEncryptionKey(stack, { - enableKeyRotation: false - }); - - const props: defaults.VerifiedProps = { - encryptionKey: key, - encryptionKeyProps: {}, - }; - - const app = () => { - defaults.CheckProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'); -}); - -// --------------------------- -// VPC Prop Tests -// --------------------------- -test('Test fail Vpc check with deployVpc', () => { - const stack = new Stack(); - - const props: defaults.VpcPropsSet = { - deployVpc: true, - existingVpc: defaults.buildVpc(stack, { - defaultVpcProps: defaults.DefaultPublicPrivateVpcProps(), - }), - }; - - const app = () => { - defaults.CheckVpcProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); -}); - -test('Test fail Vpc check with vpcProps', () => { - const stack = new Stack(); - - const props: defaults.VpcPropsSet = { - vpcProps: defaults.DefaultPublicPrivateVpcProps(), - existingVpc: defaults.buildVpc(stack, { - defaultVpcProps: defaults.DefaultPublicPrivateVpcProps(), - }), - }; - - const app = () => { - defaults.CheckVpcProps(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); -}); -// --------------------------- - -// --------------------------- -// S3 Prop Tests -// --------------------------- -test('Test fail S3 check', () => { - const stack = new Stack(); - - const props: defaults.S3Props = { - existingBucketObj: CreateScrapBucket(stack, {}), - bucketProps: {}, - }; - - const app = () => { - defaults.CheckS3Props(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n'); -}); - -test('Test fail existing log bucket and log bucket prop check', () => { - const stack = new Stack(); - - const props: defaults.S3Props = { - existingLoggingBucketObj: new s3.Bucket(stack, 'logging-bucket'), - loggingBucketProps: { - autoDeleteObjects: true - } - }; - - const app = () => { - defaults.CheckS3Props(props); - }; - - // Assertion - expect(app).toThrowError('Error - Either provide existingLoggingBucketObj or loggingBucketProps, but not both.\n'); -}); - -test('Test fail false logS3Accesslogs and loggingBucketProps check', () => { - const stack = new Stack(); - - const props: defaults.S3Props = { - existingLoggingBucketObj: new s3.Bucket(stack, 'logging-bucket'), - logS3AccessLogs: false - }; - - const app = () => { - defaults.CheckS3Props(props); - }; - - // Assertion - expect(app).toThrowError('Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'); -}); - -test('Test fail existingBucketObj and loggingBucketProps check', () => { - const stack = new Stack(); - - const props: defaults.S3Props = { - existingBucketObj: new s3.Bucket(stack, 'temp-bucket'), - loggingBucketProps: { - autoDeleteObjects: true - } - }; - - const app = () => { - defaults.CheckS3Props(props); - }; - - // Assertion - expect(app).toThrowError('Error - If existingBucketObj is provided, supplying loggingBucketProps or logS3AccessLogs is an error.\n'); -}); -// --------------------------- - -test('Test successful CheckListValues', () => { - - const app = () => { - defaults.CheckListValues(['one', 'two', 'four'], ['four', 'one'], 'test value'); - }; - - // Assertion - expect(app).not.toThrowError(); -}); - -test('Test unsuccessful CheckListValues', () => { - - const app = () => { - defaults.CheckListValues(['one', 'two', 'four'], ['four', 'three'], 'test value'); - }; - - // Assertion - expect(app).toThrowError('Invalid test value submitted - three'); -}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts index 485c3430b..12e63a482 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts @@ -17,9 +17,6 @@ import * as defaults from '../'; import * as kinesis from 'aws-cdk-lib/aws-kinesis'; import { Template } from 'aws-cdk-lib/assertions'; -// -------------------------------------------------------------- -// Test minimal deployment with no properties -// -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { // Stack const stack = new Stack(); @@ -36,9 +33,6 @@ test('Test minimal deployment with no properties', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ custom properties -// -------------------------------------------------------------- test('Test deployment w/ custom properties', () => { // Stack const stack = new Stack(); @@ -63,9 +57,6 @@ test('Test deployment w/ custom properties', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ existing stream -// -------------------------------------------------------------- test('Test deployment w/ existing stream', () => { // Stack const stack = new Stack(); @@ -97,4 +88,27 @@ test('Count Kinesis CW Alarms', () => { const cwList = defaults.buildKinesisStreamCWAlarms(stack); expect(cwList.length).toEqual(2); -}); \ No newline at end of file +}); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail Kinesis stream check', () => { + const stack = new Stack(); + + const stream = new kinesis.Stream(stack, 'placeholder', { + + }); + + const props: defaults.KinesisStreamProps = { + existingStreamObj: stream, + kinesisStreamProps: {} + }; + + const app = () => { + defaults.CheckKinesisStreamProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts index 08e04d178..00a521ac8 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts @@ -561,3 +561,32 @@ test('buildLambdaFunction uses default name when neither constructId or function }, }); }); + +// --------------------------- +// Prop Tests +// --------------------------- +test("Test fail Lambda function check", () => { + const stack = new Stack(); + + const props: defaults.LambdaProps = { + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_16_X, + handler: "index.handler", + }, + existingLambdaObj: new lambda.Function(stack, "placeholder", { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_16_X, + handler: "index.handler", + }), + }; + + const app = () => { + defaults.CheckLambdaProps(props); + }; + + // Assertion + expect(app).toThrowError( + "Error - Either provide lambdaFunctionProps or existingLambdaObj, but not both.\n" + ); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/mediastore-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/mediastore-helper.test.ts index b2c2e295c..8e8746dea 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/mediastore-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/mediastore-helper.test.ts @@ -15,6 +15,8 @@ import { Template } from 'aws-cdk-lib/assertions'; import { Stack } from 'aws-cdk-lib'; import * as mediastore from 'aws-cdk-lib/aws-mediastore'; import { MediaStoreContainer } from '../lib/mediastore-helper'; +import { MediaStoreContainerProps } from '../lib/mediastore-defaults'; +import * as defaults from '../'; test('MediaStore container override params', () => { const stack = new Stack(); @@ -46,4 +48,31 @@ test('MediaStore container override params', () => { LifecyclePolicy: '{}', ContainerName: 'TestContainer' }); -}); \ No newline at end of file +}); + +// --------------------------- +// Prop Tests +// --------------------------- +test("Test fail MediaStore container check", () => { + const stack = new Stack(); + + const mediaStoreContainer = new mediastore.CfnContainer( + stack, + "placeholder", + MediaStoreContainerProps() + ); + + const props: defaults.MediaStoreProps = { + mediaStoreContainerProps: MediaStoreContainerProps(), + existingMediaStoreContainerObj: mediaStoreContainer, + }; + + const app = () => { + defaults.CheckMediaStoreProps(props); + }; + + // Assertion + expect(app).toThrowError( + "Error - Either provide mediaStoreContainerProps or existingMediaStoreContainerObj, but not both.\n" + ); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts b/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts index b3e5b0176..f36fd43e8 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts @@ -18,6 +18,7 @@ import * as defaults from '../index'; import { overrideProps } from '../lib/utils'; import { Template } from 'aws-cdk-lib/assertions'; import { expectNonexistence } from "./test-helper"; +import { CreateScrapBucket } from './test-helper'; test('test s3Bucket override versioningConfiguration', () => { const stack = new Stack(); @@ -359,4 +360,75 @@ test('Test enforcing SSL when bucketProps is provided and enforceSSL is not set' Version: "2012-10-17" } }); -}); \ No newline at end of file +}); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail S3 check', () => { + const stack = new Stack(); + + const props: defaults.S3Props = { + existingBucketObj: CreateScrapBucket(stack, {}), + bucketProps: {}, + }; + + const app = () => { + defaults.CheckS3Props(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n'); +}); + +test('Test fail existing log bucket and log bucket prop check', () => { + const stack = new Stack(); + + const props: defaults.S3Props = { + existingLoggingBucketObj: new s3.Bucket(stack, 'logging-bucket'), + loggingBucketProps: { + autoDeleteObjects: true + } + }; + + const app = () => { + defaults.CheckS3Props(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide existingLoggingBucketObj or loggingBucketProps, but not both.\n'); +}); + +test('Test fail false logS3Accesslogs and loggingBucketProps check', () => { + const stack = new Stack(); + + const props: defaults.S3Props = { + existingLoggingBucketObj: new s3.Bucket(stack, 'logging-bucket'), + logS3AccessLogs: false + }; + + const app = () => { + defaults.CheckS3Props(props); + }; + + // Assertion + expect(app).toThrowError('Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'); +}); + +test('Test fail existingBucketObj and loggingBucketProps check', () => { + const stack = new Stack(); + + const props: defaults.S3Props = { + existingBucketObj: new s3.Bucket(stack, 'temp-bucket'), + loggingBucketProps: { + autoDeleteObjects: true + } + }; + + const app = () => { + defaults.CheckS3Props(props); + }; + + // Assertion + expect(app).toThrowError('Error - If existingBucketObj is provided, supplying loggingBucketProps or logS3AccessLogs is an error.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts index a13347c82..d496d5633 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts @@ -17,6 +17,7 @@ import * as kms from 'aws-cdk-lib/aws-kms'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as defaults from '../'; import { Template } from 'aws-cdk-lib/assertions'; +import { BuildSagemakerEndpoint } from '../lib/sagemaker-helper'; test('Test deployment with VPC', () => { // Stack @@ -237,3 +238,34 @@ test('Test exception for not providing private or isolated subnets in an existin // Assertion 1 expect(app).toThrowError(); }); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail SageMaker endpoint check', () => { + const stack = new Stack(); + + // Build Sagemaker Inference Endpoint + const modelProps = { + primaryContainer: { + image: ".dkr.ecr..amazonaws.com/linear-learner:latest", + modelDataUrl: "s3:////model.tar.gz", + }, + }; + + const buildSagemakerEndpointResponse = BuildSagemakerEndpoint(stack, { modelProps }); + + const props: defaults.SagemakerProps = { + existingSagemakerEndpointObj: buildSagemakerEndpointResponse.endpoint, + endpointProps: { + endpointConfigName: 'placeholder' + } + }; + + const app = () => { + defaults.CheckSagemakerProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide endpointProps or existingSagemakerEndpointObj, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/secretsmanager-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/secretsmanager-helper.test.ts index b6b1717c1..4e6337cd7 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/secretsmanager-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/secretsmanager-helper.test.ts @@ -18,9 +18,6 @@ import { Template } from 'aws-cdk-lib/assertions'; const DESCRIPTION = 'test secret description'; const SECRET_NAME = 'test secret name'; -// -------------------------------------------------------------- -// Test minimal deployment with no properties -// -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { // Stack const stack = new Stack(); @@ -34,9 +31,6 @@ test('Test minimal deployment with no properties', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ custom properties -// -------------------------------------------------------------- test('Test deployment with custom properties', () => { // Stack const stack = new Stack(); @@ -57,3 +51,23 @@ test('Test deployment with custom properties', () => { } }); }); + +// --------------------------- +// Prop Tests +// --------------------------- + +test('Test fail Secret check', () => { + const stack = new Stack(); + + const props: defaults.SecretsManagerProps = { + secretProps: {}, + existingSecretObj: defaults.buildSecretsManagerSecret(stack, 'secret', {}), + }; + + const app = () => { + defaults.CheckSecretsManagerProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide secretProps or existingSecretObj, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts index 225b15abe..a0ecf4812 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts @@ -307,3 +307,112 @@ test('existing unencrypted topic is not overridden with defaults', () => { template.resourceCountIs('AWS::KMS::Key', 0); template.resourceCountIs('AWS::SNS::Topic', 1); }); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail SNS topic check', () => { + const stack = new Stack(); + + const props: defaults.SnsProps = { + topicProps: {}, + existingTopicObj: new sns.Topic(stack, 'placeholder', {}) + }; + + const app = () => { + defaults.CheckSnsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide topicProps or existingTopicObj, but not both.\n'); +}); + +test('Test fail SNS topic check with bad topic attribute name', () => { + const stack = new Stack(); + + const props: defaults.SnsProps = { + topicProps: {}, + existingTopicObj: new sns.Topic(stack, 'placeholder', {}) + }; + + const app = () => { + defaults.CheckSnsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide topicProps or existingTopicObj, but not both.\n'); +}); + +test('Test fail SNS topic check when both encryptionKey and encryptionKeyProps are specified', () => { + const stack = new Stack(); + + const props: defaults.SnsProps = { + encryptionKey: new kms.Key(stack, 'key'), + encryptionKeyProps: { + description: 'a description' + } + }; + + const app = () => { + defaults.CheckSnsProps(props); + }; + + expect(app).toThrowError('Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'); +}); + +test('Test fail SNS topic check when both topicProps.masterKey and encryptionKeyProps are specified', () => { + const stack = new Stack(); + + const props: defaults.SnsProps = { + topicProps: { + masterKey: new kms.Key(stack, 'key') + }, + encryptionKeyProps: { + description: 'a description' + } + }; + + const app = () => { + defaults.CheckSnsProps(props); + }; + + expect(app).toThrowError('Error - Either provide topicProps.masterKey or encryptionKeyProps, but not both.\n'); +}); + +test('Test fail SNS topic check when both encryptionKey and topicProps.masterKey are specified', () => { + const stack = new Stack(); + + const props: defaults.SnsProps = { + encryptionKey: new kms.Key(stack, 'key'), + topicProps: { + masterKey: new kms.Key(stack, 'otherkey') + } + }; + + const app = () => { + defaults.CheckSnsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide topicProps.masterKey or encryptionKey, but not both.\n'); +}); + +test('Test fail encryption key check', () => { + const stack = new Stack(); + + const key = defaults.buildEncryptionKey(stack, { + enableKeyRotation: false + }); + + const props: defaults.SnsProps = { + encryptionKey: key, + encryptionKeyProps: {}, + }; + + const app = () => { + defaults.CheckSnsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts index 44ce77d05..2d48bda4b 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts @@ -190,3 +190,168 @@ test('Test creating a FIFO queue', () => { }); expect(buildQueueResponse.queue.fifo).toBe(true); }); + +// --------------------------- +// Prop Tests +// --------------------------- + +test("Test fail SQS Queue check", () => { + const stack = new Stack(); + + const props: defaults.SqsProps = { + queueProps: {}, + existingQueueObj: new sqs.Queue(stack, 'placeholder', {}), + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide queueProps or existingQueueObj, but not both.\n'); +}); + +test('Test fail SQS queue check when queueProps.encryptionMasterKey and encryptionKey are both specified', () => { + const stack = new Stack(); + + const props: defaults.SqsProps = { + queueProps: { + encryptionMasterKey: new kms.Key(stack, 'key') + }, + encryptionKey: new kms.Key(stack, 'otherkey') + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + expect(app).toThrowError('Error - Either provide queueProps.encryptionMasterKey or encryptionKey, but not both.\n'); +}); + +test('Test fail SQS queue check when queueProps.encryptionMasterKey and encryptionKeyProps are both specified', () => { + const stack = new Stack(); + + const props: defaults.SqsProps = { + encryptionKeyProps: { + description: 'key description' + }, + queueProps: { + encryptionMasterKey: new kms.Key(stack, 'key') + } + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide queueProps.encryptionMasterKey or encryptionKeyProps, but not both.\n'); +}); + +test('Test fail SQS check when both encryptionKey and encryptionKeyProps are specified', () => { + const stack = new Stack(); + + const props: defaults.SqsProps = { + encryptionKey: new kms.Key(stack, 'key'), + encryptionKeyProps: { + description: 'a description' + } + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + expect(app).toThrowError('Error - Either provide encryptionKey or encryptionKeyProps, but not both.\n'); +}); + +test('Test fail Dead Letter Queue check', () => { + + const props: defaults.SqsProps = { + deployDeadLetterQueue: false, + deadLetterQueueProps: {}, + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - If deployDeadLetterQueue is false then deadLetterQueueProps cannot be specified.\n'); +}); + +test('Test fail Dead Letter Queue check with queueProps fifo set to true and undefined deadLetterQueueProps', () => { + + const props: defaults.SqsProps = { + queueProps: { fifo: true }, + deadLetterQueueProps: {}, + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + + 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); +}); + +test('Test fail Dead Letter Queue check with queueProps fifo set to true and deadLetterQueueProps fifo set to false', () => { + + const props: defaults.SqsProps = { + queueProps: { fifo: true }, + deadLetterQueueProps: { fifo: false }, + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + + 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); +}); + +test('Test fail Dead Letter Queue check with queueProps fifo set to false and deadLetterQueueProps fifo set to true', () => { + + const props: defaults.SqsProps = { + deadLetterQueueProps: { fifo: true }, + queueProps: { fifo: false }, + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + + 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); +}); + +test('Test fail Dead Letter Queue check with deadLetterQueueProps fifo set to true', () => { + + const props: defaults.SqsProps = { + deadLetterQueueProps: { fifo: true }, + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + + 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); +}); + +test('Test fail Dead Letter Queue check with queueProps fifo set to false', () => { + + const props: defaults.SqsProps = { + queueProps: { fifo: false }, + }; + + const app = () => { + defaults.CheckSqsProps(props); + }; + + expect(app).toThrowError('Error - If you specify a fifo: true in either queueProps or deadLetterQueueProps, you must also set fifo: ' + + 'true in the other props object. Fifo must match for the Queue and the Dead Letter Queue.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/utils.test.ts b/source/patterns/@aws-solutions-constructs/core/test/utils.test.ts index 6597b2154..88a1a9c9e 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/utils.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/utils.test.ts @@ -212,3 +212,39 @@ test('Test generateName uniqueness', () => { const nameTwo = defaults.generateName(stackTwo, ""); expect(nameOne === nameTwo).toBe(false); }); + +test('Test successful CheckListValues', () => { + + const app = () => { + defaults.CheckListValues(['one', 'two', 'four'], ['four', 'one'], 'test value'); + }; + + // Assertion + expect(app).not.toThrowError(); +}); + +test('Test fail OpenSearch improper vpc specification', () => { + + const props: defaults.OpenSearchProps = { + openSearchDomainProps: { + vpcOptions: {} + }, + }; + + const app = () => { + defaults.CheckOpenSearchProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Define VPC using construct parameters not the OpenSearch Service props\n'); +}); + +test('Test unsuccessful CheckListValues', () => { + + const app = () => { + defaults.CheckListValues(['one', 'two', 'four'], ['four', 'three'], 'test value'); + }; + + // Assertion + expect(app).toThrowError('Invalid test value submitted - three'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts index 73c0b3322..3b52ad4ec 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts @@ -18,9 +18,6 @@ import { Template } from 'aws-cdk-lib/assertions'; import { AddAwsServiceEndpoint, ServiceEndpointTypes } from '../lib/vpc-helper'; import { DefaultPublicPrivateVpcProps, DefaultIsolatedVpcProps } from '../lib/vpc-defaults'; -// -------------------------------------------------------------- -// Test minimal Isolated deployment with no properties -// -------------------------------------------------------------- test("Test minimal deployment with no properties", () => { // Stack const stack = new Stack(); @@ -39,9 +36,6 @@ test("Test minimal deployment with no properties", () => { template.resourceCountIs('AWS::EC2::InternetGateway', 0); }); -// -------------------------------------------------------------- -// Test deployment w/ user provided custom properties -// -------------------------------------------------------------- test('Test deployment w/ user provided custom properties', () => { // Stack const stack = new Stack(); @@ -61,9 +55,6 @@ test('Test deployment w/ user provided custom properties', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ construct provided custom properties -// -------------------------------------------------------------- test('Test deployment w/ construct provided custom properties', () => { // Stack const stack = new Stack(); @@ -83,9 +74,6 @@ test('Test deployment w/ construct provided custom properties', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ construct and user provided custom properties -// -------------------------------------------------------------- test('Test deployment w/ construct and user provided custom properties', () => { // Stack const stack = new Stack(); @@ -110,9 +98,6 @@ test('Test deployment w/ construct and user provided custom properties', () => { }); }); -// -------------------------------------------------------------- -// Test priority of default, user and construct properties -// -------------------------------------------------------------- test('Test deployment w/ construct and user provided custom properties', () => { // Stack const stack = new Stack(); @@ -145,9 +130,6 @@ test('Test deployment w/ construct and user provided custom properties', () => { template.resourceCountIs('AWS::EC2::InternetGateway', 0); }); -// -------------------------------------------------------------- -// Test deployment w/ existing VPC provided -// -------------------------------------------------------------- test('Test deployment w/ existing VPC provided', () => { // Stack const stack = new Stack(); @@ -162,9 +144,6 @@ test('Test deployment w/ existing VPC provided', () => { expect(newVpc).toBe(testExistingVpc); }); -// -------------------------------------------------------------- -// Test adding Gateway Endpoint -// -------------------------------------------------------------- test('Test adding Gateway Endpoint', () => { // Stack const stack = new Stack(); @@ -188,9 +167,6 @@ test('Test adding Gateway Endpoint', () => { template.resourceCountIs('AWS::EC2::VPCEndpoint', 3); }); -// -------------------------------------------------------------- -// Test adding Interface Endpoint -// -------------------------------------------------------------- test('Test adding Interface Endpoint', () => { // Stack const stack = new Stack(); @@ -207,9 +183,6 @@ test('Test adding Interface Endpoint', () => { }); }); -// -------------------------------------------------------------- -// Test adding SAGEMAKER_RUNTIME Interface Endpoint -// -------------------------------------------------------------- test('Test adding SAGEMAKER_RUNTIME Interface Endpoint', () => { // Stack const stack = new Stack(); @@ -226,9 +199,6 @@ test('Test adding SAGEMAKER_RUNTIME Interface Endpoint', () => { }); }); -// -------------------------------------------------------------- -// Test adding a second Endpoint of same service -// -------------------------------------------------------------- test('Test adding a second Endpoint of same service', () => { // Stack const stack = new Stack(); @@ -244,9 +214,6 @@ test('Test adding a second Endpoint of same service', () => { Template.fromStack(stack).resourceCountIs('AWS::EC2::VPCEndpoint', 1); }); -// -------------------------------------------------------------- -// Test adding bad Endpoint -// -------------------------------------------------------------- test('Test adding bad Endpoint', () => { // Stack const stack = new Stack(); @@ -262,9 +229,6 @@ test('Test adding bad Endpoint', () => { expect(app).toThrowError(); }); -// -------------------------------------------------------------- -// Test adding Events Interface Endpoint -// -------------------------------------------------------------- test('Test adding Events Interface Endpoint', () => { // Stack const stack = new Stack(); @@ -279,4 +243,43 @@ test('Test adding Events Interface Endpoint', () => { Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { VpcEndpointType: 'Interface', }); -}); \ No newline at end of file +}); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test fail Vpc check with deployVpc', () => { + const stack = new Stack(); + + const props: defaults.VpcPropsSet = { + deployVpc: true, + existingVpc: defaults.buildVpc(stack, { + defaultVpcProps: defaults.DefaultPublicPrivateVpcProps(), + }), + }; + + const app = () => { + defaults.CheckVpcProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); +}); + +test('Test fail Vpc check with vpcProps', () => { + const stack = new Stack(); + + const props: defaults.VpcPropsSet = { + vpcProps: defaults.DefaultPublicPrivateVpcProps(), + existingVpc: defaults.buildVpc(stack, { + defaultVpcProps: defaults.DefaultPublicPrivateVpcProps(), + }), + }; + + const app = () => { + defaults.CheckVpcProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide an existingVpc or some combination of deployVpc and vpcProps, but not both.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/waf-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/waf-helper.test.ts index d93ba3d19..66fc14798 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/waf-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/waf-helper.test.ts @@ -256,9 +256,6 @@ test('Test deployment w/ user provided partial custom properties', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ existing WAF web ACL provided -// -------------------------------------------------------------- test('Test deployment w/ existing WAF web ACL provided', () => { // Stack const stack = new Stack(); @@ -269,4 +266,56 @@ test('Test deployment w/ existing WAF web ACL provided', () => { }); expect(newWaf).toBe(testWaf); -}); \ No newline at end of file +}); + +// --------------------------- +// Prop Tests +// --------------------------- +test('Test WebACL bad props', () => { + const stack = new Stack(); + const wafProps: waf.CfnWebACLProps = { + scope: 'CLOUDFRONT', + defaultAction: { + allow: {} + }, + visibilityConfig: { + cloudWatchMetricsEnabled: false, + metricName: 'webACL', + sampledRequestsEnabled: true + }, + rules: [ + defaults.wrapManagedRuleSet("AWSManagedRulesCommonRuleSet", "AWS", 0), + defaults.wrapManagedRuleSet("AWSManagedRulesWordPressRuleSet", "AWS", 1), + ] + }; + + const wafPropsTwo: waf.CfnWebACLProps = { + scope: 'CLOUDFRONT', + defaultAction: { + allow: {} + }, + visibilityConfig: { + cloudWatchMetricsEnabled: false, + metricName: 'webACL', + sampledRequestsEnabled: true + }, + rules: [ + defaults.wrapManagedRuleSet("AWSManagedRulesCommonRuleSet", "AWS", 0), + defaults.wrapManagedRuleSet("AWSManagedRulesWordPressRuleSet", "AWS", 1), + ] + }; + + const acl: waf.CfnWebACL = new waf.CfnWebACL(stack, 'test', wafProps); + + const props: defaults.WafWebAclProps = { + existingWebaclObj: acl, + webaclProps: wafPropsTwo, + }; + + const app = () => { + defaults.CheckWafWebAclProps(props); + }; + + // Assertion + expect(app).toThrowError('Error - Either provide existingWebaclObj or webaclProps, but not both.\n'); +});