示例#1
0
def test_can_create_default_deployer():
    session = botocore.session.get_session()
    deployer = create_default_deployer(session, Config.create(
        project_dir='.',
        chalice_stage='dev',
    ), UI())
    assert isinstance(deployer, Deployer)
示例#2
0
    def test_managed_layer_removed_if_no_deps(self):
        function = create_function_resource('myfunction')
        function.managed_layer = models.LambdaLayer(
            resource_name='managed-layer',
            layer_name='appname-dev-managed-layer',
            runtime='python2.7',
            deployment_package=models.DeploymentPackage(
                models.Placeholder.BUILD_STAGE
            )
        )
        lambda_packager = mock.Mock(spec=packager.BaseLambdaDeploymentPackager)
        layer_packager = mock.Mock(spec=packager.BaseLambdaDeploymentPackager)
        lambda_packager.create_deployment_package.return_value = 'package.zip'
        layer_packager.create_deployment_package.side_effect = \
            packager.EmptyPackageError()

        config = Config.create(project_dir='.')

        p = ManagedLayerDeploymentPackager(lambda_packager, layer_packager)
        p.handle(config, function.managed_layer)
        p.handle(config, function)
        # If the deployment package for layers would result in an empty
        # deployment package, we expect that resource to be removed, it can't
        # be created on the service.
        assert function.managed_layer is None
示例#3
0
def test_load_policy_from_disk_when_file_exists(app_policy, in_memory_osutils):
    previous_policy = '{"Statement": ["foo"]}'
    config = Config.create(project_dir='.')
    filename = os.path.join('.', '.chalice', 'policy-dev.json')
    in_memory_osutils.filemap[filename] = previous_policy
    loaded = app_policy.load_last_policy(config)
    assert loaded == json.loads(previous_policy)
示例#4
0
    def test_single_role_generated_for_default_config(self,
                                                      sample_app_lambda_only):
        # The sample_app has one lambda function.
        # We'll add a few more and verify they all share the same role.
        @sample_app_lambda_only.lambda_function()
        def second(event, context):
            pass

        @sample_app_lambda_only.lambda_function()
        def third(event, context):
            pass

        config = Config.create(chalice_app=sample_app_lambda_only,
                               project_dir='.',
                               autogen_policy=True,
                               api_gateway_stage='api')
        template = self.generate_template(config, 'dev')
        roles = [resource for resource in template['Resources'].values()
                 if resource['Type'] == 'AWS::IAM::Role']
        assert len(roles) == 1
        # The lambda functions should all reference this role.
        functions = [
            resource for resource in template['Resources'].values()
            if resource['Type'] == 'AWS::Serverless::Function'
        ]
        role_names = [
            function['Properties']['Role'] for function in functions
        ]
        assert role_names == [
            {'Fn::GetAtt': ['DefaultRole', 'Arn']},
            {'Fn::GetAtt': ['DefaultRole', 'Arn']},
            {'Fn::GetAtt': ['DefaultRole', 'Arn']},
        ]
示例#5
0
 def test_can_generate_rest_api(self, sample_app_with_auth):
     config = Config.create(chalice_app=sample_app_with_auth,
                            project_dir='.',
                            api_gateway_stage='api',
                            minimum_compression_size=100,
                            )
     template = self.generate_template(config, 'dev')
     resources = template['Resources']
     # Lambda function should be created.
     assert resources['APIHandler']['Type'] == 'AWS::Serverless::Function'
     # Along with permission to invoke from API Gateway.
     assert resources['APIHandlerInvokePermission'] == {
         'Type': 'AWS::Lambda::Permission',
         'Properties': {
             'Action': 'lambda:InvokeFunction',
             'FunctionName': {'Ref': 'APIHandler'},
             'Principal': 'apigateway.amazonaws.com',
             'SourceArn': {
                 'Fn::Sub': [
                     ('arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}'
                      ':${RestAPIId}/*'),
                     {'RestAPIId': {'Ref': 'RestAPI'}}]}},
     }
     assert resources['RestAPI']['Type'] == 'AWS::Serverless::Api'
     assert resources['RestAPI']['Properties']['MinimumCompressionSize'] \
         == 100
     # We should also create the auth lambda function.
     assert resources['Myauth']['Type'] == 'AWS::Serverless::Function'
     # Along with permission to invoke from API Gateway.
     assert resources['MyauthInvokePermission'] == {
         'Type': 'AWS::Lambda::Permission',
         'Properties': {
             'Action': 'lambda:InvokeFunction',
             'FunctionName': {'Fn::GetAtt': ['Myauth', 'Arn']},
             'Principal': 'apigateway.amazonaws.com',
             'SourceArn': {
                 'Fn::Sub': [
                     ('arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}'
                      ':${RestAPIId}/*'),
                     {'RestAPIId': {'Ref': 'RestAPI'}}]}},
     }
     # Also verify we add the expected outputs when using
     # a Rest API.
     assert template['Outputs'] == {
         'APIHandlerArn': {
             'Value': {
                 'Fn::GetAtt': ['APIHandler', 'Arn']
             }
         },
         'APIHandlerName': {'Value': {'Ref': 'APIHandler'}},
         'EndpointURL': {
             'Value': {
                 'Fn::Sub': (
                     'https://${RestAPI}.execute-api.'
                     '${AWS::Region}.amazonaws.com/api/'
                 )
             }
         },
         'RestAPIId': {'Value': {'Ref': 'RestAPI'}}
     }
