initial support for apigateway stages, in particular the update_stage method

This commit is contained in:
Waldemar Hummer 2016-08-11 16:14:13 +10:00
parent e92a8b7492
commit db275a1573
5 changed files with 80 additions and 3 deletions

View File

@ -149,6 +149,26 @@ class Resource(object):
return self.resource_methods[method_type].pop('methodIntegration')
class Stage(dict):
def __init__(self, name=None, deployment_id=None):
super(Stage, self).__init__()
self['stageName'] = name
self['deploymentId'] = deployment_id
self['methodSettings'] = {}
self['variables'] = {}
self['description'] = ''
def apply_operations(self, patch_operations):
for op in patch_operations:
if op['op'] == 'replace':
# TODO: match the path against the values hash
# (e.g., path could be '/*/*/logging/loglevel')
self[op['path']] = op['value']
else:
raise Exception('Patch operation "%s" not implemented' % op['op'])
return self
class RestAPI(object):
def __init__(self, id, region_name, name, description):
self.id = id
@ -158,6 +178,7 @@ class RestAPI(object):
self.create_date = datetime.datetime.utcnow()
self.deployments = {}
self.stages = {}
self.resources = {}
self.add_child('/') # Add default child
@ -202,6 +223,7 @@ class RestAPI(object):
deployment_id = create_id()
deployment = Deployment(deployment_id, name)
self.deployments[deployment_id] = deployment
self.stages[name] = Stage(name=name, deployment_id=deployment_id)
self.update_integration_mocks(name)
@ -276,6 +298,17 @@ class APIGatewayBackend(BaseBackend):
method = resource.add_method(method_type, authorization_type)
return method
def get_stage(self, function_id, stage_name):
api = self.get_rest_api(function_id)
return api.stages.get(stage_name)
def update_stage(self, function_id, stage_name, patch_operations):
stage = self.get_stage(function_id, stage_name)
if not stage:
api = self.get_rest_api(function_id)
stage = api.stages[stage_name] = Stage()
return stage.apply_operations(patch_operations)
def get_method_response(self, function_id, resource_id, method_type, response_code):
method = self.get_method(function_id, resource_id, method_type)
method_response = method.get_response(response_code)

View File

@ -95,6 +95,19 @@ class APIGatewayResponse(BaseResponse):
method_response = self.backend.delete_method_response(function_id, resource_id, method_type, response_code)
return 200, headers, json.dumps(method_response)
def stages(self, request, full_url, headers):
self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/")
function_id = url_path_parts[2]
stage_name = url_path_parts[4]
if self.method == 'GET':
stage_response = self.backend.get_stage(function_id, stage_name)
elif self.method == 'PATCH':
path_operations = self._get_param('patchOperations')
stage_response = self.backend.update_stage(function_id, stage_name, path_operations)
return 200, headers, json.dumps(stage_response)
def integrations(self, request, full_url, headers):
self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/")

View File

@ -9,11 +9,12 @@ url_paths = {
'{0}/restapis$': APIGatewayResponse().restapis,
'{0}/restapis/(?P<function_id>[^/]+)/?$': APIGatewayResponse().restapis_individual,
'{0}/restapis/(?P<function_id>[^/]+)/resources$': APIGatewayResponse().resources,
'{0}/restapis/(?P<function_id>[^/]+)/stages/(?P<stage_name>[^/]+)/?$': APIGatewayResponse().stages,
'{0}/restapis/(?P<function_id>[^/]+)/deployments$': APIGatewayResponse().deployments,
'{0}/restapis/(?P<function_id>[^/]+)/deployments/(?P<deployment_id>[^/]+)/?$': APIGatewayResponse().individual_deployment,
'{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/?$': APIGatewayResponse().resource_individual,
'{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/methods/(?P<method_name>[^/]+)/?$': APIGatewayResponse().resource_methods,
'{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/methods/(?P<method_name>[^/]+)/responses/200$': APIGatewayResponse().resource_method_responses,
'{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/methods/(?P<method_name>[^/]+)/responses/(?P<status_code>\d+)$': APIGatewayResponse().resource_method_responses,
'{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/methods/(?P<method_name>[^/]+)/integration/?$': APIGatewayResponse().integrations,
'{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/methods/(?P<method_name>[^/]+)/integration/responses/(?P<status_code>\d+)/?$': APIGatewayResponse().integration_responses,
}

View File

@ -16,7 +16,7 @@ from werkzeug.serving import run_simple
from moto.backends import BACKENDS
from moto.core.utils import convert_flask_to_httpretty_response
HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "HEAD"]
HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH"]
class DomainDispatcherApplication(object):

View File

@ -472,6 +472,7 @@ def test_integration_response():
@mock_apigateway
def test_deployment():
client = boto3.client('apigateway', region_name='us-west-2')
stage_name = 'staging'
response = client.create_rest_api(
name='my_api',
description='this is my api',
@ -480,7 +481,7 @@ def test_deployment():
response = client.create_deployment(
restApiId=api_id,
stageName='staging',
stageName=stage_name,
)
deployment_id = response['id']
@ -511,6 +512,35 @@ def test_deployment():
)
len(response['items']).should.equal(0)
# test deployment stages
stage = client.get_stage(
restApiId=api_id,
stageName=stage_name
)
stage['stageName'].should.equal(stage_name)
stage['deploymentId'].should.equal(deployment_id)
stage = client.update_stage(
restApiId=api_id,
stageName=stage_name,
patchOperations=[
{
'op': 'replace',
'path': 'description',
'value': '_new_description_'
},
]
)
stage = client.get_stage(
restApiId=api_id,
stageName=stage_name
)
stage['stageName'].should.equal(stage_name)
stage['deploymentId'].should.equal(deployment_id)
stage['description'].should.equal('_new_description_')
@httpretty.activate
@mock_apigateway