def normalize_cors_allow_methods(allow_methods): """ Normalize cors AllowMethods and Options to the methods if it's missing. Parameters ---------- allow_methods : str The allow_methods string provided in the query Return ------- A string with normalized route """ if allow_methods == "*": return ",".join(sorted(Route.ANY_HTTP_METHODS)) methods = allow_methods.split(",") normalized_methods = [] for method in methods: normalized_method = method.strip().upper() if normalized_method not in Route.ANY_HTTP_METHODS: raise InvalidSamDocumentException( "The method {} is not a valid CORS method".format( normalized_method)) normalized_methods.append(normalized_method) if "OPTIONS" not in normalized_methods: normalized_methods.append("OPTIONS") return ",".join(sorted(normalized_methods))
def _get_cors_prop(cors_dict, prop_name): """ Extract cors properties from dictionary and remove extra quotes. Parameters ---------- cors_dict : dict Resource properties for Cors Return ------ A string with the extra quotes removed """ prop = cors_dict.get(prop_name) if prop: if not isinstance(prop, string_types) or prop.startswith("!"): LOG.warning( "CORS Property %s was not fully resolved. Will proceed as if the Property was not defined.", prop_name, ) return None if not (prop.startswith("'") and prop.endswith("'")): raise InvalidSamDocumentException( "{} must be a quoted string " '(i.e. "\'value\'" is correct, but "value" is not).'. format(prop_name)) prop = prop.strip("'") return prop
def _convert_event_route(lambda_logical_id, event_properties): """ Converts a AWS::Serverless::Function's Event Property to an Route configuration usable by the provider. :param str lambda_logical_id: Logical Id of the AWS::Serverless::Function :param dict event_properties: Dictionary of the Event's Property :return tuple: tuple of route resource name and route """ path = event_properties.get(SamApiProvider._EVENT_PATH) method = event_properties.get(SamApiProvider._EVENT_METHOD) # An API Event, can have RestApiId property which designates the resource that owns this API. If omitted, # the API is owned by Implicit API resource. This could either be a direct resource logical ID or a # "Ref" of the logicalID api_resource_id = event_properties.get("RestApiId", SamApiProvider.IMPLICIT_API_RESOURCE_ID) if isinstance(api_resource_id, dict) and "Ref" in api_resource_id: api_resource_id = api_resource_id["Ref"] # This is still a dictionary. Something wrong with the template if isinstance(api_resource_id, dict): LOG.debug("Invalid RestApiId property of event %s", event_properties) raise InvalidSamDocumentException( "RestApiId property of resource with logicalId '{}' is invalid. " "It should either be a LogicalId string or a Ref of a Logical Id string".format(lambda_logical_id) ) return api_resource_id, Route(path=path, methods=[method], function_name=lambda_logical_id)
def test_must_raise_user_exception_on_invalid_sam_template( self, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data InvokeContextMock.side_effect = InvalidSamDocumentException( "bad template") with self.assertRaises(UserException) as ex_ctx: invoke_cli(ctx=None, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, profile=self.profile, region=self.region) msg = str(ex_ctx.exception) self.assertEquals(msg, "bad template")
def test_must_raise_user_exception_on_invalid_sam_template( self, invoke_context_mock): invoke_context_mock.side_effect = InvalidSamDocumentException( "bad template") with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = "bad template" self.assertEquals(msg, expected)
def _convert_event_route(stack_path: str, lambda_logical_id, event_properties, event_type): """ Converts a AWS::Serverless::Function's Event Property to an Route configuration usable by the provider. :param str stack_path: Path of the stack the resource is located :param str lambda_logical_id: Logical Id of the AWS::Serverless::Function :param dict event_properties: Dictionary of the Event's Property :param event_type: The event type, 'Api' or 'HttpApi', see samcli/local/apigw/local_apigw_service.py:35 :return tuple: tuple of route resource name and route """ path = event_properties.get(SamApiProvider._EVENT_PATH) method = event_properties.get(SamApiProvider._EVENT_METHOD) # An RESTAPI (HTTPAPI) Event, can have RestApiId (ApiId) property which designates the resource that owns this # API. If omitted, the API is owned by Implicit API resource. This could either be a direct resource logical ID # or a "Ref" of the logicalID api_resource_id = None payload_format_version = None if event_type == SamApiProvider._EVENT_TYPE_API: api_resource_id = event_properties.get( "RestApiId", SamApiProvider.IMPLICIT_API_RESOURCE_ID) else: api_resource_id = event_properties.get( "ApiId", SamApiProvider.IMPLICIT_HTTP_API_RESOURCE_ID) payload_format_version = event_properties.get( "PayloadFormatVersion") if isinstance(api_resource_id, dict) and "Ref" in api_resource_id: api_resource_id = api_resource_id["Ref"] # This is still a dictionary. Something wrong with the template if isinstance(api_resource_id, dict): LOG.debug("Invalid RestApiId property of event %s", event_properties) raise InvalidSamDocumentException( "RestApiId property of resource with logicalId '{}' is invalid. " "It should either be a LogicalId string or a Ref of a Logical Id string" .format(lambda_logical_id)) return ( api_resource_id, Route( path=path, methods=[method], function_name=lambda_logical_id, event_type=event_type, payload_format_version=payload_format_version, stack_path=stack_path, ), )
def extract_cors(self, cors_prop: Union[Dict, str]) -> Optional[Cors]: """ Extract Cors property from AWS::Serverless::Api resource by reading and parsing Swagger documents. The result is added to the Api. Parameters ---------- cors_prop : dict Resource properties for Cors """ cors = None if cors_prop and isinstance(cors_prop, dict): allow_methods = self._get_cors_prop(cors_prop, "AllowMethods") if allow_methods: allow_methods = CfnBaseApiProvider.normalize_cors_allow_methods( allow_methods) else: allow_methods = ",".join(sorted(Route.ANY_HTTP_METHODS)) allow_origin = self._get_cors_prop(cors_prop, "AllowOrigin") allow_headers = self._get_cors_prop(cors_prop, "AllowHeaders") allow_credentials = self._get_cors_prop(cors_prop, "AllowCredentials", True) max_age = self._get_cors_prop(cors_prop, "MaxAge") cors = Cors( allow_origin=allow_origin, allow_methods=allow_methods, allow_headers=allow_headers, allow_credentials=allow_credentials, max_age=max_age, ) elif cors_prop and isinstance(cors_prop, str): allow_origin = cors_prop if not (allow_origin.startswith("'") and allow_origin.endswith("'")): raise InvalidSamDocumentException( "Cors Properties must be a quoted string " '(i.e. "\'*\'" is correct, but "*" is not).') allow_origin = allow_origin.strip("'") cors = Cors( allow_origin=allow_origin, allow_methods=",".join(sorted(Route.ANY_HTTP_METHODS)), allow_headers=None, allow_credentials=None, max_age=None, ) return cors
def run_plugins(self, convert_local_uris=True): template_copy = self.template additional_plugins = [] if convert_local_uris: # Add all the plugins to convert local path if asked to. additional_plugins.append(self.local_uri_plugin) parser = _SamParserReimplemented() all_plugins = prepare_plugins(additional_plugins) try: parser.parse(template_copy, all_plugins) # parse() will run all configured plugins except InvalidDocumentException as e: raise InvalidSamDocumentException( reduce(lambda message, error: message + ' ' + error.message, e.causes, e.message)) return template_copy
def _get_cors_prop(cors_dict, prop_name): """ Extract cors properties from dictionary and remove extra quotes. Parameters ---------- cors_dict : dict Resource properties for Cors Return ------ A string with the extra quotes removed """ prop = cors_dict.get(prop_name) if prop: if (not isinstance(prop, string_types)) or (not (prop.startswith("'") and prop.endswith("'"))): raise InvalidSamDocumentException( "{} must be a quoted string " '(i.e. "\'value\'" is correct, but "value" is not).'.format(prop_name) ) prop = prop.strip("'") return prop
def _get_cors_prop(cors_dict: Dict, prop_name: str, allow_bool: bool = False) -> Optional[str]: """ Extract cors properties from dictionary and remove extra quotes. Parameters ---------- cors_dict : dict Resource properties for Cors prop_name : str Cors property to get the value for allow_bool : bool If a boolean value is allowed for this property or not (defaults to false) Return ------ A string with the extra quotes removed """ prop = cors_dict.get(prop_name) if prop: if allow_bool and isinstance(prop, bool): prop = "'true'" # We alredy know this is true due to L141 passing if not isinstance(prop, str) or prop.startswith("!"): LOG.warning( "CORS Property %s was not fully resolved. Will proceed as if the Property was not defined.", prop_name, ) return None if not (prop.startswith("'") and prop.endswith("'")): raise InvalidSamDocumentException( "{} must be a quoted string " '(i.e. "\'value\'" is correct, but "value" is not).'. format(prop_name)) prop = prop.strip("'") return prop
def run_plugins(self, convert_local_uris=True): template_copy = self.template additional_plugins = [] if convert_local_uris: # Add all the plugins to convert local path if asked to. additional_plugins.append(self.local_uri_plugin) parser = _SamParserReimplemented() all_plugins = prepare_plugins( additional_plugins, parameters=self.parameter_values if self.parameter_values else {}) try: parser.parse( template_copy, all_plugins) # parse() will run all configured plugins except InvalidDocumentException as e: raise InvalidSamDocumentException( functools.reduce( lambda message, error: message + " " + str(error), e.causes, str(e))) from e return template_copy
class TestCli(TestCase): def setUp(self): self.template = "template" self.env_vars = "env-vars" self.debug_ports = [123] self.debug_args = "args" self.debugger_path = "/test/path" self.container_env_vars = "container-env-vars" self.docker_volume_basedir = "basedir" self.docker_network = "network" self.log_file = "logfile" self.skip_pull_image = True self.parameter_overrides = {} self.layer_cache_basedir = "/some/layers/path" self.force_image_build = True self.shutdown = True self.region_name = "region" self.profile = "profile" self.warm_containers = None self.debug_function = None self.ctx_mock = Mock() self.ctx_mock.region = self.region_name self.ctx_mock.profile = self.profile self.host = "host" self.port = 123 self.static_dir = "staticdir" @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.lib.local_api_service.LocalApiService") def test_cli_must_setup_context_and_start_service(self, local_api_service_mock, invoke_context_mock): # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() invoke_context_mock.return_value.__enter__.return_value = context_mock service_mock = Mock() local_api_service_mock.return_value = service_mock self.warm_containers = None self.debug_function = None self.call_cli() invoke_context_mock.assert_called_with( template_file=self.template, function_identifier=None, env_vars_file=self.env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, debug_ports=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars_file=self.container_env_vars, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, aws_region=self.region_name, aws_profile=self.profile, warm_container_initialization_mode=self.warm_containers, debug_function=self.debug_function, shutdown=self.shutdown, ) local_api_service_mock.assert_called_with( lambda_invoke_context=context_mock, port=self.port, host=self.host, static_dir=self.static_dir ) service_mock.start.assert_called_with() @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.lib.local_api_service.LocalApiService") def test_must_raise_if_no_api_defined(self, local_api_service_mock, invoke_context_mock): # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() invoke_context_mock.return_value.__enter__.return_value = context_mock service_mock = Mock() local_api_service_mock.return_value = service_mock service_mock.start.side_effect = NoApisDefined("no apis") with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = "Template does not have any APIs connected to Lambda functions" self.assertEqual(msg, expected) @parameterized.expand( [ (InvalidSamDocumentException("bad template"), "bad template"), ( InvalidLayerReference(), "Layer References need to be of type " "'AWS::Serverless::LayerVersion' or 'AWS::Lambda::LayerVersion'", ), (DebuggingNotSupported("Debugging not supported"), "Debugging not supported"), ] ) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, invoke_context_mock ): invoke_context_mock.side_effect = exeception_to_raise with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = execption_message self.assertEqual(msg, expected) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_env_vars(self, invoke_context_mock): invoke_context_mock.side_effect = OverridesNotWellDefinedError("bad env vars") with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = "bad env vars" self.assertEqual(msg, expected) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_no_free_ports(self, invoke_context_mock): invoke_context_mock.side_effect = ContainerNotStartableException("no free ports on host to bind with container") with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = "no free ports on host to bind with container" self.assertEqual(msg, expected) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_imageuri(self, invoke_context_mock): invoke_context_mock.side_effect = InvalidIntermediateImageError("invalid imageuri") with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = "invalid imageuri" self.assertEqual(msg, expected) def call_cli(self): start_api_cli( ctx=self.ctx_mock, host=self.host, port=self.port, static_dir=self.static_dir, template=self.template, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, warm_containers=self.warm_containers, debug_function=self.debug_function, shutdown=self.shutdown, )
class TestCli(TestCase): def setUp(self): self.template = "template" self.env_vars = "env-vars" self.debug_port = 123 self.debug_args = "args" self.debugger_path = "/test/path" self.docker_volume_basedir = "basedir" self.docker_network = "network" self.log_file = "logfile" self.skip_pull_image = True self.parameter_overrides = {} self.layer_cache_basedir = "/some/layers/path" self.force_image_build = True self.region_name = "region" self.profile = "profile" self.ctx_mock = Mock() self.ctx_mock.region = self.region_name self.ctx_mock.profile = self.profile self.host = "host" self.port = 123 @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.lib.local_lambda_service.LocalLambdaService") def test_cli_must_setup_context_and_start_service(self, local_lambda_service_mock, invoke_context_mock): # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() invoke_context_mock.return_value.__enter__.return_value = context_mock service_mock = Mock() local_lambda_service_mock.return_value = service_mock self.call_cli() invoke_context_mock.assert_called_with( template_file=self.template, function_identifier=None, env_vars_file=self.env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, aws_region=self.region_name, aws_profile=self.profile, ) local_lambda_service_mock.assert_called_with(lambda_invoke_context=context_mock, port=self.port, host=self.host) service_mock.start.assert_called_with() @parameterized.expand( [ (InvalidSamDocumentException("bad template"), "bad template"), ( InvalidLayerReference(), "Layer References need to be of type " "'AWS::Serverless::LayerVersion' or 'AWS::Lambda::LayerVersion'", ), (DebuggingNotSupported("Debugging not supported"), "Debugging not supported"), ] ) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, invoke_context_mock ): invoke_context_mock.side_effect = exeception_to_raise with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = execption_message self.assertEqual(msg, expected) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_env_vars(self, invoke_context_mock): invoke_context_mock.side_effect = OverridesNotWellDefinedError("bad env vars") with self.assertRaises(UserException) as context: self.call_cli() msg = str(context.exception) expected = "bad env vars" self.assertEqual(msg, expected) def call_cli(self): start_lambda_cli( ctx=self.ctx_mock, host=self.host, port=self.port, template=self.template, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, )
class TestCli(TestCase): def setUp(self): self.function_id = "id" self.template = "template" self.eventfile = "eventfile" self.env_vars = "env-vars" self.debug_port = 123 self.debug_args = "args" self.debugger_path = "/test/path" self.docker_volume_basedir = "basedir" self.docker_network = "network" self.log_file = "logfile" self.skip_pull_image = True self.no_event = False self.parameter_overrides = {} self.layer_cache_basedir = "/some/layers/path" self.force_image_build = True self.region_name = "region" @patch("samcli.commands.local.invoke.cli.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_cli_must_setup_context_and_invoke(self, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock invoke_cli(ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build) InvokeContextMock.assert_called_with( template_file=self.template, function_identifier=self.function_id, env_vars_file=self.env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, aws_region=self.region_name) context_mock.local_lambda_runner.invoke.assert_called_with( context_mock.function_name, event=event_data, stdout=context_mock.stdout, stderr=context_mock.stderr) get_event_mock.assert_called_with(self.eventfile) @patch("samcli.commands.local.invoke.cli.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_cli_must_invoke_with_no_event(self, get_event_mock, InvokeContextMock): self.no_event = True ctx_mock = Mock() ctx_mock.region = self.region_name # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock invoke_cli(ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=STDIN_FILE_NAME, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build) InvokeContextMock.assert_called_with( template_file=self.template, function_identifier=self.function_id, env_vars_file=self.env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, aws_region=self.region_name) context_mock.local_lambda_runner.invoke.assert_called_with( context_mock.function_name, event="{}", stdout=context_mock.stdout, stderr=context_mock.stderr) get_event_mock.assert_not_called() @patch("samcli.commands.local.invoke.cli.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_no_event_and_event( self, get_event_mock, InvokeContextMock): self.no_event = True ctx_mock = Mock() ctx_mock.region = self.region_name with self.assertRaises(UserException) as ex_ctx: invoke_cli(ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build) msg = str(ex_ctx.exception) self.assertEquals( msg, "no_event and event cannot be used together. Please provide only one." ) @parameterized.expand([ param(FunctionNotFound("not found"), "Function id not found in template"), param(DockerImagePullFailedException("Failed to pull image"), "Failed to pull image") ]) @patch("samcli.commands.local.invoke.cli.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_function_not_found( self, side_effect_exception, expected_exectpion_message, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock context_mock.local_lambda_runner.invoke.side_effect = side_effect_exception with self.assertRaises(UserException) as ex_ctx: invoke_cli(ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build) msg = str(ex_ctx.exception) self.assertEquals(msg, expected_exectpion_message) @parameterized.expand([ (InvalidSamDocumentException("bad template"), "bad template"), (InvalidLayerReference(), "Layer References need to be of type " "'AWS::Serverless::LayerVersion' or 'AWS::Lambda::LayerVersion'"), (DebuggingNotSupported("Debugging not supported"), "Debugging not supported") ]) @patch("samcli.commands.local.invoke.cli.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name InvokeContextMock.side_effect = exeception_to_raise with self.assertRaises(UserException) as ex_ctx: invoke_cli(ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build) msg = str(ex_ctx.exception) self.assertEquals(msg, execption_message) @patch("samcli.commands.local.invoke.cli.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_invalid_env_vars( self, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name InvokeContextMock.side_effect = OverridesNotWellDefinedError( "bad env vars") with self.assertRaises(UserException) as ex_ctx: invoke_cli(ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_port, debug_args=self.debug_args, debugger_path=self.debugger_path, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build) msg = str(ex_ctx.exception) self.assertEquals(msg, "bad env vars")
class TestCli(TestCase): def setUp(self): self.function_id = "id" self.template = "template" self.eventfile = "eventfile" self.env_vars = "env-vars" self.container_env_vars = "debug-env-vars" self.debug_ports = [123] self.debug_args = "args" self.debugger_path = "/test/path" self.docker_volume_basedir = "basedir" self.docker_network = "network" self.log_file = "logfile" self.skip_pull_image = True self.no_event = True self.parameter_overrides = {} self.layer_cache_basedir = "/some/layers/path" self.force_image_build = True self.shutdown = False self.region_name = "region" self.profile = "profile" @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_cli_must_setup_context_and_invoke(self, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) InvokeContextMock.assert_called_with( template_file=self.template, function_identifier=self.function_id, env_vars_file=self.env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, debug_ports=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars_file=self.container_env_vars, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, aws_region=self.region_name, aws_profile=self.profile, ) context_mock.local_lambda_runner.invoke.assert_called_with( context_mock.function_identifier, event=event_data, stdout=context_mock.stdout, stderr=context_mock.stderr) get_event_mock.assert_called_with(self.eventfile) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_cli_must_invoke_with_no_event(self, get_event_mock, InvokeContextMock): self.event = None ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.event, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) InvokeContextMock.assert_called_with( template_file=self.template, function_identifier=self.function_id, env_vars_file=self.env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, debug_ports=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars_file=self.container_env_vars, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, aws_region=self.region_name, aws_profile=self.profile, ) get_event_mock.assert_not_called() context_mock.local_lambda_runner.invoke.assert_called_with( context_mock.function_identifier, event="{}", stdout=context_mock.stdout, stderr=context_mock.stderr) @parameterized.expand([ param(FunctionNotFound("not found"), "Function id not found in template"), param(DockerImagePullFailedException("Failed to pull image"), "Failed to pull image"), ]) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_function_not_found( self, side_effect_exception, expected_exectpion_message, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock context_mock.local_lambda_runner.invoke.side_effect = side_effect_exception with self.assertRaises(UserException) as ex_ctx: invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) msg = str(ex_ctx.exception) self.assertEqual(msg, expected_exectpion_message) @parameterized.expand([ param( InvalidIntermediateImageError( "ImageUri not set to a reference-able image for Function: MyFunction" ), "ImageUri not set to a reference-able image for Function: MyFunction", ), ]) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_function_local_invoke_image_not_found_for_IMAGE_packagetype( self, side_effect_exception, expected_exectpion_message, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock context_mock.local_lambda_runner.invoke.side_effect = side_effect_exception with self.assertRaises(UserException) as ex_ctx: invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) msg = str(ex_ctx.exception) self.assertEqual(msg, expected_exectpion_message) @parameterized.expand([ (InvalidSamDocumentException("bad template"), "bad template"), ( InvalidLayerReference(), "Layer References need to be of type " "'AWS::Serverless::LayerVersion' or 'AWS::Lambda::LayerVersion'", ), (DebuggingNotSupported("Debugging not supported"), "Debugging not supported"), ]) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile InvokeContextMock.side_effect = exeception_to_raise with self.assertRaises(UserException) as ex_ctx: invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) msg = str(ex_ctx.exception) self.assertEqual(msg, execption_message) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_invalid_env_vars( self, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile InvokeContextMock.side_effect = OverridesNotWellDefinedError( "bad env vars") with self.assertRaises(UserException) as ex_ctx: invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) msg = str(ex_ctx.exception) self.assertEqual(msg, "bad env vars") @parameterized.expand([ param( ContainerNotStartableException( "Container cannot be started, no free ports on host"), "Container cannot be started, no free ports on host", ), ]) @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_function_no_free_ports( self, side_effect_exception, expected_exectpion_message, get_event_mock, InvokeContextMock): event_data = "data" get_event_mock.return_value = event_data ctx_mock = Mock() ctx_mock.region = self.region_name ctx_mock.profile = self.profile # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() InvokeContextMock.return_value.__enter__.return_value = context_mock context_mock.local_lambda_runner.invoke.side_effect = side_effect_exception with self.assertRaises(UserException) as ex_ctx: invoke_cli( ctx=ctx_mock, function_identifier=self.function_id, template=self.template, event=self.eventfile, no_event=self.no_event, env_vars=self.env_vars, debug_port=self.debug_ports, debug_args=self.debug_args, debugger_path=self.debugger_path, container_env_vars=self.container_env_vars, docker_volume_basedir=self.docker_volume_basedir, docker_network=self.docker_network, log_file=self.log_file, skip_pull_image=self.skip_pull_image, parameter_overrides=self.parameter_overrides, layer_cache_basedir=self.layer_cache_basedir, force_image_build=self.force_image_build, shutdown=self.shutdown, ) msg = str(ex_ctx.exception) self.assertEqual(msg, expected_exectpion_message)