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)
Beispiel #2
0
    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)
Beispiel #4
0
  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)
Beispiel #5
0
    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)