diff --git a/samcli/commands/local/invoke/cli.py b/samcli/commands/local/invoke/cli.py index c35727b941cab..cde0a9ae688e5 100644 --- a/samcli/commands/local/invoke/cli.py +++ b/samcli/commands/local/invoke/cli.py @@ -11,6 +11,8 @@ from samcli.commands.local.cli_common.invoke_context import InvokeContext from samcli.local.lambdafn.exceptions import FunctionNotFound from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError + LOG = logging.getLogger(__name__) @@ -94,7 +96,7 @@ def do_cli(ctx, function_identifier, template, event, no_event, env_vars, debug_ except FunctionNotFound: raise UserException("Function {} not found in template".format(function_identifier)) - except InvalidSamDocumentException as ex: + except (InvalidSamDocumentException, OverridesNotWellDefinedError) as ex: raise UserException(str(ex)) diff --git a/samcli/commands/local/lib/exceptions.py b/samcli/commands/local/lib/exceptions.py index f7fefd0259b96..1df90f9217ddf 100644 --- a/samcli/commands/local/lib/exceptions.py +++ b/samcli/commands/local/lib/exceptions.py @@ -8,3 +8,10 @@ class NoApisDefined(Exception): Raised when there are no APIs defined in the template """ pass + + +class OverridesNotWellDefinedError(Exception): + """ + Raised when the overrides file is invalid + """ + pass diff --git a/samcli/commands/local/lib/local_lambda.py b/samcli/commands/local/lib/local_lambda.py index ff20cdc1ac8e1..12455b2788719 100644 --- a/samcli/commands/local/lib/local_lambda.py +++ b/samcli/commands/local/lib/local_lambda.py @@ -9,6 +9,7 @@ from samcli.local.lambdafn.env_vars import EnvironmentVariables from samcli.local.lambdafn.config import FunctionConfig from samcli.local.lambdafn.exceptions import FunctionNotFound +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError LOG = logging.getLogger(__name__) @@ -121,12 +122,23 @@ def _get_invoke_config(self, function): env_vars=env_vars) def _make_env_vars(self, function): - """ - Returns the environment variables configuration for this function + """Returns the environment variables configuration for this function + + Parameters + ---------- + function : samcli.commands.local.lib.provider.Function + Lambda function to generate the configuration for + + Returns + ------- + samcli.local.lambdafn.env_vars.EnvironmentVariables + Environment variable configuration for this function + + Raises + ------ + samcli.commands.local.lib.exceptions.OverridesNotWellDefinedError + If the environment dict is in the wrong format to process environment vars - :param samcli.commands.local.lib.provider.Function function: Lambda function to generate the configuration for - :return samcli.local.lambdafn.env_vars.EnvironmentVariables: Environment variable configuration for this - function """ name = function.name @@ -141,6 +153,16 @@ def _make_env_vars(self, function): # # Standard format is {FunctionName: {key:value}, FunctionName: {key:value}} # CloudFormation parameter file is {"Parameters": {key:value}} + + for env_var_value in self.env_vars_values.values(): + if not isinstance(env_var_value, dict): + reason = """ + Environment variables must be in either CloudFormation parameter file + format or in {FunctionName: {key:value}} JSON pairs + """ + LOG.debug(reason) + raise OverridesNotWellDefinedError(reason) + if "Parameters" in self.env_vars_values: LOG.debug("Environment variables overrides data is in CloudFormation parameter file format") # CloudFormation parameter file format diff --git a/samcli/commands/local/start_api/cli.py b/samcli/commands/local/start_api/cli.py index c5144a3dac280..61a411b6b328b 100644 --- a/samcli/commands/local/start_api/cli.py +++ b/samcli/commands/local/start_api/cli.py @@ -12,6 +12,7 @@ from samcli.commands.exceptions import UserException from samcli.commands.local.lib.local_api_service import LocalApiService from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError LOG = logging.getLogger(__name__) @@ -90,5 +91,5 @@ def do_cli(ctx, host, port, static_dir, template, env_vars, debug_port, debug_ar except NoApisDefined: raise UserException("Template does not have any APIs connected to Lambda functions") - except InvalidSamDocumentException as ex: + except (InvalidSamDocumentException, OverridesNotWellDefinedError) as ex: raise UserException(str(ex)) diff --git a/samcli/commands/local/start_lambda/cli.py b/samcli/commands/local/start_lambda/cli.py index b13d930c8da7a..f84aadf573282 100644 --- a/samcli/commands/local/start_lambda/cli.py +++ b/samcli/commands/local/start_lambda/cli.py @@ -11,6 +11,8 @@ from samcli.commands.local.cli_common.user_exceptions import UserException from samcli.commands.local.lib.local_lambda_service import LocalLambdaService from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError + LOG = logging.getLogger(__name__) @@ -99,5 +101,5 @@ def do_cli(ctx, host, port, template, env_vars, debug_port, debug_args, # pylin host=host) service.start() - except InvalidSamDocumentException as ex: + except (InvalidSamDocumentException, OverridesNotWellDefinedError) as ex: raise UserException(str(ex)) diff --git a/tests/unit/commands/local/invoke/test_cli.py b/tests/unit/commands/local/invoke/test_cli.py index 7b3a907b3c00a..39665c01d2b80 100644 --- a/tests/unit/commands/local/invoke/test_cli.py +++ b/tests/unit/commands/local/invoke/test_cli.py @@ -10,6 +10,8 @@ from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException from samcli.commands.exceptions import UserException from samcli.commands.local.invoke.cli import do_cli as invoke_cli, _get_event as invoke_cli_get_event +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError + STDIN_FILE_NAME = "-" @@ -215,6 +217,36 @@ def test_must_raise_user_exception_on_invalid_sam_template(self, get_event_mock, msg = str(ex_ctx.exception) self.assertEquals(msg, "bad template") + @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 + + InvokeContextMock.side_effect = OverridesNotWellDefinedError("bad env vars") + + 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, + parameter_overrides=self.parameter_overrides) + + msg = str(ex_ctx.exception) + self.assertEquals(msg, "bad env vars") + class TestGetEvent(TestCase): diff --git a/tests/unit/commands/local/lib/test_local_lambda.py b/tests/unit/commands/local/lib/test_local_lambda.py index 8417f4fc5a01d..f2bbfed631dc7 100644 --- a/tests/unit/commands/local/lib/test_local_lambda.py +++ b/tests/unit/commands/local/lib/test_local_lambda.py @@ -10,6 +10,7 @@ from samcli.commands.local.lib.local_lambda import LocalLambdaRunner from samcli.commands.local.lib.provider import Function from samcli.local.lambdafn.exceptions import FunctionNotFound +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError class TestLocalLambda_get_aws_creds(TestCase): @@ -298,7 +299,7 @@ def setUp(self): ({"otherfunction": {"c": "d"}}, None), # Using a CloudFormation parameter file format - ({"Parameters": {"p1": "v1"}}, {"p1": "v1"}), + ({"Parameters": {"p1": "v1"}}, {"p1": "v1"}) ]) @patch("samcli.commands.local.lib.local_lambda.EnvironmentVariables") @patch("samcli.commands.local.lib.local_lambda.os") @@ -328,6 +329,33 @@ def test_must_work_with_override_values(self, env_vars_values, expected_override override_values=expected_override_value, aws_creds=self.aws_creds) + @parameterized.expand([ + # Using a invalid file format + ({"a": "b"}, OverridesNotWellDefinedError), + + ({"a": False}, OverridesNotWellDefinedError), + + ({"a": [True, False]}, OverridesNotWellDefinedError) + ]) + @patch("samcli.commands.local.lib.local_lambda.os") + def test_must_not_work_with_invalid_override_values(self, env_vars_values, expected_exception, os_mock): + os_environ = {"some": "value"} + os_mock.environ = os_environ + + function = Function(name="function_name", + runtime="runtime", + memory=1234, + timeout=12, + handler="handler", + codeuri="codeuri", + environment=self.environ, + rolearn=None) + + self.local_lambda.env_vars_values = env_vars_values + + with self.assertRaises(expected_exception): + self.local_lambda._make_env_vars(function) + @parameterized.expand([ param({"a": "b"}), # Does not have the "Variables" Key param("somestring"), # Must be a dict type diff --git a/tests/unit/commands/local/start_api/test_cli.py b/tests/unit/commands/local/start_api/test_cli.py index eaaacd0e2842e..5f49aa05b1271 100644 --- a/tests/unit/commands/local/start_api/test_cli.py +++ b/tests/unit/commands/local/start_api/test_cli.py @@ -9,6 +9,7 @@ from samcli.commands.local.lib.exceptions import NoApisDefined from samcli.commands.exceptions import UserException from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError class TestCli(TestCase): @@ -96,6 +97,17 @@ def test_must_raise_user_exception_on_invalid_sam_template(self, invoke_context_ expected = "bad template" self.assertEquals(msg, expected) + @patch("samcli.commands.local.start_api.cli.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.assertEquals(msg, expected) + def call_cli(self): start_api_cli(ctx=None, host=self.host, diff --git a/tests/unit/commands/local/start_lambda/test_cli.py b/tests/unit/commands/local/start_lambda/test_cli.py index 9cfba83d9e53e..07f6a33d952a9 100644 --- a/tests/unit/commands/local/start_lambda/test_cli.py +++ b/tests/unit/commands/local/start_lambda/test_cli.py @@ -4,6 +4,7 @@ from samcli.commands.local.start_lambda.cli import do_cli as start_lambda_cli from samcli.commands.local.cli_common.user_exceptions import UserException from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException +from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError class TestCli(TestCase): @@ -69,6 +70,17 @@ def test_must_raise_user_exception_on_invalid_sam_template(self, invoke_context_ expected = "bad template" self.assertEquals(msg, expected) + @patch("samcli.commands.local.start_lambda.cli.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.assertEquals(msg, expected) + def call_cli(self): start_lambda_cli(ctx=None, host=self.host,