import re from aws_cdk import aws_sns as sns from aws_cdk import core as cdk from aws_cdk.assertions import Capture, Match, Template from app.processor_stack import ProcessorStack def test_synthesizes_properly(): app = cdk.App() # Since the ProcessorStack consumes resources from a separate stack # (cross-stack references), we create a stack for our SNS topics to live # in here. These topics can then be passed to the ProcessorStack later, # creating a cross-stack reference. topics_stack = cdk.Stack(app, "TopicsStack") # Create the topic the stack we're testing will reference. topics = [sns.Topic(topics_stack, "Topic1")] # Create the ProcessorStack. processor_stack = ProcessorStack( app, "ProcessorStack", topics=topics # Cross-stack reference ) # Prepare the stack for assertions. template = Template.from_stack(processor_stack) # Assert it creates the function with the correct properties... template.has_resource_properties( "AWS::Lambda::Function", { "Handler": "handler", "Runtime": "nodejs14.x", }, ) # Creates the subscription... template.resource_count_is("AWS::SNS::Subscription", 1) # Gives permission to SNS to invoke the function for the topic... template.has_resource_properties( "AWS::Lambda::Permission", { "Action": "lambda:InvokeFunction", "Principal": "sns.amazonaws.com", }, ) # Creates the function's execution role... template.has_resource_properties( "AWS::IAM::Role", { "AssumeRolePolicyDocument": { "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com", }, }, ], }, }, ) # And finally the execution role's policy template.has_resource_properties( "AWS::IAM::Policy", { # It should be allowed to execute the state machine "PolicyDocument": { "Statement": [ # We need to use Match.object_like() explicitly since we're now # inside an array. Match.object_like( { "Action": "states:StartExecution", "Effect": "Allow", } ), ], }, }, ) # Fully assert on the state machine's IAM role with matchers. template.has_resource_properties( "AWS::IAM::Role", Match.object_equals( { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": { "Fn::Join": [ "", [ "states.", Match.any_value(), ".amazonaws.com", ], ], }, }, }, ], }, } ), ) # Assert on the state machine's definition with the serialized_json matcher. template.has_resource_properties( "AWS::StepFunctions::StateMachine", { "DefinitionString": Match.serialized_json( # Match.object_equals() is used implicitly, but we use it explicitly # here for extra clarity. Match.object_equals( { "StartAt": "StartState", "States": { "StartState": { "Type": "Pass", "End": True, # Make sure this state doesn't provide a next state -- # we can't provide both Next and set End to true. "Next": Match.absent(), }, }, } ) ), }, ) # Capture some data from the state machine's definition. start_at_capture = Capture() states_capture = Capture() template.has_resource_properties( "AWS::StepFunctions::StateMachine", { "DefinitionString": Match.serialized_json( Match.object_like( { "StartAt": start_at_capture, "States": states_capture, } ) ), }, ) # Assert that the start state starts with "Start". assert re.match("^Start", start_at_capture.as_string()) # Assert that the start state actually exists in the states object of the # state machine definition. assert start_at_capture.as_string() in states_capture.as_object()