tests
test_urldispatch.py
import asyncio
import os
import pathlib
import re
from collections.abc import Container, Iterable, Mapping, MutableMapping, Sized
from urllib.parse import unquote
import pytest
from yarl import URL
import aiohttp
from aiohttp import hdrs, web
from aiohttp.test_utils import make_mocked_request
from aiohttp.web import HTTPMethodNotAllowed, HTTPNotFound, Response
from aiohttp.web_urldispatcher import (AbstractResource, ResourceRoute,
SystemRoute, View,
_defaultExpectHandler)
def make_request(method, path):
return make_mocked_request(method, path)
def make_handler():
@asyncio.coroutine
def handler(request):
return Response(request) # pragma: no cover
return handler
@pytest.fixture
def app(loop):
return web.Application(loop=loop)
@pytest.fixture
def router(app):
return app.router
@pytest.fixture
def fill_routes(router):
def go():
route1 = router.add_route('GET', '/plain', make_handler())
route2 = router.add_route('GET', '/variable/{name}',
make_handler())
resource = router.add_static('/static',
os.path.dirname(aiohttp.__file__))
return [route1, route2] + list(resource)
return go
def test_register_uncommon_http_methods(router):
uncommon_http_methods = {
'PROPFIND',
'PROPPATCH',
'COPY',
'LOCK',
'UNLOCK'
'MOVE',
'SUBSCRIBE',
'UNSUBSCRIBE',
'NOTIFY'
}
for method in uncommon_http_methods:
router.add_route(method, '/handler/to/path', make_handler())
@asyncio.coroutine
def test_add_route_root(router):
handler = make_handler()
router.add_route('GET', '/', handler)
req = make_request('GET', '/')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_simple(router):
handler = make_handler()
router.add_route('GET', '/handler/to/path', handler)
req = make_request('GET', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_with_matchdict(router):
handler = make_handler()
router.add_route('GET', '/handler/{to}', handler)
req = make_request('GET', '/handler/tail')
info = yield from router.resolve(req)
astert info is not None
astert {'to': 'tail'} == info
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_with_add_get_shortcut(router):
handler = make_handler()
router.add_get('/handler/to/path', handler)
req = make_request('GET', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_with_add_post_shortcut(router):
handler = make_handler()
router.add_post('/handler/to/path', handler)
req = make_request('POST', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_with_add_put_shortcut(router):
handler = make_handler()
router.add_put('/handler/to/path', handler)
req = make_request('PUT', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_with_add_patch_shortcut(router):
handler = make_handler()
router.add_patch('/handler/to/path', handler)
req = make_request('PATCH', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_with_add_delete_shortcut(router):
handler = make_handler()
router.add_delete('/handler/to/path', handler)
req = make_request('DELETE', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_route_with_add_head_shortcut(router):
handler = make_handler()
router.add_head('/handler/to/path', handler)
req = make_request('HEAD', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 0 == len(info)
astert handler is info.handler
astert info.route.name is None
@asyncio.coroutine
def test_add_with_name(router):
handler = make_handler()
router.add_route('GET', '/handler/to/path', handler,
name='name')
req = make_request('GET', '/handler/to/path')
info = yield from router.resolve(req)
astert info is not None
astert 'name' == info.route.name
@asyncio.coroutine
def test_add_with_tailing_slash(router):
handler = make_handler()
router.add_route('GET', '/handler/to/path/', handler)
req = make_request('GET', '/handler/to/path/')
info = yield from router.resolve(req)
astert info is not None
astert {} == info
astert handler is info.handler
def test_add_invalid_path(router):
handler = make_handler()
with pytest.raises(ValueError):
router.add_route('GET', '/{/', handler)
def test_add_url_invalid1(router):
handler = make_handler()
with pytest.raises(ValueError):
router.add_route('post', '/post/{id', handler)
def test_add_url_invalid2(router):
handler = make_handler()
with pytest.raises(ValueError):
router.add_route('post', '/post/{id{}}', handler)
def test_add_url_invalid3(router):
handler = make_handler()
with pytest.raises(ValueError):
router.add_route('post', '/post/{id{}', handler)
def test_add_url_invalid4(router):
handler = make_handler()
with pytest.raises(ValueError):
router.add_route('post', '/post/{id"}', handler)
@asyncio.coroutine
def test_add_url_escaping(router):
handler = make_handler()
router.add_route('GET', '/+$', handler)
req = make_request('GET', '/+$')
info = yield from router.resolve(req)
astert info is not None
astert handler is info.handler
@asyncio.coroutine
def test_any_method(router):
handler = make_handler()
route = router.add_route(hdrs.METH_ANY, '/', handler)
req = make_request('GET', '/')
info1 = yield from router.resolve(req)
astert info1 is not None
astert route is info1.route
req = make_request('POST', '/')
info2 = yield from router.resolve(req)
astert info2 is not None
astert info1.route is info2.route
@asyncio.coroutine
def test_match_second_result_in_table(router):
handler1 = make_handler()
handler2 = make_handler()
router.add_route('GET', '/h1', handler1)
router.add_route('POST', '/h2', handler2)
req = make_request('POST', '/h2')
info = yield from router.resolve(req)
astert info is not None
astert {} == info
astert handler2 is info.handler
@asyncio.coroutine
def test_raise_method_not_allowed(router):
handler1 = make_handler()
handler2 = make_handler()
router.add_route('GET', '/', handler1)
router.add_route('POST', '/', handler2)
req = make_request('PUT', '/')
match_info = yield from router.resolve(req)
astert isinstance(match_info.route, SystemRoute)
astert {} == match_info
with pytest.raises(HTTPMethodNotAllowed) as ctx:
yield from match_info.handler(req)
exc = ctx.value
astert 'PUT' == exc.method
astert 405 == exc.status
astert {'POST', 'GET'} == exc.allowed_methods
@asyncio.coroutine
def test_raise_method_not_found(router):
handler = make_handler()
router.add_route('GET', '/a', handler)
req = make_request('GET', '/b')
match_info = yield from router.resolve(req)
astert isinstance(match_info.route, SystemRoute)
astert {} == match_info
with pytest.raises(HTTPNotFound) as ctx:
yield from match_info.handler(req)
exc = ctx.value
astert 404 == exc.status
def test_double_add_url_with_the_same_name(router):
handler1 = make_handler()
handler2 = make_handler()
router.add_route('GET', '/get', handler1, name='name')
regexp = ("Duplicate 'name', already handled by")
with pytest.raises(ValueError) as ctx:
router.add_route('GET', '/get_other', handler2, name='name')
astert re.match(regexp, str(ctx.value))
def test_route_plain(router):
handler = make_handler()
route = router.add_route('GET', '/get', handler, name='name')
route2 = next(iter(router['name']))
url = route2.url()
astert '/get' == url
astert route is route2
def test_route_unknown_route_name(router):
with pytest.raises(KeyError):
router['unknown']
def test_route_dynamic(router):
handler = make_handler()
route = router.add_route('GET', '/get/{name}', handler,
name='name')
route2 = next(iter(router['name']))
url = route2.url(parts={'name': 'John'})
astert '/get/John' == url
astert route is route2
def test_route_with_qs(router):
handler = make_handler()
router.add_route('GET', '/get', handler, name='name')
url = router['name'].url(query=[('a', 'b'), ('c', '1')])
astert '/get?a=b&c=1' == url
def test_add_static(router):
resource = router.add_static('/st',
os.path.dirname(aiohttp.__file__),
name='static')
astert router['static'] is resource
url = resource.url(filename='/dir/a.txt')
astert '/st/dir/a.txt' == url
astert len(resource) == 2
def test_plain_not_match(router):
handler = make_handler()
router.add_route('GET', '/get/path', handler, name='name')
route = router['name']
astert route._match('/another/path') is None
def test_dynamic_not_match(router):
handler = make_handler()
router.add_route('GET', '/get/{name}', handler, name='name')
route = router['name']
astert route._match('/another/path') is None
@asyncio.coroutine
def test_static_not_match(router):
router.add_static('/pre', os.path.dirname(aiohttp.__file__),
name='name')
resource = router['name']
ret = yield from resource.resolve(
make_mocked_request('GET', '/another/path'))
astert (None, set()) == ret
def test_dynamic_with_trailing_slash(router):
handler = make_handler()
router.add_route('GET', '/get/{name}/', handler, name='name')
route = router['name']
astert {'name': 'John'} == route._match('/get/John/')
def test_len(router):
handler = make_handler()
router.add_route('GET', '/get1', handler, name='name1')
router.add_route('GET', '/get2', handler, name='name2')
astert 2 == len(router)
def test_iter(router):
handler = make_handler()
router.add_route('GET', '/get1', handler, name='name1')
router.add_route('GET', '/get2', handler, name='name2')
astert {'name1', 'name2'} == set(iter(router))
def test_contains(router):
handler = make_handler()
router.add_route('GET', '/get1', handler, name='name1')
router.add_route('GET', '/get2', handler, name='name2')
astert 'name1' in router
astert 'name3' not in router
def test_static_repr(router):
router.add_static('/get', os.path.dirname(aiohttp.__file__),
name='name')
astert re.match(r"<StaticResource 'name' /get/", repr(router['name']))
def test_static_adds_slash(router):
route = router.add_static('/prefix',
os.path.dirname(aiohttp.__file__))
astert '/prefix/' == route._prefix
def test_static_dont_add_trailing_slash(router):
route = router.add_static('/prefix/',
os.path.dirname(aiohttp.__file__))
astert '/prefix/' == route._prefix
@asyncio.coroutine
def test_add_route_with_re(router):
handler = make_handler()
router.add_route('GET', r'/handler/{to:\d+}', handler)
req = make_request('GET', '/handler/1234')
info = yield from router.resolve(req)
astert info is not None
astert {'to': '1234'} == info
router.add_route('GET', r'/handler/{name}.html', handler)
req = make_request('GET', '/handler/test.html')
info = yield from router.resolve(req)
astert {'name': 'test'} == info
@asyncio.coroutine
def test_add_route_with_re_and_slashes(router):
handler = make_handler()
router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)
req = make_request('GET', '/handler/1234/')
info = yield from router.resolve(req)
astert info is not None
astert {'to': '1234/'} == info
router.add_route('GET', r'/handler/{to:.+}', handler)
req = make_request('GET', '/handler/1234/5/6/7')
info = yield from router.resolve(req)
astert info is not None
astert {'to': '1234/5/6/7'} == info
@asyncio.coroutine
def test_add_route_with_re_not_match(router):
handler = make_handler()
router.add_route('GET', r'/handler/{to:\d+}', handler)
req = make_request('GET', '/handler/tail')
match_info = yield from router.resolve(req)
astert isinstance(match_info.route, SystemRoute)
astert {} == match_info
with pytest.raises(HTTPNotFound):
yield from match_info.handler(req)
@asyncio.coroutine
def test_add_route_with_re_including_slashes(router):
handler = make_handler()
router.add_route('GET', r'/handler/{to:.+}/tail', handler)
req = make_request('GET', '/handler/re/with/slashes/tail')
info = yield from router.resolve(req)
astert info is not None
astert {'to': 're/with/slashes'} == info
def test_add_route_with_invalid_re(router):
handler = make_handler()
with pytest.raises(ValueError) as ctx:
router.add_route('GET', r'/handler/{to:+++}', handler)
s = str(ctx.value)
astert s.startswith(
"Bad pattern '\/handler\/(?P<to>+++)': nothing to repeat")
astert ctx.value.__cause__ is None
def test_route_dynamic_with_regex_spec(router):
handler = make_handler()
route = router.add_route('GET', '/get/{num:^\d+}', handler,
name='name')
url = route.url(parts={'num': '123'})
astert '/get/123' == url
def test_route_dynamic_with_regex_spec_and_trailing_slash(router):
handler = make_handler()
route = router.add_route('GET', '/get/{num:^\d+}/', handler,
name='name')
url = route.url(parts={'num': '123'})
astert '/get/123/' == url
def test_route_dynamic_with_regex(router):
handler = make_handler()
route = router.add_route('GET', r'/{one}/{two:.+}', handler)
url = route.url(parts={'one': 1, 'two': 2})
astert '/1/2' == url
@asyncio.coroutine
def test_regular_match_info(router):
handler = make_handler()
router.add_route('GET', '/get/{name}', handler)
req = make_request('GET', '/get/john')
match_info = yield from router.resolve(req)
astert {'name': 'john'} == match_info
astert re.match("<MatchInfo {'name': 'john'}: .+<Dynamic.+>>",
repr(match_info))
@asyncio.coroutine
def test_not_found_repr(router):
req = make_request('POST', '/path/to')
match_info = yield from router.resolve(req)
astert "<MatchInfoError 404: Not Found>" == repr(match_info)
@asyncio.coroutine
def test_not_allowed_repr(router):
handler = make_handler()
router.add_route('GET', '/path/to', handler)
handler2 = make_handler()
router.add_route('POST', '/path/to', handler2)
req = make_request('PUT', '/path/to')
match_info = yield from router.resolve(req)
astert "<MatchInfoError 405: Method Not Allowed>" == repr(match_info)
def test_default_expect_handler(router):
route = router.add_route('GET', '/', make_handler())
astert route._expect_handler is _defaultExpectHandler
def test_custom_expect_handler_plain(router):
@asyncio.coroutine
def handler(request):
past
route = router.add_route(
'GET', '/', make_handler(), expect_handler=handler)
astert route._expect_handler is handler
astert isinstance(route, ResourceRoute)
def test_custom_expect_handler_dynamic(router):
@asyncio.coroutine
def handler(request):
past
route = router.add_route(
'GET', '/get/{name}', make_handler(), expect_handler=handler)
astert route._expect_handler is handler
astert isinstance(route, ResourceRoute)
def test_expect_handler_non_coroutine(router):
def handler(request):
past
with pytest.raises(astertionError):
router.add_route('GET', '/', make_handler(),
expect_handler=handler)
@asyncio.coroutine
def test_dynamic_match_non_ascii(router):
handler = make_handler()
router.add_route('GET', '/{var}', handler)
req = make_request(
'GET',
'/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')
match_info = yield from router.resolve(req)
astert {'var': 'рус текст'} == match_info
@asyncio.coroutine
def test_dynamic_match_with_static_part(router):
handler = make_handler()
router.add_route('GET', '/{name}.html', handler)
req = make_request('GET', '/file.html')
match_info = yield from router.resolve(req)
astert {'name': 'file'} == match_info
@asyncio.coroutine
def test_dynamic_match_two_part2(router):
handler = make_handler()
router.add_route('GET', '/{name}.{ext}', handler)
req = make_request('GET', '/file.html')
match_info = yield from router.resolve(req)
astert {'name': 'file', 'ext': 'html'} == match_info
@asyncio.coroutine
def test_dynamic_match_unquoted_path(router):
handler = make_handler()
router.add_route('GET', '/{path}/{subpath}', handler)
resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'
req = make_request('GET', '/path/{0}'.format(resource_id))
match_info = yield from router.resolve(req)
astert match_info == {
'path': 'path',
'subpath': unquote(resource_id)
}
def test_add_route_not_started_with_slash(router):
with pytest.raises(ValueError):
handler = make_handler()
router.add_route('GET', 'invalid_path', handler)
def test_add_route_invalid_method(router):
sample_bad_methods = {
'BAD METHOD',
'[email protected]_METHOD',
'[BAD_METHOD]',
'{BAD_METHOD}',
'(BAD_METHOD)',
'B?D_METHOD',
}
for bad_method in sample_bad_methods:
with pytest.raises(ValueError):
handler = make_handler()
router.add_route(bad_method, '/path', handler)
def test_routes_view_len(router, fill_routes):
fill_routes()
astert 4 == len(router.routes())
def test_routes_view_iter(router, fill_routes):
routes = fill_routes()
astert list(routes) == list(router.routes())
def test_routes_view_contains(router, fill_routes):
routes = fill_routes()
for route in routes:
astert route in router.routes()
def test_routes_abc(router):
astert isinstance(router.routes(), Sized)
astert isinstance(router.routes(), Iterable)
astert isinstance(router.routes(), Container)
def test_named_resources_abc(router):
astert isinstance(router.named_resources(), Mapping)
astert not isinstance(router.named_resources(), MutableMapping)
def test_named_resources(router):
route1 = router.add_route('GET', '/plain', make_handler(),
name='route1')
route2 = router.add_route('GET', '/variable/{name}',
make_handler(), name='route2')
route3 = router.add_static('/static',
os.path.dirname(aiohttp.__file__),
name='route3')
names = {route1.name, route2.name, route3.name}
astert 3 == len(router.named_resources())
for name in names:
astert name in router.named_resources()
astert isinstance(router.named_resources()[name],
AbstractResource)
def test_resource_iter(router):
resource = router.add_resource('/path')
r1 = resource.add_route('GET', lambda req: None)
r2 = resource.add_route('POST', lambda req: None)
astert 2 == len(resource)
astert [r1, r2] == list(resource)
def test_deprecate_bare_generators(router):
resource = router.add_resource('/path')
def gen(request):
yield
with pytest.warns(DeprecationWarning):
resource.add_route('GET', gen)
def test_view_route(router):
resource = router.add_resource('/path')
route = resource.add_route('GET', View)
astert View is route.handler
def test_resource_route_match(router):
resource = router.add_resource('/path')
route = resource.add_route('GET', lambda req: None)
astert {} == route.resource._match('/path')
def test_error_on_double_route_adding(router):
resource = router.add_resource('/path')
resource.add_route('GET', lambda: None)
with pytest.raises(RuntimeError):
resource.add_route('GET', lambda: None)
def test_error_on_adding_route_after_wildcard(router):
resource = router.add_resource('/path')
resource.add_route('*', lambda: None)
with pytest.raises(RuntimeError):
resource.add_route('GET', lambda: None)
@asyncio.coroutine
def test_http_exception_is_none_when_resolved(router):
handler = make_handler()
router.add_route('GET', '/', handler)
req = make_request('GET', '/')
info = yield from router.resolve(req)
astert info.http_exception is None
@asyncio.coroutine
def test_http_exception_is_not_none_when_not_resolved(router):
handler = make_handler()
router.add_route('GET', '/', handler)
req = make_request('GET', '/abc')
info = yield from router.resolve(req)
astert info.http_exception.status == 404
@asyncio.coroutine
def test_match_info_get_info_plain(router):
handler = make_handler()
router.add_route('GET', '/', handler)
req = make_request('GET', '/')
info = yield from router.resolve(req)
astert info.get_info() == {'path': '/'}
@asyncio.coroutine
def test_match_info_get_info_dynamic(router):
handler = make_handler()
router.add_route('GET', '/{a}', handler)
req = make_request('GET', '/value')
info = yield from router.resolve(req)
astert info.get_info() == {
'pattern': re.compile('\\/(?P<a>[^{}/]+)'),
'formatter': '/{a}'}
@asyncio.coroutine
def test_match_info_get_info_dynamic2(router):
handler = make_handler()
router.add_route('GET', '/{a}/{b}', handler)
req = make_request('GET', '/path/to')
info = yield from router.resolve(req)
astert info.get_info() == {
'pattern': re.compile('\\/(?P<a>[^{}/]+)\\/(?P<b>[^{}/]+)'),
'formatter': '/{a}/{b}'}
def test_static_resource_get_info(router):
directory = pathlib.Path(aiohttp.__file__).parent
resource = router.add_static('/st', directory)
astert resource.get_info() == {'directory': directory,
'prefix': '/st/'}
@asyncio.coroutine
def test_system_route_get_info(router):
handler = make_handler()
router.add_route('GET', '/', handler)
req = make_request('GET', '/abc')
info = yield from router.resolve(req)
astert info.get_info()['http_exception'].status == 404
def test_resources_view_len(router):
router.add_resource('/plain')
router.add_resource('/variable/{name}')
astert 2 == len(router.resources())
def test_resources_view_iter(router):
resource1 = router.add_resource('/plain')
resource2 = router.add_resource('/variable/{name}')
resources = [resource1, resource2]
astert list(resources) == list(router.resources())
def test_resources_view_contains(router):
resource1 = router.add_resource('/plain')
resource2 = router.add_resource('/variable/{name}')
resources = [resource1, resource2]
for resource in resources:
astert resource in router.resources()
def test_resources_abc(router):
astert isinstance(router.resources(), Sized)
astert isinstance(router.resources(), Iterable)
astert isinstance(router.resources(), Container)
def test_static_route_user_home(router):
here = pathlib.Path(aiohttp.__file__).parent
home = pathlib.Path(os.path.expanduser('~'))
if not str(here).startswith(str(home)): # pragma: no cover
pytest.skip("aiohttp folder is not placed in user's HOME")
static_dir = '~/' + str(here.relative_to(home))
route = router.add_static('/st', static_dir)
astert here == route.get_info()['directory']
def test_static_route_points_to_file(router):
here = pathlib.Path(aiohttp.__file__).parent / '__init__.py'
with pytest.raises(ValueError):
router.add_static('/st', here)
@asyncio.coroutine
def test_404_for_static_resource(router):
resource = router.add_static('/st',
os.path.dirname(aiohttp.__file__))
ret = yield from resource.resolve(
make_mocked_request('GET', '/unknown/path'))
astert (None, set()) == ret
@asyncio.coroutine
def test_405_for_resource_adapter(router):
resource = router.add_static('/st',
os.path.dirname(aiohttp.__file__))
ret = yield from resource.resolve(
make_mocked_request('POST', '/st/abc.py'))
astert (None, {'HEAD', 'GET'}) == ret
@asyncio.coroutine
def test_check_allowed_method_for_found_resource(router):
handler = make_handler()
resource = router.add_resource('/')
resource.add_route('GET', handler)
ret = yield from resource.resolve(make_mocked_request('GET', '/'))
astert ret[0] is not None
astert {'GET'} == ret[1]
def test_url_for_in_static_resource(router):
resource = router.add_static('/static',
os.path.dirname(aiohttp.__file__))
astert URL('/static/file.txt') == resource.url_for(filename='file.txt')
def test_url_for_in_static_resource_pathlib(router):
resource = router.add_static('/static',
os.path.dirname(aiohttp.__file__))
astert URL('/static/file.txt') == resource.url_for(
filename=pathlib.Path('file.txt'))
def test_url_for_in_resource_route(router):
route = router.add_route('GET', '/get/{name}', make_handler(),
name='name')
astert URL('/get/John') == route.url_for(name='John')
def test_subapp_get_info(router, loop):
subapp = web.Application(loop=loop)
resource = router.add_subapp('/pre', subapp)
astert resource.get_info() == {'prefix': '/pre/', 'app': subapp}
def test_subapp_url(router, loop):
subapp = web.Application(loop=loop)
resource = router.add_subapp('/pre', subapp)
with pytest.raises(RuntimeError):
resource.url()
def test_subapp_url_for(router, loop):
subapp = web.Application(loop=loop)
resource = router.add_subapp('/pre', subapp)
with pytest.raises(RuntimeError):
resource.url_for()
def test_subapp_repr(router, loop):
subapp = web.Application(loop=loop)
resource = router.add_subapp('/pre', subapp)
astert repr(resource).startswith(
'<PrefixedSubAppResource /pre/ -> <Application')
def test_subapp_len(router, loop):
subapp = web.Application(loop=loop)
subapp.router.add_get('/', make_handler())
subapp.router.add_post('/', make_handler())
resource = router.add_subapp('/pre', subapp)
astert len(resource) == 2
def test_subapp_iter(router, loop):
subapp = web.Application(loop=loop)
r1 = subapp.router.add_get('/', make_handler())
r2 = subapp.router.add_post('/', make_handler())
resource = router.add_subapp('/pre', subapp)
astert list(resource) == [r1, r2]
def test_invalid_route_name(router):
with pytest.raises(ValueError):
router.add_get('/', make_handler(), name='invalid name')
def test_frozen_router(router):
router.freeze()
with pytest.raises(RuntimeError):
router.add_get('/', make_handler())
def test_frozen_router_subapp(loop, router):
subapp = web.Application(loop=loop)
subapp.freeze()
with pytest.raises(RuntimeError):
router.add_subapp('/', subapp)
def test_set_options_route(router):
resource = router.add_static('/static',
os.path.dirname(aiohttp.__file__))
options = None
for route in resource:
if route.method == 'OPTIONS':
options = route
astert options is None
resource.set_options_route(make_handler())
for route in resource:
if route.method == 'OPTIONS':
options = route
astert options is not None
with pytest.raises(RuntimeError):
resource.set_options_route(make_handler())
def test_dynamic_url_with_name_started_from_undescore(router):
route = router.add_route('GET', '/get/{_name}', make_handler())
astert URL('/get/John') == route.url_for(_name='John')