示例#6
0
    def test_deploy_delegates_properly(self):
        app = mock.Mock(spec=models.Application)
        resources = [mock.Mock(spec=models.Model)]
        api_calls = [mock.Mock(spec=APICall)]

        self.resource_builder.build.return_value = app
        self.deps_builder.build_dependencies.return_value = resources
        self.plan_stage.execute.return_value = api_calls
        self.executor.resource_values = {'foo': {'name': 'bar'}}

        deployer = self.create_deployer()
        config = Config.create(project_dir='.', chalice_app=self.chalice_app)
        result = deployer.deploy(config, 'dev')

        self.resource_builder.build.assert_called_with(config, 'dev')
        self.deps_builder.build_dependencies.assert_called_with(app)
        self.build_stage.execute.assert_called_with(config, resources)
        self.plan_stage.execute.assert_called_with(resources)
        self.sweeper.execute.assert_called_with(api_calls, config)
        self.executor.execute.assert_called_with(api_calls)

        expected_result = {
            'resources': {
                'foo': {
                    'name': 'bar'
                }
            },
            'schema_version': '2.0',
            'backend': 'api',
        }

        self.recorder.record_results.assert_called_with(
            expected_result, 'dev', '.')
        assert result == expected_result
示例#7
0
    def test_deploy_errors_raises_chalice_error(self):
        self.resource_builder.build.side_effect = AWSClientError()

        deployer = self.create_deployer()
        config = Config.create(project_dir='.', chalice_app=self.chalice_app)
        with pytest.raises(ChaliceDeploymentError):
            deployer.deploy(config, 'dev')
示例#8
0
    def test_can_generate_layer_package(self):
        function = create_function_resource('myfunction')
        function.managed_layer = models.LambdaLayer(
            resource_name='managed-layer',
            layer_name='appname-dev-managed-layer',
            runtime='python2.7',
            deployment_package=models.DeploymentPackage(
                models.Placeholder.BUILD_STAGE))
        lambda_packager = mock.Mock(spec=packager.BaseLambdaDeploymentPackager)
        layer_packager = mock.Mock(spec=packager.BaseLambdaDeploymentPackager)
        lambda_packager.create_deployment_package.return_value = 'package.zip'
        layer_packager.create_deployment_package.return_value = (
            'package-layer.zip')

        config = Config.create(project_dir='.')

        p = ManagedLayerDeploymentPackager(lambda_packager, layer_packager)
        p.handle(config, function.managed_layer)
        p.handle(config, function)
        assert function.deployment_package.filename == 'package.zip'
        lambda_packager.create_deployment_package.assert_called_with(
            '.', config.lambda_python_version)
        assert function.managed_layer.deployment_package.filename == (
            'package-layer.zip')
        layer_packager.create_deployment_package.assert_called_with(
            '.', config.lambda_python_version)
示例#9
0
def config_obj(sample_app):
    config = Config.create(
        chalice_app=sample_app,
        stage='dev',
        api_gateway_stage='api',
    )
    return config
示例#10
0
 def test_no_injection_when_values_are_set(self):
     injector = InjectDefaults(
         lambda_timeout=100,
         lambda_memory_size=512,
     )
     function = models.LambdaFunction(
         # The timeout/memory_size are set to
         # None, so the injector should fill them
         # in the with the default values above.
         timeout=1,
         memory_size=1,
         resource_name='foo',
         function_name='app-stage-foo',
         environment_variables={},
         runtime='python2.7',
         handler='app.app',
         tags={},
         deployment_package=None,
         role=None,
         security_group_ids=[],
         subnet_ids=[],
         layers=[],
         reserved_concurrency=None,
     )
     config = Config.create()
     injector.handle(config, function)
     assert function.timeout == 1
     assert function.memory_size == 1
示例#11
0
def test_config_create_method():
    c = Config.create(app_name='foo')
    assert c.app_name == 'foo'
    # Otherwise attributes default to None meaning 'not set'.
    assert c.lambda_arn is None
    assert c.profile is None
    assert c.stage is None
示例#12
0
def test_deployer_returns_deployed_resources(sample_app):
    cfg = Config.create(
        chalice_stage='dev',
        chalice_app=sample_app,
        project_dir='.',
    )
    lambda_deploy = mock.Mock(spec=LambdaDeployer)
    apig_deploy = mock.Mock(spec=APIGatewayDeployer)

    apig_deploy.deploy.return_value = ('api_id', 'region', 'stage')
    lambda_deploy.deploy.return_value = {
        'api_handler_name': 'lambda_function',
        'api_handler_arn': 'my_lambda_arn',
    }

    d = Deployer(apig_deploy, lambda_deploy)
    deployed_values = d.deploy(cfg)
    assert deployed_values == {
        'dev': {
            'backend': 'api',
            'api_handler_arn': 'my_lambda_arn',
            'api_handler_name': 'lambda_function',
            'rest_api_id': 'api_id',
            'api_gateway_stage': 'stage',
            'region': 'region',
            'chalice_version': chalice_version,
        }
    }
