diff --git a/endpoints/api_config.py b/endpoints/api_config.py index 59256a0..c2a60e6 100644 --- a/endpoints/api_config.py +++ b/endpoints/api_config.py @@ -1927,10 +1927,9 @@ def get_descriptor_defaults(self, api_info, hostname=None): """ hostname = (hostname or endpoints_util.get_app_hostname() or api_info.hostname) - protocol = ('http' if hostname and hostname.startswith('localhost') else - 'https') - protocol = ('http' if hostname and hostname.startswith('localhost') else - 'https') + protocol = 'http' if ((hostname and hostname.startswith('localhost')) or + endpoints_util.is_running_on_devserver()) else 'https' + defaults = { 'extends': 'thirdParty.api', 'root': '{0}://{1}/_ah/api'.format(protocol, hostname), diff --git a/endpoints/swagger_generator.py b/endpoints/swagger_generator.py index 576585f..7de9427 100644 --- a/endpoints/swagger_generator.py +++ b/endpoints/swagger_generator.py @@ -835,10 +835,8 @@ def get_descriptor_defaults(self, api_info, hostname=None): """ hostname = (hostname or util.get_app_hostname() or api_info.hostname) - protocol = ('http' if hostname and hostname.startswith('localhost') else - 'https') - protocol = ('http' if hostname and hostname.startswith('localhost') else - 'https') + protocol = 'http' if ((hostname and hostname.startswith('localhost')) or + util.is_running_on_devserver()) else 'https' defaults = { 'swagger': '2.0', 'info': { diff --git a/endpoints/test/discovery_service_test.py b/endpoints/test/discovery_service_test.py index 1c1f05d..838e89a 100644 --- a/endpoints/test/discovery_service_test.py +++ b/endpoints/test/discovery_service_test.py @@ -14,12 +14,14 @@ """Tests for discovery_service.""" +import os import unittest import endpoints.api_config as api_config import endpoints.api_config_manager as api_config_manager import endpoints.apiserving as apiserving import endpoints.discovery_service as discovery_service +import test_util from protorpc import message_types from protorpc import remote @@ -70,6 +72,9 @@ def _check_api_config(self, expected_base_url, server, port, url_scheme, api, # Check root self.assertEqual(expected_base_url, config_dict.get('root')) + +class ProdDiscoveryServiceTest(DiscoveryServiceTest): + def testGenerateApiConfigWithRoot(self): server = 'test.appspot.com' port = '12345' @@ -92,7 +97,7 @@ def testGenerateApiConfigWithRootLocalhost(self): self._check_api_config(expected_base_url, server, port, url_scheme, api, version) - def testGenerateApiConfigWithRootDefaultHttpPort(self): + def testGenerateApiConfigLocalhostDefaultHttpPort(self): server = 'localhost' port = '80' url_scheme = 'http' @@ -114,5 +119,49 @@ def testGenerateApiConfigWithRootDefaultHttpsPort(self): self._check_api_config(expected_base_url, server, port, url_scheme, api, version) + +class DevServerDiscoveryServiceTest(DiscoveryServiceTest, + test_util.DevServerTest): + + def setUp(self): + super(DevServerDiscoveryServiceTest, self).setUp() + self.env_key, self.orig_env_value = (test_util.DevServerTest. + setUpDevServerEnv()) + self.addCleanup(test_util.DevServerTest.restoreEnv, + self.env_key, self.orig_env_value) + + def testGenerateApiConfigWithRootDefaultHttpPort(self): + server = 'test.appspot.com' + port = '80' + url_scheme = 'http' + api = 'aservice' + version = 'v3' + expected_base_url = '{0}://{1}/_ah/api'.format(url_scheme, server) + + self._check_api_config(expected_base_url, server, port, url_scheme, api, + version) + + def testGenerateApiConfigLocalhostDefaultHttpPort(self): + server = 'localhost' + port = '80' + url_scheme = 'http' + api = 'aservice' + version = 'v3' + expected_base_url = '{0}://{1}/_ah/api'.format(url_scheme, server) + + self._check_api_config(expected_base_url, server, port, url_scheme, api, + version) + + def testGenerateApiConfigHTTPS(self): + server = 'test.appspot.com' + port = '443' + url_scheme = 'http' # Should still be 'http' because we're using devserver + api = 'aservice' + version = 'v3' + expected_base_url = '{0}://{1}:{2}/_ah/api'.format(url_scheme, server, port) + + self._check_api_config(expected_base_url, server, port, url_scheme, api, + version) + if __name__ == '__main__': unittest.main() diff --git a/endpoints/test/swagger_generator_test.py b/endpoints/test/swagger_generator_test.py index 63e53d9..b3a2e6a 100644 --- a/endpoints/test/swagger_generator_test.py +++ b/endpoints/test/swagger_generator_test.py @@ -68,7 +68,7 @@ class AllFields(messages.Message): **{field.name: field for field in AllFields.all_fields()}) -class SwaggerGeneratorTest(unittest.TestCase): +class BaseSwaggerGeneratorTest(unittest.TestCase): @classmethod def setUpClass(cls): @@ -80,6 +80,9 @@ def setUp(self): def _def_path(self, path): return '#/definitions/' + path + +class SwaggerGeneratorTest(BaseSwaggerGeneratorTest): + def testAllFieldTypes(self): class PutRequest(messages.Message): @@ -751,5 +754,71 @@ def noop_get(self, unused_request): test_util.AssertDictEqual(expected_swagger, api, self) + +class DevServerSwaggerGeneratorTest(BaseSwaggerGeneratorTest, + test_util.DevServerTest): + + def setUp(self): + super(DevServerSwaggerGeneratorTest, self).setUp() + self.env_key, self.orig_env_value = (test_util.DevServerTest. + setUpDevServerEnv()) + self.addCleanup(test_util.DevServerTest.restoreEnv, + self.env_key, self.orig_env_value) + + def testDevServerSwagger(self): + @api_config.api(name='root', hostname='example.appspot.com', 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_config_to_json(MyService)) + + expected_swagger = { + 'swagger': '2.0', + 'info': { + 'title': 'root', + 'description': 'Describes MyService.', + 'version': 'v1', + }, + 'host': 'example.appspot.com', + 'consumes': ['application/json'], + 'produces': ['application/json'], + 'schemes': ['http'], + 'basePath': '/_ah/api', + 'paths': { + '/root/v1/noop': { + 'get': { + 'operationId': 'MyService_noopGet', + 'parameters': [], + 'responses': { + '200': { + 'description': 'A successful response', + }, + }, + 'security': [], + 'x-security': [ + {'google_id_token': {'audiences': []}}, + ], + }, + }, + }, + '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_swagger, api, self) + + if __name__ == '__main__': unittest.main() diff --git a/endpoints/test/test_util.py b/endpoints/test/test_util.py index a8d4d16..131b224 100644 --- a/endpoints/test/test_util.py +++ b/endpoints/test/test_util.py @@ -22,6 +22,7 @@ import __future__ import json +import os import types @@ -174,3 +175,21 @@ def testNoExportedModules(self): exported_modules.append(attribute) if exported_modules: self.fail('%s are modules and may not be exported.' % exported_modules) + + +class DevServerTest(object): + + @staticmethod + def setUpDevServerEnv(server_software_key='SERVER_SOFTWARE', + server_software_value='Development/2.0.0'): + original_env_value = os.environ.get(server_software_key) + os.environ[server_software_key] = server_software_value + return server_software_key, original_env_value + + @staticmethod + def restoreEnv(server_software_key, server_software_value): + if server_software_value is None: + os.environ.pop(server_software_key, None) + else: + os.environ[server_software_key] = server_software_value + diff --git a/endpoints/util.py b/endpoints/util.py index 9ca0026..bd1e0ba 100644 --- a/endpoints/util.py +++ b/endpoints/util.py @@ -184,7 +184,11 @@ def put_headers_in_environ(headers, environ): def is_running_on_app_engine(): - return os.environ.get('SERVER_SOFTWARE', '').startswith('Google App Engine/') + return os.environ.get('GAE_MODULE_NAME') is not None + + +def is_running_on_devserver(): + return os.environ.get('SERVER_SOFTWARE', '').startswith('Development/') def is_running_on_localhost():