Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
 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
     )
Exemplo n.º 4
0
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}')
Exemplo n.º 5
0
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 + '/'
Exemplo n.º 6
0
 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}")
Exemplo n.º 7
0
    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))
Exemplo n.º 8
0
 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
Exemplo n.º 9
0
    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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
 def __init__(self, application):
     self._dispatcher = UrlDispatcher()
     self._application = application
Exemplo n.º 12
0
 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)
Exemplo n.º 13
0
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())
Exemplo n.º 14
0
 def register(self, router: web.UrlDispatcher) -> web.AbstractRoute:
     return router.add_route(self.method,
                             self.path,
                             self.handler,
                             name=self.name)
Exemplo n.º 15
0
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/")
Exemplo n.º 16
0
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')
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
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)
Exemplo n.º 19
0
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])
Exemplo n.º 20
0
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)
Exemplo n.º 21
0
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']),
    ])
Exemplo n.º 22
0
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])
Exemplo n.º 23
0
def router():
    return UrlDispatcher()
Exemplo n.º 24
0
 def __init__(self, application):
     self._dispatcher = UrlDispatcher()
     self._application = application
Exemplo n.º 25
0
 def setUp(self):
     self.loop = asyncio.new_event_loop()
     asyncio.set_event_loop(None)
     self.router = UrlDispatcher()
Exemplo n.º 26
0
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)
Exemplo n.º 27
0
 def setUp(self):
     self.loop = asyncio.new_event_loop()
     asyncio.set_event_loop(None)
     self.router = UrlDispatcher()
Exemplo n.º 28
0
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())
Exemplo n.º 29
0
 def __init__(self, path, *, name=None):
     super(ParentResource, self).__init__(name=name)
     self._path = path.rstrip('/')
     self.router = UrlDispatcher()
Exemplo n.º 30
0
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)