示例#13
0
 def test_tags_specified_does_not_override_chalice_tag(self):
     c = Config.create(chalice_stage='dev',
                       app_name='myapp',
                       tags={'aws-chalice': 'attempted-override'})
     assert c.tags == {
         'aws-chalice': 'version=%s:stage=dev:app=myapp' % chalice_version,
     }
示例#14
0
def test_can_create_app_packager_with_no_autogen():
    # We can't actually observe a change here, but we want
    # to make sure the function can handle this param being
    # False.
    config = Config.create(autogen_policy=False)
    packager = package.create_app_packager(config)
    assert isinstance(packager, package.AppPackager)
示例#15
0
def test_validation_error_if_no_role_provided_when_manage_false(sample_app):
    # We're indicating that we should not be managing the
    # IAM role, but we're not giving a role ARN to use.
    # This is a validation error.
    config = Config.create(chalice_app=sample_app, manage_iam_role=False)
    with pytest.raises(ValueError):
        validate_configuration(config)
示例#16
0
 def test_tags_specified_does_not_override_chalice_tag(self):
     c = Config.create(
         chalice_stage='dev', app_name='myapp',
         tags={'aws-chalice': 'attempted-override'})
     assert c.tags == {
         'aws-chalice': 'version=%s:stage=dev:app=myapp' % chalice_version,
     }
示例#17
0
    def test_lambda_deployer_with_tags(self, sample_app):
        cfg = Config.create(chalice_stage='dev',
                            app_name='myapp',
                            chalice_app=sample_app,
                            manage_iam_role=False,
                            iam_role_arn='role-arn',
                            project_dir='.',
                            tags={'mykey': 'myvalue'})
        deployer = LambdaDeployer(self.aws_client, self.packager, None,
                                  self.osutils, self.app_policy)

        deployer.deploy(cfg, None, 'dev')
        self.aws_client.create_function.assert_called_with(
            function_name='myapp-dev',
            role_arn='role-arn',
            zip_contents=b'package contents',
            runtime=cfg.lambda_python_version,
            tags={
                'aws-chalice':
                'version=%s:stage=dev:app=myapp' % (chalice_version),
                'mykey': 'myvalue'
            },
            environment_variables={},
            timeout=60,
            memory_size=128)
示例#18
0
    def test_single_role_generated_for_default_config(self,
                                                      sample_app_lambda_only):
        # The sample_app has one lambda function.
        # We'll add a few more and verify they all share the same role.
        @sample_app_lambda_only.lambda_function()
        def second(event, context):
            pass

        @sample_app_lambda_only.lambda_function()
        def third(event, context):
            pass

        config = Config.create(chalice_app=sample_app_lambda_only,
                               project_dir='.',
                               autogen_policy=True,
                               api_gateway_stage='api')
        template = self.generate_template(config, 'dev')
        roles = [resource for resource in template['Resources'].values()
                 if resource['Type'] == 'AWS::IAM::Role']
        assert len(roles) == 1
        # The lambda functions should all reference this role.
        functions = [
            resource for resource in template['Resources'].values()
            if resource['Type'] == 'AWS::Serverless::Function'
        ]
        role_names = [
            function['Properties']['Role'] for function in functions
        ]
        assert role_names == [
            {'Fn::GetAtt': ['DefaultRole', 'Arn']},
            {'Fn::GetAtt': ['DefaultRole', 'Arn']},
            {'Fn::GetAtt': ['DefaultRole', 'Arn']},
        ]
示例#19
0
def test_lambda_deployer_initial_deploy(app_policy, sample_app):
    osutils = InMemoryOSUtils({'packages.zip': b'package contents'})
    aws_client = mock.Mock(spec=TypedAWSClient)
    aws_client.create_function.return_value = 'lambda-arn'
    packager = mock.Mock(LambdaDeploymentPackager)
    packager.create_deployment_package.return_value = 'packages.zip'
    cfg = Config.create(chalice_stage='dev',
                        app_name='myapp',
                        chalice_app=sample_app,
                        manage_iam_role=False,
                        iam_role_arn='role-arn',
                        project_dir='.',
                        environment_variables={"FOO": "BAR"},
                        lambda_timeout=120,
                        lambda_memory_size=256,
                        tags={'mykey': 'myvalue'})

    d = LambdaDeployer(aws_client, packager, None, osutils, app_policy)
    deployed = d.deploy(cfg, None, 'dev')
    assert deployed == {
        'api_handler_arn': 'lambda-arn',
        'api_handler_name': 'myapp-dev',
    }
    aws_client.create_function.assert_called_with(
        function_name='myapp-dev',
        role_arn='role-arn',
        zip_contents=b'package contents',
        environment_variables={"FOO": "BAR"},
        runtime=cfg.lambda_python_version,
        tags={
            'aws-chalice': 'version=%s:stage=dev:app=myapp' % chalice_version,
            'mykey': 'myvalue'
        },
        timeout=120,
        memory_size=256)
