from __future__ import unicode_literals from datetime import datetime from dateutil.tz import tzutc import boto3 from freezegun import freeze_time import httpretty import requests import sure # noqa from botocore.exceptions import ClientError from moto import mock_apigateway @freeze_time("2015-01-01") @mock_apigateway def test_create_and_get_rest_api(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] response = client.get_rest_api( restApiId=api_id ) response.pop('ResponseMetadata') response.should.equal({ 'id': api_id, 'name': 'my_api', 'description': 'this is my api', 'createdDate': datetime(2015, 1, 1, tzinfo=tzutc()) }) @mock_apigateway def test_list_and_delete_apis(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] client.create_rest_api( name='my_api2', description='this is my api2', ) response = client.get_rest_apis() len(response['items']).should.equal(2) client.delete_rest_api( restApiId=api_id ) response = client.get_rest_apis() len(response['items']).should.equal(1) @mock_apigateway def test_create_resource(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] root_resource = client.get_resource( restApiId=api_id, resourceId=root_id, ) root_resource['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it root_resource['ResponseMetadata'].pop('RetryAttempts', None) root_resource.should.equal({ 'path': '/', 'id': root_id, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'resourceMethods': { 'GET': {} } }) response = client.create_resource( restApiId=api_id, parentId=root_id, pathPart='/users', ) resources = client.get_resources(restApiId=api_id)['items'] len(resources).should.equal(2) non_root_resource = [resource for resource in resources if resource['path'] != '/'][0] response = client.delete_resource( restApiId=api_id, resourceId=non_root_resource['id'] ) len(client.get_resources(restApiId=api_id)['items']).should.equal(1) @mock_apigateway def test_child_resource(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] response = client.create_resource( restApiId=api_id, parentId=root_id, pathPart='users', ) users_id = response['id'] response = client.create_resource( restApiId=api_id, parentId=users_id, pathPart='tags', ) tags_id = response['id'] child_resource = client.get_resource( restApiId=api_id, resourceId=tags_id, ) child_resource['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it child_resource['ResponseMetadata'].pop('RetryAttempts', None) child_resource.should.equal({ 'path': '/users/tags', 'pathPart': 'tags', 'parentId': users_id, 'id': tags_id, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'resourceMethods': {'GET': {}}, }) @mock_apigateway def test_create_method(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] client.put_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', authorizationType='none', ) response = client.get_method( restApiId=api_id, resourceId=root_id, httpMethod='GET' ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'httpMethod': 'GET', 'authorizationType': 'none', 'ResponseMetadata': {'HTTPStatusCode': 200} }) @mock_apigateway def test_create_method_response(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] client.put_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', authorizationType='none', ) response = client.get_method( restApiId=api_id, resourceId=root_id, httpMethod='GET' ) response = client.put_method_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'ResponseMetadata': {'HTTPStatusCode': 200}, 'statusCode': '200' }) response = client.get_method_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'ResponseMetadata': {'HTTPStatusCode': 200}, 'statusCode': '200' }) response = client.delete_method_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({'ResponseMetadata': {'HTTPStatusCode': 200}}) @mock_apigateway def test_integrations(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] client.put_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', authorizationType='none', ) client.put_method_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response = client.put_integration( restApiId=api_id, resourceId=root_id, httpMethod='GET', type='HTTP', uri='http://httpbin.org/robots.txt', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'ResponseMetadata': {'HTTPStatusCode': 200}, 'httpMethod': 'GET', 'integrationResponses': { '200': { 'responseTemplates': { 'application/json': None }, 'statusCode': 200 } }, 'type': 'HTTP', 'uri': 'http://httpbin.org/robots.txt' }) response = client.get_integration( restApiId=api_id, resourceId=root_id, httpMethod='GET' ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'ResponseMetadata': {'HTTPStatusCode': 200}, 'httpMethod': 'GET', 'integrationResponses': { '200': { 'responseTemplates': { 'application/json': None }, 'statusCode': 200 } }, 'type': 'HTTP', 'uri': 'http://httpbin.org/robots.txt' }) response = client.get_resource( restApiId=api_id, resourceId=root_id, ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response['resourceMethods']['GET']['methodIntegration'].should.equal({ 'httpMethod': 'GET', 'integrationResponses': { '200': { 'responseTemplates': { 'application/json': None }, 'statusCode': 200 } }, 'type': 'HTTP', 'uri': 'http://httpbin.org/robots.txt' }) client.delete_integration( restApiId=api_id, resourceId=root_id, httpMethod='GET' ) response = client.get_resource( restApiId=api_id, resourceId=root_id, ) response['resourceMethods']['GET'].shouldnt.contain("methodIntegration") # Create a new integration with a requestTemplates config client.put_method( restApiId=api_id, resourceId=root_id, httpMethod='POST', authorizationType='none', ) templates = { # example based on http://docs.aws.amazon.com/apigateway/latest/developerguide/api-as-kinesis-proxy-export-swagger-with-extensions.html 'application/json': "{\n \"StreamName\": \"$input.params('stream-name')\",\n \"Records\": []\n}" } test_uri = 'http://example.com/foobar.txt' response = client.put_integration( restApiId=api_id, resourceId=root_id, httpMethod='POST', type='HTTP', uri=test_uri, requestTemplates=templates ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response['ResponseMetadata'].should.equal({'HTTPStatusCode': 200}) response = client.get_integration( restApiId=api_id, resourceId=root_id, httpMethod='POST' ) response['uri'].should.equal(test_uri) response['requestTemplates'].should.equal(templates) @mock_apigateway def test_integration_response(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] client.put_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', authorizationType='none', ) client.put_method_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response = client.put_integration( restApiId=api_id, resourceId=root_id, httpMethod='GET', type='HTTP', uri='http://httpbin.org/robots.txt', ) response = client.put_integration_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', selectionPattern='foobar', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'statusCode': '200', 'selectionPattern': 'foobar', 'ResponseMetadata': {'HTTPStatusCode': 200}, 'responseTemplates': { 'application/json': None } }) response = client.get_integration_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'statusCode': '200', 'selectionPattern': 'foobar', 'ResponseMetadata': {'HTTPStatusCode': 200}, 'responseTemplates': { 'application/json': None } }) response = client.get_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response['methodIntegration']['integrationResponses'].should.equal({ '200': { 'responseTemplates': { 'application/json': None }, 'selectionPattern': 'foobar', 'statusCode': '200' } }) response = client.delete_integration_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response = client.get_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', ) response['methodIntegration']['integrationResponses'].should.equal({}) @mock_apigateway def test_update_stage_configuration(): 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', ) api_id = response['id'] response = client.create_deployment( restApiId=api_id, stageName=stage_name, description="1.0.1" ) deployment_id = response['id'] response = client.get_deployment( restApiId=api_id, deploymentId=deployment_id, ) response.pop('createdDate',None) # createdDate is hard to match against, remove it response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'id': deployment_id, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description' : '1.0.1' }) response = client.create_deployment( restApiId=api_id, stageName=stage_name, description="1.0.2" ) deployment_id2 = response['id'] stage = client.get_stage( restApiId=api_id, stageName=stage_name ) stage['stageName'].should.equal(stage_name) stage['deploymentId'].should.equal(deployment_id2) stage.shouldnt.have.key('cacheClusterSize') client.update_stage(restApiId=api_id,stageName=stage_name, patchOperations=[ { "op" : "replace", "path" : "/cacheClusterEnabled", "value": "True" } ]) stage = client.get_stage( restApiId=api_id, stageName=stage_name ) stage.should.have.key('cacheClusterSize').which.should.equal("0.5") client.update_stage(restApiId=api_id,stageName=stage_name, patchOperations=[ { "op" : "replace", "path" : "/cacheClusterSize", "value": "1.6" } ]) stage = client.get_stage( restApiId=api_id, stageName=stage_name ) stage.should.have.key('cacheClusterSize').which.should.equal("1.6") client.update_stage(restApiId=api_id,stageName=stage_name, patchOperations=[ { "op" : "replace", "path" : "/deploymentId", "value": deployment_id }, { "op" : "replace", "path" : "/variables/environment", "value" : "dev" }, { "op" : "replace", "path" : "/variables/region", "value" : "eu-west-1" }, { "op" : "replace", "path" : "/*/*/caching/dataEncrypted", "value" : "True" }, { "op" : "replace", "path" : "/cacheClusterEnabled", "value" : "True" }, { "op" : "replace", "path" : "/description", "value" : "stage description update" }, { "op" : "replace", "path" : "/cacheClusterSize", "value" : "1.6" } ]) client.update_stage(restApiId=api_id,stageName=stage_name, patchOperations=[ { "op" : "remove", "path" : "/variables/region", "value" : "eu-west-1" } ]) stage = client.get_stage(restApiId=api_id,stageName=stage_name) stage['description'].should.match('stage description update') stage['cacheClusterSize'].should.equal("1.6") stage['variables']['environment'].should.match('dev') stage['variables'].should_not.have.key('region') stage['cacheClusterEnabled'].should.be.true stage['deploymentId'].should.match(deployment_id) stage['methodSettings'].should.have.key('*/*') stage['methodSettings']['*/*'].should.have.key('cacheDataEncrypted').which.should.be.true try: client.update_stage(restApiId=api_id,stageName=stage_name, patchOperations=[ { "op" : "add", "path" : "/notasetting", "value" : "eu-west-1" } ]) assert False.should.be.ok #Fail, should not be here except Exception: assert True.should.be.ok @mock_apigateway def test_non_existent_stage(): client = boto3.client('apigateway', region_name='us-west-2') response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] client.get_stage.when.called_with(restApiId=api_id,stageName='xxx').should.throw(ClientError) @mock_apigateway def test_create_stage(): 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', ) api_id = response['id'] response = client.create_deployment( restApiId=api_id, stageName=stage_name, ) deployment_id = response['id'] response = client.get_deployment( restApiId=api_id, deploymentId=deployment_id, ) response.pop('createdDate',None) # createdDate is hard to match against, remove it response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'id': deployment_id, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description' : '' }) response = client.create_deployment( restApiId=api_id, stageName=stage_name, ) deployment_id2 = response['id'] response = client.get_deployments( restApiId=api_id, ) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response['items'][0].pop('createdDate') response['items'][1].pop('createdDate') response['items'][0]['id'].should.match(r"{0}|{1}".format(deployment_id2,deployment_id)) response['items'][1]['id'].should.match(r"{0}|{1}".format(deployment_id2,deployment_id)) new_stage_name = 'current' response = client.create_stage(restApiId=api_id,stageName=new_stage_name,deploymentId=deployment_id2) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'stageName':new_stage_name, 'deploymentId':deployment_id2, 'methodSettings':{}, 'variables':{}, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description':'', 'cacheClusterEnabled':False }) stage = client.get_stage( restApiId=api_id, stageName=new_stage_name ) stage['stageName'].should.equal(new_stage_name) stage['deploymentId'].should.equal(deployment_id2) new_stage_name_with_vars = 'stage_with_vars' response = client.create_stage(restApiId=api_id,stageName=new_stage_name_with_vars,deploymentId=deployment_id2,variables={ "env" : "dev" }) response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'stageName':new_stage_name_with_vars, 'deploymentId':deployment_id2, 'methodSettings':{}, 'variables':{ "env" : "dev" }, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description':'', 'cacheClusterEnabled': False }) stage = client.get_stage( restApiId=api_id, stageName=new_stage_name_with_vars ) stage['stageName'].should.equal(new_stage_name_with_vars) stage['deploymentId'].should.equal(deployment_id2) stage['variables'].should.have.key('env').which.should.match("dev") new_stage_name = 'stage_with_vars_and_cache_settings' response = client.create_stage(restApiId=api_id,stageName=new_stage_name,deploymentId=deployment_id2,variables={ "env" : "dev" }, cacheClusterEnabled=True,description="hello moto") response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'stageName':new_stage_name, 'deploymentId':deployment_id2, 'methodSettings':{}, 'variables':{ "env" : "dev" }, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description':'hello moto', 'cacheClusterEnabled': True, 'cacheClusterSize' : "0.5" }) stage = client.get_stage( restApiId=api_id, stageName=new_stage_name ) stage['cacheClusterSize'].should.equal("0.5") new_stage_name = 'stage_with_vars_and_cache_settings_and_size' response = client.create_stage(restApiId=api_id,stageName=new_stage_name,deploymentId=deployment_id2,variables={ "env" : "dev" }, cacheClusterEnabled=True,cacheClusterSize="1.6",description="hello moto") response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'stageName':new_stage_name, 'deploymentId':deployment_id2, 'methodSettings':{}, 'variables':{ "env" : "dev" }, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description':'hello moto', 'cacheClusterEnabled': True, 'cacheClusterSize' : "1.6" }) stage = client.get_stage( restApiId=api_id, stageName=new_stage_name ) stage['stageName'].should.equal(new_stage_name) stage['deploymentId'].should.equal(deployment_id2) stage['variables'].should.have.key('env').which.should.match("dev") stage['cacheClusterSize'].should.equal("1.6") @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', ) api_id = response['id'] response = client.create_deployment( restApiId=api_id, stageName=stage_name, ) deployment_id = response['id'] response = client.get_deployment( restApiId=api_id, deploymentId=deployment_id, ) response.pop('createdDate',None) # createdDate is hard to match against, remove it response['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it response['ResponseMetadata'].pop('RetryAttempts', None) response.should.equal({ 'id': deployment_id, 'ResponseMetadata': {'HTTPStatusCode': 200}, 'description' : '' }) response = client.get_deployments( restApiId=api_id, ) response['items'][0].pop('createdDate') response['items'].should.equal([ {'id': deployment_id, 'description': ''} ]) response = client.delete_deployment( restApiId=api_id, deploymentId=deployment_id, ) response = client.get_deployments( restApiId=api_id, ) 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 def test_http_proxying_integration(): httpretty.register_uri( httpretty.GET, "http://httpbin.org/robots.txt", body='a fake response' ) region_name = 'us-west-2' client = boto3.client('apigateway', region_name=region_name) response = client.create_rest_api( name='my_api', description='this is my api', ) api_id = response['id'] resources = client.get_resources(restApiId=api_id) root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] client.put_method( restApiId=api_id, resourceId=root_id, httpMethod='GET', authorizationType='none', ) client.put_method_response( restApiId=api_id, resourceId=root_id, httpMethod='GET', statusCode='200', ) response = client.put_integration( restApiId=api_id, resourceId=root_id, httpMethod='GET', type='HTTP', uri='http://httpbin.org/robots.txt', ) stage_name = 'staging' client.create_deployment( restApiId=api_id, stageName=stage_name, ) deploy_url = "https://{api_id}.execute-api.{region_name}.amazonaws.com/{stage_name}".format(api_id=api_id, region_name=region_name, stage_name=stage_name) requests.get(deploy_url).content.should.equal(b"a fake response")