def testNamespaceDefaultPath(self): @api_config.api(name='root', hostname='example.appspot.com', version='v1', description='This is an API', namespace=api_config.Namespace('domain', 'name', None)) class MyService(remote.Service): """Describes MyService.""" @api_config.method(IdField, message_types.VoidMessage, path='entries', http_method='GET', name='get_entry') def entries_get(self, unused_request): """Id (integer) field type in the query parameters.""" return message_types.VoidMessage() api = json.loads(self.generator.pretty_print_config_to_json(MyService)) try: pwd = os.path.dirname(os.path.realpath(__file__)) test_file = os.path.join(pwd, 'testdata', 'discovery', 'namespace.json') with open(test_file) as f: expected_discovery = json.loads(f.read()) except IOError as e: print 'Could not find expected output file ' + test_file raise e # Clear the value of the packagePath parameter in the expected results expected_discovery['packagePath'] = '' test_util.AssertDictEqual(expected_discovery, api, self)
def testCustomUrl(self): @api_config.api(name='root', hostname='example.appspot.com', version='v1', base_path='/my/base/path/') class MyService(remote.Service): """Describes MyService.""" @api_config.method(message_types.VoidMessage, message_types.VoidMessage, path='noop', http_method='GET', name='noop') def noop_get(self, unused_request): return message_types.VoidMessage() api = json.loads(self.generator.pretty_print_config_to_json(MyService)) expected_openapi = { 'swagger': '2.0', 'info': { 'title': 'root', 'description': 'Describes MyService.', 'version': 'v1', }, 'host': 'example.appspot.com', 'consumes': ['application/json'], 'produces': ['application/json'], 'schemes': ['https'], 'basePath': '/my/base/path', 'paths': { '/root/v1/noop': { 'get': { 'operationId': 'MyService_noopGet', 'parameters': [], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, }, 'securityDefinitions': { 'google_id_token': { 'authorizationUrl': '', 'flow': 'implicit', 'type': 'oauth2', 'x-issuer': 'accounts.google.com', 'x-jwks_uri': 'https://www.googleapis.com/oauth2/v1/certs', }, }, } test_util.AssertDictEqual(expected_openapi, api, self)
def testLocalhost(self): @api_config.api(name='root', hostname='localhost:8080', version='v1', description='This is an API') class RootService(remote.Service): """Describes RootService.""" @api_config.method(message_types.VoidMessage, message_types.VoidMessage, path='foo', http_method='GET', name='foo') def foo(self, unused_request): """Blank endpoint.""" return message_types.VoidMessage() @api_config.api(name='myapi', hostname='localhost:8081', version='v1', description='This is my API') class MyService(remote.Service): """Describes MyService.""" @api_config.method(message_types.VoidMessage, message_types.VoidMessage, path='foo', http_method='GET', name='foo') def foo(self, unused_request): """Blank endpoint.""" return message_types.VoidMessage() api_server = apiserving.api_server([RootService, MyService]) api_config_response = api_server.get_api_configs() if api_config_response: api_server.config_manager.process_api_config_response(api_config_response) else: raise Exception('Could not process API config response') configs = [] for config in api_server.config_manager.configs.itervalues(): if config != API_CONFIG: configs.append(config) environ = test_util.create_fake_environ( 'http', 'localhost', path='/_ah/api/discovery/v1/apis') request = api_request.ApiRequest(environ, base_paths=['/_ah/api']) generator = directory_list_generator.DirectoryListGenerator(request) directory = json.loads(generator.pretty_print_config_to_json(configs)) try: pwd = os.path.dirname(os.path.realpath(__file__)) test_file = os.path.join(pwd, 'testdata', 'directory_list', 'localhost.json') with open(test_file) as f: expected_directory = json.loads(f.read()) except IOError as e: print 'Could not find expected output file ' + test_file raise e test_util.AssertDictEqual(expected_directory, directory, self)
def testLocalhost(self): @api_config.api(name='root', hostname='localhost:8080', version='v1') class MyService(remote.Service): """Describes MyService.""" @api_config.method(message_types.VoidMessage, message_types.VoidMessage, path='noop', http_method='GET', name='noop') def noop_get(self, unused_request): return message_types.VoidMessage() api = json.loads(self.generator.pretty_print_swagger_to_json(MyService)) expected_swagger = { 'swagger': '2.0', 'info': { 'title': 'root', 'description': 'Describes MyService.', 'version': 'v1', }, 'host': 'localhost:8080', 'consumes': ['application/json'], 'produces': ['application/json'], 'schemes': ['http'], 'basePath': '/_ah/api', 'paths': { '/noop': { 'get': { 'operationId': 'MyService_noopGet', 'parameters': [], 'responses': { '200': { 'description': '200_response', }, }, }, }, }, } test_util.AssertDictEqual(expected_swagger, api, self)
def testAllFieldTypes(self): class PutRequest(messages.Message): """Message with just a body field.""" body = messages.MessageField(AllFields, 1) # pylint: disable=invalid-name class ItemsPutRequest(messages.Message): """Message with path params and a body field.""" body = messages.MessageField(AllFields, 1) entryId = messages.StringField(2, required=True) class ItemsPutRequestForContainer(messages.Message): """Message with path params and a body field.""" body = messages.MessageField(AllFields, 1) items_put_request_container = resource_container.ResourceContainer( ItemsPutRequestForContainer, entryId=messages.StringField(2, required=True)) # pylint: disable=invalid-name class EntryPublishRequest(messages.Message): """Message with two required params, one in path, one in body.""" title = messages.StringField(1, required=True) entryId = messages.StringField(2, required=True) class EntryPublishRequestForContainer(messages.Message): """Message with two required params, one in path, one in body.""" title = messages.StringField(1, required=True) entry_publish_request_container = resource_container.ResourceContainer( EntryPublishRequestForContainer, entryId=messages.StringField(2, required=True)) class BooleanMessageResponse(messages.Message): result = messages.BooleanField(1, required=True) @api_config.api(name='root', hostname='example.appspot.com', version='v1') class MyService(remote.Service): """Describes MyService.""" @api_config.method(AllFields, message_types.VoidMessage, path='entries', http_method='GET', name='entries.get') def entries_get(self, unused_request): """All field types in the query parameters.""" return message_types.VoidMessage() @api_config.method(ALL_FIELDS_AS_PARAMETERS, message_types.VoidMessage, path='entries/container', http_method='GET', name='entries.getContainer') def entries_get_container(self, unused_request): """All field types in the query parameters.""" return message_types.VoidMessage() @api_config.method(PutRequest, BooleanMessageResponse, path='entries', name='entries.put') def entries_put(self, unused_request): """Request body is in the body field.""" return BooleanMessageResponse(result=True) @api_config.method(AllFields, message_types.VoidMessage, path='process', name='entries.process') def entries_process(self, unused_request): """Message is the request body.""" return message_types.VoidMessage() @api_config.method(message_types.VoidMessage, message_types.VoidMessage, name='entries.nested.collection.action', path='nested') def entries_nested_collection_action(self, unused_request): """A VoidMessage for a request body.""" return message_types.VoidMessage() @api_config.method(AllFields, AllFields, name='entries.roundtrip', path='roundtrip') def entries_roundtrip(self, unused_request): """All field types in the request and response.""" pass # Test a method with a required parameter in the request body. @api_config.method(EntryPublishRequest, message_types.VoidMessage, path='entries/{entryId}/publish', name='entries.publish') def entries_publish(self, unused_request): """Path has a parameter and request body has a required param.""" return message_types.VoidMessage() @api_config.method(entry_publish_request_container, message_types.VoidMessage, path='entries/container/{entryId}/publish', name='entries.publishContainer') def entries_publish_container(self, unused_request): """Path has a parameter and request body has a required param.""" return message_types.VoidMessage() # Test a method with a parameter in the path and a request body. @api_config.method(ItemsPutRequest, message_types.VoidMessage, path='entries/{entryId}/items', name='entries.items.put') def items_put(self, unused_request): """Path has a parameter and request body is in the body field.""" return message_types.VoidMessage() @api_config.method(items_put_request_container, message_types.VoidMessage, path='entries/container/{entryId}/items', name='entries.items.putContainer') def items_put_container(self, unused_request): """Path has a parameter and request body is in the body field.""" return message_types.VoidMessage() api = json.loads(self.generator.pretty_print_config_to_json(MyService)) # Some constants to shorten line length in expected OpenAPI output prefix = 'OpenApiGeneratorTest' boolean_response = prefix + 'BooleanMessageResponse' all_fields = prefix + 'AllFields' nested = prefix + 'Nested' entry_publish_request = prefix + 'EntryPublishRequest' publish_request_for_container = prefix + 'EntryPublishRequestForContainer' items_put_request = prefix + 'ItemsPutRequest' put_request_for_container = prefix + 'ItemsPutRequestForContainer' put_request = prefix + 'PutRequest' expected_openapi = { 'swagger': '2.0', 'info': { 'title': 'root', 'description': 'Describes MyService.', 'version': 'v1', }, 'host': 'example.appspot.com', 'consumes': ['application/json'], 'produces': ['application/json'], 'schemes': ['https'], 'basePath': '/_ah/api', 'paths': { '/root/v1/entries': { 'get': { 'operationId': 'MyService_entriesGet', 'parameters': [{ 'name': 'bool_value', 'in': 'query', 'type': 'boolean', }, { 'name': 'bytes_value', 'in': 'query', 'type': 'string', 'format': 'byte', }, { 'name': 'double_value', 'in': 'query', 'type': 'number', 'format': 'double', }, { 'name': 'enum_value', 'in': 'query', 'type': 'string', 'enum': [ 'VAL1', 'VAL2', ], }, { 'name': 'float_value', 'in': 'query', 'type': 'number', 'format': 'float', }, { 'name': 'int32_value', 'in': 'query', 'type': 'integer', 'format': 'int32', }, { 'name': 'int64_value', 'in': 'query', 'type': 'string', 'format': 'int64', }, { 'name': 'string_value', 'in': 'query', 'type': 'string', }, { 'name': 'uint32_value', 'in': 'query', 'type': 'integer', 'format': 'uint32', }, { 'name': 'uint64_value', 'in': 'query', 'type': 'string', 'format': 'uint64', }, { 'name': 'sint32_value', 'in': 'query', 'type': 'integer', 'format': 'int32', }, { 'name': 'sint64_value', 'in': 'query', 'type': 'string', 'format': 'int64', }], 'responses': { '200': { 'description': 'A successful response', }, }, }, 'post': { 'operationId': 'MyService_entriesPut', 'parameters': [], 'responses': { '200': { 'description': 'A successful response', 'schema': { '$ref': self._def_path(boolean_response), }, }, }, }, }, '/root/v1/entries/container': { 'get': { 'operationId': 'MyService_entriesGetContainer', 'parameters': [ { 'name': 'bool_value', 'in': 'query', 'type': 'boolean', }, { 'name': 'bytes_value', 'in': 'query', 'type': 'string', 'format': 'byte', }, { 'name': 'double_value', 'in': 'query', 'type': 'number', 'format': 'double', }, { 'name': 'enum_value', 'in': 'query', 'type': 'string', 'enum': [ 'VAL1', 'VAL2', ], }, { 'name': 'float_value', 'in': 'query', 'type': 'number', 'format': 'float', }, { 'name': 'int32_value', 'in': 'query', 'type': 'integer', 'format': 'int32', }, { 'name': 'int64_value', 'in': 'query', 'type': 'string', 'format': 'int64', }, { 'name': 'string_value', 'in': 'query', 'type': 'string', }, { 'name': 'uint32_value', 'in': 'query', 'type': 'integer', 'format': 'uint32', }, { 'name': 'uint64_value', 'in': 'query', 'type': 'string', 'format': 'uint64', }, { 'name': 'sint32_value', 'in': 'query', 'type': 'integer', 'format': 'int32', }, { 'name': 'sint64_value', 'in': 'query', 'type': 'string', 'format': 'int64', }, ], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/entries/container/{entryId}/items': { 'post': { 'operationId': 'MyService_itemsPutContainer', 'parameters': [ { 'name': 'entryId', 'in': 'path', 'required': True, 'type': 'string', }, ], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/entries/container/{entryId}/publish': { 'post': { 'operationId': 'MyService_entriesPublishContainer', 'parameters': [ { 'name': 'entryId', 'in': 'path', 'required': True, 'type': 'string', }, ], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/entries/{entryId}/items': { 'post': { 'operationId': 'MyService_itemsPut', 'parameters': [ { 'name': 'entryId', 'in': 'path', 'required': True, 'type': 'string', }, ], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/entries/{entryId}/publish': { 'post': { 'operationId': 'MyService_entriesPublish', 'parameters': [ { 'name': 'entryId', 'in': 'path', 'required': True, 'type': 'string', }, ], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/nested': { 'post': { 'operationId': 'MyService_entriesNestedCollectionAction', 'parameters': [], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/process': { 'post': { 'operationId': 'MyService_entriesProcess', 'parameters': [], 'responses': { '200': { 'description': 'A successful response', }, }, }, }, '/root/v1/roundtrip': { 'post': { 'operationId': 'MyService_entriesRoundtrip', 'parameters': [], 'responses': { '200': { 'description': 'A successful response', 'schema': { '$ref': self._def_path(all_fields) }, }, }, }, }, }, 'definitions': { all_fields: { 'type': 'object', 'properties': { 'bool_value': { 'type': 'boolean', }, 'bytes_value': { 'type': 'string', 'format': 'byte', }, 'datetime_value': { 'type': 'string', 'format': 'date-time', }, 'double_value': { 'type': 'number', 'format': 'double', }, 'enum_value': { 'type': 'string', 'enum': [ 'VAL1', 'VAL2', ], }, 'float_value': { 'type': 'number', 'format': 'float', }, 'int32_value': { 'type': 'integer', 'format': 'int32', }, 'int64_value': { 'type': 'string', 'format': 'int64', }, 'message_field_value': { '$ref': self._def_path(nested), 'description': 'Message class to be used in a message field.', }, 'sint32_value': { 'type': 'integer', 'format': 'int32', }, 'sint64_value': { 'type': 'string', 'format': 'int64', }, 'string_value': { 'type': 'string', }, 'uint32_value': { 'type': 'integer', 'format': 'uint32', }, 'uint64_value': { 'type': 'string', 'format': 'uint64', }, }, }, boolean_response: { 'type': 'object', 'properties': { 'result': { 'type': 'boolean', }, }, 'required': ['result'], }, entry_publish_request: { 'type': 'object', 'properties': { 'entryId': { 'type': 'string', }, 'title': { 'type': 'string', }, }, 'required': [ 'entryId', 'title', ] }, publish_request_for_container: { 'type': 'object', 'properties': { 'title': { 'type': 'string', }, }, 'required': [ 'title', ] }, items_put_request: { 'type': 'object', 'properties': { 'body': { '$ref': self._def_path(all_fields), 'description': 'Contains all field types.' }, 'entryId': { 'type': 'string', }, }, 'required': [ 'entryId', ] }, nested: { 'type': 'object', 'properties': { 'int_value': { 'type': 'string', 'format': 'int64', }, 'string_value': { 'type': 'string', }, }, }, put_request: { 'type': 'object', 'properties': { 'body': { '$ref': self._def_path(all_fields), 'description': 'Contains all field types.', }, }, }, put_request_for_container: { 'type': 'object', 'properties': { 'body': { '$ref': self._def_path(all_fields), 'description': 'Contains all field types.', }, }, }, }, 'securityDefinitions': { 'google_id_token': { 'authorizationUrl': '', 'flow': 'implicit', 'type': 'oauth2', 'x-issuer': 'accounts.google.com', 'x-jwks_uri': 'https://www.googleapis.com/oauth2/v1/certs', }, }, } test_util.AssertDictEqual(expected_openapi, api, self)
def testAllFieldTypes(self): class PutRequest(messages.Message): """Message with just a body field.""" body = messages.MessageField(AllFields, 1) # pylint: disable=invalid-name class ItemsPutRequest(messages.Message): """Message with path params and a body field.""" body = messages.MessageField(AllFields, 1) entryId = messages.StringField(2, required=True) class ItemsPutRequestForContainer(messages.Message): """Message with path params and a body field.""" body = messages.MessageField(AllFields, 1) items_put_request_container = resource_container.ResourceContainer( ItemsPutRequestForContainer, entryId=messages.StringField(2, required=True)) # pylint: disable=invalid-name class EntryPublishRequest(messages.Message): """Message with two required params, one in path, one in body.""" title = messages.StringField(1, required=True) entryId = messages.StringField(2, required=True) class EntryPublishRequestForContainer(messages.Message): """Message with two required params, one in path, one in body.""" title = messages.StringField(1, required=True) entry_publish_request_container = resource_container.ResourceContainer( EntryPublishRequestForContainer, entryId=messages.StringField(2, required=True)) class BooleanMessageResponse(messages.Message): result = messages.BooleanField(1, required=True) @api_config.api(name='root', hostname='example.appspot.com', version='v1', description='This is an API') class MyService(remote.Service): """Describes MyService.""" @api_config.method(message_types.VoidMessage, BooleanMessageResponse, path='toplevel:withcolon', http_method='GET', name='toplevelwithcolon') def toplevel(self, unused_request): return BooleanMessageResponse(result=True) @api_config.method(AllFields, message_types.VoidMessage, path='entries', http_method='GET', name='entries.get') def entries_get(self, unused_request): """All field types in the query parameters.""" return message_types.VoidMessage() @api_config.method(ALL_FIELDS_AS_PARAMETERS, message_types.VoidMessage, path='entries/container', http_method='GET', name='entries.getContainer') def entries_get_container(self, unused_request): """All field types in the query parameters.""" return message_types.VoidMessage() @api_config.method(PutRequest, BooleanMessageResponse, path='entries', name='entries.put') def entries_put(self, unused_request): """Request body is in the body field.""" return BooleanMessageResponse(result=True) @api_config.method(AllFields, message_types.VoidMessage, path='process', name='entries.process') def entries_process(self, unused_request): """Message is the request body.""" return message_types.VoidMessage() @api_config.method(message_types.VoidMessage, message_types.VoidMessage, name='entries.nested.collection.action', path='nested') def entries_nested_collection_action(self, unused_request): """A VoidMessage for a request body.""" return message_types.VoidMessage() @api_config.method(AllFields, AllFields, name='entries.roundtrip', path='roundtrip') def entries_roundtrip(self, unused_request): """All field types in the request and response.""" pass # Test a method with a required parameter in the request body. @api_config.method(EntryPublishRequest, message_types.VoidMessage, path='entries/{entryId}/publish', name='entries.publish') def entries_publish(self, unused_request): """Path has a parameter and request body has a required param.""" return message_types.VoidMessage() @api_config.method(entry_publish_request_container, message_types.VoidMessage, path='entries/container/{entryId}/publish', name='entries.publishContainer') def entries_publish_container(self, unused_request): """Path has a parameter and request body has a required param.""" return message_types.VoidMessage() # Test a method with a parameter in the path and a request body. @api_config.method(ItemsPutRequest, message_types.VoidMessage, path='entries/{entryId}/items', name='entries.items.put') def items_put(self, unused_request): """Path has a parameter and request body is in the body field.""" return message_types.VoidMessage() @api_config.method(items_put_request_container, message_types.VoidMessage, path='entries/container/{entryId}/items', name='entries.items.putContainer') def items_put_container(self, unused_request): """Path has a parameter and request body is in the body field.""" return message_types.VoidMessage() api = json.loads(self.generator.pretty_print_config_to_json(MyService)) try: pwd = os.path.dirname(os.path.realpath(__file__)) test_file = os.path.join(pwd, 'testdata', 'discovery', 'allfields.json') with open(test_file) as f: expected_discovery = json.loads(f.read()) except IOError as e: print 'Could not find expected output file ' + test_file raise e test_util.AssertDictEqual(expected_discovery, api, self)