示例#20
0
def test_prompted_on_runtime_change_can_reject_change(app_policy, sample_app):
    osutils = InMemoryOSUtils({'packages.zip': b'package contents'})
    aws_client = mock.Mock(spec=TypedAWSClient)
    packager = mock.Mock(spec=LambdaDeploymentPackager)
    packager.deployment_package_filename.return_value = 'packages.zip'
    aws_client.lambda_function_exists.return_value = True
    aws_client.get_function_configuration.return_value = {
        'Runtime': 'python1.0',
    }
    aws_client.update_function.return_value = {"FunctionArn": "myarn"}
    cfg = Config.create(
        chalice_stage='dev',
        chalice_app=sample_app,
        manage_iam_role=False,
        app_name='appname',
        iam_role_arn=True,
        project_dir='./myproject',
        environment_variables={"FOO": "BAR"},
    )
    prompter = mock.Mock(spec=NoPrompt)
    prompter.confirm.side_effect = RuntimeError("Aborted")

    d = LambdaDeployer(aws_client, packager, prompter, osutils, app_policy)
    # Doing a lambda deploy with a different runtime:
    lambda_function_name = 'lambda_function_name'
    deployed = DeployedResources('api', 'api_handler_arn',
                                 lambda_function_name, None, 'dev', None, None)
    with pytest.raises(RuntimeError):
        d.deploy(cfg, deployed, 'dev')

    assert not packager.inject_latest_app.called
    assert not aws_client.update_function.called
    assert prompter.confirm.called
    message = prompter.confirm.call_args[0][0]
    assert 'runtime will change' in message
示例#21
0
def test_app_policy_generator_vpc_policy():
    config = Config.create(subnet_ids=['sn1', 'sn2'],
                           security_group_ids=['sg1', 'sg2'],
                           project_dir='.')
    generator = AppPolicyGenerator(OsUtilsMock())
    policy = generator.generate_policy(config)
    assert policy == {
        'Statement': [
            {
                'Action': [
                    'logs:CreateLogGroup', 'logs:CreateLogStream',
                    'logs:PutLogEvents'
                ],
                'Effect':
                'Allow',
                'Resource':
                'arn:aws:logs:*:*:*'
            },
            {
                'Action': [
                    'ec2:CreateNetworkInterface',
                    'ec2:DescribeNetworkInterfaces',
                    'ec2:DetachNetworkInterface', 'ec2:DeleteNetworkInterface'
                ],
                'Effect':
                'Allow',
                'Resource':
                '*'
            },
        ],
        'Version':
        '2012-10-17'
    }
示例#22
0
def test_validation_error_if_no_role_provided_when_manage_false(sample_app):
    # We're indicating that we should not be managing the
    # IAM role, but we're not giving a role ARN to use.
    # This is a validation error.
    config = Config.create(chalice_app=sample_app, manage_iam_role=False)
    with pytest.raises(ValueError):
        validate_configuration(config)
示例#23
0
def test_can_create_deployer_with_layer_builds():
    session = botocore.session.get_session()
    deployer = create_default_deployer(session, Config.create(
        project_dir='.',
        chalice_stage='dev',
        automatic_layer=True,
    ), UI())
    assert isinstance(deployer, Deployer)
示例#24
0
    def test_error_raised_if_file_policy_not_exists(self):
        p = self.create_policy_generator()
        policy = models.FileBasedIAMPolicy(
            filename='foo.json', document=models.Placeholder.BUILD_STAGE)
        self.osutils.get_file_contents.side_effect = IOError()

        with pytest.raises(RuntimeError):
            p.handle(Config.create(), policy)
示例#25
0
def test_policy_autogenerated_when_enabled(app_policy, in_memory_osutils):
    cfg = Config.create(autogen_policy=True, project_dir='.')
    in_memory_osutils.filemap['./app.py'] = ''
    generated = app_policy.generate_policy_from_app_source(cfg)
    # We don't actually need to validate the exact policy, we'll just
    # check that it looks ok.
    assert 'Statement' in generated
    assert 'Version' in generated
示例#26
0
def test_no_policy_generated_when_disabled_in_config(app_policy,
                                                     in_memory_osutils):
    previous_policy = '{"Statement": ["foo"]}'
    filename = os.path.join('.', '.chalice', 'policy.json')
    in_memory_osutils.filemap[filename] = previous_policy
    cfg = Config.create(autogen_policy=False, project_dir='.')
    generated = app_policy.generate_policy_from_app_source(cfg)
    assert generated == json.loads(previous_policy)
