import os import sys import json import pytest from click.testing import CliRunner from chalice.cli import newproj try: from aws_cdk import core as cdk CDK_VERSION = 1 except ImportError: try: import aws_cdk as cdk CDK_VERSION = 2 except ImportError: pytestmark = pytest.mark.skip( "aws_cdk package needed to run CDK tests.") @pytest.fixture def runner(): return CliRunner() def verify_code_asset_exists_v1(uri_props): bucket_ref = uri_props['Bucket']['Ref'] assert bucket_ref.startswith('AssetParameters') def verify_code_asset_exists_v2(uri_props): bucket_ref = uri_props['Bucket']['Fn::Sub'] # Actual sub value will look something like this: # 'cdk-abcdefghi-assets-${AWS::AccountId}-${AWS::Region}'}, assert bucket_ref.startswith('cdk-') @pytest.fixture def verify_code_asset_exists(): if CDK_VERSION == 1: return verify_code_asset_exists_v1 elif CDK_VERSION == 2: return verify_code_asset_exists_v2 def load_chalice_construct(dirname, stack_name='testcdk'): try: sys.path.append(dirname) sys.modules.pop('stacks.chaliceapp', None) sys.modules.pop('stacks', None) import stacks.chaliceapp app = cdk.App() chalice_app = stacks.chaliceapp.ChaliceApp(app, stack_name) return app, chalice_app.chalice finally: sys.modules.pop('app', None) sys.modules.pop('stacks', None) sys.path.pop() sys.path_importer_cache.clear() def filter_resources(template, resource_type): return [(name, props) for name, props in template['Resources'].items() if props['Type'] == resource_type] def test_cdk_construct_api(runner): # The CDK loading/synth can take a while so we're testing the # various APIs out in one test to cut down on test time. with runner.isolated_filesystem(): newproj.create_new_project_skeleton( 'testcdk', project_type='cdk-ddb') dirname = os.path.abspath(os.path.join('testcdk', 'infrastructure')) os.chdir(dirname) cdk_app, chalice_app = load_chalice_construct(dirname, 'testcdk') api_handler = chalice_app.get_function('APIHandler') assert api_handler == chalice_app.get_function('APIHandler') role = chalice_app.get_role('DefaultRole') assert hasattr(role, 'role_name') def test_can_package_as_cdk_app(runner, verify_code_asset_exists): # The CDK loading/synth can take a while so we're testing the # various APIs out in one test to cut down on test time. with runner.isolated_filesystem(): newproj.create_new_project_skeleton( 'testcdkpackage', project_type='cdk-ddb') dirname = os.path.abspath(os.path.join('testcdkpackage', 'infrastructure')) os.chdir(dirname) cdk_app, chalice_app = load_chalice_construct( dirname, 'testcdkpackage') assembly = cdk_app.synth() stack = assembly.get_stack_by_name('testcdkpackage') cfn_template = stack.template resources = cfn_template['Resources'] # Sanity check that we have the resources from Chalice as well as the # resources from the ChaliceApp construct. assert 'APIHandler' in resources assert 'DefaultRole' in resources ddb_tables = filter_resources(cfn_template, 'AWS::DynamoDB::Table')[0] # CDK adds a random suffix to our resource name so we verify that # the name starts with our provided name "AppTable". assert ddb_tables[0].startswith('AppTable') # We also need to verify that we've replaces the CodUri with the # CDK specific assets. functions = filter_resources( cfn_template, 'AWS::Serverless::Function')[0] verify_code_asset_exists(functions[1]['Properties']['CodeUri']) def test_can_package_managed_layer(runner, verify_code_asset_exists): with runner.isolated_filesystem(): newproj.create_new_project_skeleton( 'testcdklayers', project_type='cdk-ddb') project_dir = os.path.abspath('testcdklayers') config_file = os.path.join(project_dir, 'runtime', '.chalice', 'config.json') with open(config_file) as f: config = json.load(f) config['automatic_layer'] = True with open(config_file, 'w') as f: f.write(json.dumps(config)) infrastructure_dir = os.path.join(project_dir, 'infrastructure') os.chdir(infrastructure_dir) cdk_app, chalice_app = load_chalice_construct(infrastructure_dir, 'testcdklayers') assembly = cdk_app.synth() stack = assembly.get_stack_by_name('testcdklayers') cfn_template = stack.template layers = filter_resources( cfn_template, 'AWS::Serverless::LayerVersion')[0] verify_code_asset_exists(layers[1]['Properties']['ContentUri'])