Skip to content

Commit 65cbca3

Browse files
author
Review
committed
fix(tests): reset session adapters after import-time HTTP calls
The test conftest opens HTTP connections at import time via ``run_until_complete`` to check ``app_api`` capability and (later) NC version. After the sync removal in v0.31.0 those connections live in niquests AsyncSession pools bound to whatever event loop ran the ``run_until_complete`` call. pytest-asyncio runs the actual tests on a different loop, so the first request hits a stale pooled connection and fails with:: RuntimeError: got Future <Future pending> attached to a different loop Recreate the session adapters (``init_adapter(restart=True)`` and ``init_adapter_dav(restart=True)``) right after the import-time check so pytest's loop populates fresh empty pools lazily on first use. Apply the same reset after the version lookup in ``pytest_collection_modifyitems``, and short-circuit that hook entirely when no test carries the ``require_nc`` marker.
1 parent ea70a3c commit 65cbca3

1 file changed

Lines changed: 22 additions & 3 deletions

File tree

tests/conftest.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@
1010

1111
_TEST_FAILED_INCREMENTAL: dict[str, dict[tuple[int, ...], str]] = {}
1212

13+
14+
def _reset_session_adapters(client) -> None:
15+
"""Recreate AsyncSession adapters after import-time HTTP calls so pytest-asyncio's
16+
event loop can populate fresh connection pools bound to its own loop. Without this,
17+
connections opened here stay attached to whatever loop ran ``run_until_complete``
18+
and break with "Future attached to a different loop" once tests start."""
19+
if client is None:
20+
return
21+
client._session.init_adapter(restart=True)
22+
client._session.init_adapter_dav(restart=True)
23+
client._session._capabilities = {}
24+
25+
1326
NC_CLIENT = None if environ.get("SKIP_NC_CLIENT_TESTS", False) else Nextcloud()
1427
NC_CLIENT_ASYNC = NC_CLIENT
1528
if environ.get("SKIP_AA_TESTS", False):
@@ -23,6 +36,9 @@
2336
if NC_CLIENT is None and NC_APP is None:
2437
raise EnvironmentError("Tests require at least Nextcloud or NextcloudApp.")
2538

39+
_reset_session_adapters(NC_CLIENT)
40+
_reset_session_adapters(NC_APP)
41+
2642

2743
@pytest.fixture(scope="session")
2844
async def nc_version() -> _session.ServerVersion:
@@ -105,14 +121,17 @@ def pytest_generate_tests(metafunc):
105121

106122

107123
def pytest_collection_modifyitems(items):
124+
require_any = any("require_nc" in [m.name for m in item.own_markers] for item in items)
125+
if not require_any:
126+
return
127+
src = NC_APP if NC_APP else NC_CLIENT
128+
srv_ver = asyncio.get_event_loop().run_until_complete(src._session.nc_version)
129+
_reset_session_adapters(src)
108130
for item in items:
109131
require_nc = [i for i in item.own_markers if i.name == "require_nc"]
110132
if require_nc:
111133
min_major = require_nc[0].kwargs["major"]
112134
min_minor = require_nc[0].kwargs.get("minor", 0)
113-
srv_ver = asyncio.get_event_loop().run_until_complete(
114-
NC_APP._session.nc_version if NC_APP else NC_CLIENT._session.nc_version
115-
)
116135
if srv_ver["major"] < min_major:
117136
item.add_marker(pytest.mark.skip(reason=f"Need NC>={min_major}"))
118137
elif srv_ver["major"] == min_major and srv_ver["minor"] < min_minor:

0 commit comments

Comments
 (0)