示例#27
0
    def test_can_generate_rest_api(self, sample_app_with_auth):
        config = Config.create(chalice_app=sample_app_with_auth,
                               project_dir='.',
                               minimum_compression_size=8192,
                               api_gateway_endpoint_type='PRIVATE',
                               api_gateway_endpoint_vpce='vpce-abc123',
                               app_name='sample_app',
                               api_gateway_stage='api')
        template = self.generate_template(config, 'dev')
        resources = template['resource']
        # Lambda function should be created.
        assert resources['aws_lambda_function']
        # Along with permission to invoke from API Gateway.
        assert list(resources['aws_lambda_permission'].values())[0] == {
            'function_name': 'sample_app-dev',
            'action': 'lambda:InvokeFunction',
            'principal': 'apigateway.amazonaws.com',
            'source_arn':
            ('${aws_api_gateway_rest_api.rest_api.execution_arn}/*')
        }
        assert resources['aws_api_gateway_rest_api']
        assert resources['aws_api_gateway_rest_api']['rest_api']['policy']
        assert resources['aws_api_gateway_rest_api']['rest_api'][
            'minimum_compression_size'] == 8192
        assert resources['aws_api_gateway_rest_api']['rest_api'][
            'endpoint_configuration'] == {
                'types': ['PRIVATE']
            }

        assert 'aws_api_gateway_stage' not in resources
        assert resources['aws_api_gateway_deployment']['rest_api'] == {
            'rest_api_id':
            '${aws_api_gateway_rest_api.rest_api.id}',
            'stage_description':
            ('${md5(data.template_file.chalice_api_swagger.rendered)}'),
            'stage_name':
            'api'
        }

        # We should also create the auth lambda function.
        assert 'myauth' in resources['aws_lambda_function']

        # Along with permission to invoke from API Gateway.
        assert resources['aws_lambda_permission']['myauth_invoke'] == {
            'action': 'lambda:InvokeFunction',
            'function_name': 'sample_app-dev-myauth',
            'principal': 'apigateway.amazonaws.com',
            'source_arn':
            ('${aws_api_gateway_rest_api.rest_api.execution_arn}/*')
        }

        # Also verify we add the expected outputs when using
        # a Rest API.
        assert template['output'] == {
            'EndpointURL': {
                'value': '${aws_api_gateway_deployment.rest_api.invoke_url}'
            }
        }
示例#28
0
def new_project(project_name, profile):
    # type: (str, str) -> None
    if project_name is None:
        project_name = getting_started_prompt(click)
    if os.path.isdir(project_name):
        click.echo("Directory already exists: %s" % project_name, err=True)
        raise click.Abort()
    create_new_project_skeleton(project_name, profile)
    validate_python_version(Config.create())
示例#29
0
def test_queue_arn_must_be_arn(sample_app):
    @sample_app.on_sqs_message(
        queue_arn='https://sqs.us-west-2.amazonaws.com/12345/myqueue')
    def handler(event):
        pass

    config = Config.create(chalice_app=sample_app)
    with pytest.raises(ValueError):
        validate_configuration(config)
示例#30
0
    def test_validation_errors_raise_failure(self):
        @self.chalice_app.route('')
        def bad_route_empty_string():
            return {}

        deployer = self.create_deployer()
        config = Config.create(project_dir='.', chalice_app=self.chalice_app)
        with pytest.raises(ChaliceDeploymentError):
            deployer.deploy(config, 'dev')
示例#31
0
def test_will_create_outdir_if_needed(tmpdir):
    appdir = _create_app_structure(tmpdir)
    outdir = str(appdir.join('outdir'))
    config = Config.create(project_dir=str(appdir), chalice_app=sample_app())
    p = package.create_app_packager(config)
    p.package_app(config, str(outdir))
    contents = os.listdir(str(outdir))
    assert 'deployment.zip' in contents
    assert 'sam.json' in contents
示例#32
0
def new_project(project_name, profile):
    # type: (str, str) -> None
    if project_name is None:
        project_name = getting_started_prompt(click)
    if os.path.isdir(project_name):
        click.echo("Directory already exists: %s" % project_name, err=True)
        raise click.Abort()
    create_new_project_skeleton(project_name, profile)
    validate_python_version(Config.create())
示例#33
0
def test_preconfigured_policy_proxies():
    policy_gen = mock.Mock(spec=ApplicationPolicyHandler)
    config = Config.create(project_dir='project_dir', autogen_policy=False)
    generator = package.PreconfiguredPolicyGenerator(config,
                                                     policy_gen=policy_gen)
    policy_gen.generate_policy_from_app_source.return_value = {'policy': True}
    policy = generator.generate_policy_from_app_source()
    policy_gen.generate_policy_from_app_source.assert_called_with(config)
    assert policy == {'policy': True}
