diff --git a/moto/apigateway/exceptions.py b/moto/apigateway/exceptions.py index 8f6d21aa0..4d3475d0e 100644 --- a/moto/apigateway/exceptions.py +++ b/moto/apigateway/exceptions.py @@ -112,6 +112,15 @@ class ApiKeyNotFoundException(RESTError): ) +class UsagePlanNotFoundException(RESTError): + code = 404 + + def __init__(self): + super(UsagePlanNotFoundException, self).__init__( + "NotFoundException", "Invalid Usage Plan ID specified" + ) + + class ApiKeyAlreadyExists(RESTError): code = 409 diff --git a/moto/apigateway/models.py b/moto/apigateway/models.py index e011af601..d39b719d6 100644 --- a/moto/apigateway/models.py +++ b/moto/apigateway/models.py @@ -20,6 +20,7 @@ from moto.core.utils import path_url from moto.sts.models import ACCOUNT_ID from .exceptions import ( ApiKeyNotFoundException, + UsagePlanNotFoundException, AwsProxyNotAllowed, CrossAccountNotAllowed, IntegrationMethodNotDefined, @@ -1045,6 +1046,9 @@ class APIGatewayBackend(BaseBackend): return plans def get_usage_plan(self, usage_plan_id): + if usage_plan_id not in self.usage_plans: + raise UsagePlanNotFoundException() + return self.usage_plans[usage_plan_id] def delete_usage_plan(self, usage_plan_id): @@ -1077,6 +1081,17 @@ class APIGatewayBackend(BaseBackend): return list(self.usage_plan_keys[usage_plan_id].values()) def get_usage_plan_key(self, usage_plan_id, key_id): + # first check if is a valid api key + if key_id not in self.keys: + raise ApiKeyNotFoundException() + + # then check if is a valid api key and that the key is in the plan + if ( + usage_plan_id not in self.usage_plan_keys + or key_id not in self.usage_plan_keys[usage_plan_id] + ): + raise UsagePlanNotFoundException() + return self.usage_plan_keys[usage_plan_id][key_id] def delete_usage_plan_key(self, usage_plan_id, key_id): diff --git a/moto/apigateway/responses.py b/moto/apigateway/responses.py index a3c41a6d4..1a7689d28 100644 --- a/moto/apigateway/responses.py +++ b/moto/apigateway/responses.py @@ -6,6 +6,7 @@ from moto.core.responses import BaseResponse from .models import apigateway_backends from .exceptions import ( ApiKeyNotFoundException, + UsagePlanNotFoundException, BadRequestException, CrossAccountNotAllowed, AuthorizerNotFoundException, @@ -490,7 +491,16 @@ class APIGatewayResponse(BaseResponse): usage_plan = url_path_parts[2] if self.method == "GET": - usage_plan_response = self.backend.get_usage_plan(usage_plan) + try: + usage_plan_response = self.backend.get_usage_plan(usage_plan) + except (UsagePlanNotFoundException) as error: + return ( + error.code, + {}, + '{{"message":"{0}","code":"{1}"}}'.format( + error.message, error.error_type + ), + ) elif self.method == "DELETE": usage_plan_response = self.backend.delete_usage_plan(usage_plan) return 200, {}, json.dumps(usage_plan_response) @@ -529,7 +539,18 @@ class APIGatewayResponse(BaseResponse): key_id = url_path_parts[4] if self.method == "GET": - usage_plan_response = self.backend.get_usage_plan_key(usage_plan_id, key_id) + try: + usage_plan_response = self.backend.get_usage_plan_key( + usage_plan_id, key_id + ) + except (UsagePlanNotFoundException, ApiKeyNotFoundException) as error: + return ( + error.code, + {}, + '{{"message":"{0}","code":"{1}"}}'.format( + error.message, error.error_type + ), + ) elif self.method == "DELETE": usage_plan_response = self.backend.delete_usage_plan_key( usage_plan_id, key_id diff --git a/tests/test_apigateway/test_apigateway.py b/tests/test_apigateway/test_apigateway.py index b04328a03..7495372d2 100644 --- a/tests/test_apigateway/test_apigateway.py +++ b/tests/test_apigateway/test_apigateway.py @@ -1797,6 +1797,14 @@ def test_usage_plans(): response = client.get_usage_plans() len(response["items"]).should.equal(0) + # # Try to get info about a non existing usage + with assert_raises(ClientError) as ex: + client.get_usage_plan(usagePlanId="not_existing") + ex.exception.response["Error"]["Code"].should.equal("NotFoundException") + ex.exception.response["Error"]["Message"].should.equal( + "Invalid Usage Plan ID specified" + ) + usage_plan_name = "TEST-PLAN" payload = {"name": usage_plan_name} response = client.create_usage_plan(**payload) @@ -1879,6 +1887,30 @@ def test_usage_plan_keys(): response = client.get_usage_plan_keys(usagePlanId=usage_plan_id) len(response["items"]).should.equal(0) + # Try to get info about a non existing api key + with assert_raises(ClientError) as ex: + client.get_usage_plan_key(usagePlanId=usage_plan_id, keyId="not_existing_key") + ex.exception.response["Error"]["Code"].should.equal("NotFoundException") + ex.exception.response["Error"]["Message"].should.equal( + "Invalid API Key identifier specified" + ) + + # Try to get info about an existing api key that has not jet added to a valid usage plan + with assert_raises(ClientError) as ex: + client.get_usage_plan_key(usagePlanId=usage_plan_id, keyId=key_id) + ex.exception.response["Error"]["Code"].should.equal("NotFoundException") + ex.exception.response["Error"]["Message"].should.equal( + "Invalid Usage Plan ID specified" + ) + + # Try to get info about an existing api key that has not jet added to a valid usage plan + with assert_raises(ClientError) as ex: + client.get_usage_plan_key(usagePlanId="not_existing_plan_id", keyId=key_id) + ex.exception.response["Error"]["Code"].should.equal("NotFoundException") + ex.exception.response["Error"]["Message"].should.equal( + "Invalid Usage Plan ID specified" + ) + @mock_apigateway def test_create_usage_plan_key_non_existent_api_key(): diff --git a/tests/test_apigateway/test_server.py b/tests/test_apigateway/test_server.py index 08b20cc61..9be948ef6 100644 --- a/tests/test_apigateway/test_server.py +++ b/tests/test_apigateway/test_server.py @@ -39,6 +39,10 @@ def test_usage_plans_apis(): fetched_plan = json.loads(res.data) fetched_plan.should.equal(created_plan) + # Not existing usage plan + res = test_client.get("/usageplans/{0}".format("not_existing")) + res.status_code.should.equal(404) + # Delete usage plan res = test_client.delete("/usageplans/{0}".format(created_plan["id"])) res.data.should.equal(b"{}") @@ -61,6 +65,24 @@ def test_usage_plans_keys(): res = test_client.get("/usageplans/{0}/keys".format(usage_plan_id)) json.loads(res.data)["item"].should.have.length_of(0) + # Invalid api key (does not exists at all) + res = test_client.get( + "/usageplans/{0}/keys/{1}".format(usage_plan_id, "not_existing") + ) + res.status_code.should.equal(404) + + # not existing usage plan with existing api key + res = test_client.get( + "/usageplans/{0}/keys/{1}".format("not_existing", created_api_key["id"]) + ) + res.status_code.should.equal(404) + + # not jet added api key + res = test_client.get( + "/usageplans/{0}/keys/{1}".format(usage_plan_id, created_api_key["id"]) + ) + res.status_code.should.equal(404) + # Create usage plan key res = test_client.post( "/usageplans/{0}/keys".format(usage_plan_id),