From 8b87e881e5d58d82832333509e626a355647e473 Mon Sep 17 00:00:00 2001 From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Date: Tue, 29 Oct 2024 19:36:44 +0800 Subject: [PATCH 1/7] :bug: fix global asgi test client --- nonebug/fixture.py | 63 ++++++++++++++++++++++++++++------------- nonebug/mixin/driver.py | 27 ++++++++++++++++-- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/nonebug/fixture.py b/nonebug/fixture.py index 006cc4c..a046e8d 100644 --- a/nonebug/fixture.py +++ b/nonebug/fixture.py @@ -1,10 +1,50 @@ +from contextlib import asynccontextmanager, nullcontext + import pytest +from async_asgi_testclient import TestClient from nonebug.app import App +from nonebug.mixin.driver import set_global_client from . import NONEBOT_INIT_KWARGS, NONEBOT_START_LIFESPAN +@asynccontextmanager +async def lifespan_ctx(): + import nonebot + from nonebot.drivers import ASGIMixin + + driver = nonebot.get_driver() + + if isinstance(driver, ASGIMixin): + # if the driver has an asgi application + # use asgi lifespan to startup/shutdown + ctx = TestClient(driver.asgi) + set_global_client(ctx) + else: + ctx = driver._lifespan + + try: + await ctx.__aenter__() + except Exception as e: + logger.opt(colors=True, exception=e).error( + "Error occurred while running startup hook." + "" + ) + raise + + try: + yield + finally: + try: + await ctx.__aexit__(None, None, None) + except Exception as e: + logger.opt(colors=True, exception=e).error( + "Error occurred while running shutdown hook." + "" + ) + + @pytest.fixture(scope="session", autouse=True) async def nonebug_init(request: pytest.FixtureRequest): # noqa: PT004 """ @@ -20,28 +60,11 @@ async def nonebug_init(request: pytest.FixtureRequest): # noqa: PT004 matchers.set_provider(NoneBugProvider) run_lifespan = request.config.stash.get(NONEBOT_START_LIFESPAN, True) - driver = nonebot.get_driver() - if run_lifespan: - try: - await driver._lifespan.startup() - except Exception as e: - logger.opt(colors=True, exception=e).error( - "Error occurred while running startup hook." - "" - ) - raise - try: + ctx = lifespan_ctx() if run_lifespan else nullcontext() + + async with ctx: yield - finally: - if run_lifespan: - try: - await driver._lifespan.shutdown() - except Exception as e: - logger.opt(colors=True, exception=e).error( - "Error occurred while running shutdown hook." - "" - ) @pytest.fixture(name="app") diff --git a/nonebug/mixin/driver.py b/nonebug/mixin/driver.py index c14b1f8..eedd6d4 100644 --- a/nonebug/mixin/driver.py +++ b/nonebug/mixin/driver.py @@ -7,6 +7,20 @@ from nonebug.base import BaseApp, Context +_global_client: Optional[TestClient] = None + + +def set_global_client(client: TestClient): + global _global_client + + if _global_client is not None: + raise RuntimeError() + + +def get_global_client() -> Optional[TestClient]: + return _global_client + + @final class ServerContext(Context): def __init__( @@ -14,18 +28,21 @@ def __init__( app: BaseApp, *args, asgi: ASGIApplication, + client: Optional[TestClient] = None, **kwargs, ): super().__init__(app, *args, **kwargs) self.asgi = asgi + self.specified_client = client self.client = TestClient(self.asgi) def get_client(self) -> TestClient: - return self.client + return self.specified_client or self.client async def setup(self) -> None: await super().setup() - await self.stack.enter_async_context(self.client) + if self.specified_client is None: + await self.stack.enter_async_context(self.client) # @final @@ -50,8 +67,12 @@ class DriverMixin(BaseApp): def test_server(self, asgi: Optional[ASGIApplication] = None) -> ServerContext: import nonebot + client = None + if asgi is None: + client = get_global_client() + asgi = asgi or nonebot.get_asgi() - return ServerContext(self, asgi=asgi) + return ServerContext(self, asgi=asgi, client=client) # def test_client(self): # ... From b493a2862673b94a17b0266ac8ea114d84ad52ab Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:38:54 +0000 Subject: [PATCH 2/7] :rotating_light: auto fix by pre-commit hooks --- nonebug/fixture.py | 3 +-- nonebug/mixin/driver.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/nonebug/fixture.py b/nonebug/fixture.py index a046e8d..3e6c813 100644 --- a/nonebug/fixture.py +++ b/nonebug/fixture.py @@ -1,4 +1,4 @@ -from contextlib import asynccontextmanager, nullcontext +from contextlib import nullcontext, asynccontextmanager import pytest from async_asgi_testclient import TestClient @@ -51,7 +51,6 @@ async def nonebug_init(request: pytest.FixtureRequest): # noqa: PT004 Initialize nonebot before test case running. """ import nonebot - from nonebot import logger from nonebot.matcher import matchers from nonebug.provider import NoneBugProvider diff --git a/nonebug/mixin/driver.py b/nonebug/mixin/driver.py index eedd6d4..18f5617 100644 --- a/nonebug/mixin/driver.py +++ b/nonebug/mixin/driver.py @@ -6,7 +6,6 @@ from nonebug.base import BaseApp, Context - _global_client: Optional[TestClient] = None From aa2fb4a94ac698cdc10dc03e46fc79d9694a431c Mon Sep 17 00:00:00 2001 From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Date: Tue, 29 Oct 2024 19:40:32 +0800 Subject: [PATCH 3/7] :bug: fix import --- nonebug/fixture.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nonebug/fixture.py b/nonebug/fixture.py index 3e6c813..f93a32b 100644 --- a/nonebug/fixture.py +++ b/nonebug/fixture.py @@ -12,6 +12,7 @@ @asynccontextmanager async def lifespan_ctx(): import nonebot + from nonebot import logger from nonebot.drivers import ASGIMixin driver = nonebot.get_driver() From 7b757b76d27c162b874d6e442ca2e62350461dad Mon Sep 17 00:00:00 2001 From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:04:51 +0800 Subject: [PATCH 4/7] Update driver.py --- nonebug/mixin/driver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nonebug/mixin/driver.py b/nonebug/mixin/driver.py index 18f5617..bc79c77 100644 --- a/nonebug/mixin/driver.py +++ b/nonebug/mixin/driver.py @@ -15,6 +15,8 @@ def set_global_client(client: TestClient): if _global_client is not None: raise RuntimeError() + _global_client = client + def get_global_client() -> Optional[TestClient]: return _global_client From f7dca9ed4c7d5e10146373cf84a063cf7abb94de Mon Sep 17 00:00:00 2001 From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Date: Wed, 30 Oct 2024 06:53:11 +0000 Subject: [PATCH 5/7] :bug: fix startup before init setup --- nonebug/fixture.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nonebug/fixture.py b/nonebug/fixture.py index f93a32b..90a3acf 100644 --- a/nonebug/fixture.py +++ b/nonebug/fixture.py @@ -47,7 +47,7 @@ async def lifespan_ctx(): @pytest.fixture(scope="session", autouse=True) -async def nonebug_init(request: pytest.FixtureRequest): # noqa: PT004 +def _nonebot_init(request: pytest.FixtureRequest): """ Initialize nonebot before test case running. """ @@ -59,6 +59,14 @@ async def nonebug_init(request: pytest.FixtureRequest): # noqa: PT004 nonebot.init(**request.config.stash.get(NONEBOT_INIT_KWARGS, {})) matchers.set_provider(NoneBugProvider) + +@pytest.fixture(scope="session", autouse=True) +async def after_nonebot_init(_nonebot_init: None): # noqa: PT004 + pass + + +@pytest.fixture(scope="session", autouse=True) +async def nonebug_init(after_nonebot_init: None, request: pytest.FixtureRequest): # noqa: PT004 run_lifespan = request.config.stash.get(NONEBOT_START_LIFESPAN, True) ctx = lifespan_ctx() if run_lifespan else nullcontext() From cb4f075c065e74c7ff545e1a2ff11697e9d97c66 Mon Sep 17 00:00:00 2001 From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Date: Wed, 30 Oct 2024 07:16:41 +0000 Subject: [PATCH 6/7] :bug: fix test --- nonebug/fixture.py | 4 +++- tests/conftest.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nonebug/fixture.py b/nonebug/fixture.py index 90a3acf..6eea0ba 100644 --- a/nonebug/fixture.py +++ b/nonebug/fixture.py @@ -66,7 +66,9 @@ async def after_nonebot_init(_nonebot_init: None): # noqa: PT004 @pytest.fixture(scope="session", autouse=True) -async def nonebug_init(after_nonebot_init: None, request: pytest.FixtureRequest): # noqa: PT004 +async def nonebug_init( # noqa: PT004 + _nonebot_init: None, after_nonebot_init: None, request: pytest.FixtureRequest +): run_lifespan = request.config.stash.get(NONEBOT_START_LIFESPAN, True) ctx = lifespan_ctx() if run_lifespan else nullcontext() diff --git a/tests/conftest.py b/tests/conftest.py index 6685658..e3328dd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,6 +12,6 @@ def pytest_configure(config: pytest.Config) -> None: config.stash[NONEBOT_INIT_KWARGS] = {"custom_key": "custom_value"} -@pytest.fixture(scope="session") -def load_plugin(nonebug_init: None) -> set[Plugin]: +@pytest.fixture(scope="session", autouse=True) +async def after_nonebot_init(_nonebot_init: None) -> set[Plugin]: return nonebot.load_plugins(str(Path(__file__).parent / "plugins")) From 11642e54c43a487ed72c5067d7a9b17ac2c24f2d Mon Sep 17 00:00:00 2001 From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Date: Wed, 30 Oct 2024 08:19:57 +0000 Subject: [PATCH 7/7] :white_check_mark: fix test --- nonebug/fixture.py | 2 +- tests/conftest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nonebug/fixture.py b/nonebug/fixture.py index 6eea0ba..d7254f7 100644 --- a/nonebug/fixture.py +++ b/nonebug/fixture.py @@ -86,4 +86,4 @@ def nonebug_app(nonebug_init) -> App: return App() -__all__ = ["nonebug_init", "nonebug_app"] +__all__ = ["after_nonebot_init", "nonebug_init", "nonebug_app"] diff --git a/tests/conftest.py b/tests/conftest.py index e3328dd..76ba821 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ from nonebot.plugin import Plugin from nonebug import NONEBOT_INIT_KWARGS -from nonebug.fixture import * # noqa: F403 +from nonebug.fixture import nonebug_app, nonebug_init, _nonebot_init # noqa: F401 def pytest_configure(config: pytest.Config) -> None: @@ -13,5 +13,5 @@ def pytest_configure(config: pytest.Config) -> None: @pytest.fixture(scope="session", autouse=True) -async def after_nonebot_init(_nonebot_init: None) -> set[Plugin]: +async def after_nonebot_init(_nonebot_init: None) -> set[Plugin]: # noqa: F811 return nonebot.load_plugins(str(Path(__file__).parent / "plugins"))