66import random
77import string
88from pathlib import Path
9- from typing import NoReturn , Optional
9+ from typing import List , NoReturn , Optional , cast
1010from unittest import mock
1111
12+ import pytest
1213from multidict import CIMultiDict , CIMultiDictProxy
1314from pytest_codspeed import BenchmarkFixture
1415from yarl import URL
1819from aiohttp .http import HttpVersion , RawRequestMessage
1920
2021
22+ @pytest .fixture
23+ def github_urls () -> List [str ]:
24+ """GitHub api urls."""
25+ # The fixture provides OpenAPI generated info for github.
26+ # To update the local data file please run the following command:
27+ # $ curl https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json | jq ".paths | keys" > github-urls.json
28+
29+ here = Path (__file__ ).parent
30+ with (here / "github-urls.json" ).open () as f :
31+ urls = json .load (f )
32+
33+ return cast (List [str ], urls )
34+
35+
2136def _mock_request (method : str , path : str ) -> web .Request :
2237 message = RawRequestMessage (
2338 method ,
@@ -366,23 +381,15 @@ def _run() -> None:
366381def test_resolve_gitapi (
367382 loop : asyncio .AbstractEventLoop ,
368383 benchmark : BenchmarkFixture ,
384+ github_urls : List [str ],
369385) -> None :
370- """Resolve DynamicResource for simulated github API.
371-
372- The benchmark uses OpenAPI generated info for github.
373- To update the local data file please run the following command:
374- $ curl https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json | jq ".paths | keys" > github-urls.json
375- """
386+ """Resolve DynamicResource for simulated github API."""
376387
377388 async def handler (request : web .Request ) -> NoReturn :
378389 assert False
379390
380- here = Path (__file__ ).parent
381- with (here / "github-urls.json" ).open () as f :
382- urls = json .load (f )
383-
384391 app = web .Application ()
385- for url in urls :
392+ for url in github_urls :
386393 app .router .add_get (url , handler )
387394 app .freeze ()
388395 router = app .router
@@ -425,21 +432,13 @@ def _run() -> None:
425432def test_resolve_gitapi_subapps (
426433 loop : asyncio .AbstractEventLoop ,
427434 benchmark : BenchmarkFixture ,
435+ github_urls : List [str ],
428436) -> None :
429- """Resolve DynamicResource for simulated github API, grouped in subapps.
430-
431- The benchmark uses OpenAPI generated info for github.
432- To update the local data file please run the following command:
433- $ curl https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json | jq ".paths | keys" > github-urls.json
434- """
437+ """Resolve DynamicResource for simulated github API, grouped in subapps."""
435438
436439 async def handler (request : web .Request ) -> NoReturn :
437440 assert False
438441
439- here = Path (__file__ ).parent
440- with (here / "github-urls.json" ).open () as f :
441- urls = json .load (f )
442-
443442 subapps = {
444443 "gists" : web .Application (),
445444 "orgs" : web .Application (),
@@ -451,7 +450,7 @@ async def handler(request: web.Request) -> NoReturn:
451450 }
452451
453452 app = web .Application ()
454- for url in urls :
453+ for url in github_urls :
455454 parts = url .split ("/" )
456455 subapp = subapps .get (parts [1 ])
457456 if subapp is not None :
@@ -501,6 +500,39 @@ def _run() -> None:
501500 loop .run_until_complete (run_url_dispatcher_benchmark ())
502501
503502
503+ def test_resolve_gitapi_root (
504+ loop : asyncio .AbstractEventLoop ,
505+ benchmark : BenchmarkFixture ,
506+ github_urls : List [str ],
507+ ) -> None :
508+ """Resolve the plain root for simulated github API."""
509+
510+ async def handler (request : web .Request ) -> NoReturn :
511+ assert False
512+
513+ app = web .Application ()
514+ for url in github_urls :
515+ app .router .add_get (url , handler )
516+ app .freeze ()
517+ router = app .router
518+
519+ request = _mock_request (method = "GET" , path = "/" )
520+
521+ async def run_url_dispatcher_benchmark () -> Optional [web .UrlMappingMatchInfo ]:
522+ ret = None
523+ for i in range (250 ):
524+ ret = await router .resolve (request )
525+ return ret
526+
527+ ret = loop .run_until_complete (run_url_dispatcher_benchmark ())
528+ assert ret is not None
529+ assert ret .get_info ()["path" ] == "/" , ret .get_info ()
530+
531+ @benchmark
532+ def _run () -> None :
533+ loop .run_until_complete (run_url_dispatcher_benchmark ())
534+
535+
504536def test_resolve_prefix_resources_many_prefix_many_plain (
505537 loop : asyncio .AbstractEventLoop ,
506538 benchmark : BenchmarkFixture ,
0 commit comments