class RouteProvider(): def __init__(self, application): self._dispatcher = UrlDispatcher() self._application = application def add_url_rule(self, method, path, handler, *, name=None): name = name or pythonify_name(handler.__name__) self._dispatcher.add_route(method, path, handler, name=name) def add_with_decorator(self, path, *, method="GET", name=None): def _wrapper(fn): self.add_url_rule(method, path, fn, name=name) return fn return _wrapper @asyncio.coroutine def resolve(self, request): """ 根据请求里面的 method 和 path 找到对应的 match dict """ return (yield from self._dispatcher.resolve(request)) def url(self, name, **kwargs): assert name in self._dispatcher return self._dispatcher[name].url(**kwargs)
def register(self, router: UrlDispatcher): router.add_route( '*', f'/{self.resource_name}/{{instance_id}}', self.instance_endpoint.dispatch ) router.add_route( '*', f"/{self.resource_name}", self.list_endpoint.dispatch )
def add_routes(base_path: str, router: web.UrlDispatcher): router.add_static(base_path + '/swagger-ui', 'swagger-ui-dist', follow_symlinks=True) #router.add_route('GET', base_path + '/authorization', handlers.authorization, name='authorization') handlers.Root.add_to_router(router, base_path + '/') handlers.Accounts.add_to_router(router, base_path + '/accounts') handlers.Account.add_to_router(router, base_path + '/accounts/{account}') handlers.Datasets.add_to_router(router, base_path + '/datasets') handlers.Dataset.add_to_router(router, base_path + '/datasets/{dataset}') handlers.Scope.add_to_router(router, base_path + '/datasets/{dataset}/{scope}') handlers.Profiles.add_to_router(router, base_path + '/profiles') handlers.Profile.add_to_router(router, base_path + '/profiles/{profile}') handlers.Roles.add_to_router(router, base_path + '/roles') handlers.Role.add_to_router(router, base_path + '/roles/{role}')
class ParentResource(Resource): def __init__(self, path, *, name=None): super(ParentResource, self).__init__(name=name) self._path = path.rstrip('/') self.router = UrlDispatcher() @asyncio.coroutine def resolve(self, method, path): allowed_methods = set() if not path.startswith(self._path + '/'): return None, allowed_methods path = path[len(self._path):] for resource in self.router._resources: match_dict, allowed = yield from resource.resolve(method, path) if match_dict is not None: return match_dict, allowed_methods else: allowed_methods |= allowed return None, allowed_methods def add_resource(self, path, *, name=None): """Add resource.""" return self.router.add_resource(path, name=name) def get_info(self): return {'path': self._path} def url(self, name=None, **kwargs): if name: return self._path + self.router[name].url(**kwargs) return self._path + '/'
def __init__(self, router: web.UrlDispatcher) -> None: self.index = router.add_resource(name="index", path="/") self.market = router.add_resource(name="market", path="/market/{id}") self.create_market = router.add_resource(name="create_market", path="/create-market") self.user_login = router.add_resource(name="user_login", path="/user_login") self.logout = router.add_resource(name="logout", path="/logout") self.petname = router.add_resource(name="petname", path="/petname") self.entity = router.add_resource(name="entity", path="/entity/{id}")
def register(self, app: web.Application, router: web.UrlDispatcher) -> None: """Register the view with a router.""" assert self.url is not None, "No url set for view" urls = [self.url] + self.extra_urls routes: list[AbstractRoute] = [] for method in ("get", "post", "delete", "put", "patch", "head", "options"): if not (handler := getattr(self, method, None)): continue handler = request_handler_factory(self, handler) for url in urls: routes.append(router.add_route(method, url, handler))
def add_to_router(cls, router: web.UrlDispatcher, path: str, expect_handler: T.Callable = None): # language=rst """Adds this View class to the aiohttp router.""" cls._aiohttp_resource = router.add_resource(path) # Register the current class in the appropriate registry: if isinstance(cls._aiohttp_resource, web.DynamicResource): View.PATTERNS[cls._aiohttp_resource.get_info()['pattern']] = cls elif isinstance(cls._aiohttp_resource, web.PlainResource): View.PATHS[cls._aiohttp_resource.get_info()['path']] = cls else: _logger.critical( "aiohttp router method 'add_resource()' returned resource object of unexpected type %s", cls._aiohttp_resource.__class__) cls._aiohttp_resource.rest_utils_class = cls cls._aiohttp_resource.add_route('*', cls, expect_handler=expect_handler) return cls._aiohttp_resource
def register(self, app: web.Application, router: web.UrlDispatcher) -> None: """Register the view with a router.""" assert self.url is not None, "No url set for view" urls = [self.url] + self.extra_urls routes = [] for method in ("get", "post", "delete", "put", "patch", "head", "options"): handler = getattr(self, method, None) if not handler: continue handler = request_handler_factory(self, handler) for url in urls: routes.append(router.add_route(method, url, handler)) if not self.cors_allowed: return for route in routes: app["allow_cors"](route)
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), MultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.writer, 15) return req def test_add_route_root(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/to/path', handler, name='name') req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual('name', info.route.name) def test_add_with_tailing_slash(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', lambda req: None) def test_add_url_invalid1(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', lambda: None) def test_add_url_invalid2(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', lambda: None) def test_add_url_invalid3(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', lambda: None) def test_add_url_invalid4(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', lambda: None) def test_add_url_invalid5(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post"{id}', lambda: None) def test_add_url_escaping(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_match_second_result_in_table(self): handler1 = asyncio.coroutine(lambda req: Response(req)) handler2 = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = lambda req: Response(req) handler2 = lambda req: Response(req) self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = lambda req: Response(req) self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): self.router.add_route('GET', '/get', lambda r: None, name='name') regexp = ("Duplicate 'name', already handled by") with self.assertRaisesRegex(ValueError, regexp): self.router.add_route('GET', '/get_other', lambda r: None, name='name') def test_route_plain(self): route = self.router.add_route('GET', '/get', lambda r: None, name='name') route2 = self.router['name'] url = route2.url() self.assertEqual('/get', url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router['unknown'] def test_route_dynamic(self): route = self.router.add_route('GET', '/get/{name}', lambda r: None, name='name') route2 = self.router['name'] url = route2.url(parts={'name': 'John'}) self.assertEqual('/get/John', url) self.assertIs(route, route2) def test_route_with_qs(self): self.router.add_route('GET', '/get', lambda r: None, name='name') url = self.router['name'].url(query=[('a', 'b'), ('c', 1)]) self.assertEqual('/get?a=b&c=1', url) def test_add_static(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__), name='static') route2 = self.router['static'] url = route2.url(filename='/dir/a.txt') self.assertEqual('/st/dir/a.txt', url) self.assertIs(route, route2) def test_plain_not_match(self): self.router.add_route('GET', '/get/path', lambda r: None, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_not_match(self): self.router.add_route('GET', '/get/{name}', lambda r: None, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_static_not_match(self): self.router.add_static('/pre', os.path.dirname(aiohttp.__file__), name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_with_trailing_slash(self): self.router.add_route('GET', '/get/{name}/', lambda r: None, name='name') route = self.router['name'] self.assertEqual({'name': 'John'}, route.match('/get/John/')) def test_len(self): self.router.add_route('GET', '/get1', lambda r: None, name='name1') self.router.add_route('GET', '/get2', lambda r: None, name='name2') self.assertEqual(2, len(self.router)) def test_iter(self): self.router.add_route('GET', '/get1', lambda r: None, name='name1') self.router.add_route('GET', '/get2', lambda r: None, name='name2') self.assertEqual({'name1', 'name2'}, set(iter(self.router))) def test_contains(self): self.router.add_route('GET', '/get1', lambda r: None, name='name1') self.router.add_route('GET', '/get2', lambda r: None, name='name2') self.assertIn('name1', self.router) self.assertNotIn('name3', self.router) def test_plain_repr(self): self.router.add_route('GET', '/get/path', lambda r: None, name='name') self.assertRegex(repr(self.router['name']), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): self.router.add_route('GET', '/get/{path}', lambda r: None, name='name') self.assertRegex(repr(self.router['name']), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static('/get', os.path.dirname(aiohttp.__file__), name='name') self.assertRegex(repr(self.router['name']), r"<StaticRoute 'name' \[GET\] /get/") def test_static_adds_slash(self): route = self.router.add_static('/prefix', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_static_dont_add__double_slash(self): route = self.router.add_static('/prefix/', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix)
def __init__(self, application): self._dispatcher = UrlDispatcher() self._application = application
def register(self, router: web.UrlDispatcher): router.add_route('*', '/{address}/'.format(address=self.address), self.collection_endpoint.dispatch) router.add_route( '*', '/{address}/{{instance_id}}'.format(address=self.address), self.instance_endpoint.dispatch)
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), CIMultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.reader = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.reader, self.writer) return req def make_handler(self): @asyncio.coroutine def handler(request): return Response(request) # pragma: no cover return handler def test_system_route(self): route = SystemRoute(201, 'test') self.assertIsNone(route.match('any')) with self.assertRaises(RuntimeError): route.url() self.assertEqual("<SystemRoute 201: test>", repr(route)) self.assertEqual(201, route.status) self.assertEqual('test', route.reason) def test_register_route(self): handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(route, info.route) self.assertIs(handler, info.handler) self.assertEqual(info.route.name, 'test') def test_register_route_checks(self): self.assertRaises( AssertionError, self.router.register_route, object()) handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) self.assertRaises(ValueError, self.router.register_route, route) def test_add_route_root(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = self.make_handler() self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler, name='name') req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual('name', info.route.name) def test_add_with_tailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', handler) def test_add_url_invalid1(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', handler) def test_add_url_invalid2(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', handler) def test_add_url_invalid3(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', handler) def test_add_url_invalid4(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', handler) def test_add_url_escaping(self): handler = self.make_handler() self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_any_method(self): handler = self.make_handler() route = self.router.add_route(hdrs.METH_ANY, '/', handler) req = self.make_request('GET', '/') info1 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info1) self.assertIs(route, info1.route) req = self.make_request('POST', '/') info2 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info2) self.assertIs(info1.route, info2.route) def test_match_second_result_in_table(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = self.make_handler() self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/get', handler1, name='name') regexp = ("Duplicate 'name', already handled by") with self.assertRaisesRegex(ValueError, regexp): self.router.add_route('GET', '/get_other', handler2, name='name') def test_route_plain(self): handler = self.make_handler() route = self.router.add_route('GET', '/get', handler, name='name') route2 = self.router['name'] url = route2.url() self.assertEqual('/get', url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router['unknown'] def test_route_dynamic(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{name}', handler, name='name') route2 = self.router['name'] url = route2.url(parts={'name': 'John'}) self.assertEqual('/get/John', url) self.assertIs(route, route2) def test_route_with_qs(self): handler = self.make_handler() self.router.add_route('GET', '/get', handler, name='name') url = self.router['name'].url(query=[('a', 'b'), ('c', 1)]) self.assertEqual('/get?a=b&c=1', url) def test_add_static(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__), name='static') route2 = self.router['static'] url = route2.url(filename='/dir/a.txt') self.assertEqual('/st/dir/a.txt', url) self.assertIs(route, route2) def test_plain_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_static_not_match(self): self.router.add_static('/pre', os.path.dirname(aiohttp.__file__), name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_with_trailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}/', handler, name='name') route = self.router['name'] self.assertEqual({'name': 'John'}, route.match('/get/John/')) def test_len(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual(2, len(self.router)) def test_iter(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual({'name1', 'name2'}, set(iter(self.router))) def test_contains(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertIn('name1', self.router) self.assertNotIn('name3', self.router) def test_plain_repr(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') self.assertRegex(repr(self.router['name']), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): handler = self.make_handler() self.router.add_route('GET', '/get/{path}', handler, name='name') self.assertRegex(repr(self.router['name']), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static('/get', os.path.dirname(aiohttp.__file__), name='name') self.assertRegex(repr(self.router['name']), r"<StaticRoute 'name' \[GET\] /get/") def test_static_adds_slash(self): route = self.router.add_static('/prefix', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_static_dont_add_trailing_slash(self): route = self.router.add_static('/prefix/', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_add_route_with_re(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/1234') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234'}, info) self.router.add_route('GET', r'/handler/{name}.html', handler) req = self.make_request('GET', '/handler/test.html') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual({'name': 'test'}, info) def test_add_route_with_re_and_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler) req = self.make_request('GET', '/handler/1234/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/'}, info) self.router.add_route('GET', r'/handler/{to:.+}', handler) req = self.make_request('GET', '/handler/1234/5/6/7') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/5/6/7'}, info) def test_add_route_with_re_not_match(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/tail') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound): self.loop.run_until_complete(match_info.handler(req)) def test_add_route_with_re_including_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:.+}/tail', handler) req = self.make_request('GET', '/handler/re/with/slashes/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 're/with/slashes'}, info) def test_add_route_with_invalid_re(self): handler = self.make_handler() with self.assertRaises(ValueError) as ctx: self.router.add_route('GET', r'/handler/{to:+++}', handler) s = str(ctx.exception) self.assertTrue(s.startswith( "Bad pattern '\/handler\/(?P<to>+++)': nothing to repeat"), s) self.assertIsNone(ctx.exception.__cause__) def test_route_dynamic_with_regex_spec(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123', url) def test_route_dynamic_with_regex_spec_and_trailing_slash(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}/', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123/', url) def test_route_dynamic_with_regex(self): handler = self.make_handler() route = self.router.add_route('GET', r'/{one}/{two:.+}', handler) url = route.url(parts={'one': 1, 'two': 2}) self.assertEqual('/1/2', url) def test_regular_match_info(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler) req = self.make_request('GET', '/get/john') match_info = yield from self.router.resolve(req) self.maxDiff = None self.assertRegex(repr(match_info), "<MatchInfo {'name': 'john'}: <DynamicRoute.+>>") self.loop.run_until_complete(go()) def test_not_found_repr(self): @asyncio.coroutine def go(): req = self.make_request('POST', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfo: not found>", repr(match_info)) self.loop.run_until_complete(go()) def test_not_allowed_repr(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/path/to', handler) handler2 = self.make_handler() self.router.add_route('POST', '/path/to', handler2) req = self.make_request('PUT', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfo: method PUT is not allowed " "(allowed methods: GET, POST>", repr(match_info)) self.loop.run_until_complete(go()) def test_default_expect_handler(self): route = self.router.add_route('GET', '/', self.make_handler()) self.assertIs(route._expect_handler, _defaultExpectHandler) def test_custom_expect_handler_plain(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route( 'GET', '/', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, PlainRoute) def test_custom_expect_handler_dynamic(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route( 'GET', '/get/{name}', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, DynamicRoute) def test_expect_handler_non_coroutine(self): def handler(request): pass self.assertRaises( AssertionError, self.router.add_route, 'GET', '/', self.make_handler(), expect_handler=handler) def test_dynamic_match_non_ascii(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{var}', handler) req = self.make_request( 'GET', '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82') match_info = yield from self.router.resolve(req) self.assertEqual({'var': 'рус текст'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_with_static_part(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.html', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_two_part2(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.{ext}', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file', 'ext': 'html'}, match_info) self.loop.run_until_complete(go())
def register(self, router: web.UrlDispatcher) -> web.AbstractRoute: return router.add_route(self.method, self.path, self.handler, name=self.name)
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), MultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.writer, 15) return req def test_add_route_root(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/to/path', handler, name='name') req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual('name', info.route.name) def test_add_with_tailing_slash(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', lambda req: None) def test_add_url_invalid1(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', lambda: None) def test_add_url_invalid2(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', lambda: None) def test_add_url_invalid3(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', lambda: None) def test_add_url_invalid4(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', lambda: None) def test_add_url_invalid5(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post"{id}', lambda: None) def test_add_url_escaping(self): handler = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_match_second_result_in_table(self): handler1 = asyncio.coroutine(lambda req: Response(req)) handler2 = asyncio.coroutine(lambda req: Response(req)) self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = lambda req: Response(req) handler2 = lambda req: Response(req) self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = lambda req: Response(req) self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): self.router.add_route('GET', '/get', lambda r: None, name='name') regexp = ("Duplicate 'name', already handled by") with self.assertRaisesRegex(ValueError, regexp): self.router.add_route('GET', '/get_other', lambda r: None, name='name') def test_route_plain(self): route = self.router.add_route('GET', '/get', lambda r: None, name='name') route2 = self.router['name'] url = route2.url() self.assertEqual('/get', url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router['unknown'] def test_route_dynamic(self): route = self.router.add_route('GET', '/get/{name}', lambda r: None, name='name') route2 = self.router['name'] url = route2.url(parts={'name': 'John'}) self.assertEqual('/get/John', url) self.assertIs(route, route2) def test_route_with_qs(self): self.router.add_route('GET', '/get', lambda r: None, name='name') url = self.router['name'].url(query=[('a', 'b'), ('c', 1)]) self.assertEqual('/get?a=b&c=1', url) def test_add_static(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__), name='static') route2 = self.router['static'] url = route2.url(filename='/dir/a.txt') self.assertEqual('/st/dir/a.txt', url) self.assertIs(route, route2) def test_plain_not_match(self): self.router.add_route('GET', '/get/path', lambda r: None, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_not_match(self): self.router.add_route('GET', '/get/{name}', lambda r: None, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_static_not_match(self): self.router.add_static('/pre', os.path.dirname(aiohttp.__file__), name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_with_trailing_slash(self): self.router.add_route('GET', '/get/{name}/', lambda r: None, name='name') route = self.router['name'] self.assertEqual({'name': 'John'}, route.match('/get/John/')) def test_len(self): self.router.add_route('GET', '/get1', lambda r: None, name='name1') self.router.add_route('GET', '/get2', lambda r: None, name='name2') self.assertEqual(2, len(self.router)) def test_iter(self): self.router.add_route('GET', '/get1', lambda r: None, name='name1') self.router.add_route('GET', '/get2', lambda r: None, name='name2') self.assertEqual({'name1', 'name2'}, set(iter(self.router))) def test_contains(self): self.router.add_route('GET', '/get1', lambda r: None, name='name1') self.router.add_route('GET', '/get2', lambda r: None, name='name2') self.assertIn('name1', self.router) self.assertNotIn('name3', self.router) def test_plain_repr(self): self.router.add_route('GET', '/get/path', lambda r: None, name='name') self.assertRegex(repr(self.router['name']), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): self.router.add_route('GET', '/get/{path}', lambda r: None, name='name') self.assertRegex(repr(self.router['name']), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static('/get', os.path.dirname(aiohttp.__file__), name='name') self.assertRegex(repr(self.router['name']), r"<StaticRoute 'name' \[GET\] /get/")
from aiohttp.web import UrlDispatcher from rates.core.views import PairsList, WebSocket __all__ = ('urls', ) urls = UrlDispatcher() urls.add_route('GET', r'/pairs', PairsList, name='pairs-list') urls.add_route('GET', r'/ws', WebSocket, name='websocket')
class TestWebSendFile(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() # def make_handler(self): # @asyncio.coroutine # def handler(request): # return aiohttp.Response(request) # pragma: no cover # # return handler def test_env_nosendfile(self): directory = os.path.dirname(__file__) with mock.patch.dict(os.environ, {'AIOHTTP_NOSENDFILE': '1'}): route = web.StaticRoute(None, "/", directory) file_sender = FileSender(resp_factory=route._response_factory, chunk_size=route._chunk_size ) self.assertEqual(file_sender._sendfile, file_sender._sendfile_fallback) def test_static_handle_eof(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.helpers.os') as m_os: out_fd = 30 in_fd = 31 fut = helpers.create_future(self.loop) m_os.sendfile.return_value = 0 file_sender = FileSender(resp_factory=route._response_factory, chunk_size=route._chunk_size ) file_sender._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIsNone(fut.result()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def test_static_handle_again(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.helpers.os') as m_os: out_fd = 30 in_fd = 31 fut = helpers.create_future(self.loop) m_os.sendfile.side_effect = BlockingIOError() file_sender = FileSender(resp_factory=route._response_factory, chunk_size=route._chunk_size ) file_sender._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertFalse(fut.done()) loop.add_writer.assert_called_with(out_fd, file_sender._sendfile_cb, fut, out_fd, in_fd, 0, 100, loop, True) self.assertFalse(loop.remove_writer.called) def test_static_handle_exception(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.helpers.os') as m_os: out_fd = 30 in_fd = 31 fut = helpers.create_future(self.loop) exc = OSError() m_os.sendfile.side_effect = exc file_sender = FileSender(resp_factory=route._response_factory, chunk_size=route._chunk_size ) file_sender._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIs(exc, fut.exception()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called)
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), CIMultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.reader = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.reader, self.writer) return req def make_handler(self): @asyncio.coroutine def handler(request): return Response(request) # pragma: no cover return handler def test_system_route(self): route = SystemRoute(201, 'test') self.assertIsNone(route.match('any')) with self.assertRaises(RuntimeError): route.url() self.assertEqual("<SystemRoute 201: test>", repr(route)) self.assertEqual(201, route.status) self.assertEqual('test', route.reason) def test_register_route(self): handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(route, info.route) self.assertIs(handler, info.handler) self.assertEqual(info.route.name, 'test') def test_register_route_checks(self): self.assertRaises(AssertionError, self.router.register_route, object()) handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute('GET', handler, '1bad name', '/handler/to/path') self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute('GET', handler, 'return', '/handler/to/path') self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute('GET', handler, 'test.test:test', '/handler/to/path') self.router.register_route(route) def test_add_route_root(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = self.make_handler() self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler, name='name') req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual('name', info.route.name) def test_add_with_tailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', handler) def test_add_url_invalid1(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', handler) def test_add_url_invalid2(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', handler) def test_add_url_invalid3(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', handler) def test_add_url_invalid4(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', handler) def test_add_url_escaping(self): handler = self.make_handler() self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_any_method(self): handler = self.make_handler() route = self.router.add_route(hdrs.METH_ANY, '/', handler) req = self.make_request('GET', '/') info1 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info1) self.assertIs(route, info1.route) req = self.make_request('POST', '/') info2 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info2) self.assertIs(info1.route, info2.route) def test_match_second_result_in_table(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = self.make_handler() self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/get', handler1, name='name') regexp = ("Duplicate 'name', already handled by") with self.assertRaisesRegex(ValueError, regexp): self.router.add_route('GET', '/get_other', handler2, name='name') def test_route_plain(self): handler = self.make_handler() route = self.router.add_route('GET', '/get', handler, name='name') route2 = self.router['name'] url = route2.url() self.assertEqual('/get', url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router['unknown'] def test_route_dynamic(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{name}', handler, name='name') route2 = self.router['name'] url = route2.url(parts={'name': 'John'}) self.assertEqual('/get/John', url) self.assertIs(route, route2) def test_route_with_qs(self): handler = self.make_handler() self.router.add_route('GET', '/get', handler, name='name') url = self.router['name'].url(query=[('a', 'b'), ('c', 1)]) self.assertEqual('/get?a=b&c=1', url) def test_add_static(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__), name='static') route2 = self.router['static'] url = route2.url(filename='/dir/a.txt') self.assertEqual('/st/dir/a.txt', url) self.assertIs(route, route2) def test_plain_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_static_not_match(self): self.router.add_static('/pre', os.path.dirname(aiohttp.__file__), name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_with_trailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}/', handler, name='name') route = self.router['name'] self.assertEqual({'name': 'John'}, route.match('/get/John/')) def test_len(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual(2, len(self.router)) def test_iter(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual({'name1', 'name2'}, set(iter(self.router))) def test_contains(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertIn('name1', self.router) self.assertNotIn('name3', self.router) def test_plain_repr(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') self.assertRegex(repr(self.router['name']), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): handler = self.make_handler() self.router.add_route('GET', '/get/{path}', handler, name='name') self.assertRegex(repr(self.router['name']), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static('/get', os.path.dirname(aiohttp.__file__), name='name') self.assertRegex(repr(self.router['name']), r"<StaticRoute 'name' \[GET\] /get/") def test_static_adds_slash(self): route = self.router.add_static('/prefix', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_static_dont_add_trailing_slash(self): route = self.router.add_static('/prefix/', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_add_route_with_re(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/1234') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234'}, info) self.router.add_route('GET', r'/handler/{name}.html', handler) req = self.make_request('GET', '/handler/test.html') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual({'name': 'test'}, info) def test_add_route_with_re_and_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler) req = self.make_request('GET', '/handler/1234/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/'}, info) self.router.add_route('GET', r'/handler/{to:.+}', handler) req = self.make_request('GET', '/handler/1234/5/6/7') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/5/6/7'}, info) def test_add_route_with_re_not_match(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/tail') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound): self.loop.run_until_complete(match_info.handler(req)) def test_add_route_with_re_including_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:.+}/tail', handler) req = self.make_request('GET', '/handler/re/with/slashes/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 're/with/slashes'}, info) def test_add_route_with_invalid_re(self): handler = self.make_handler() with self.assertRaises(ValueError) as ctx: self.router.add_route('GET', r'/handler/{to:+++}', handler) s = str(ctx.exception) self.assertTrue( s.startswith( "Bad pattern '\/handler\/(?P<to>+++)': nothing to repeat"), s) self.assertIsNone(ctx.exception.__cause__) def test_route_dynamic_with_regex_spec(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123', url) def test_route_dynamic_with_regex_spec_and_trailing_slash(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}/', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123/', url) def test_route_dynamic_with_regex(self): handler = self.make_handler() route = self.router.add_route('GET', r'/{one}/{two:.+}', handler) url = route.url(parts={'one': 1, 'two': 2}) self.assertEqual('/1/2', url) def test_regular_match_info(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler) req = self.make_request('GET', '/get/john') match_info = yield from self.router.resolve(req) self.maxDiff = None self.assertRegex(repr(match_info), "<MatchInfo {'name': 'john'}: <DynamicRoute.+>>") self.loop.run_until_complete(go()) def test_not_found_repr(self): @asyncio.coroutine def go(): req = self.make_request('POST', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfo: not found>", repr(match_info)) self.loop.run_until_complete(go()) def test_not_allowed_repr(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/path/to', handler) handler2 = self.make_handler() self.router.add_route('POST', '/path/to', handler2) req = self.make_request('PUT', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual( "<MatchInfo: method PUT is not allowed " "(allowed methods: GET, POST>", repr(match_info)) self.loop.run_until_complete(go()) def test_default_expect_handler(self): route = self.router.add_route('GET', '/', self.make_handler()) self.assertIs(route._expect_handler, _defaultExpectHandler) def test_custom_expect_handler_plain(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route('GET', '/', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, PlainRoute) def test_custom_expect_handler_dynamic(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route('GET', '/get/{name}', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, DynamicRoute) def test_expect_handler_non_coroutine(self): def handler(request): pass self.assertRaises(AssertionError, self.router.add_route, 'GET', '/', self.make_handler(), expect_handler=handler) def test_dynamic_match_non_ascii(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{var}', handler) req = self.make_request( 'GET', '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82') match_info = yield from self.router.resolve(req) self.assertEqual({'var': 'рус текст'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_with_static_part(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.html', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_two_part2(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.{ext}', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file', 'ext': 'html'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_unquoted_path(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{path}/{subpath}', handler) resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters' req = self.make_request('GET', '/path/{0}'.format(resource_id)) match_info = yield from self.router.resolve(req) self.assertEqual(match_info, { 'path': 'path', 'subpath': unquote(resource_id) }) self.loop.run_until_complete(go()) def test_add_route_not_started_with_slash(self): with self.assertRaises(ValueError): handler = self.make_handler() self.router.add_route('GET', 'invalid_path', handler) def test_add_route_invalid_method(self): with self.assertRaises(ValueError): handler = self.make_handler() self.router.add_route('INVALID_METHOD', '/path', handler) def test_static_handle_eof(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.web_urldispatcher.os') as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) m_os.sendfile.return_value = 0 route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIsNone(fut.result()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def test_static_handle_again(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.web_urldispatcher.os') as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) m_os.sendfile.side_effect = BlockingIOError() route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertFalse(fut.done()) loop.add_writer.assert_called_with(out_fd, route._sendfile_cb, fut, out_fd, in_fd, 0, 100, loop, True) self.assertFalse(loop.remove_writer.called) def test_static_handle_exception(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.web_urldispatcher.os') as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) exc = OSError() m_os.sendfile.side_effect = exc route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIs(exc, fut.exception()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def fill_routes(self): route1 = self.router.add_route('GET', '/plain', self.make_handler()) route2 = self.router.add_route('GET', '/variable/{name}', self.make_handler()) route3 = self.router.add_static('/static', os.path.dirname(aiohttp.__file__)) return route1, route2, route3 def test_routes_view_len(self): self.fill_routes() self.assertEqual(3, len(self.router.routes())) def test_routes_view_iter(self): routes = self.fill_routes() self.assertEqual(list(routes), list(self.router.routes())) def test_routes_view_contains(self): routes = self.fill_routes() for route in routes: self.assertIn(route, self.router.routes()) def test_routes_abc(self): self.assertIsInstance(self.router.routes(), Sized) self.assertIsInstance(self.router.routes(), Iterable) self.assertIsInstance(self.router.routes(), Container)
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), CIMultiDict(), [], False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.reader = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.reader, self.writer) return req def make_handler(self): @asyncio.coroutine def handler(request): return Response(request) # pragma: no cover return handler def test_system_route(self): route = SystemRoute(HTTPCreated(reason='test')) self.assertIsNone(route.match('any')) with self.assertRaises(RuntimeError): route.url() self.assertEqual("<SystemRoute 201: test>", repr(route)) self.assertEqual(201, route.status) self.assertEqual('test', route.reason) def test_register_route(self): handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(route, info.route) self.assertIs(handler, info.handler) self.assertEqual(info.route.name, 'test') def test_register_route_checks(self): self.assertRaises( AssertionError, self.router.register_route, object()) handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute('GET', handler, '1bad name', '/handler/to/path') self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute('GET', handler, 'return', '/handler/to/path') self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute('GET', handler, 'test.test:test-test', '/handler/to/path') self.router.register_route(route) def test_add_route_root(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = self.make_handler() self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler, name='name') req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual('name', info.route.name) def test_add_with_tailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', handler) def test_add_url_invalid1(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', handler) def test_add_url_invalid2(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', handler) def test_add_url_invalid3(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', handler) def test_add_url_invalid4(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', handler) def test_add_url_escaping(self): handler = self.make_handler() self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_any_method(self): handler = self.make_handler() route = self.router.add_route(hdrs.METH_ANY, '/', handler) req = self.make_request('GET', '/') info1 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info1) self.assertIs(route, info1.route) req = self.make_request('POST', '/') info2 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info2) self.assertIs(info1.route, info2.route) def test_match_second_result_in_table(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = self.make_handler() self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/get', handler1, name='name') regexp = ("Duplicate 'name', already handled by") with self.assertRaisesRegex(ValueError, regexp): self.router.add_route('GET', '/get_other', handler2, name='name') def test_route_plain(self): handler = self.make_handler() route = self.router.add_route('GET', '/get', handler, name='name') route2 = next(iter(self.router['name'])) url = route2.url() self.assertEqual('/get', url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router['unknown'] def test_route_dynamic(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{name}', handler, name='name') route2 = next(iter(self.router['name'])) url = route2.url(parts={'name': 'John'}) self.assertEqual('/get/John', url) self.assertIs(route, route2) def test_route_with_qs(self): handler = self.make_handler() self.router.add_route('GET', '/get', handler, name='name') url = self.router['name'].url(query=[('a', 'b'), ('c', 1)]) self.assertEqual('/get?a=b&c=1', url) def test_add_static(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__), name='static') resource = self.router['static'] url = resource.url(filename='/dir/a.txt') self.assertEqual('/st/dir/a.txt', url) self.assertIs(route, next(iter(resource))) def test_plain_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') route = self.router['name'] self.assertIsNone(route._match('/another/path')) def test_dynamic_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler, name='name') route = self.router['name'] self.assertIsNone(route._match('/another/path')) def test_static_not_match(self): self.router.add_static('/pre', os.path.dirname(aiohttp.__file__), name='name') route = self.router['name'] self.assertIsNone(route._route.match('/another/path')) def test_dynamic_with_trailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}/', handler, name='name') route = self.router['name'] self.assertEqual({'name': 'John'}, route._match('/get/John/')) def test_len(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual(2, len(self.router)) def test_iter(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual({'name1', 'name2'}, set(iter(self.router))) def test_contains(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertIn('name1', self.router) self.assertNotIn('name3', self.router) def test_plain_repr(self): handler = self.make_handler() route = PlainRoute('GET', handler, 'name', '/get/path') self.assertRegex(repr(route), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): handler = self.make_handler() route = DynamicRoute('GET', handler, 'name', 'pattern', '/get/{path}') self.assertRegex(repr(route), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static('/get', os.path.dirname(aiohttp.__file__), name='name') self.assertRegex(repr(next(iter(self.router['name']))), r"<StaticRoute 'name' \[GET\] /get/") def test_static_adds_slash(self): route = self.router.add_static('/prefix', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_static_dont_add_trailing_slash(self): route = self.router.add_static('/prefix/', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_add_route_with_re(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/1234') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234'}, info) self.router.add_route('GET', r'/handler/{name}.html', handler) req = self.make_request('GET', '/handler/test.html') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual({'name': 'test'}, info) def test_add_route_with_re_and_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler) req = self.make_request('GET', '/handler/1234/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/'}, info) self.router.add_route('GET', r'/handler/{to:.+}', handler) req = self.make_request('GET', '/handler/1234/5/6/7') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/5/6/7'}, info) def test_add_route_with_re_not_match(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/tail') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound): self.loop.run_until_complete(match_info.handler(req)) def test_add_route_with_re_including_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:.+}/tail', handler) req = self.make_request('GET', '/handler/re/with/slashes/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 're/with/slashes'}, info) def test_add_route_with_invalid_re(self): handler = self.make_handler() with self.assertRaises(ValueError) as ctx: self.router.add_route('GET', r'/handler/{to:+++}', handler) s = str(ctx.exception) self.assertTrue(s.startswith( "Bad pattern '\/handler\/(?P<to>+++)': nothing to repeat"), s) self.assertIsNone(ctx.exception.__cause__) def test_route_dynamic_with_regex_spec(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123', url) def test_route_dynamic_with_regex_spec_and_trailing_slash(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}/', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123/', url) def test_route_dynamic_with_regex(self): handler = self.make_handler() route = self.router.add_route('GET', r'/{one}/{two:.+}', handler) url = route.url(parts={'one': 1, 'two': 2}) self.assertEqual('/1/2', url) def test_regular_match_info(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler) req = self.make_request('GET', '/get/john') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'john'}, match_info) self.maxDiff = None self.assertRegex(repr(match_info), "<MatchInfo {'name': 'john'}: .+<Dynamic.+>>") self.loop.run_until_complete(go()) def test_not_found_repr(self): @asyncio.coroutine def go(): req = self.make_request('POST', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfoError 404: Not Found>", repr(match_info)) self.loop.run_until_complete(go()) def test_not_allowed_repr(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/path/to', handler) handler2 = self.make_handler() self.router.add_route('POST', '/path/to', handler2) req = self.make_request('PUT', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfoError 405: Method Not Allowed>", repr(match_info)) self.loop.run_until_complete(go()) def test_default_expect_handler(self): route = self.router.add_route('GET', '/', self.make_handler()) self.assertIs(route._expect_handler, _defaultExpectHandler) def test_custom_expect_handler_plain(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route( 'GET', '/', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, ResourceRoute) def test_custom_expect_handler_dynamic(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route( 'GET', '/get/{name}', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, ResourceRoute) def test_expect_handler_non_coroutine(self): def handler(request): pass self.assertRaises( AssertionError, self.router.add_route, 'GET', '/', self.make_handler(), expect_handler=handler) def test_dynamic_match_non_ascii(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{var}', handler) req = self.make_request( 'GET', '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82') match_info = yield from self.router.resolve(req) self.assertEqual({'var': 'рус текст'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_with_static_part(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.html', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_two_part2(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.{ext}', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file', 'ext': 'html'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_unquoted_path(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{path}/{subpath}', handler) resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters' req = self.make_request('GET', '/path/{0}'.format(resource_id)) match_info = yield from self.router.resolve(req) self.assertEqual(match_info, { 'path': 'path', 'subpath': unquote(resource_id) }) self.loop.run_until_complete(go()) def test_add_route_not_started_with_slash(self): with self.assertRaises(ValueError): handler = self.make_handler() self.router.add_route('GET', 'invalid_path', handler) def test_add_route_invalid_method(self): with self.assertRaises(ValueError): handler = self.make_handler() self.router.add_route('INVALID_METHOD', '/path', handler) def test_static_handle_eof(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.web_urldispatcher.os') as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) m_os.sendfile.return_value = 0 route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIsNone(fut.result()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def test_static_handle_again(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.web_urldispatcher.os') as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) m_os.sendfile.side_effect = BlockingIOError() route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertFalse(fut.done()) loop.add_writer.assert_called_with(out_fd, route._sendfile_cb, fut, out_fd, in_fd, 0, 100, loop, True) self.assertFalse(loop.remove_writer.called) def test_static_handle_exception(self): loop = mock.Mock() route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) with mock.patch('aiohttp.web_urldispatcher.os') as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) exc = OSError() m_os.sendfile.side_effect = exc route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIs(exc, fut.exception()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def fill_routes(self): route1 = self.router.add_route('GET', '/plain', self.make_handler()) route2 = self.router.add_route('GET', '/variable/{name}', self.make_handler()) route3 = self.router.add_static('/static', os.path.dirname(aiohttp.__file__)) return route1, route2, route3 def test_routes_view_len(self): self.fill_routes() self.assertEqual(3, len(self.router.routes())) def test_routes_view_iter(self): routes = self.fill_routes() self.assertEqual(list(routes), list(self.router.routes())) def test_routes_view_contains(self): routes = self.fill_routes() for route in routes: self.assertIn(route, self.router.routes()) def test_routes_abc(self): self.assertIsInstance(self.router.routes(), Sized) self.assertIsInstance(self.router.routes(), Iterable) self.assertIsInstance(self.router.routes(), Container) def fill_named_resources(self): route1 = self.router.add_route('GET', '/plain', self.make_handler(), name='route1') route2 = self.router.add_route('GET', '/variable/{name}', self.make_handler(), name='route2') route3 = self.router.add_static('/static', os.path.dirname(aiohttp.__file__), name='route3') return route1.name, route2.name, route3.name def test_named_routes_abc(self): self.assertIsInstance(self.router.named_routes(), Mapping) self.assertNotIsInstance(self.router.named_routes(), MutableMapping) def test_named_resources_abc(self): self.assertIsInstance(self.router.named_resources(), Mapping) self.assertNotIsInstance(self.router.named_resources(), MutableMapping) def test_named_routes(self): self.fill_named_resources() with self.assertWarns(DeprecationWarning): self.assertEqual(3, len(self.router.named_routes())) def test_named_resources(self): names = self.fill_named_resources() self.assertEqual(3, len(self.router.named_resources())) for name in names: self.assertIn(name, self.router.named_routes()) self.assertIsInstance(self.router.named_routes()[name], AbstractResource) def test_resource_adapter_not_match(self): route = PlainRoute('GET', lambda req: None, None, '/path') self.router.register_route(route) resource = route.resource self.assertIsNotNone(resource) self.assertIsNone(resource._route.match('/another/path')) def test_resource_adapter_resolve_not_math(self): route = PlainRoute('GET', lambda req: None, None, '/path') self.router.register_route(route) resource = route.resource self.assertEqual((None, set()), self.loop.run_until_complete( resource.resolve('GET', '/another/path'))) def test_resource_adapter_resolve_bad_method(self): route = PlainRoute('POST', lambda req: None, None, '/path') self.router.register_route(route) resource = route.resource self.assertEqual((None, {'POST'}), self.loop.run_until_complete( resource.resolve('GET', '/path'))) def test_resource_adapter_resolve_wildcard(self): route = PlainRoute('*', lambda req: None, None, '/path') self.router.register_route(route) resource = route.resource match_info, allowed = self.loop.run_until_complete( resource.resolve('GET', '/path')) self.assertEqual(allowed, {'*'}) # TODO: expand wildcard self.assertIsNotNone(match_info) def test_resource_adapter_iter(self): route = PlainRoute('GET', lambda req: None, None, '/path') self.router.register_route(route) resource = route.resource self.assertEqual(1, len(resource)) self.assertEqual([route], list(resource)) def test_resource_iter(self): resource = self.router.add_resource('/path') r1 = resource.add_route('GET', lambda req: None) r2 = resource.add_route('POST', lambda req: None) self.assertEqual(2, len(resource)) self.assertEqual([r1, r2], list(resource)) def test_deprecate_bare_generators(self): resource = self.router.add_resource('/path') def gen(request): yield with self.assertWarns(DeprecationWarning): resource.add_route('GET', gen) def test_view_route(self): resource = self.router.add_resource('/path') route = resource.add_route('GET', View) self.assertIs(View, route.handler) def test_resource_route_match(self): resource = self.router.add_resource('/path') route = resource.add_route('GET', lambda req: None) self.assertEqual({}, route.resource._match('/path')) def test_plain_route_url(self): route = PlainRoute('GET', lambda req: None, None, '/path') self.router.register_route(route) self.assertEqual('/path?arg=1', route.url(query={'arg': 1})) def test_dynamic_route_url(self): route = DynamicRoute('GET', lambda req: None, None, '<pattern>', '/{path}') self.router.register_route(route) self.assertEqual('/path?arg=1', route.url(parts={'path': 'path'}, query={'arg': 1})) def test_dynamic_route_match_not_found(self): route = DynamicRoute('GET', lambda req: None, None, re.compile('/path/(?P<to>.+)'), '/path/{to}') self.router.register_route(route) self.assertEqual(None, route.match('/another/path')) def test_dynamic_route_match_found(self): route = DynamicRoute('GET', lambda req: None, None, re.compile('/path/(?P<to>.+)'), '/path/{to}') self.router.register_route(route) self.assertEqual({'to': 'to'}, route.match('/path/to')) def test_deprecate_register_route(self): route = PlainRoute('GET', lambda req: None, None, '/path') with self.assertWarns(DeprecationWarning): self.router.register_route(route) def test_error_on_double_route_adding(self): resource = self.router.add_resource('/path') resource.add_route('GET', lambda: None) with self.assertRaises(RuntimeError): resource.add_route('GET', lambda: None) def test_error_on_adding_route_after_wildcard(self): resource = self.router.add_resource('/path') resource.add_route('*', lambda: None) with self.assertRaises(RuntimeError): resource.add_route('GET', lambda: None) def test_http_exception_is_none_when_resolved(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNone(info.http_exception) def test_http_exception_is_not_none_when_not_resolved(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/abc') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual(info.http_exception.status, 404) def test_match_info_get_info_plain(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual(info.get_info(), {'path': '/'}) def test_match_info_get_info_dynamic(self): handler = self.make_handler() self.router.add_route('GET', '/{a}', handler) req = self.make_request('GET', '/value') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual(info.get_info(), {'pattern': re.compile('^\\/(?P<a>[^{}/]+)$'), 'formatter': '/{a}'}) def test_resource_adapter_get_info(self): directory = pathlib.Path(aiohttp.__file__).parent route = self.router.add_static('/st', directory) self.assertEqual(route.resource.get_info(), {'directory': directory, 'prefix': '/st/'}) def test_plain_old_style_route_get_info(self): handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) self.assertEqual(route.get_info(), {'path': '/handler/to/path'}) def test_dynamic_old_style_get_info(self): handler = self.make_handler() route = DynamicRoute('GET', handler, 'name', '<pattern>', '/get/{path}') self.router.register_route(route) self.assertEqual(route.get_info(), {'formatter': '/get/{path}', 'pattern': '<pattern>'}) def test_system_route_get_info(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/abc') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual(info.get_info()['http_exception'].status, 404) def fill_resources(self): resource1 = self.router.add_resource('/plain') resource2 = self.router.add_resource('/variable/{name}') return resource1, resource2 def test_resources_view_len(self): self.fill_resources() self.assertEqual(2, len(self.router.resources())) def test_resources_view_iter(self): resources = self.fill_resources() self.assertEqual(list(resources), list(self.router.resources())) def test_resources_view_contains(self): resources = self.fill_resources() for resource in resources: self.assertIn(resource, self.router.resources()) def test_resources_abc(self): self.assertIsInstance(self.router.resources(), Sized) self.assertIsInstance(self.router.resources(), Iterable) self.assertIsInstance(self.router.resources(), Container) def test_static_route_user_home(self): here = pathlib.Path(aiohttp.__file__).parent home = pathlib.Path(os.path.expanduser('~')) if not str(here).startswith(str(home)): # pragma: no cover self.skipTest("aiohttp folder is not placed in user's HOME") static_dir = '~/' + str(here.relative_to(home)) route = self.router.add_static('/st', static_dir) self.assertEqual(here, route.get_info()['directory']) def test_static_route_points_to_file(self): here = pathlib.Path(aiohttp.__file__).parent / '__init__.py' with self.assertRaises(ValueError): self.router.add_static('/st', here) def test_404_for_resource_adapter(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) resource = route.resource ret = self.loop.run_until_complete( resource.resolve('GET', '/unknown/path')) self.assertEqual((None, set()), ret) def test_405_for_resource_adapter(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__)) resource = route.resource ret = self.loop.run_until_complete( resource.resolve('POST', '/st/abc.py')) self.assertEqual((None, {'GET'}), ret) def test_check_allowed_method_for_found_resource(self): handler = self.make_handler() resource = self.router.add_resource('/') resource.add_route('GET', handler) ret = self.loop.run_until_complete(resource.resolve('GET', '/')) self.assertIsNotNone(ret[0]) self.assertEqual({'GET'}, ret[1])
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), MultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.writer, 15) return req def test_add_route_root(self): handler = lambda req: Response(req) self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) def test_add_route_simple(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) def test_add_with_matchdict(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) def test_add_with_tailing_slash(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', lambda req: None) def test_add_url_invalid1(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', lambda: None) def test_add_url_invalid2(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', lambda: None) def test_add_url_invalid3(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', lambda: None) def test_add_url_invalid4(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', lambda: None) def test_add_url_invalid5(self): with self.assertRaises(ValueError): self.router.add_route('post', '/post"{id}', lambda: None) def test_add_url_escaping(self): handler = lambda req: Response(req) self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_match_second_result_in_table(self): handler1 = lambda req: Response(req) handler2 = lambda req: Response(req) self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = lambda req: Response(req) handler2 = lambda req: Response(req) self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = lambda req: Response(req) self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual(404, exc.status)
def assign_routes(router: web.UrlDispatcher) -> None: router.add_routes([ web.post('/predict', predict.handle), web.get('/', root.handle), web.static('/templates', config.CONFIG['templates_path']), ])
def router(): return UrlDispatcher()
def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher()
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), CIMultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.reader = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.reader, self.writer) return req def make_handler(self): @asyncio.coroutine def handler(request): return Response(request) # pragma: no cover return handler def test_system_route(self): route = SystemRoute(201, "test") self.assertIsNone(route.match("any")) with self.assertRaises(RuntimeError): route.url() self.assertEqual("<SystemRoute 201: test>", repr(route)) self.assertEqual(201, route.status) self.assertEqual("test", route.reason) def test_register_route(self): handler = self.make_handler() route = PlainRoute("GET", handler, "test", "/handler/to/path") self.router.register_route(route) req = self.make_request("GET", "/handler/to/path") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(route, info.route) self.assertIs(handler, info.handler) self.assertEqual(info.route.name, "test") def test_register_route_checks(self): self.assertRaises(AssertionError, self.router.register_route, object()) handler = self.make_handler() route = PlainRoute("GET", handler, "test", "/handler/to/path") self.router.register_route(route) self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute("GET", handler, "1bad name", "/handler/to/path") self.assertRaises(ValueError, self.router.register_route, route) route = PlainRoute("GET", handler, "return", "/handler/to/path") self.assertRaises(ValueError, self.router.register_route, route) def test_add_route_root(self): handler = self.make_handler() self.router.add_route("GET", "/", handler) req = self.make_request("GET", "/") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = self.make_handler() self.router.add_route("GET", "/handler/to/path", handler) req = self.make_request("GET", "/handler/to/path") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = self.make_handler() self.router.add_route("GET", "/handler/{to}", handler) req = self.make_request("GET", "/handler/tail") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({"to": "tail"}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = self.make_handler() self.router.add_route("GET", "/handler/to/path", handler, name="name") req = self.make_request("GET", "/handler/to/path") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual("name", info.route.name) def test_add_with_tailing_slash(self): handler = self.make_handler() self.router.add_route("GET", "/handler/to/path/", handler) req = self.make_request("GET", "/handler/to/path/") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route("GET", "/{/", handler) def test_add_url_invalid1(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route("post", "/post/{id", handler) def test_add_url_invalid2(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route("post", "/post/{id{}}", handler) def test_add_url_invalid3(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route("post", "/post/{id{}", handler) def test_add_url_invalid4(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route("post", '/post/{id"}', handler) def test_add_url_escaping(self): handler = self.make_handler() self.router.add_route("GET", "/+$", handler) req = self.make_request("GET", "/+$") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_any_method(self): handler = self.make_handler() route = self.router.add_route(hdrs.METH_ANY, "/", handler) req = self.make_request("GET", "/") info1 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info1) self.assertIs(route, info1.route) req = self.make_request("POST", "/") info2 = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info2) self.assertIs(info1.route, info2.route) def test_match_second_result_in_table(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route("GET", "/h1", handler1) self.router.add_route("POST", "/h2", handler2) req = self.make_request("POST", "/h2") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route("GET", "/", handler1) self.router.add_route("POST", "/", handler2) req = self.make_request("PUT", "/") match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual("PUT", exc.method) self.assertEqual(405, exc.status) self.assertEqual({"POST", "GET"}, exc.allowed_methods) def test_raise_method_not_found(self): handler = self.make_handler() self.router.add_route("GET", "/a", handler) req = self.make_request("GET", "/b") match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route("GET", "/get", handler1, name="name") regexp = "Duplicate 'name', already handled by" with self.assertRaisesRegex(ValueError, regexp): self.router.add_route("GET", "/get_other", handler2, name="name") def test_route_plain(self): handler = self.make_handler() route = self.router.add_route("GET", "/get", handler, name="name") route2 = self.router["name"] url = route2.url() self.assertEqual("/get", url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router["unknown"] def test_route_dynamic(self): handler = self.make_handler() route = self.router.add_route("GET", "/get/{name}", handler, name="name") route2 = self.router["name"] url = route2.url(parts={"name": "John"}) self.assertEqual("/get/John", url) self.assertIs(route, route2) def test_route_with_qs(self): handler = self.make_handler() self.router.add_route("GET", "/get", handler, name="name") url = self.router["name"].url(query=[("a", "b"), ("c", 1)]) self.assertEqual("/get?a=b&c=1", url) def test_add_static(self): route = self.router.add_static("/st", os.path.dirname(aiohttp.__file__), name="static") route2 = self.router["static"] url = route2.url(filename="/dir/a.txt") self.assertEqual("/st/dir/a.txt", url) self.assertIs(route, route2) def test_plain_not_match(self): handler = self.make_handler() self.router.add_route("GET", "/get/path", handler, name="name") route = self.router["name"] self.assertIsNone(route.match("/another/path")) def test_dynamic_not_match(self): handler = self.make_handler() self.router.add_route("GET", "/get/{name}", handler, name="name") route = self.router["name"] self.assertIsNone(route.match("/another/path")) def test_static_not_match(self): self.router.add_static("/pre", os.path.dirname(aiohttp.__file__), name="name") route = self.router["name"] self.assertIsNone(route.match("/another/path")) def test_dynamic_with_trailing_slash(self): handler = self.make_handler() self.router.add_route("GET", "/get/{name}/", handler, name="name") route = self.router["name"] self.assertEqual({"name": "John"}, route.match("/get/John/")) def test_len(self): handler = self.make_handler() self.router.add_route("GET", "/get1", handler, name="name1") self.router.add_route("GET", "/get2", handler, name="name2") self.assertEqual(2, len(self.router)) def test_iter(self): handler = self.make_handler() self.router.add_route("GET", "/get1", handler, name="name1") self.router.add_route("GET", "/get2", handler, name="name2") self.assertEqual({"name1", "name2"}, set(iter(self.router))) def test_contains(self): handler = self.make_handler() self.router.add_route("GET", "/get1", handler, name="name1") self.router.add_route("GET", "/get2", handler, name="name2") self.assertIn("name1", self.router) self.assertNotIn("name3", self.router) def test_plain_repr(self): handler = self.make_handler() self.router.add_route("GET", "/get/path", handler, name="name") self.assertRegex(repr(self.router["name"]), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): handler = self.make_handler() self.router.add_route("GET", "/get/{path}", handler, name="name") self.assertRegex(repr(self.router["name"]), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static("/get", os.path.dirname(aiohttp.__file__), name="name") self.assertRegex(repr(self.router["name"]), r"<StaticRoute 'name' \[GET\] /get/") def test_static_adds_slash(self): route = self.router.add_static("/prefix", os.path.dirname(aiohttp.__file__)) self.assertEqual("/prefix/", route._prefix) def test_static_dont_add_trailing_slash(self): route = self.router.add_static("/prefix/", os.path.dirname(aiohttp.__file__)) self.assertEqual("/prefix/", route._prefix) def test_add_route_with_re(self): handler = self.make_handler() self.router.add_route("GET", r"/handler/{to:\d+}", handler) req = self.make_request("GET", "/handler/1234") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({"to": "1234"}, info) self.router.add_route("GET", r"/handler/{name}.html", handler) req = self.make_request("GET", "/handler/test.html") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual({"name": "test"}, info) def test_add_route_with_re_and_slashes(self): handler = self.make_handler() self.router.add_route("GET", r"/handler/{to:[^/]+/?}", handler) req = self.make_request("GET", "/handler/1234/") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({"to": "1234/"}, info) self.router.add_route("GET", r"/handler/{to:.+}", handler) req = self.make_request("GET", "/handler/1234/5/6/7") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({"to": "1234/5/6/7"}, info) def test_add_route_with_re_not_match(self): handler = self.make_handler() self.router.add_route("GET", r"/handler/{to:\d+}", handler) req = self.make_request("GET", "/handler/tail") match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsInstance(match_info.route, SystemRoute) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound): self.loop.run_until_complete(match_info.handler(req)) def test_add_route_with_re_including_slashes(self): handler = self.make_handler() self.router.add_route("GET", r"/handler/{to:.+}/tail", handler) req = self.make_request("GET", "/handler/re/with/slashes/tail") info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({"to": "re/with/slashes"}, info) def test_add_route_with_invalid_re(self): handler = self.make_handler() with self.assertRaises(ValueError) as ctx: self.router.add_route("GET", r"/handler/{to:+++}", handler) s = str(ctx.exception) self.assertTrue(s.startswith("Bad pattern '\/handler\/(?P<to>+++)': nothing to repeat"), s) self.assertIsNone(ctx.exception.__cause__) def test_route_dynamic_with_regex_spec(self): handler = self.make_handler() route = self.router.add_route("GET", "/get/{num:^\d+}", handler, name="name") url = route.url(parts={"num": "123"}) self.assertEqual("/get/123", url) def test_route_dynamic_with_regex_spec_and_trailing_slash(self): handler = self.make_handler() route = self.router.add_route("GET", "/get/{num:^\d+}/", handler, name="name") url = route.url(parts={"num": "123"}) self.assertEqual("/get/123/", url) def test_route_dynamic_with_regex(self): handler = self.make_handler() route = self.router.add_route("GET", r"/{one}/{two:.+}", handler) url = route.url(parts={"one": 1, "two": 2}) self.assertEqual("/1/2", url) def test_regular_match_info(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route("GET", "/get/{name}", handler) req = self.make_request("GET", "/get/john") match_info = yield from self.router.resolve(req) self.maxDiff = None self.assertRegex(repr(match_info), "<MatchInfo {'name': 'john'}: <DynamicRoute.+>>") self.loop.run_until_complete(go()) def test_not_found_repr(self): @asyncio.coroutine def go(): req = self.make_request("POST", "/path/to") match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfo: not found>", repr(match_info)) self.loop.run_until_complete(go()) def test_not_allowed_repr(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route("GET", "/path/to", handler) handler2 = self.make_handler() self.router.add_route("POST", "/path/to", handler2) req = self.make_request("PUT", "/path/to") match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfo: method PUT is not allowed " "(allowed methods: GET, POST>", repr(match_info)) self.loop.run_until_complete(go()) def test_default_expect_handler(self): route = self.router.add_route("GET", "/", self.make_handler()) self.assertIs(route._expect_handler, _defaultExpectHandler) def test_custom_expect_handler_plain(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route("GET", "/", self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, PlainRoute) def test_custom_expect_handler_dynamic(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route("GET", "/get/{name}", self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, DynamicRoute) def test_expect_handler_non_coroutine(self): def handler(request): pass self.assertRaises( AssertionError, self.router.add_route, "GET", "/", self.make_handler(), expect_handler=handler ) def test_dynamic_match_non_ascii(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route("GET", "/{var}", handler) req = self.make_request("GET", "/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82") match_info = yield from self.router.resolve(req) self.assertEqual({"var": "рус текст"}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_with_static_part(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route("GET", "/{name}.html", handler) req = self.make_request("GET", "/file.html") match_info = yield from self.router.resolve(req) self.assertEqual({"name": "file"}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_two_part2(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route("GET", "/{name}.{ext}", handler) req = self.make_request("GET", "/file.html") match_info = yield from self.router.resolve(req) self.assertEqual({"name": "file", "ext": "html"}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_unquoted_path(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route("GET", "/{path}/{subpath}", handler) resource_id = "my%2Fpath%7Cwith%21some%25strange%24characters" req = self.make_request("GET", "/path/{0}".format(resource_id)) match_info = yield from self.router.resolve(req) self.assertEqual(match_info, {"path": "path", "subpath": unquote(resource_id)}) self.loop.run_until_complete(go()) def test_add_route_not_started_with_slash(self): with self.assertRaises(ValueError): handler = self.make_handler() self.router.add_route("GET", "invalid_path", handler) def test_add_route_invalid_method(self): with self.assertRaises(ValueError): handler = self.make_handler() self.router.add_route("INVALID_METHOD", "/path", handler) def test_static_handle_eof(self): loop = mock.Mock() route = self.router.add_static("/st", os.path.dirname(aiohttp.__file__)) with mock.patch("aiohttp.web_urldispatcher.os") as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) m_os.sendfile.return_value = 0 route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIsNone(fut.result()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def test_static_handle_again(self): loop = mock.Mock() route = self.router.add_static("/st", os.path.dirname(aiohttp.__file__)) with mock.patch("aiohttp.web_urldispatcher.os") as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) m_os.sendfile.side_effect = BlockingIOError() route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertFalse(fut.done()) loop.add_writer.assert_called_with(out_fd, route._sendfile_cb, fut, out_fd, in_fd, 0, 100, loop, True) self.assertFalse(loop.remove_writer.called) def test_static_handle_exception(self): loop = mock.Mock() route = self.router.add_static("/st", os.path.dirname(aiohttp.__file__)) with mock.patch("aiohttp.web_urldispatcher.os") as m_os: out_fd = 30 in_fd = 31 fut = asyncio.Future(loop=self.loop) exc = OSError() m_os.sendfile.side_effect = exc route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False) m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100) self.assertTrue(fut.done()) self.assertIs(exc, fut.exception()) self.assertFalse(loop.add_writer.called) self.assertFalse(loop.remove_writer.called) def fill_routes(self): route1 = self.router.add_route("GET", "/plain", self.make_handler()) route2 = self.router.add_route("GET", "/variable/{name}", self.make_handler()) route3 = self.router.add_static("/static", os.path.dirname(aiohttp.__file__)) return route1, route2, route3 def test_routes_view_len(self): self.fill_routes() self.assertEqual(3, len(self.router.routes())) def test_routes_view_iter(self): routes = self.fill_routes() self.assertEqual(list(routes), list(self.router.routes())) def test_routes_view_contains(self): routes = self.fill_routes() for route in routes: self.assertIn(route, self.router.routes()) def test_routes_abc(self): self.assertIsInstance(self.router.routes(), Sized) self.assertIsInstance(self.router.routes(), Iterable) self.assertIsInstance(self.router.routes(), Container)
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path): self.app = mock.Mock() message = RawRequestMessage(method, path, HttpVersion(1, 1), CIMultiDict(), False, False) self.payload = mock.Mock() self.transport = mock.Mock() self.reader = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.transport, self.reader, self.writer) return req def make_handler(self): @asyncio.coroutine def handler(request): return Response(request) # pragma: no cover return handler def test_register_route(self): handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(route, info.route) self.assertIs(handler, info.handler) self.assertEqual(info.route.name, 'test') def test_register_route_checks(self): self.assertRaises(AssertionError, self.router.register_route, object()) handler = self.make_handler() route = PlainRoute('GET', handler, 'test', '/handler/to/path') self.router.register_route(route) self.assertRaises(ValueError, self.router.register_route, route) def test_add_route_root(self): handler = self.make_handler() self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_route_simple(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_matchdict(self): handler = self.make_handler() self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) self.assertIsNone(info.route.name) def test_add_with_name(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path', handler, name='name') req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual('name', info.route.name) def test_add_with_tailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', handler) def test_add_url_invalid1(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id', handler) def test_add_url_invalid2(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}}', handler) def test_add_url_invalid3(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id{}', handler) def test_add_url_invalid4(self): handler = self.make_handler() with self.assertRaises(ValueError): self.router.add_route('post', '/post/{id"}', handler) def test_add_url_escaping(self): handler = self.make_handler() self.router.add_route('GET', '/+$', handler) req = self.make_request('GET', '/+$') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertIs(handler, info.handler) def test_match_second_result_in_table(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNone(match_info.route) self.assertEqual({}, match_info) with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = self.make_handler() self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNone(match_info.route) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(match_info.handler(req)) exc = ctx.exception self.assertEqual(404, exc.status) def test_double_add_url_with_the_same_name(self): handler1 = self.make_handler() handler2 = self.make_handler() self.router.add_route('GET', '/get', handler1, name='name') regexp = ("Duplicate 'name', already handled by") with self.assertRaisesRegex(ValueError, regexp): self.router.add_route('GET', '/get_other', handler2, name='name') def test_route_plain(self): handler = self.make_handler() route = self.router.add_route('GET', '/get', handler, name='name') route2 = self.router['name'] url = route2.url() self.assertEqual('/get', url) self.assertIs(route, route2) def test_route_unknown_route_name(self): with self.assertRaises(KeyError): self.router['unknown'] def test_route_dynamic(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{name}', handler, name='name') route2 = self.router['name'] url = route2.url(parts={'name': 'John'}) self.assertEqual('/get/John', url) self.assertIs(route, route2) def test_route_with_qs(self): handler = self.make_handler() self.router.add_route('GET', '/get', handler, name='name') url = self.router['name'].url(query=[('a', 'b'), ('c', 1)]) self.assertEqual('/get?a=b&c=1', url) def test_add_static(self): route = self.router.add_static('/st', os.path.dirname(aiohttp.__file__), name='static') route2 = self.router['static'] url = route2.url(filename='/dir/a.txt') self.assertEqual('/st/dir/a.txt', url) self.assertIs(route, route2) def test_plain_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_not_match(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler, name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_static_not_match(self): self.router.add_static('/pre', os.path.dirname(aiohttp.__file__), name='name') route = self.router['name'] self.assertIsNone(route.match('/another/path')) def test_dynamic_with_trailing_slash(self): handler = self.make_handler() self.router.add_route('GET', '/get/{name}/', handler, name='name') route = self.router['name'] self.assertEqual({'name': 'John'}, route.match('/get/John/')) def test_len(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual(2, len(self.router)) def test_iter(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertEqual({'name1', 'name2'}, set(iter(self.router))) def test_contains(self): handler = self.make_handler() self.router.add_route('GET', '/get1', handler, name='name1') self.router.add_route('GET', '/get2', handler, name='name2') self.assertIn('name1', self.router) self.assertNotIn('name3', self.router) def test_plain_repr(self): handler = self.make_handler() self.router.add_route('GET', '/get/path', handler, name='name') self.assertRegex(repr(self.router['name']), r"<PlainRoute 'name' \[GET\] /get/path") def test_dynamic_repr(self): handler = self.make_handler() self.router.add_route('GET', '/get/{path}', handler, name='name') self.assertRegex(repr(self.router['name']), r"<DynamicRoute 'name' \[GET\] /get/{path}") def test_static_repr(self): self.router.add_static('/get', os.path.dirname(aiohttp.__file__), name='name') self.assertRegex(repr(self.router['name']), r"<StaticRoute 'name' \[GET\] /get/") def test_static_adds_slash(self): route = self.router.add_static('/prefix', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_static_dont_add_trailing_slash(self): route = self.router.add_static('/prefix/', os.path.dirname(aiohttp.__file__)) self.assertEqual('/prefix/', route._prefix) def test_add_route_with_re(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/1234') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234'}, info) self.router.add_route('GET', r'/handler/{name}.html', handler) req = self.make_request('GET', '/handler/test.html') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertEqual({'name': 'test'}, info) def test_add_route_with_re_and_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler) req = self.make_request('GET', '/handler/1234/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/'}, info) self.router.add_route('GET', r'/handler/{to:.+}', handler) req = self.make_request('GET', '/handler/1234/5/6/7') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': '1234/5/6/7'}, info) def test_add_route_with_re_not_match(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:\d+}', handler) req = self.make_request('GET', '/handler/tail') match_info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNone(match_info.route) self.assertEqual({}, match_info) with self.assertRaises(HTTPNotFound): self.loop.run_until_complete(match_info.handler(req)) def test_add_route_with_re_including_slashes(self): handler = self.make_handler() self.router.add_route('GET', r'/handler/{to:.+}/tail', handler) req = self.make_request('GET', '/handler/re/with/slashes/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 're/with/slashes'}, info) def test_add_route_with_invalid_re(self): handler = self.make_handler() with self.assertRaises(ValueError) as ctx: self.router.add_route('GET', r'/handler/{to:+++}', handler) s = str(ctx.exception) self.assertTrue( s.startswith( "Bad pattern '\/handler\/(?P<to>+++)': nothing to repeat"), s) self.assertIsNone(ctx.exception.__cause__) def test_route_dynamic_with_regex_spec(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123', url) def test_route_dynamic_with_regex_spec_and_trailing_slash(self): handler = self.make_handler() route = self.router.add_route('GET', '/get/{num:^\d+}/', handler, name='name') url = route.url(parts={'num': '123'}) self.assertEqual('/get/123/', url) def test_route_dynamic_with_regex(self): handler = self.make_handler() route = self.router.add_route('GET', r'/{one}/{two:.+}', handler) url = route.url(parts={'one': 1, 'two': 2}) self.assertEqual('/1/2', url) def test_regular_match_info(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/get/{name}', handler) req = self.make_request('GET', '/get/john') match_info = yield from self.router.resolve(req) self.maxDiff = None self.assertRegex(repr(match_info), "<MatchInfo {'name': 'john'}: <DynamicRoute.+>>") self.loop.run_until_complete(go()) def test_not_found_repr(self): @asyncio.coroutine def go(): req = self.make_request('POST', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual("<MatchInfo: not found>", repr(match_info)) self.loop.run_until_complete(go()) def test_not_allowed_repr(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/path/to', handler) handler2 = self.make_handler() self.router.add_route('POST', '/path/to', handler2) req = self.make_request('PUT', '/path/to') match_info = yield from self.router.resolve(req) self.assertEqual( "<MatchInfo: method PUT is not allowed " "(allowed methods: GET, POST>", repr(match_info)) self.loop.run_until_complete(go()) def test_default_expect_handler(self): route = self.router.add_route('GET', '/', self.make_handler()) self.assertIs(route._expect_handler, _defaultExpectHandler) def test_custom_expect_handler_plain(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route('GET', '/', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, PlainRoute) def test_custom_expect_handler_dynamic(self): @asyncio.coroutine def handler(request): pass route = self.router.add_route('GET', '/get/{name}', self.make_handler(), expect_handler=handler) self.assertIs(route._expect_handler, handler) self.assertIsInstance(route, DynamicRoute) def test_expect_handler_non_coroutine(self): def handler(request): pass self.assertRaises(AssertionError, self.router.add_route, 'GET', '/', self.make_handler(), expect_handler=handler) def test_dynamic_match_non_ascii(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{var}', handler) req = self.make_request( 'GET', '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82') match_info = yield from self.router.resolve(req) self.assertEqual({'var': 'рус текст'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_with_static_part(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.html', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file'}, match_info) self.loop.run_until_complete(go()) def test_dynamic_match_two_part2(self): @asyncio.coroutine def go(): handler = self.make_handler() self.router.add_route('GET', '/{name}.{ext}', handler) req = self.make_request('GET', '/file.html') match_info = yield from self.router.resolve(req) self.assertEqual({'name': 'file', 'ext': 'html'}, match_info) self.loop.run_until_complete(go())
def __init__(self, path, *, name=None): super(ParentResource, self).__init__(name=name) self._path = path.rstrip('/') self.router = UrlDispatcher()
class TestUrlDispatcher(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) self.router = UrlDispatcher() def tearDown(self): self.loop.close() def make_request(self, method, path, headers=MultiDict(), *, version=HttpVersion(1, 1), closing=False): self.app = mock.Mock() message = RawRequestMessage(method, path, version, headers, closing, False) self.payload = mock.Mock() self.writer = mock.Mock() req = Request(self.app, message, self.payload, self.writer) return req def test_add_route_root(self): handler = lambda req: Response(req) self.router.add_route('GET', '/', handler) req = self.make_request('GET', '/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) def test_add_route_simple(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/to/path', handler) req = self.make_request('GET', '/handler/to/path') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual(0, len(info)) self.assertIs(handler, info.handler) def test_add_with_matchdict(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/{to}', handler) req = self.make_request('GET', '/handler/tail') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({'to': 'tail'}, info) self.assertIs(handler, info.handler) def test_add_with_tailing_slash(self): handler = lambda req: Response(req) self.router.add_route('GET', '/handler/to/path/', handler) req = self.make_request('GET', '/handler/to/path/') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler, info.handler) def test_add_invalid_path(self): with self.assertRaises(ValueError): self.router.add_route('GET', '/{/', lambda req: None) def test_match_second_result_in_table(self): handler1 = lambda req: Response(req) handler2 = lambda req: Response(req) self.router.add_route('GET', '/h1', handler1) self.router.add_route('POST', '/h2', handler2) req = self.make_request('POST', '/h2') info = self.loop.run_until_complete(self.router.resolve(req)) self.assertIsNotNone(info) self.assertEqual({}, info) self.assertIs(handler2, info.handler) def test_raise_method_not_allowed(self): handler1 = lambda req: Response(req) handler2 = lambda req: Response(req) self.router.add_route('GET', '/', handler1) self.router.add_route('POST', '/', handler2) req = self.make_request('PUT', '/') with self.assertRaises(HTTPMethodNotAllowed) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual('PUT', exc.method) self.assertEqual(405, exc.status) self.assertEqual({'POST', 'GET'}, exc.allowed_methods) def test_raise_method_not_found(self): handler = lambda req: Response(req) self.router.add_route('GET', '/a', handler) req = self.make_request('GET', '/b') with self.assertRaises(HTTPNotFound) as ctx: self.loop.run_until_complete(self.router.resolve(req)) exc = ctx.exception self.assertEqual(404, exc.status)