def test_must_print_routes(self): host = "host" port = 123 api_provider = Mock() apis = [ Api(path="/1", method="GET", function_name="name1", cors="CORS1"), Api(path="/1", method="POST", function_name="name1", cors="CORS1"), Api(path="/1", method="DELETE", function_name="othername1", cors="CORS1"), Api(path="/2", method="GET2", function_name="name2", cors="CORS2"), Api(path="/3", method="GET3", function_name="name3", cors="CORS3"), ] api_provider.get_all.return_value = apis expected = { "Mounting name1 at http://host:123/1 [GET, POST]", "Mounting othername1 at http://host:123/1 [DELETE]", "Mounting name2 at http://host:123/2 [GET2]", "Mounting name3 at http://host:123/3 [GET3]" } actual = LocalApiService._print_routes(api_provider, host, port) self.assertEquals(expected, set(actual))
def test_with_binary_media_types(self): template = { "Resources": { "Api1": { "Type": "AWS::Serverless::Api", "Properties": { "StageName": "Prod", "DefinitionBody": make_swagger(self.input_apis, binary_media_types=self.binary_types) } } } } expected_binary_types = sorted(self.binary_types) expected_apis = [ Api(path="/path1", method="GET", function_name="SamFunc1", cors=None, binary_media_types=expected_binary_types, stage_name="Prod"), Api(path="/path1", method="POST", function_name="SamFunc1", cors=None, binary_media_types=expected_binary_types, stage_name="Prod"), Api(path="/path2", method="PUT", function_name="SamFunc1", cors=None, binary_media_types=expected_binary_types, stage_name="Prod"), Api(path="/path2", method="GET", function_name="SamFunc1", cors=None, binary_media_types=expected_binary_types, stage_name="Prod"), Api(path="/path3", method="DELETE", function_name="SamFunc1", cors=None, binary_media_types=expected_binary_types, stage_name="Prod") ] provider = SamApiProvider(template) assertCountEqual(self, expected_apis, provider.apis)
def test_binary_media_types_with_rest_api_id_reference(self): events = { "Event1": { "Type": "Api", "Properties": { "Path": "/connected-to-explicit-path", "Method": "POST", "RestApiId": "Api1" } }, "Event2": { "Type": "Api", "Properties": { "Path": "/true-implicit-path", "Method": "POST" } } } # Binary type for implicit self.template["Globals"] = { "Api": { "BinaryMediaTypes": ["image~1gif", "image~1png"] } } self.template["Resources"]["ImplicitFunc"]["Properties"]["Events"] = events self.template["Resources"]["Api1"]["Properties"]["DefinitionBody"] = self.swagger # Binary type for explicit self.template["Resources"]["Api1"]["Properties"]["BinaryMediaTypes"] = ["explicit/type1", "explicit/type2"] # Because of Globals, binary types will be concatenated on the explicit API expected_explicit_binary_types = ["explicit/type1", "explicit/type2", "image/gif", "image/png"] expected_implicit_binary_types = ["image/gif", "image/png"] expected_apis = [ # From Explicit APIs Api(path="/path1", method="GET", function_name="explicitfunction", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), Api(path="/path2", method="GET", function_name="explicitfunction", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), Api(path="/path3", method="GET", function_name="explicitfunction", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), # Because of the RestApiId, Implicit APIs will also get the binary media types inherited from # the corresponding Explicit API Api(path="/connected-to-explicit-path", method="POST", function_name="ImplicitFunc", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), # This is still just a true implicit API because it does not have RestApiId property Api(path="/true-implicit-path", method="POST", function_name="ImplicitFunc", binary_media_types=expected_implicit_binary_types, stage_name="Prod") ] provider = SamApiProvider(self.template) assertCountEqual(self, expected_apis, provider.apis)
def test_must_prefer_implicit_with_any_method(self): implicit_apis = { "Event1": { "Type": "Api", "Properties": { # This API is duplicated between implicit & explicit "Path": "/path", "Method": "ANY" } } } explicit_apis = [ # Explicit should be over masked completely by implicit, because of "ANY" Api(path="/path", method="GET", function_name="explicitfunction", cors=None), Api(path="/path", method="DELETE", function_name="explicitfunction", cors=None), ] self.template["Resources"]["Api1"]["Properties"]["DefinitionBody"] = make_swagger(explicit_apis) self.template["Resources"]["ImplicitFunc"]["Properties"]["Events"] = implicit_apis expected_apis = [ Api(path="/path", method="GET", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path", method="POST", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path", method="PUT", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path", method="DELETE", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path", method="HEAD", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path", method="OPTIONS", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path", method="PATCH", function_name="ImplicitFunc", cors=None, stage_name="Prod") ] provider = SamApiProvider(self.template) assertCountEqual(self, expected_apis, provider.apis)
def test_both_apis_must_get_binary_media_types(self): events = { "Event1": { "Type": "Api", "Properties": { "Path": "/newpath1", "Method": "POST" } }, "Event2": { "Type": "Api", "Properties": { "Path": "/newpath2", "Method": "POST" } } } # Binary type for implicit self.template["Globals"] = { "Api": { "BinaryMediaTypes": ["image~1gif", "image~1png"] } } self.template["Resources"]["ImplicitFunc"]["Properties"]["Events"] = events self.template["Resources"]["Api1"]["Properties"]["DefinitionBody"] = self.swagger # Binary type for explicit self.template["Resources"]["Api1"]["Properties"]["BinaryMediaTypes"] = ["explicit/type1", "explicit/type2"] # Because of Globals, binary types will be concatenated on the explicit API expected_explicit_binary_types = ["explicit/type1", "explicit/type2", "image/gif", "image/png"] expected_implicit_binary_types = ["image/gif", "image/png"] expected_apis = [ # From Explicit APIs Api(path="/path1", method="GET", function_name="explicitfunction", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), Api(path="/path2", method="GET", function_name="explicitfunction", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), Api(path="/path3", method="GET", function_name="explicitfunction", binary_media_types=expected_explicit_binary_types, stage_name="Prod"), # From Implicit APIs Api(path="/newpath1", method="POST", function_name="ImplicitFunc", binary_media_types=expected_implicit_binary_types, stage_name="Prod"), Api(path="/newpath2", method="POST", function_name="ImplicitFunc", binary_media_types=expected_implicit_binary_types, stage_name="Prod") ] provider = SamApiProvider(self.template) assertCountEqual(self, expected_apis, provider.apis)
def setUp(self): self.binary_types = ["image/png", "image/jpg"] self.input_apis = [ Api(path="/path1", method="GET", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path1", method="POST", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path2", method="PUT", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path2", method="GET", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path3", method="DELETE", function_name="SamFunc1", cors=None, stage_name="Prod") ]
def test_swagger_with_any_method(self): apis = [ Api(path="/path", method="any", function_name="SamFunc1", cors=None) ] expected_apis = [ Api(path="/path", method="GET", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path", method="POST", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path", method="PUT", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path", method="DELETE", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path", method="HEAD", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path", method="OPTIONS", function_name="SamFunc1", cors=None, stage_name="Prod"), Api(path="/path", method="PATCH", function_name="SamFunc1", cors=None, stage_name="Prod") ] template = { "Resources": { "Api1": { "Type": "AWS::Serverless::Api", "Properties": { "StageName": "Prod", "DefinitionBody": make_swagger(apis) } } } } provider = SamApiProvider(template) assertCountEqual(self, expected_apis, provider.apis)
def test_provider_get_all(self): template = { "Resources": { "SamFunc1": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": "GET" } } } } }, "SamFunc2": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": "POST" } } } } } } } provider = SamApiProvider(template) result = [f for f in provider.get_all()] api1 = Api(path="/path", method="GET", function_name="SamFunc1", stage_name="Prod") api2 = Api(path="/path", method="POST", function_name="SamFunc2", stage_name="Prod") self.assertIn(api1, result) self.assertIn(api2, result)
def test_provider_has_correct_template(self): template = { "Resources": { "SamFunc1": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": "GET" } } } } }, "SamFunc2": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": "POST" } } } } } } } provider = SamApiProvider(template) api1 = Api(path="/path", method="GET", function_name="SamFunc1", cors=None, stage_name="Prod") api2 = Api(path="/path", method="POST", function_name="SamFunc2", cors=None, stage_name="Prod") self.assertIn(api1, provider.apis) self.assertIn(api2, provider.apis)
def test_provider_has_correct_api(self, method): template = { "Resources": { "SamFunc1": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": method } } } } } } } provider = SamApiProvider(template) self.assertEquals(len(provider.apis), 1) self.assertEquals(list(provider.apis)[0], Api(path="/path", method="GET", function_name="SamFunc1", cors=None, stage_name="Prod"))
def test_with_one_path_method(self): function_name = "myfunction" swagger = { "paths": { "/path1": { "get": { "x-amazon-apigateway-integration": { "type": "aws_proxy", "uri": "someuri" } } } } } parser = SwaggerParser(swagger) parser._get_integration_function_name = Mock() parser._get_integration_function_name.return_value = function_name expected = [Api(path="/path1", method="get", function_name=function_name, cors=None)] result = parser.get_apis() self.assertEquals(expected, result) parser._get_integration_function_name.assert_called_with({ "x-amazon-apigateway-integration": { "type": "aws_proxy", "uri": "someuri" } })
def get_apis(self): """ Parses a swagger document and returns a list of APIs configured in the document. Swagger documents have the following structure { "/path1": { # path "get": { # method "x-amazon-apigateway-integration": { # integration "type": "aws_proxy", # URI contains the Lambda function ARN that needs to be parsed to get Function Name "uri": { "Fn::Sub": "arn:aws:apigateway:aws:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/..." } } }, "post": { }, }, "/path2": { ... } } Returns ------- list of samcli.commands.local.lib.provider.Api List of APIs that are configured in the Swagger document """ result = [] paths_dict = self.swagger.get("paths", {}) binary_media_types = self.get_binary_media_types() for full_path, path_config in paths_dict.items(): for method, method_config in path_config.items(): function_name = self._get_integration_function_name( method_config) if not function_name: LOG.debug( "Lambda function integration not found in Swagger document at path='%s' method='%s'", full_path, method) continue if method.lower() == self._ANY_METHOD_EXTENSION_KEY: # Convert to a more commonly used method notation method = self._ANY_METHOD api = Api(path=full_path, method=method, function_name=function_name, cors=None, binary_media_types=binary_media_types) result.append(api) return result
def _convert_event_api(lambda_logical_id, event_properties): """ Converts a AWS::Serverless::Function's Event Property to an Api configuration usable by the provider. :param str lambda_logical_id: Logical Id of the AWS::Serverless::Function :param dict event_properties: Dictionary of the Event's Property :return tuple: tuple of API resource name and Api namedTuple """ path = event_properties.get(SamApiProvider._EVENT_PATH) method = event_properties.get(SamApiProvider._EVENT_METHOD) # An API Event, can have RestApiId property which designates the resource that owns this API. If omitted, # the API is owned by Implicit API resource. This could either be a direct resource logical ID or a # "Ref" of the logicalID api_resource_id = event_properties.get( "RestApiId", SamApiProvider._IMPLICIT_API_RESOURCE_ID) if isinstance(api_resource_id, dict) and "Ref" in api_resource_id: api_resource_id = api_resource_id["Ref"] # This is still a dictionary. Something wrong with the template if isinstance(api_resource_id, dict): LOG.debug("Invalid RestApiId property of event %s", event_properties) raise InvalidSamDocumentException( "RestApiId property of resource with logicalId '{}' is invalid. " "It should either be a LogicalId string or a Ref of a Logical Id string" .format(lambda_logical_id)) return api_resource_id, Api(path=path, method=method, function_name=lambda_logical_id)
def test_initalize_with_values(self): lambda_runner = Mock() local_service = LocalApigwService(Api(), lambda_runner, static_dir="dir/static", port=5000, host="129.0.0.0") self.assertEqual(local_service.port, 5000) self.assertEqual(local_service.host, "129.0.0.0") self.assertEqual(local_service.api.routes, []) self.assertEqual(local_service.static_dir, "dir/static") self.assertEqual(local_service.lambda_runner, lambda_runner)
def setUp(self): self.host = "127.0.0.1" self.port = random.randint(30000, 40000) # get a random port self.url = "http://{}:{}".format(self.host, self.port) self.code_abs_path = nodejs_lambda(API_GATEWAY_ECHO_EVENT) # Let's convert this absolute path to relative path. Let the parent be the CWD, and codeuri be the folder self.cwd = os.path.dirname(self.code_abs_path) self.code_uri = os.path.relpath(self.code_abs_path, self.cwd) # Get relative path with respect to CWD # Setup a static file in the directory self.static_dir = "mystaticdir" self.static_file_name = "myfile.txt" self.static_file_content = "This is a static file" self._setup_static_file( os.path.join(self.cwd, self.static_dir), # Create static directory with in cwd self.static_file_name, self.static_file_content, ) # Create one Lambda function self.function_name = "name" self.function = provider.Function( name=self.function_name, runtime="nodejs4.3", memory=256, timeout=5, handler="index.handler", codeuri=self.code_uri, environment={}, rolearn=None, layers=[], ) self.mock_function_provider = Mock() self.mock_function_provider.get.return_value = self.function # Setup two APIs pointing to the same function routes = [ Route(path="/get", methods=["GET"], function_name=self.function_name), Route(path="/post", methods=["POST"], function_name=self.function_name), ] api = Api(routes=routes) self.api_provider_mock = Mock() self.api_provider_mock.get_all.return_value = api # Now wire up the Lambda invoker and pass it through the context self.lambda_invoke_context_mock = Mock() manager = ContainerManager() layer_downloader = LayerDownloader("./", "./") lambda_image = LambdaImage(layer_downloader, False, False) local_runtime = LambdaRuntime(manager, lambda_image) lambda_runner = LocalLambdaRunner(local_runtime, self.mock_function_provider, self.cwd, debug_context=None) self.lambda_invoke_context_mock.local_lambda_runner = lambda_runner self.lambda_invoke_context_mock.get_cwd.return_value = self.cwd
def test_must_return_routing_list_from_apis(self): api_provider = Mock() apis = [ Api(path="/1", method="GET1", function_name="name1", cors="CORS1"), Api(path="/2", method="GET2", function_name="name2", cors="CORS2"), Api(path="/3", method="GET3", function_name="name3", cors="CORS3"), ] expected = [ Route(path="/1", methods=["GET1"], function_name="name1"), Route(path="/2", methods=["GET2"], function_name="name2"), Route(path="/3", methods=["GET3"], function_name="name3") ] api_provider.get_all.return_value = apis result = LocalApiService._make_routing_list(api_provider) self.assertEquals(len(result), len(expected)) for index, r in enumerate(result): self.assertEquals(r.__dict__, expected[index].__dict__)
def test_with_combination_of_paths_methods(self): function_name = "myfunction" swagger = { "paths": { "/path1": { "get": { "x-amazon-apigateway-integration": { "type": "aws_proxy", "uri": "someuri" } }, "delete": { "x-amazon-apigateway-integration": { "type": "aws_proxy", "uri": "someuri" } } }, "/path2": { "post": { "x-amazon-apigateway-integration": { "type": "aws_proxy", "uri": "someuri" } } } } } parser = SwaggerParser(swagger) parser._get_integration_function_name = Mock() parser._get_integration_function_name.return_value = function_name expected = { Api(path="/path1", method="get", function_name=function_name, cors=None), Api(path="/path1", method="delete", function_name=function_name, cors=None), Api(path="/path2", method="post", function_name=function_name, cors=None), } result = parser.get_apis() self.assertEquals(expected, set(result))
def test_provider_with_valid_template(self, SamBaseProviderMock, extract_api_mock): extract_api_mock.return_value = Api(routes={"set", "of", "values"}) template = {"Resources": {"a": "b"}} SamBaseProviderMock.get_template.return_value = template provider = ApiProvider(template) self.assertEqual(len(provider.routes), 3) self.assertEqual(provider.routes, set(["set", "of", "values"])) self.assertEqual(provider.template_dict, {"Resources": {"a": "b"}}) self.assertEqual(provider.resources, {"a": "b"})
def setUp(self): self.function_name = Mock() self.api_gateway_route = Route(methods=["GET"], function_name=self.function_name, path="/") self.list_of_routes = [self.api_gateway_route] self.lambda_runner = Mock() self.lambda_runner.is_debugging.return_value = False self.stderr = Mock() self.api = Api(routes=self.list_of_routes) self.service = LocalApigwService(self.api, self.lambda_runner, port=3000, host="127.0.0.1", stderr=self.stderr)
def test_must_prefer_implicit_api_over_explicit(self): implicit_apis = { "Event1": { "Type": "Api", "Properties": { # This API is duplicated between implicit & explicit "Path": "/path1", "Method": "get" } }, "Event2": { "Type": "Api", "Properties": { "Path": "/path2", "Method": "POST" } } } self.template["Resources"]["Api1"]["Properties"]["DefinitionBody"] = self.swagger self.template["Resources"]["ImplicitFunc"]["Properties"]["Events"] = implicit_apis expected_apis = [ Api(path="/path1", method="GET", function_name="ImplicitFunc", stage_name="Prod"), # Comes from Implicit Api(path="/path2", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), Api(path="/path2", method="POST", function_name="ImplicitFunc", stage_name="Prod"), # Comes from implicit Api(path="/path3", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), ] provider = SamApiProvider(self.template) assertCountEqual(self, expected_apis, provider.apis)
def test_must_add_explicit_api_when_ref_with_rest_api_id(self): events = { "Event1": { "Type": "Api", "Properties": { "Path": "/newpath1", "Method": "POST", "RestApiId": "Api1" # This path must get added to this API } }, "Event2": { "Type": "Api", "Properties": { "Path": "/newpath2", "Method": "POST", "RestApiId": {"Ref": "Api1"} # This path must get added to this API } } } self.template["Resources"]["Api1"]["Properties"]["DefinitionBody"] = self.swagger self.template["Resources"]["ImplicitFunc"]["Properties"]["Events"] = events expected_apis = [ # From Explicit APIs Api(path="/path1", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), Api(path="/path2", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), Api(path="/path3", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), # From Implicit APIs Api(path="/newpath1", method="POST", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/newpath2", method="POST", function_name="ImplicitFunc", cors=None, stage_name="Prod") ] provider = SamApiProvider(self.template) assertCountEqual(self, expected_apis, provider.apis)
def test_create_creates_dict_of_routes(self): function_name_1 = Mock() function_name_2 = Mock() api_gateway_route_1 = Route(methods=["GET"], function_name=function_name_1, path="/") api_gateway_route_2 = Route(methods=["POST"], function_name=function_name_2, path="/") list_of_routes = [api_gateway_route_1, api_gateway_route_2] lambda_runner = Mock() api = Api(routes=list_of_routes) service = LocalApigwService(api, lambda_runner) service.create() self.assertEqual(service._dict_of_routes, {"/:GET": api_gateway_route_1, "/:POST": api_gateway_route_2})
def test_provider_must_support_binary_media_types_with_any_method(self): template = { "Globals": { "Api": { "BinaryMediaTypes": [ "image~1gif", "image~1png", "text/html" ] } }, "Resources": { "SamFunc1": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": "any" } } } } } } } binary = ["image/gif", "image/png", "text/html"] expected_apis = [ Api(path="/path", method="GET", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod"), Api(path="/path", method="POST", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod"), Api(path="/path", method="PUT", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod"), Api(path="/path", method="DELETE", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod"), Api(path="/path", method="HEAD", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod"), Api(path="/path", method="OPTIONS", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod"), Api(path="/path", method="PATCH", function_name="SamFunc1", binary_media_types=binary, stage_name="Prod") ] provider = SamApiProvider(template) assertCountEqual(self, provider.apis, expected_apis)
def test_provider_stage_variables(self): template = { "Resources": { "TestApi": { "Type": "AWS::Serverless::Api", "Properties": { "StageName": "dev", "Variables": { "vis": "data", "random": "test", "foo": "bar" }, "DefinitionBody": { "paths": { "/path": { "get": { "x-amazon-apigateway-integration": { "httpMethod": "POST", "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31" "/functions/${NoApiEventFunction.Arn}/invocations", }, "responses": {}, }, } } } } } } } } provider = SamApiProvider(template) api1 = Api(path='/path', method='GET', function_name='NoApiEventFunction', cors=None, binary_media_types=[], stage_name='dev', stage_variables={ "vis": "data", "random": "test", "foo": "bar" }) self.assertIn(api1, provider.apis)
def test_must_raise_if_route_not_available(self, extract_api, log_routes_mock, make_static_dir_mock, SamApiProviderMock, ApiGwServiceMock): routing_list = [] # Empty api = Api() extract_api.return_value = api SamApiProviderMock.extract_api.return_value = api SamApiProviderMock.return_value = self.api_provider_mock ApiGwServiceMock.return_value = self.apigw_service # Now start the service local_service = LocalApiService(self.lambda_invoke_context_mock, self.port, self.host, self.static_dir) local_service.api_provider.api.routes = routing_list with self.assertRaises(NoApisDefined): local_service.start()
def test_provider_must_support_binary_media_types(self): template = { "Globals": { "Api": { "BinaryMediaTypes": [ "image~1gif", "image~1png", "image~1png", # Duplicates must be ignored {"Ref": "SomeParameter"} # Refs are ignored as well ] } }, "Resources": { "SamFunc1": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": "get" } } } } } } } provider = SamApiProvider(template) self.assertEquals(len(provider.apis), 1) self.assertEquals(list(provider.apis)[0], Api(path="/path", method="GET", function_name="SamFunc1", binary_media_types=["image/gif", "image/png"], cors=None, stage_name="Prod"))
def test_provider_with_any_method(self, method): template = { "Resources": { "SamFunc1": { "Type": "AWS::Serverless::Function", "Properties": { "CodeUri": "/usr/foo/bar", "Runtime": "nodejs4.3", "Handler": "index.handler", "Events": { "Event1": { "Type": "Api", "Properties": { "Path": "/path", "Method": method } } } } } } } provider = SamApiProvider(template) api_get = Api(path="/path", method="GET", function_name="SamFunc1", cors=None, stage_name="Prod") api_post = Api(path="/path", method="POST", function_name="SamFunc1", cors=None, stage_name="Prod") api_put = Api(path="/path", method="PUT", function_name="SamFunc1", cors=None, stage_name="Prod") api_delete = Api(path="/path", method="DELETE", function_name="SamFunc1", cors=None, stage_name="Prod") api_patch = Api(path="/path", method="PATCH", function_name="SamFunc1", cors=None, stage_name="Prod") api_head = Api(path="/path", method="HEAD", function_name="SamFunc1", cors=None, stage_name="Prod") api_options = Api(path="/path", method="OPTIONS", function_name="SamFunc1", cors=None, stage_name="Prod") self.assertEquals(len(provider.apis), 7) self.assertIn(api_get, provider.apis) self.assertIn(api_post, provider.apis) self.assertIn(api_put, provider.apis) self.assertIn(api_delete, provider.apis) self.assertIn(api_patch, provider.apis) self.assertIn(api_head, provider.apis) self.assertIn(api_options, provider.apis)
def get_api(self): """ Creates the api using the parts from the ApiCollector. The routes are also deduped so that there is no duplicate routes with the same function name, path, but different method. The normalised_routes are the routes that have been processed. By default, this will get all the routes. However, it can be changed to override the default value of normalised routes such as in SamApiProvider Return ------- An Api object with all the properties """ api = Api() routes = self.dedupe_function_routes(self.routes) routes = self.normalize_cors_methods(routes, self.cors) api.routes = routes api.binary_media_types_set = self.binary_media_types_set api.stage_name = self.stage_name api.stage_variables = self.stage_variables api.cors = self.cors return api
def test_must_union_implicit_and_explicit(self): events = { "Event1": { "Type": "Api", "Properties": { "Path": "/path1", "Method": "POST" } }, "Event2": { "Type": "Api", "Properties": { "Path": "/path2", "Method": "POST" } }, "Event3": { "Type": "Api", "Properties": { "Path": "/path3", "Method": "POST" } } } self.template["Resources"]["Api1"]["Properties"]["DefinitionBody"] = self.swagger self.template["Resources"]["ImplicitFunc"]["Properties"]["Events"] = events expected_apis = [ # From Explicit APIs Api(path="/path1", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), Api(path="/path2", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), Api(path="/path3", method="GET", function_name="explicitfunction", cors=None, stage_name="Prod"), # From Implicit APIs Api(path="/path1", method="POST", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path2", method="POST", function_name="ImplicitFunc", cors=None, stage_name="Prod"), Api(path="/path3", method="POST", function_name="ImplicitFunc", cors=None, stage_name="Prod") ] provider = SamApiProvider(self.template) assertCountEqual(self, expected_apis, provider.apis)
def test_multi_stage_get_all(self): template = { "Resources": { "TestApi": { "Type": "AWS::Serverless::Api", "Properties": { "StageName": "dev", "Variables": { "vis": "data", "random": "test", "foo": "bar" }, "DefinitionBody": { "paths": { "/path2": { "get": { "x-amazon-apigateway-integration": { "httpMethod": "POST", "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31" "/functions/${NoApiEventFunction.Arn}/invocations", }, "responses": {}, }, } } } } } }, "ProductionApi": { "Type": "AWS::Serverless::Api", "Properties": { "StageName": "Production", "Variables": { "vis": "prod data", "random": "test", "foo": "bar" }, "DefinitionBody": { "paths": { "/path": { "get": { "x-amazon-apigateway-integration": { "httpMethod": "POST", "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31" "/functions/${NoApiEventFunction.Arn}/invocations", }, "responses": {}, }, } }, "/anotherpath": { "post": { "x-amazon-apigateway-integration": { "httpMethod": "POST", "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31" "/functions/${NoApiEventFunction.Arn}/invocations", }, "responses": {}, }, } } } } } } } } provider = SamApiProvider(template) result = [f for f in provider.get_all()] api1 = Api(path='/path2', method='GET', function_name='NoApiEventFunction', cors=None, binary_media_types=[], stage_name='dev', stage_variables={ "vis": "data", "random": "test", "foo": "bar" }) api2 = Api(path='/path', method='GET', function_name='NoApiEventFunction', cors=None, binary_media_types=[], stage_name='Production', stage_variables={'vis': 'prod data', 'random': 'test', 'foo': 'bar'}) api3 = Api(path='/anotherpath', method='POST', function_name='NoApiEventFunction', cors=None, binary_media_types=[], stage_name='Production', stage_variables={ "vis": "prod data", "random": "test", "foo": "bar" }) self.assertEquals(len(result), 3) self.assertIn(api1, result) self.assertIn(api2, result) self.assertIn(api3, result)