From 5ae0ced349dae371303bcb5b19093f03bf688e11 Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Tue, 15 Mar 2022 14:07:01 -0100 Subject: [PATCH] AWSLambda - raise correct error when publishing unknown function (#4934) --- moto/awslambda/exceptions.py | 7 +++++++ moto/awslambda/models.py | 12 ++++++++++-- moto/awslambda/responses.py | 3 ++- moto/awslambda/urls.py | 2 +- tests/test_awslambda/test_lambda.py | 19 +++++++++++++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/moto/awslambda/exceptions.py b/moto/awslambda/exceptions.py index 8f1c99f44..210cb0205 100644 --- a/moto/awslambda/exceptions.py +++ b/moto/awslambda/exceptions.py @@ -43,3 +43,10 @@ class UnknownPolicyException(LambdaClientError): "ResourceNotFoundException", "No policy is associated with the given resource.", ) + + +class UnknownFunctionException(LambdaClientError): + code = 404 + + def __init__(self, arn): + super().__init__("ResourceNotFoundException", f"Function not found: {arn}") diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 8ee60f81c..25709a169 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -36,6 +36,7 @@ from .exceptions import ( CrossAccountNotAllowed, InvalidRoleFormat, InvalidParameterValueException, + UnknownFunctionException, ) from .utils import ( make_function_arn, @@ -932,10 +933,11 @@ class LambdaVersion(CloudFormationModel): class LambdaStorage(object): - def __init__(self): + def __init__(self, region_name): # Format 'func_name' {'alias': {}, 'versions': []} self._functions = {} self._arns = weakref.WeakValueDictionary() + self.region_name = region_name def _get_latest(self, name): return self._functions[name]["latest"] @@ -1011,6 +1013,12 @@ class LambdaStorage(object): def publish_function(self, name_or_arn, description=""): function = self.get_function_by_name_or_arn(name_or_arn) + if not function: + if name_or_arn.startswith("arn:aws"): + arn = name_or_arn + else: + arn = make_function_arn(self.region_name, ACCOUNT_ID, name_or_arn) + raise UnknownFunctionException(arn) name = function.function_name if name not in self._functions: return None @@ -1180,7 +1188,7 @@ class LambdaBackend(BaseBackend): """ def __init__(self, region_name): - self._lambdas = LambdaStorage() + self._lambdas = LambdaStorage(region_name) self._event_source_mappings = {} self._layers = LayerStorage() self.region_name = region_name diff --git a/moto/awslambda/responses.py b/moto/awslambda/responses.py index 2ea3670a1..f155c6722 100644 --- a/moto/awslambda/responses.py +++ b/moto/awslambda/responses.py @@ -95,6 +95,7 @@ class LambdaResponse(BaseResponse): else: raise ValueError("Cannot handle request") + @error_handler def versions(self, request, full_url, headers): self.setup_class(request, full_url, headers) if request.method == "GET": @@ -324,7 +325,7 @@ class LambdaResponse(BaseResponse): return 404, {}, "{}" def _publish_function(self): - function_name = self.path.rsplit("/", 2)[-2] + function_name = unquote(self.path.split("/")[-2]) description = self._get_param("Description") fn = self.lambda_backend.publish_function(function_name, description) diff --git a/moto/awslambda/urls.py b/moto/awslambda/urls.py index 6d94b95a4..eea1a1958 100644 --- a/moto/awslambda/urls.py +++ b/moto/awslambda/urls.py @@ -7,7 +7,7 @@ response = LambdaResponse() url_paths = { r"{0}/(?P[^/]+)/functions/?$": response.root, r"{0}/(?P[^/]+)/functions/(?P[\w_:%-]+)/?$": response.function, - r"{0}/(?P[^/]+)/functions/(?P[\w_-]+)/versions/?$": response.versions, + r"{0}/(?P[^/]+)/functions/(?P[\w_:%-]+)/versions/?$": response.versions, r"{0}/(?P[^/]+)/event-source-mappings/?$": response.event_source_mappings, r"{0}/(?P[^/]+)/event-source-mappings/(?P[\w_-]+)/?$": response.event_source_mapping, r"{0}/(?P[^/]+)/functions/(?P[\w_-]+)/invocations/?$": response.invoke, diff --git a/tests/test_awslambda/test_lambda.py b/tests/test_awslambda/test_lambda.py index 4c62af8e0..e74d1559b 100644 --- a/tests/test_awslambda/test_lambda.py +++ b/tests/test_awslambda/test_lambda.py @@ -486,6 +486,25 @@ def test_delete_unknown_function(): ).should.throw(botocore.client.ClientError) +@mock_lambda +@pytest.mark.parametrize( + "name", + [ + "bad_function_name", + f"arn:aws:lambda:eu-west-1:{ACCOUNT_ID}:function:bad_function_name", + ], +) +def test_publish_version_unknown_function(name): + client = boto3.client("lambda", "eu-west-1") + with pytest.raises(ClientError) as exc: + client.publish_version(FunctionName=name, Description="v2") + err = exc.value.response["Error"] + err["Code"].should.equal("ResourceNotFoundException") + err["Message"].should.equal( + f"Function not found: arn:aws:lambda:eu-west-1:{ACCOUNT_ID}:function:bad_function_name" + ) + + @mock_lambda @mock_s3 def test_publish():