Merge pull request #2927 from apalumbo/master

Api gateway api get_usage_plan and get_usage_plan_key revised to handle missing values
This commit is contained in:
Steve Pulec 2020-04-27 19:24:40 -05:00 committed by GitHub
commit 9410daa28c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 2 deletions

View File

@ -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): class ApiKeyAlreadyExists(RESTError):
code = 409 code = 409

View File

@ -20,6 +20,7 @@ from moto.core.utils import path_url
from moto.sts.models import ACCOUNT_ID from moto.sts.models import ACCOUNT_ID
from .exceptions import ( from .exceptions import (
ApiKeyNotFoundException, ApiKeyNotFoundException,
UsagePlanNotFoundException,
AwsProxyNotAllowed, AwsProxyNotAllowed,
CrossAccountNotAllowed, CrossAccountNotAllowed,
IntegrationMethodNotDefined, IntegrationMethodNotDefined,
@ -1045,6 +1046,9 @@ class APIGatewayBackend(BaseBackend):
return plans return plans
def get_usage_plan(self, usage_plan_id): 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] return self.usage_plans[usage_plan_id]
def delete_usage_plan(self, 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()) return list(self.usage_plan_keys[usage_plan_id].values())
def get_usage_plan_key(self, usage_plan_id, key_id): 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] return self.usage_plan_keys[usage_plan_id][key_id]
def delete_usage_plan_key(self, usage_plan_id, key_id): def delete_usage_plan_key(self, usage_plan_id, key_id):

View File

@ -6,6 +6,7 @@ from moto.core.responses import BaseResponse
from .models import apigateway_backends from .models import apigateway_backends
from .exceptions import ( from .exceptions import (
ApiKeyNotFoundException, ApiKeyNotFoundException,
UsagePlanNotFoundException,
BadRequestException, BadRequestException,
CrossAccountNotAllowed, CrossAccountNotAllowed,
AuthorizerNotFoundException, AuthorizerNotFoundException,
@ -490,7 +491,16 @@ class APIGatewayResponse(BaseResponse):
usage_plan = url_path_parts[2] usage_plan = url_path_parts[2]
if self.method == "GET": 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": elif self.method == "DELETE":
usage_plan_response = self.backend.delete_usage_plan(usage_plan) usage_plan_response = self.backend.delete_usage_plan(usage_plan)
return 200, {}, json.dumps(usage_plan_response) return 200, {}, json.dumps(usage_plan_response)
@ -529,7 +539,18 @@ class APIGatewayResponse(BaseResponse):
key_id = url_path_parts[4] key_id = url_path_parts[4]
if self.method == "GET": 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": elif self.method == "DELETE":
usage_plan_response = self.backend.delete_usage_plan_key( usage_plan_response = self.backend.delete_usage_plan_key(
usage_plan_id, key_id usage_plan_id, key_id

View File

@ -1797,6 +1797,14 @@ def test_usage_plans():
response = client.get_usage_plans() response = client.get_usage_plans()
len(response["items"]).should.equal(0) 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" usage_plan_name = "TEST-PLAN"
payload = {"name": usage_plan_name} payload = {"name": usage_plan_name}
response = client.create_usage_plan(**payload) 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) response = client.get_usage_plan_keys(usagePlanId=usage_plan_id)
len(response["items"]).should.equal(0) 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 @mock_apigateway
def test_create_usage_plan_key_non_existent_api_key(): def test_create_usage_plan_key_non_existent_api_key():

View File

@ -39,6 +39,10 @@ def test_usage_plans_apis():
fetched_plan = json.loads(res.data) fetched_plan = json.loads(res.data)
fetched_plan.should.equal(created_plan) 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 # Delete usage plan
res = test_client.delete("/usageplans/{0}".format(created_plan["id"])) res = test_client.delete("/usageplans/{0}".format(created_plan["id"]))
res.data.should.equal(b"{}") 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)) res = test_client.get("/usageplans/{0}/keys".format(usage_plan_id))
json.loads(res.data)["item"].should.have.length_of(0) 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 # Create usage plan key
res = test_client.post( res = test_client.post(
"/usageplans/{0}/keys".format(usage_plan_id), "/usageplans/{0}/keys".format(usage_plan_id),