示例#34
0
 def test_can_generate_rest_api(self, sample_app_with_auth):
     config = Config.create(chalice_app=sample_app_with_auth,
                            project_dir='.',
                            api_gateway_stage='api')
     template = self.generate_template(config, 'dev')
     resources = template['Resources']
     # Lambda function should be created.
     assert resources['APIHandler']['Type'] == 'AWS::Serverless::Function'
     # Along with permission to invoke from API Gateway.
     assert resources['APIHandlerInvokePermission'] == {
         'Type': 'AWS::Lambda::Permission',
         'Properties': {
             'Action': 'lambda:InvokeFunction',
             'FunctionName': {'Ref': 'APIHandler'},
             'Principal': 'apigateway.amazonaws.com',
             'SourceArn': {
                 'Fn::Sub': [
                     ('arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}'
                      ':${RestAPIId}/*'),
                     {'RestAPIId': {'Ref': 'RestAPI'}}]}},
     }
     assert resources['RestAPI']['Type'] == 'AWS::Serverless::Api'
     # We should also create the auth lambda function.
     assert resources['Myauth']['Type'] == 'AWS::Serverless::Function'
     # Along with permission to invoke from API Gateway.
     assert resources['MyauthInvokePermission'] == {
         'Type': 'AWS::Lambda::Permission',
         'Properties': {
             'Action': 'lambda:InvokeFunction',
             'FunctionName': {'Fn::GetAtt': ['Myauth', 'Arn']},
             'Principal': 'apigateway.amazonaws.com',
             'SourceArn': {
                 'Fn::Sub': [
                     ('arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}'
                      ':${RestAPIId}/*'),
                     {'RestAPIId': {'Ref': 'RestAPI'}}]}},
     }
     # Also verify we add the expected outputs when using
     # a Rest API.
     assert template['Outputs'] == {
         'APIHandlerArn': {
             'Value': {
                 'Fn::GetAtt': ['APIHandler', 'Arn']
             }
         },
         'APIHandlerName': {'Value': {'Ref': 'APIHandler'}},
         'EndpointURL': {
             'Value': {
                 'Fn::Sub': (
                     'https://${RestAPI}.execute-api.'
                     '${AWS::Region}.amazonaws.com/api/'
                 )
             }
         },
         'RestAPIId': {'Value': {'Ref': 'RestAPI'}}
     }
示例#35
0
    def test_policy_loaded_from_file_if_needed(self):
        p = self.create_policy_generator()
        policy = models.FileBasedIAMPolicy(
            filename='foo.json', document=models.Placeholder.BUILD_STAGE)
        self.osutils.get_file_contents.return_value = '{"iam": "policy"}'

        p.handle(Config.create(), policy)

        assert policy.document == {'iam': 'policy'}
        self.osutils.get_file_contents.assert_called_with('foo.json')
示例#36
0
    def test_invokes_policy_generator(self):
        generator = mock.Mock(spec=AppPolicyGenerator)
        generator.generate_policy.return_value = {'policy': 'doc'}
        policy = models.AutoGenIAMPolicy(models.Placeholder.BUILD_STAGE)
        config = Config.create()

        p = self.create_policy_generator(generator)
        p.handle(config, policy)

        assert policy.document == {'policy': 'doc'}
示例#37
0
def test_preconfigured_policy_proxies():
    policy_gen = mock.Mock(spec=ApplicationPolicyHandler)
    config = Config.create(project_dir='project_dir', autogen_policy=False)
    generator = package.PreconfiguredPolicyGenerator(
        config, policy_gen=policy_gen)
    policy_gen.generate_policy_from_app_source.return_value = {
        'policy': True}
    policy = generator.generate_policy_from_app_source()
    policy_gen.generate_policy_from_app_source.assert_called_with(config)
    assert policy == {'policy': True}
示例#38
0
def test_will_create_outdir_if_needed(tmpdir):
    appdir = _create_app_structure(tmpdir)
    outdir = str(appdir.join('outdir'))
    config = Config.create(project_dir=str(appdir),
                           chalice_app=sample_app())
    p = package.create_app_packager(config)
    p.package_app(config, str(outdir))
    contents = os.listdir(str(outdir))
    assert 'deployment.zip' in contents
    assert 'sam.json' in contents
示例#39
0
def test_validate_names_using_name_kwarg(sample_app):
    @sample_app.authorizer(name='duplicate')
    def foo(auth_request):
        pass

    @sample_app.lambda_function(name='duplicate')
    def bar(event):
        pass

    config = Config.create(chalice_app=sample_app, manage_iam_role=False)
    with pytest.raises(ValueError):
        validate_unique_function_names(config)
示例#40
0
def test_validate_names_across_function_types(sample_app):
    @sample_app.lambda_function()
    def foo(event, context):
        pass

    @sample_app.schedule('rate(1 hour)', name='foo')
    def bar(event):
        pass

    config = Config.create(chalice_app=sample_app, manage_iam_role=False)
    with pytest.raises(ValueError):
        validate_unique_function_names(config)
