def service_mappings(services, registry_path='/_rpc/meta', protocols=None): ''' ''' if not protocols: from canteen.base import protocol protocols = protocol.Protocol.mapping if isinstance(services, dict): services = services.iteritems() final_mapping, paths, registry_map = ( [], set(), {} if registry_path else None ) for service_path, service_factory in services: service_class = service_factory.service_class if hasattr(service_factory, 'service_class') else service_factory if service_path not in paths: paths.add(service_path) else: raise premote.ServiceConfigurationError( 'Path %r is already defined in service mapping' % service_path.encode('utf-8')) if registry_map is not None: registry_map[service_path] = service_class final_mapping.append(pservice.service_mapping(service_factory, service_path, protocols=protocols)) if registry_map is not None: final_mapping.append(pservice.service_mapping( pregistry.RegistryService.new_factory(registry_map), registry_path, protocols=protocols)) return pwsgi_util.first_found(final_mapping)
def testIterator(self): self.ResetServer(wsgi_util.first_found(iter([APP1]))) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEqual(six.moves.http_client.OK, status) self.assertEqual( six.moves.http_client.responses[six.moves.http_client.OK], status_text) self.assertEqual('App1', content) self.assertEqual( { 'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers) # Do request again to make sure iterator was properly copied. status, status_text, content, headers = self.DoHttpRequest('/') self.assertEqual(six.moves.http_client.OK, status) self.assertEqual( six.moves.http_client.responses[six.moves.http_client.OK], status_text) self.assertEqual('App1', content) self.assertEqual( { 'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers)
def CreateWsgiApplication(self): """Create WSGI application used on the server side for testing.""" my_service = service.service_mapping(webapp_test_util.TestService, '/my/service') my_other_service = service.service_mapping( webapp_test_util.TestService.new_factory('initialized'), '/my/other_service', protocols=self.protocols) return util.first_found([my_service, my_other_service])
def testFirstNotFound(self): self.ResetServer(wsgi_util.first_found([NOT_FOUND, APP2])) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEquals(six.moves.http_client.OK, status) self.assertEquals(six.moves.http_client.responses[six.moves.http_client.OK], status_text) self.assertEquals('App2', content) self.assertEquals({'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers)
def testEmptyConfiguration(self): self.ResetServer(wsgi_util.first_found([])) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEquals(six.moves.http_client.NOT_FOUND, status) self.assertEquals(six.moves.http_client.responses[six.moves.http_client.NOT_FOUND], status_text) self.assertEquals(util.pad_string(six.moves.http_client.responses[six.moves.http_client.NOT_FOUND]), content) self.assertEquals({'content-length': '512', 'content-type': 'text/plain; charset=utf-8', }, headers)
def testTwoApps(self): self.ResetServer(wsgi_util.first_found([APP1, APP2])) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEquals(httplib.OK, status) self.assertEquals(httplib.responses[httplib.OK], status_text) self.assertEquals('App1', content) self.assertEquals({'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers)
def testFirstNotFound(self): self.ResetServer(wsgi_util.first_found([NOT_FOUND, APP2])) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEqual(six.moves.http_client.OK, status) self.assertEqual( six.moves.http_client.responses[six.moves.http_client.OK], status_text) self.assertEqual('App2', content) self.assertEqual( { 'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers)
def testEmptyConfiguration(self): self.ResetServer(wsgi_util.first_found([])) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEqual(six.moves.http_client.NOT_FOUND, status) self.assertEqual( six.moves.http_client.responses[six.moves.http_client.NOT_FOUND], status_text) self.assertEqual( util.pad_string(six.moves.http_client.responses[ six.moves.http_client.NOT_FOUND]), content) self.assertEqual( { 'content-length': '512', 'content-type': 'text/plain; charset=utf-8', }, headers)
def testOnlyNotFound(self): def current_error(environ, start_response): """The variable current_status is defined in loop after ResetServer.""" headers = [('content-type', 'text/plain')] status_line = '%03d Whatever' % current_status start_response(status_line, headers) return [] self.ResetServer(wsgi_util.first_found([current_error, APP2])) statuses_to_check = sorted(httplib.responses.keys()) # 100, 204 and 304 have slightly different expectations, so they are left # out of this test in order to keep the code simple. for dont_check in (100, 200, 204, 304, 404): statuses_to_check.remove(dont_check) for current_status in statuses_to_check: status, status_text, content, headers = self.DoHttpRequest('/') self.assertEqual(current_status, status) self.assertEqual('Whatever', status_text)
def testOnlyNotFound(self): def current_error(environ, start_response): """The variable current_status is defined in loop after ResetServer.""" headers = [('content-type', 'text/plain')] status_line = '%03d Whatever' % current_status start_response(status_line, headers) return [] self.ResetServer(wsgi_util.first_found([current_error, APP2])) statuses_to_check = sorted(httplib.responses.keys()) # 100, 204 and 304 have slightly different expectations, so they are left # out of this test in order to keep the code simple. for dont_check in (100, 200, 204, 304, 404): statuses_to_check.remove(dont_check) for current_status in statuses_to_check: status, status_text, content, headers = self.DoHttpRequest('/') self.assertEquals(current_status, status) self.assertEquals('Whatever', status_text)
def testIterator(self): self.ResetServer(wsgi_util.first_found(iter([APP1]))) status, status_text, content, headers = self.DoHttpRequest('/') self.assertEquals(six.moves.http_client.OK, status) self.assertEquals(six.moves.http_client.responses[six.moves.http_client.OK], status_text) self.assertEquals('App1', content) self.assertEquals({'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers) # Do request again to make sure iterator was properly copied. status, status_text, content, headers = self.DoHttpRequest('/') self.assertEquals(six.moves.http_client.OK, status) self.assertEquals(six.moves.http_client.responses[six.moves.http_client.OK], status_text) self.assertEquals('App1', content) self.assertEquals({'content-length': '4', 'content-type': 'text/html; charset=utf-8', }, headers)
def service_mappings(services, registry_path='/_rpc/meta', protocols=None): ''' ''' if not protocols: from canteen.base import protocol protocols = protocol.Protocol.mapping if isinstance(services, dict): services = services.iteritems() final_mapping, paths, registry_map = ([], set(), {} if registry_path else None) for service_path, service_factory in services: service_class = service_factory.service_class if hasattr( service_factory, 'service_class') else service_factory if service_path not in paths: paths.add(service_path) else: raise premote.ServiceConfigurationError( 'Path %r is already defined in service mapping' % service_path.encode('utf-8')) if registry_map is not None: registry_map[service_path] = service_class final_mapping.append( pservice.service_mapping(service_factory, service_path, protocols=protocols)) if registry_map is not None: final_mapping.append( pservice.service_mapping( pregistry.RegistryService.new_factory(registry_map), registry_path, protocols=protocols)) return pwsgi_util.first_found(final_mapping)
def service_mappings(services, registry_path='/_rpc/meta', protocols=None): """ Generates mappings from `url -> service` for registered Canteen RPC services. Takes an iterable of URL and service mappings, wraps with appropriate WSGI utilities, and registers with registry service for Endpoints/meta integration. :param services: Iterable of services, preferably a ``list`` of ``tuples``, where each is in the format ``(url, service)``. ``url`` should be a relative prefix for matching requests, like ``/_rpc/hello`` for something called ``HelloService``. :param registry_path: Path prefix for ``RegistryService``, which returns metadata about registered RPC services. Required for integration with Google Cloud Endpoints or the various ProtoRPC client-side library generation options out there. :param protocols: Protocols to use for dispatching services. Custom protocol implementations are supported and two are shipped with canteen - ``JSON`` and ``msgpack`` RPC formats (note: not necessarily affiliated with any standards that are actually called "msgpack-rpc" or "jsonrpc"). :returns: WSGI application prepared by :py:mod:`protorpc`, which, upon dispatch, will attempt to delegate response to the first matching ``Service`` implementation, as governed by the mappings generated in this function from ``services``. """ if not protocols: # load canteen builtin protocols from canteen.base import protocol protocols = protocol.Protocol.mapping if isinstance(services, dict): services = services.iteritems() final_mapping, paths, registry_map = ( [], set(), {} if registry_path else None ) for service_path, service_factory in services: service_class = service_factory.service_class if ( hasattr(service_factory, 'service_class')) else service_factory if service_path not in paths: paths.add(service_path) else: raise premote.ServiceConfigurationError( 'Path %r is already defined in service mapping' % service_path.encode('utf-8')) if registry_map is not None: registry_map[service_path] = service_class final_mapping.append(( pservice.service_mapping(*( service_factory, service_path), protocols=protocols))) if registry_map is not None: final_mapping.append(pservice.service_mapping(*( pregistry.RegistryService.new_factory(registry_map), registry_path), protocols=protocols)) return pwsgi_util.first_found(final_mapping)