From a87231c289dbfa69179c91b67e3a01f97793fbb1 Mon Sep 17 00:00:00 2001 From: biffgaut <78155736+biffgaut@users.noreply.github.com> Date: Tue, 10 May 2022 16:47:42 -0400 Subject: [PATCH] Added additional tests --- .../core/test/kinesis-analytics.test.ts | 177 ++++++++++++++++-- .../core/test/sqs-helper.test.ts | 92 +++++++++ 2 files changed, 249 insertions(+), 20 deletions(-) diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts index be21dd4fe..db1f9be73 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts @@ -11,32 +11,38 @@ * and limitations under the License. */ -import { Stack } from '@aws-cdk/core'; -import * as kinesisanalytics from '@aws-cdk/aws-kinesisanalytics'; -import * as defaults from '../index'; -import { overrideProps } from '../lib/utils'; -import '@aws-cdk/assert/jest'; +import { Stack, RemovalPolicy } from "@aws-cdk/core"; +import * as cdk from "@aws-cdk/core"; +import * as kinesisanalytics from "@aws-cdk/aws-kinesisanalytics"; +import * as kinesisFirehose from "@aws-cdk/aws-kinesisfirehose"; +import * as iam from "@aws-cdk/aws-iam"; +import * as kms from "@aws-cdk/aws-kms"; +import * as logs from "@aws-cdk/aws-logs"; +import * as defaults from "../index"; +import { overrideProps } from "../lib/utils"; +import "@aws-cdk/assert/jest"; -test('test kinesisanalytics override inputProperty', () => { +test("test kinesisanalytics override inputProperty", () => { const stack = new Stack(); const inputProperty: kinesisanalytics.CfnApplication.InputProperty = { inputSchema: { - recordColumns: [{name: 'x', sqlType: 'y'}], - recordFormat: { recordFormatType: 'csv' } + recordColumns: [{ name: "x", sqlType: "y" }], + recordFormat: { recordFormatType: "csv" }, }, - namePrefix: 'zzz' + namePrefix: "zzz", }; - const defaultProps: kinesisanalytics.CfnApplicationProps = defaults.DefaultCfnApplicationProps; + const defaultProps: kinesisanalytics.CfnApplicationProps = + defaults.DefaultCfnApplicationProps; const inProps: kinesisanalytics.CfnApplicationProps = { - inputs: [inputProperty] + inputs: [inputProperty], }; const outProps = overrideProps(defaultProps, inProps); - new kinesisanalytics.CfnApplication(stack, 'KinesisAnalytics', outProps); + new kinesisanalytics.CfnApplication(stack, "KinesisAnalytics", outProps); expect(stack).toHaveResource("AWS::KinesisAnalytics::Application", { Inputs: [ @@ -45,15 +51,146 @@ test('test kinesisanalytics override inputProperty', () => { RecordColumns: [ { Name: "x", - SqlType: "y" - } + SqlType: "y", + }, ], RecordFormat: { - RecordFormatType: "csv" - } + RecordFormatType: "csv", + }, }, - NamePrefix: "zzz" - } - ] + NamePrefix: "zzz", + }, + ], }); -}); \ No newline at end of file +}); + +test("Test default implementation", () => { + const stack = new Stack(); + + const newFirehose = CreateFirehose(stack); + const kinesisProps: defaults.BuildKinesisAnalyticsAppProps = { + kinesisFirehose: newFirehose, + kinesisAnalyticsProps: { + inputs: [{ + inputSchema: { + recordColumns: [{ + name: 'ts', + sqlType: 'TIMESTAMP', + mapping: '$.timestamp' + }, { + name: 'trip_id', + sqlType: 'VARCHAR(64)', + mapping: '$.trip_id' + }], + recordFormat: { + recordFormatType: 'JSON' + }, + recordEncoding: 'UTF-8' + }, + namePrefix: 'SOURCE_SQL_STREAM' + }] + }, + }; + + defaults.buildKinesisAnalyticsApp(stack, kinesisProps); + + expect(stack).toHaveResourceLike("AWS::KinesisAnalytics::Application", { + Inputs: [{ + InputSchema: { + RecordColumns: [{ + Name: 'ts', + SqlType: 'TIMESTAMP', + Mapping: '$.timestamp' + }, { + Name: 'trip_id', + SqlType: 'VARCHAR(64)', + Mapping: '$.trip_id' + }], + RecordFormat: { + RecordFormatType: 'JSON' + }, + RecordEncoding: 'UTF-8' + }, + NamePrefix: 'SOURCE_SQL_STREAM' + }] + }); +}); + +// test('Test for customer overrides', { +// test('Check policy created', { + +function CreateFirehose(stack: Stack): kinesisFirehose.CfnDeliveryStream { + // Creating the Firehose is kind of a big deal. FirehoseToS3 is not readily available here in core, + // so this routine pretty much replicates it. If this function ceases to work correctly, look at + // FirehoseToS3 and see if that changed. + const destinationBucket = defaults.CreateScrapBucket(stack, { + removalPolicy: RemovalPolicy.DESTROY, + autoDeleteObjects: true, + }); + + const kinesisFirehoseLogGroup = defaults.buildLogGroup( + stack, + "firehose-log-group", + {} + ); + + const cwLogStream: logs.LogStream = kinesisFirehoseLogGroup.addStream( + "firehose-log-stream" + ); + + const firehoseRole = new iam.Role(stack, "test-role", { + assumedBy: new iam.ServicePrincipal("firehose.amazonaws.com"), + }); + + // Setup the IAM policy for Kinesis Firehose + const firehosePolicy = new iam.Policy(stack, "KinesisFirehosePolicy", { + statements: [ + new iam.PolicyStatement({ + actions: [ + "s3:AbortMultipartUpload", + "s3:GetBucketLocation", + "s3:GetObject", + "s3:ListBucket", + "s3:ListBucketMultipartUploads", + "s3:PutObject", + ], + resources: [ + `${destinationBucket.bucketArn}`, + `${destinationBucket.bucketArn}/*`, + ], + }), + new iam.PolicyStatement({ + actions: ["logs:PutLogEvents"], + resources: [ + `arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:${kinesisFirehoseLogGroup.logGroupName}:log-stream:${cwLogStream.logStreamName}`, + ], + }), + ], + }); + + // Attach policy to role + firehosePolicy.attachToRole(firehoseRole); + + const awsManagedKey: kms.IKey = kms.Alias.fromAliasName( + stack, + "aws-managed-key", + "alias/aws/s3" + ); + + const defaultKinesisFirehoseProps: kinesisFirehose.CfnDeliveryStreamProps = defaults.DefaultCfnDeliveryStreamProps( + destinationBucket.bucketArn, + firehoseRole.roleArn, + kinesisFirehoseLogGroup.logGroupName, + cwLogStream.logStreamName, + awsManagedKey + ); + + destinationBucket.grantPut(firehoseRole); + + const firehose = new kinesisFirehose.CfnDeliveryStream( + stack, + "KinesisFirehose", + defaultKinesisFirehoseProps + ); + return firehose; +} 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 d28d2add4..eefb7a441 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 @@ -13,8 +13,10 @@ // Imports import { Stack } from "@aws-cdk/core"; +import * as sqs from '@aws-cdk/aws-sqs'; import * as defaults from '../'; import '@aws-cdk/assert/jest'; +import { buildDeadLetterQueue } from "../lib/sqs-helper"; // -------------------------------------------------------------- // Test deployment w/ imported encryption key @@ -57,3 +59,93 @@ test('Test deployment without imported encryption key', () => { KmsMasterKeyId: "alias/aws/sqs" }); }); + +// -------------------------------------------------------------- +// Test deployment w/ construct created encryption key +// -------------------------------------------------------------- +test('Test deployment w/ construct created encryption key', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const [queue, key] = defaults.buildQueue(stack, 'existing-queue', { + queueProps: { + queueName: 'existing-queue' + }, + enableEncryptionWithCustomerManagedKey: true, + }); + + expect(stack).toHaveResource("AWS::SQS::Queue", { + QueueName: "existing-queue" + }); + expect(stack).toHaveResource("AWS::KMS::Key", { + EnableKeyRotation: true + }); + expect(queue).toBeDefined(); + expect(key).toBeDefined(); +}); + +test('Test DLQ when existing Queue Provided', () => { + const stack = new Stack(); + + const existingQueue = new sqs.Queue(stack, 'test-queue'); + const buildDlqProps: defaults.BuildDeadLetterQueueProps = { + existingQueueObj: existingQueue, + }; + + const returnedQueueu = defaults.buildDeadLetterQueue(stack, buildDlqProps); + + expect(returnedQueueu).toBeUndefined(); + expect(stack).toCountResources("AWS::SQS::Queue", 1); +}); + +test('Test DLQ with all defaults', () => { + const stack = new Stack(); + + buildDeadLetterQueue(stack, {}); + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + KmsMasterKeyId: "alias/aws/sqs" + }); +}); + +test("Test DLQ with a provided properties", () => { + const stack = new Stack(); + const testQueueName = "test-unique252"; + + const returnedQueue = buildDeadLetterQueue(stack, { + deadLetterQueueProps: { + queueName: testQueueName, + }, + }); + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + QueueName: testQueueName, + }); + expect(returnedQueue).toBeDefined(); +}); + +test('Test DLQ with a provided maxReceiveCount', () => { + const stack = new Stack(); + const testMaxReceiveCount = 31; + + const dlqInterface = buildDeadLetterQueue(stack, { + maxReceiveCount: testMaxReceiveCount + }); + expect(dlqInterface?.maxReceiveCount).toEqual(testMaxReceiveCount); +}); + +test('Test returning an existing Queue', () => { + const stack = new Stack(); + const testQueueName = 'existing-queue'; + + const existingQueue = new sqs.Queue(stack, 'test-queue', { + queueName: testQueueName + }); + + const [returnedQueue] = defaults.buildQueue(stack, 'newQueue', { + existingQueueObj: existingQueue + }); + + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + QueueName: testQueueName, + }); + expect(existingQueue.queueName).toEqual(returnedQueue.queueName); +}); \ No newline at end of file