示例#41
0
def test_default_function_memory_size(sample_app,
                                      mock_swagger_generator,
                                      mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(chalice_app=sample_app, api_gateway_stage='dev')
    template = p.generate_sam_template(config)
    properties = template['Resources']['APIHandler']['Properties']
    assert properties['MemorySize'] == 128
示例#42
0
def test_will_create_outdir_if_needed(tmpdir):
    appdir = _create_app_structure(tmpdir)
    outdir = str(appdir.join('outdir'))
    default_params = {'autogen_policy': True}
    config = Config.create(project_dir=str(appdir),
                           chalice_app=sample_app(),
                           **default_params)
    p = package.create_app_packager(config)
    p.package_app(config, str(outdir), 'dev')
    contents = os.listdir(str(outdir))
    assert 'deployment.zip' in contents
    assert 'sam.json' in contents
示例#43
0
def test_sam_injects_swagger_doc(sample_app,
                                 mock_swagger_generator,
                                 mock_policy_generator):
    p = package.SAMTemplateGenerator(mock_swagger_generator,
                                      mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(chalice_app=sample_app,
                           api_gateway_stage='dev')
    template = p.generate_sam_template(config)
    properties = template['Resources']['RestAPI']['Properties']
    assert properties['DefinitionBody'] == {'swagger': 'document'}
示例#44
0
def test_timeout_added_to_function(sample_app,
                                   mock_swagger_generator,
                                   mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(chalice_app=sample_app, api_gateway_stage='dev',
                           app_name='myapp', lambda_timeout=240)
    template = p.generate_sam_template(config)
    properties = template['Resources']['APIHandler']['Properties']
    assert properties['Timeout'] == 240
示例#45
0
def test_can_create_app_packager_with_no_autogen(tmpdir):
    appdir = _create_app_structure(tmpdir)

    outdir = tmpdir.mkdir('outdir')
    config = Config.create(project_dir=str(appdir),
                           chalice_app=sample_app())
    p = package.create_app_packager(config)
    p.package_app(config, str(outdir))
    # We're not concerned with the contents of the files
    # (those are tested in the unit tests), we just want to make
    # sure they're written to disk and look (mostly) right.
    contents = os.listdir(str(outdir))
    assert 'deployment.zip' in contents
    assert 'sam.json' in contents
示例#46
0
def test_sam_generates_sam_template_basic(sample_app,
                                          mock_swagger_generator,
                                          mock_policy_generator):
    p = package.SAMTemplateGenerator(mock_swagger_generator,
                                     mock_policy_generator)
    config = Config.create(chalice_app=sample_app,
                           api_gateway_stage='dev')
    template = p.generate_sam_template(config, 'code-uri')
    # Verify the basic structure is in place.  The specific parts
    # are validated in other tests.
    assert template['AWSTemplateFormatVersion'] == '2010-09-09'
    assert template['Transform'] == 'AWS::Serverless-2016-10-31'
    assert 'Outputs' in template
    assert 'Resources' in template
示例#47
0
def test_validate_unique_lambda_function_names(sample_app):
    @sample_app.lambda_function()
    def foo(event, context):
        pass

    # This will cause a validation error because
    # 'foo' is already registered as a lambda function.
    @sample_app.lambda_function(name='foo')
    def bar(event, context):
        pass

    config = Config.create(chalice_app=sample_app, manage_iam_role=False)
    with pytest.raises(ValueError):
        validate_unique_function_names(config)
示例#48
0
    def test_helpful_error_message_on_s3_event(self, sample_app):
        @sample_app.on_s3_event(bucket='foo')
        def handler(event):
            pass

        config = Config.create(chalice_app=sample_app,
                               project_dir='.',
                               api_gateway_stage='api')
        with pytest.raises(NotImplementedError) as excinfo:
            self.generate_template(config, 'dev')
        # Should mention the decorator name.
        assert '@app.on_s3_event' in str(excinfo.value)
        # Should mention you can use `chalice deploy`.
        assert 'chalice deploy' in str(excinfo.value)
示例#49
0
def test_chalice_tag_added_to_function(sample_app,
                                       mock_swagger_generator,
                                       mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(chalice_app=sample_app, api_gateway_stage='dev',
                           app_name='myapp')
    template = p.generate_sam_template(config)
    properties = template['Resources']['APIHandler']['Properties']
    assert properties['Tags'] == {
        'aws-chalice': 'version=%s:stage=dev:app=myapp' % chalice_version}
示例#50
0
def test_env_vars_set_in_local(runner, mock_cli_factory,
                               monkeypatch):
    local_server = mock.Mock(spec=local.LocalDevServer)
    mock_cli_factory.create_local_server.return_value = local_server
    mock_cli_factory.create_config_obj.return_value = Config.create(
        project_dir='.', environment_variables={'foo': 'bar'})
    actual_env = {}
    monkeypatch.setattr(os, 'environ', actual_env)
    with runner.isolated_filesystem():
        cli.create_new_project_skeleton('testproject')
        os.chdir('testproject')
        _run_cli_command(runner, cli.local, [],
                         cli_factory=mock_cli_factory)
        assert actual_env['foo'] == 'bar'
示例#51
0
def test_can_lazy_load_chalice_app():

    app = Chalice(app_name='foo')
    calls = []

    def call_recorder(*args, **kwargs):
        calls.append((args, kwargs))
        return app

    c = Config.create(chalice_app=call_recorder)
    # Accessing the property multiple times will only
    # invoke the call once.
    assert isinstance(c.chalice_app, Chalice)
    assert isinstance(c.chalice_app, Chalice)
    assert len(calls) == 1
示例#52
0
def test_role_arn_added_to_function(sample_app,
                                    mock_swagger_generator,
                                    mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(
        chalice_app=sample_app, api_gateway_stage='dev', app_name='myapp',
        manage_iam_role=False, iam_role_arn='role-arn')
    template = p.generate_sam_template(config)
    properties = template['Resources']['APIHandler']['Properties']
    assert properties['Role'] == 'role-arn'
    assert 'Policies' not in properties
示例#53
0
    def test_vpc_config_added_to_function(self, sample_app_lambda_only):
        config = Config.create(chalice_app=sample_app_lambda_only,
                               project_dir='.',
                               autogen_policy=True,
                               api_gateway_stage='api',
                               security_group_ids=['sg1', 'sg2'],
                               subnet_ids=['sn1', 'sn2'])
        template = self.generate_template(config, 'dev')
        resources = template['Resources'].values()
        lambda_fns = [resource for resource in resources
                      if resource['Type'] == 'AWS::Serverless::Function']
        assert len(lambda_fns) == 1

        vpc_config = lambda_fns[0]['Properties']['VpcConfig']
        assert vpc_config['SubnetIds'] == ['sn1', 'sn2']
        assert vpc_config['SecurityGroupIds'] == ['sg1', 'sg2']
示例#54
0
def test_endpoint_url_reflects_apig_stage(sample_app,
                                          mock_swagger_generator,
                                          mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(
        chalice_app=sample_app,
        api_gateway_stage='prod',
    )
    template = p.generate_sam_template(config)
    endpoint_url = template['Outputs']['EndpointURL']['Value']['Fn::Sub']
    assert endpoint_url == (
        'https://${RestAPI}.execute-api.${AWS::Region}.amazonaws.com/prod/')
示例#55
0
def test_sam_injects_policy(sample_app,
                            mock_swagger_generator,
                            mock_policy_generator):
    p = package.SAMTemplateGenerator(mock_swagger_generator,
                                     mock_policy_generator)

    mock_policy_generator.generate_policy_from_app_source.return_value = {
        'iam': 'policy',
    }
    config = Config.create(chalice_app=sample_app,
                           api_gateway_stage='dev')
    template = p.generate_sam_template(config)
    assert template['Resources']['APIHandler']['Properties']['Policies'] == [{
        'iam': 'policy',
    }]
    assert 'Role' not in template['Resources']['APIHandler']['Properties']
示例#56
0
def test_maps_python_version(sample_app,
                             mock_swagger_generator,
                             mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(
        chalice_app=sample_app,
        api_gateway_stage='dev',
    )
    template = p.generate_sam_template(config)
    expected = config.lambda_python_version
    actual = template['Resources']['APIHandler']['Properties']['Runtime']
    assert actual == expected
示例#57
0
 def test_sam_generates_sam_template_basic(self, sample_app):
     config = Config.create(chalice_app=sample_app,
                            project_dir='.',
                            api_gateway_stage='api')
     template = self.generate_template(config, 'dev')
     # Verify the basic structure is in place.  The specific parts
     # are validated in other tests.
     assert template['AWSTemplateFormatVersion'] == '2010-09-09'
     assert template['Transform'] == 'AWS::Serverless-2016-10-31'
     assert 'Outputs' in template
     assert 'Resources' in template
     assert list(sorted(template['Resources'])) == [
         'APIHandler', 'APIHandlerInvokePermission',
         # This casing on the ApiHandlerRole name is unfortunate, but the 3
         # other resources in this list are hardcoded from the old deployer.
         'ApiHandlerRole',
         'RestAPI',
     ]
示例#58
0
def _deploy_app():
    if not os.path.isdir(CHALICE_DIR):
        os.makedirs(CHALICE_DIR)
    session = botocore.session.get_session()
    config = Config.create(
        project_dir=PROJECT_DIR,
        app_name='smoketestapp',
        stage_name='dev',
        autogen_policy=True,
        chalice_app=load_chalice_app(PROJECT_DIR),
    )
    d = deployer.create_default_deployer(session=session)
    rest_api_id, region_name, stage = d.deploy(config)
    url = (
        "https://{api_id}.execute-api.{region}.amazonaws.com/{stage}/".format(
            api_id=rest_api_id, region=region_name, stage=stage))
    application = SmokeTestApplication(url, rest_api_id, region_name, 'smoketestapp')
    return application
示例#59
0
def test_can_inject_environment_vars(sample_app,
                                     mock_swagger_generator,
                                     mock_policy_generator):
    p = package.SAMTemplateGenerator(
        mock_swagger_generator, mock_policy_generator)
    mock_swagger_generator.generate_swagger.return_value = {
        'swagger': 'document'
    }
    config = Config.create(
        chalice_app=sample_app,
        api_gateway_stage='dev',
        environment_variables={
            'FOO': 'BAR'
        }
    )
    template = p.generate_sam_template(config)
    properties = template['Resources']['APIHandler']['Properties']
    assert 'Environment' in properties
    assert properties['Environment']['Variables'] == {'FOO': 'BAR'}
示例#60
0
    def test_can_package_sns_arn_handler(self, sample_app):
        arn = 'arn:aws:sns:space-leo-1:1234567890:foo'

        @sample_app.on_sns_message(topic=arn)
        def handler(event):
            pass

        config = Config.create(chalice_app=sample_app,
                               project_dir='.',
                               api_gateway_stage='api')
        template = self.generate_template(config, 'dev')
        sns_handler = template['Resources']['Handler']
        assert sns_handler['Properties']['Events'] == {
            'HandlerSnsSubscription': {
                'Type': 'SNS',
                'Properties': {
                    'Topic': arn,
                }
            }
        }