@aws-solutions-constructs/core
Version:
Core CDK Construct for patterns library
787 lines • 103 kB
JavaScript
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const sqs_helper_1 = require("../lib/sqs-helper");
const step_function_helper_1 = require("../lib/step-function-helper");
const dynamodb_table_helper_1 = require("../lib/dynamodb-table-helper");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const defaults = require("../");
const lambda = require("aws-cdk-lib/aws-lambda");
const s3 = require("aws-cdk-lib/aws-s3");
const assertions_1 = require("aws-cdk-lib/assertions");
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
// =================================
// Test sources and targets generation
// =================================
test('Create a default SQS Source', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildQueueResponse = (0, sqs_helper_1.buildQueue)(stack, 'test-queue', {});
const sqsSource = defaults.CreateSqsSource(buildQueueResponse.queue);
expect(sqsSource.sourceArn).toEqual(buildQueueResponse.queue.queueArn);
expect(Object.keys(sqsSource.sourceParameters).length).toEqual(0);
// best we can do here, confirm values when we instantiate the actual pipe
expect(sqsSource.sourcePolicy.statementCount).toEqual(1);
assertions_1.Template.fromStack(stack);
});
test('Create an SQS Source with overrides', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildQueueResponse = (0, sqs_helper_1.buildQueue)(stack, 'test-queue', {});
const sqsSource = defaults.CreateSqsSource(buildQueueResponse.queue, {
sqsQueueParameters: {
batchSize: 123,
},
});
expect(sqsSource.sourceArn).toEqual(buildQueueResponse.queue.queueArn);
// Because sqsQueueParameters type include 'IResolvable |', we need to extract the property this way
const batchSizeProp = sqsSource.sourceParameters.sqsQueueParameters.batchSize;
expect(batchSizeProp).toEqual(123);
// best we can do here, confirm values when we instantiate the actual pipe
expect(sqsSource.sourcePolicy.statementCount).toEqual(1);
});
test('Create a default DDB Streams Source', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildTableResponse = (0, dynamodb_table_helper_1.buildDynamoDBTableWithStream)(stack, {});
const tableSource = defaults.CreateDynamoDBStreamsSource(stack, {
table: buildTableResponse.tableObject
});
expect(tableSource.sourceArn).toEqual(buildTableResponse.tableObject?.tableStreamArn);
expect(Object.keys(tableSource.sourceParameters).length).toEqual(1);
expect(tableSource.sourcePolicy.statementCount).toEqual(2);
expect(tableSource.dlq).toBeDefined();
const streamParamters = tableSource.sourceParameters.dynamoDbStreamParameters;
expect(streamParamters.deadLetterConfig).toBeDefined();
});
test('Confirm that we use custom DLQ props', () => {
const queueName = 'something-unique-asdf';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildTableResponse = (0, dynamodb_table_helper_1.buildDynamoDBTableWithStream)(stack, {});
defaults.CreateDynamoDBStreamsSource(stack, {
table: buildTableResponse.tableObject,
sqsDlqQueueProps: {
queueName,
}
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::SQS::Queue", {
QueueName: queueName
});
});
test('Create DDB Streams Source with no DLQ', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildTableResponse = (0, dynamodb_table_helper_1.buildDynamoDBTableWithStream)(stack, {});
const tableSource = defaults.CreateDynamoDBStreamsSource(stack, {
table: buildTableResponse.tableObject,
deploySqsDlqQueue: false
});
expect(tableSource.sourceArn).toEqual(buildTableResponse.tableObject?.tableStreamArn);
expect(Object.keys(tableSource.sourceParameters).length).toEqual(1);
expect(tableSource.sourcePolicy.statementCount).toEqual(1);
expect(tableSource.dlq).toBeUndefined();
const streamParamters = tableSource.sourceParameters.dynamoDbStreamParameters;
expect(streamParamters.maximumRetryAttempts).toBeUndefined();
expect(streamParamters.deadLetterConfig).toBeUndefined();
expect(streamParamters.startingPosition).toBeDefined();
});
test('Create an DDB Streams Source with overrides', () => {
const batchSizeValue = 4642;
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildTableResponse = (0, dynamodb_table_helper_1.buildDynamoDBTableWithStream)(stack, {});
const tableSource = defaults.CreateDynamoDBStreamsSource(stack, {
table: buildTableResponse.tableObject,
clientProps: {
dynamoDbStreamParameters: {
startingPosition: 'LATEST',
batchSize: batchSizeValue
}
}
});
expect(tableSource.sourceArn).toEqual(buildTableResponse.tableObject?.tableStreamArn);
// Because sqsQueueParameters type include 'IResolvable |', we need to extract the property this way
const batchSizeProp = tableSource.sourceParameters.dynamoDbStreamParameters.batchSize;
expect(batchSizeProp).toEqual(batchSizeValue);
// best we can do here, confirm values when we instantiate the actual pipe
expect(tableSource.sourcePolicy.statementCount).toEqual(2);
const streamParamters = tableSource.sourceParameters.dynamoDbStreamParameters;
expect(streamParamters.maximumRetryAttempts).toEqual(3);
expect(streamParamters.deadLetterConfig).toBeDefined();
expect(streamParamters.startingPosition).toBeDefined();
});
test('Create a default Step Functions Target', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildStateMachineResponse = (0, step_function_helper_1.buildStateMachine)(stack, 'test-state-machine', {
stateMachineProps: {
definitionBody: defaults.CreateTestStateMachineDefinitionBody(stack, 'stub-state-machine')
}
});
const stateMachineTarget = defaults.CreateStateMachineTarget(buildStateMachineResponse.stateMachine);
expect(stateMachineTarget.targetArn).toEqual(buildStateMachineResponse.stateMachine.stateMachineArn);
expect(stateMachineTarget.targetParameters.stepFunctionStateMachineParameters).toBeDefined();
const invocationType = stateMachineTarget.targetParameters.stepFunctionStateMachineParameters.invocationType;
expect(invocationType).toEqual('FIRE_AND_FORGET');
expect(Object.keys(stateMachineTarget.targetParameters).length).toEqual(1);
// best we can do here, confirm values when we instantiate the actual pipe
expect(stateMachineTarget.targetPolicy.statementCount).toEqual(1);
assertions_1.Template.fromStack(stack);
});
test('Create a Step Functions Target with overrides', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildStateMachineResponse = (0, step_function_helper_1.buildStateMachine)(stack, 'test-state-machine', {
stateMachineProps: {
definitionBody: defaults.CreateTestStateMachineDefinitionBody(stack, 'stub-state-machine')
}
});
const stateMachineTarget = defaults.CreateStateMachineTarget(buildStateMachineResponse.stateMachine, {
stepFunctionStateMachineParameters: {
invocationType: 'REQUEST_RESPONSE'
}
});
expect(stateMachineTarget.targetArn).toEqual(buildStateMachineResponse.stateMachine.stateMachineArn);
expect(stateMachineTarget.targetParameters.stepFunctionStateMachineParameters).toBeDefined();
const invocationType = stateMachineTarget.targetParameters.stepFunctionStateMachineParameters.invocationType;
expect(invocationType).toEqual('REQUEST_RESPONSE');
expect(Object.keys(stateMachineTarget.targetParameters).length).toEqual(1);
// best we can do here, confirm values when we instantiate the actual pipe
expect(stateMachineTarget.targetPolicy.statementCount).toEqual(1);
});
test('Check for error when DLQ is off but max constraint set', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const buildTableResponse = (0, dynamodb_table_helper_1.buildDynamoDBTableWithStream)(stack, {});
const app = () => {
defaults.CreateDynamoDBStreamsSource(stack, {
clientProps: {
dynamoDbStreamParameters: {
startingPosition: 'LATEST',
maximumRecordAgeInSeconds: 100
}
},
table: buildTableResponse.tableObject,
deploySqsDlqQueue: false
});
};
// Assertion
expect(app).toThrowError('ERROR - retry and record age constraints cannot be specified with no DLQ\n');
});
// =================================
// Test pipe creation
// =================================
test('Create a default pipe', () => {
const prerequisiteId = 'alldefault';
const pipeId = 'defaultpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {}
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
});
test('Create a pipe with overrides', () => {
const prerequisiteId = 'overridestest';
const pipeId = 'overridespipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const testDescription = 'test-description';
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
description: testDescription
}
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
// The description is unique to this test, so check it here
template.hasResourceProperties('AWS::Pipes::Pipe', {
Description: testDescription
});
});
test('Create a pipe with a filter', () => {
const prerequisiteId = 'filtertest';
const pipeId = 'filterpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const testFilterPattern = `{
"body": {
"state": ["open"]
}
}`;
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
sourceParameters: {
filterCriteria: {
filters: [{ pattern: testFilterPattern }],
},
}
},
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
// SourceParameters is unique to this test, so check it here
template.hasResourceProperties('AWS::Pipes::Pipe', {
SourceParameters: {
FilterCriteria: {
Filters: [
{
Pattern: testFilterPattern
}
]
}
}
});
});
test('Create a pipe with Lambda function enrichment', () => {
const prerequisiteId = 'lambdaenrichtest';
const pipeId = 'lambdaenrichpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const enrichmentFunction = new lambda.Function(stack, 'enrichment-function', {
code: lambda.Code.fromAsset(`${__dirname}/lambda-test`),
handler: "index.handler",
runtime: lambda.Runtime.NODEJS_20_X,
});
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
enrichmentFunction
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckLogGroup(template);
// Enrichment is unique to this test so check it here
template.hasResourceProperties('AWS::Pipes::Pipe', {
Enrichment: {
"Fn::GetAtt": [
assertions_1.Match.stringLikeRegexp('enrichmentfunction.*'),
"Arn"
]
},
});
// This checks for everything but enrichment
CheckPipeRole(template, prerequisiteId);
// This checks for enrichment permissions
template.hasResourceProperties('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: "lambda:InvokeFunction",
Effect: "Allow",
Resource: {
"Fn::GetAtt": [
assertions_1.Match.stringLikeRegexp('enrichmentfunction.*'),
"Arn"
]
}
}
],
Version: "2012-10-17"
},
PolicyName: assertions_1.Match.stringLikeRegexp(`enrichmentpolicy${pipeId}.*`),
Roles: [
{
Ref: assertions_1.Match.stringLikeRegexp(`PipeRole${pipeId}.*`)
}
]
});
});
test('Create a pipe with state machine enrichment', () => {
const prerequisiteId = 'smenrichtest';
const pipeId = 'smenrichpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const enrichmentStateMachine = defaults.CreateTestStateMachine(stack, 'state-machine-enrichment');
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
enrichmentStateMachine
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
// Look for additional enrichment permision
template.hasResourceProperties('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
// This won't run if we actually launched it as the enrichmentStateMachine is not EXPRESS
Action: "states:StartSyncExecution",
Effect: "Allow",
Resource: {
Ref: assertions_1.Match.stringLikeRegexp('statemachineenrichment.*'),
}
}
],
Version: "2012-10-17"
},
PolicyName: assertions_1.Match.stringLikeRegexp(`enrichmentpolicy${pipeId}.*`),
Roles: [
{
Ref: assertions_1.Match.stringLikeRegexp(`PipeRole${pipeId}.*`)
}
]
});
template.hasResourceProperties('AWS::Pipes::Pipe', {
Enrichment: {
Ref: assertions_1.Match.stringLikeRegexp("statemachineenrichment.*")
},
});
});
test('Provide replacement LogConfiguration', () => {
const prerequisiteId = 'logconfigtest';
const pipeId = 'logconfigpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const customLogConfiguration = {
s3LogDestination: {
bucketName: new s3.Bucket(stack, 'test').bucketName,
},
level: defaults.PipesLogLevel.ERROR
};
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
logConfiguration: customLogConfiguration
}
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
CheckPipeSourceAndTarget(template, prerequisiteId);
template.hasResourceProperties('AWS::Pipes::Pipe', {
LogConfiguration: {
Level: "ERROR",
S3LogDestination: {
BucketName: {
Ref: assertions_1.Match.stringLikeRegexp("test.*")
}
}
}
});
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeRole(template, prerequisiteId);
});
test('Override the default log level', () => {
const prerequisiteId = 'loglevelttest';
const pipeId = 'loglevelpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
logLevel: defaults.PipesLogLevel.ERROR
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
// Level is unique to this test
template.hasResourceProperties('AWS::Pipes::Pipe', {
LogConfiguration: {
Level: defaults.PipesLogLevel.ERROR,
}
});
});
test('Test no logging', () => {
const prerequisiteId = 'nologs';
const pipeId = 'testpipe';
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
logLevel: defaults.PipesLogLevel.OFF
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeSourceAndTarget(template, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
// One log group for the state machine, none for the pipe
template.resourceCountIs('AWS::Logs::LogGroup', 1);
});
test('Override a subset of SQS source paramters', () => {
const prerequisiteId = 'srcparamtest';
const pipeId = 'srcparampipe';
const testBatchSize = 7;
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
sourceParameters: {
sqsQueueParameters: {
batchSize: testBatchSize,
}
}
}
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
template.hasResourceProperties('AWS::Pipes::Pipe', {
SourceParameters: {
SqsQueueParameters: {
BatchSize: testBatchSize
}
},
});
});
test('Provide pipeLogProps', () => {
const prerequisiteId = 'pipelogpropstest';
const pipeId = 'pipelogpropspipe';
// While this is an enum we need to use, in the template
// it is converted to days, in this case 120
const testRetention = aws_logs_1.RetentionDays.FOUR_MONTHS;
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, prerequisiteId);
const pipeResponse = defaults.BuildPipe(stack, pipeId, {
source: prerequisites.source,
target: prerequisites.target,
pipeLogProps: {
retention: testRetention
}
});
CheckPipeResponseProperties(pipeResponse, prerequisites);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Pipes::Pipe', 1);
CheckPipeResource(template, pipeId, prerequisiteId);
CheckPipeRole(template, prerequisiteId);
CheckLogGroup(template);
CheckPipeLogConfiguration(template, pipeId);
// Look for additional property we passed in pipeLogProps
template.hasResourceProperties('AWS::Logs::LogGroup', {
RetentionInDays: 120,
});
});
test('Check for error when providing source in CfnProps', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
source: prerequisites.source.sourceArn
}
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify source, target, roleArn, or enrichment');
});
test('Check for error when providing target in CfnProps', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
target: prerequisites.target.targetArn,
}
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify source, target, roleArn, or enrichment');
});
test('Check for error when providing a roleArn', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
roleArn: "some-arn",
}
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify source, target, roleArn, or enrichment');
});
test('Check for error when providing enrichment', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
clientProps: {
enrichment: "functionArn",
}
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify source, target, roleArn, or enrichment');
});
test('Check for error when log level and log configuration are both provided', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
logLevel: defaults.PipesLogLevel.ERROR,
clientProps: {
logConfiguration: { some: "object" },
}
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify logLevel and logConfiguration');
});
test('Check for error when pipeLogProps and log configuration are both provided', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
pipeLogProps: { logGroupName: "anyvalue" },
clientProps: {
logConfiguration: { some: "object" },
}
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify pipeLogProps and logConfiguration');
});
test('Check for error when enrichmentFunction and enrichmentStateMachine are both provided', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
enrichmentFunction: { place: "holder" },
enrichmentStateMachine: { place: "holder" }
});
};
// Assertion
expect(app).toThrowError('ERROR - Only one of enrichmentFunction or enrichmentStateMachine can be provided');
});
test('Check for error when pipeLogProps and log level is set to OFF', () => {
// Stack
const stack = new aws_cdk_lib_1.Stack();
const prerequisites = CreatePrerequisites(stack, 'log-level-test');
const app = () => {
defaults.BuildPipe(stack, 'test-pipe', {
source: prerequisites.source,
target: prerequisites.target,
logLevel: defaults.PipesLogLevel.OFF,
pipeLogProps: { logGroupName: "anyvalue" },
});
};
// Assertion
expect(app).toThrowError('ERROR - BuildPipeProps cannot specify pipeLogProps and log level OFF');
});
test('Test all of CheckPipesProps', () => {
const app = () => {
defaults.CheckPipesProps({
pipesProps: { source: "value" },
});
};
// Assertion
expect(app).toThrowError('Do not set source in pipesProps. It is set by the construct.\n');
const appTwo = () => {
defaults.CheckPipesProps({
pipesProps: { target: "value" },
});
};
// Assertion
expect(appTwo).toThrowError('Do not set target in pipesProps. It is set by the construct.\n');
});
function CreatePrerequisites(scope, id) {
const buildQueueResponse = (0, sqs_helper_1.buildQueue)(scope, `${id}-source-queue`, {});
const sqsSource = defaults.CreateSqsSource(buildQueueResponse.queue);
const buildStateMachineResponse = (0, step_function_helper_1.buildStateMachine)(scope, `${id}-target-state-machine`, {
stateMachineProps: {
definitionBody: defaults.CreateTestStateMachineDefinitionBody(scope, `${id}-steps`)
}
});
const stateMachineTarget = defaults.CreateStateMachineTarget(buildStateMachineResponse.stateMachine, {
stepFunctionStateMachineParameters: {
invocationType: 'REQUEST_RESPONSE'
}
});
return {
source: sqsSource,
target: stateMachineTarget
};
}
// ==============================
// Shared functions that check default settings
// ==============================
function CheckPipeResponseProperties(pipeResponse, prerequisites) {
expect(pipeResponse.pipe).toBeDefined();
expect(pipeResponse.pipe.source).toEqual(prerequisites.source.sourceArn);
expect(pipeResponse.pipe.target).toEqual(prerequisites.target.targetArn);
expect(pipeResponse.pipeRole).toBeDefined();
expect(pipeResponse.pipeRole.node).toBeDefined();
}
function CheckPipeResource(template, pipeId, prerequisiteId) {
CheckPipeSourceAndTarget(template, prerequisiteId);
CheckPipeLogConfiguration(template, pipeId);
}
function CheckPipeSourceAndTarget(template, prerequisiteId) {
template.hasResourceProperties('AWS::Pipes::Pipe', {
Source: {
"Fn::GetAtt": [
assertions_1.Match.stringLikeRegexp(`${prerequisiteId}sourcequeue.*`),
"Arn"
]
},
Target: {
Ref: assertions_1.Match.stringLikeRegexp(`StateMachine${prerequisiteId}targetstatemachine.*`),
},
});
}
function CheckPipeLogConfiguration(template, pipeId) {
template.hasResourceProperties('AWS::Pipes::Pipe', {
LogConfiguration: {
CloudwatchLogsLogDestination: {
LogGroupArn: {
"Fn::GetAtt": [
assertions_1.Match.stringLikeRegexp(`LogGroup${pipeId}.*`),
"Arn"
]
}
}
}
});
}
function CheckPipeRole(template, prerequisiteId) {
template.hasResourceProperties('AWS::IAM::Role', {
AssumeRolePolicyDocument: {
Statement: [
{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "pipes.amazonaws.com"
}
}
],
Version: "2012-10-17"
},
Policies: [
{
PolicyDocument: {
Statement: [
{
Action: [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
],
Effect: "Allow",
Resource: {
"Fn::GetAtt": [
assertions_1.Match.stringLikeRegexp(`${prerequisiteId}sourcequeue.*`),
"Arn"
]
}
}
],
Version: "2012-10-17"
},
PolicyName: "sourcePolicy"
},
{
PolicyDocument: {
Statement: [
{
Action: "states:StartExecution",
Effect: "Allow",
Resource: {
Ref: assertions_1.Match.stringLikeRegexp(`StateMachine${prerequisiteId}targetstatemachine.*`)
}
}
],
Version: "2012-10-17"
},
PolicyName: "targetPolicy"
}
]
});
}
function CheckLogGroup(template) {
template.hasResourceProperties('AWS::Logs::LogGroup', {
LogGroupName: {
"Fn::Join": [
"",
[
assertions_1.Match.stringLikeRegexp('/aws/vendedlogs/pipes/constructs'),
{
"Fn::Select": [
2,
assertions_1.Match.anyValue()
]
}
]
]
},
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGlwZXMtaGVscGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJwaXBlcy1oZWxwZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7O0dBV0c7O0FBRUgsa0RBQStDO0FBQy9DLHNFQUFnRTtBQUNoRSx3RUFBNEU7QUFDNUUsNkNBQW9DO0FBQ3BDLGdDQUFnQztBQUVoQyxpREFBaUQ7QUFFakQseUNBQXlDO0FBQ3pDLHVEQUF5RDtBQUN6RCxtREFBcUQ7QUFFckQsb0NBQW9DO0FBQ3BDLHNDQUFzQztBQUN0QyxvQ0FBb0M7QUFFcEMsSUFBSSxDQUFDLDZCQUE2QixFQUFFLEdBQUcsRUFBRTtJQUN2QyxRQUFRO0lBQ1IsTUFBTSxLQUFLLEdBQUcsSUFBSSxtQkFBSyxFQUFFLENBQUM7SUFFMUIsTUFBTSxrQkFBa0IsR0FBRyxJQUFBLHVCQUFVLEVBQUMsS0FBSyxFQUFFLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMvRCxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsZUFBZSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRXJFLE1BQU0sQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN2RSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEUsMEVBQTBFO0lBQzFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RCxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUM1QixDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyxxQ0FBcUMsRUFBRSxHQUFH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