# © 2023 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. # This AWS Content is provided subject to the terms of the AWS Customer Agreement # available at http://aws.amazon.com/agreement or other written agreement between # Customer and either Amazon Web Services, Inc. or Amazon Web Services EMEA SARL or both. # # SPDX-License-Identifier: MIT-0 # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # software and associated documentation files (the "Software"), to deal in the Software # without restriction, including without limitation the rights to use, copy, modify, # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import unittest from botocore.stub import Stubber import boto3 from src.table_sync import dynamodb_stream_settings def test_build_dynamodb_stream_triggers(): lambda_client = boto3.client("lambda", "us-east-1") lambda_stubber = Stubber(lambda_client) lambda_stubber.activate() source_table_describe_response = { "Table": { "AttributeDefinitions": [ {"AttributeName": "department", "AttributeType": "S"}, {"AttributeName": "email", "AttributeType": "S"}, {"AttributeName": "phone_number", "AttributeType": "S"}, {"AttributeName": "salary", "AttributeType": "S"}, ], "TableName": "sample-table", "KeySchema": [ {"AttributeName": "email", "KeyType": "HASH"}, {"AttributeName": "phone_number", "KeyType": "RANGE"}, ], "TableStatus": "ACTIVE", "CreationDateTime": "2020-10-15T20:21:09.725000-04:00", "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, }, "TableSizeBytes": 79, "ItemCount": 1, "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table", "TableId": "d98ecabe-02e3-45cc-8247-72c2ea152468", "BillingModeSummary": { "BillingMode": "PROVISIONED", "LastUpdateToPayPerRequestDateTime": "2022-07-23T20:42:06.471000-04:00", }, "GlobalSecondaryIndexes": [ { "IndexName": "salary-department-index", "KeySchema": [ {"AttributeName": "salary", "KeyType": "HASH"}, {"AttributeName": "department", "KeyType": "RANGE"}, ], "Projection": {"ProjectionType": "ALL"}, "IndexStatus": "ACTIVE", "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, }, "IndexSizeBytes": 0, "ItemCount": 0, "IndexArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/index/salary-department" "-index ", } ], "StreamSpecification": { "StreamEnabled": True, "StreamViewType": "NEW_AND_OLD_IMAGES", }, "LatestStreamLabel": "2022-05-13T19:00:22.332", "LatestStreamArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/stream/2022-05-13T19:00:22" ".332", "GlobalTableVersion": "2019.11.21", "Replicas": [{"RegionName": "ap-south-1", "ReplicaStatus": "ACTIVE"}], } } lambda_stubber.add_response( "list_event_source_mappings", { "EventSourceMappings": [ { "UUID": "a73e82f9-d895-45db-b836-108516b49644", "StartingPosition": "LATEST", "BatchSize": 1, "MaximumBatchingWindowInSeconds": 0, "ParallelizationFactor": 1, "EventSourceArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/stream/2022-05" "-13T19:00:22 " ".332", "FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:print-event-paylaod", "LastModified": "2022-08-23T19:50:00-04:00", "LastProcessingResult": "No records processed", "State": "Enabled", "StateTransitionReason": "User action", "DestinationConfig": {"OnFailure": {}}, "MaximumRecordAgeInSeconds": -1, "BisectBatchOnFunctionError": False, "MaximumRetryAttempts": -1, "TumblingWindowInSeconds": 0, "FunctionResponseTypes": [], } ] }, { "EventSourceArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/stream/2022-05-13T19:00:22" ".332" }, ) expected_cfn_resources = { "EventSourceMapping1": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { "BatchSize": 1, "EventSourceArn": {"Fn::GetAtt": ["RestoredTable", "StreamArn"]}, "MaximumRecordAgeInSeconds": -1, "MaximumRetryAttempts": -1, "ParallelizationFactor": 1, "StartingPosition": "LATEST", "FunctionName": "arn:aws:lambda:us-east-1:123456789012:function:print-event-paylaod", }, } } actual_cfn_resources = dynamodb_stream_settings.build_dynamodb_stream_triggers( source_table_describe_response=source_table_describe_response, lambda_client=lambda_client, restored_table_cfn_logical_name="RestoredTable", ) assert actual_cfn_resources == expected_cfn_resources return def test_build_dynamodb_stream_template_stream_enabled(): source_table_describe_response = { "Table": { "AttributeDefinitions": [ {"AttributeName": "department", "AttributeType": "S"}, {"AttributeName": "email", "AttributeType": "S"}, {"AttributeName": "phone_number", "AttributeType": "S"}, {"AttributeName": "salary", "AttributeType": "S"}, ], "TableName": "sample-table", "KeySchema": [ {"AttributeName": "email", "KeyType": "HASH"}, {"AttributeName": "phone_number", "KeyType": "RANGE"}, ], "TableStatus": "ACTIVE", "CreationDateTime": "2020-10-15T20:21:09.725000-04:00", "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, }, "TableSizeBytes": 79, "ItemCount": 1, "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table", "TableId": "d98ecabe-02e3-45cc-8247-72c2ea152468", "BillingModeSummary": { "BillingMode": "PROVISIONED", "LastUpdateToPayPerRequestDateTime": "2022-07-23T20:42:06.471000-04:00", }, "GlobalSecondaryIndexes": [ { "IndexName": "salary-department-index", "KeySchema": [ {"AttributeName": "salary", "KeyType": "HASH"}, {"AttributeName": "department", "KeyType": "RANGE"}, ], "Projection": {"ProjectionType": "ALL"}, "IndexStatus": "ACTIVE", "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, }, "IndexSizeBytes": 0, "ItemCount": 0, "IndexArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/index/salary-department" "-index ", } ], "StreamSpecification": { "StreamEnabled": True, "StreamViewType": "NEW_AND_OLD_IMAGES", }, "LatestStreamLabel": "2022-05-13T19:00:22.332", "LatestStreamArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/stream/2022-05-13T19:00:22" ".332", "GlobalTableVersion": "2019.11.21", "Replicas": [{"RegionName": "ap-south-1", "ReplicaStatus": "ACTIVE"}], } } expected_stream_template = {"StreamViewType": "NEW_AND_OLD_IMAGES"} actual_stream_template = dynamodb_stream_settings.build_dynamodb_stream_template( source_table_describe_response=source_table_describe_response ) assert expected_stream_template == actual_stream_template def test_build_dynamodb_stream_template_stream_disabled(): source_table_describe_response = { "Table": { "AttributeDefinitions": [ {"AttributeName": "department", "AttributeType": "S"}, {"AttributeName": "email", "AttributeType": "S"}, {"AttributeName": "phone_number", "AttributeType": "S"}, {"AttributeName": "salary", "AttributeType": "S"}, ], "TableName": "sample-table", "KeySchema": [ {"AttributeName": "email", "KeyType": "HASH"}, {"AttributeName": "phone_number", "KeyType": "RANGE"}, ], "TableStatus": "ACTIVE", "CreationDateTime": "2020-10-15T20:21:09.725000-04:00", "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, }, "TableSizeBytes": 79, "ItemCount": 1, "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table", "TableId": "d98ecabe-02e3-45cc-8247-72c2ea152468", "BillingModeSummary": { "BillingMode": "PROVISIONED", "LastUpdateToPayPerRequestDateTime": "2022-07-23T20:42:06.471000-04:00", }, "GlobalSecondaryIndexes": [ { "IndexName": "salary-department-index", "KeySchema": [ {"AttributeName": "salary", "KeyType": "HASH"}, {"AttributeName": "department", "KeyType": "RANGE"}, ], "Projection": {"ProjectionType": "ALL"}, "IndexStatus": "ACTIVE", "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, }, "IndexSizeBytes": 0, "ItemCount": 0, "IndexArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/index/salary-department" "-index ", } ], "LatestStreamLabel": "2022-05-13T19:00:22.332", "LatestStreamArn": "arn:aws:dynamodb:us-east-1:123456789012:table/source-table/stream/2022-05-13T19:00:22" ".332", "GlobalTableVersion": "2019.11.21", "Replicas": [{"RegionName": "ap-south-1", "ReplicaStatus": "ACTIVE"}], } } expected_stream_template = None actual_stream_template = dynamodb_stream_settings.build_dynamodb_stream_template( source_table_describe_response=source_table_describe_response ) assert expected_stream_template == actual_stream_template if __name__ == "__main__": unittest.main()