diff --git a/tests/apis/test_api_requests.py b/tests/apis/test_api_requests.py index 1b5bb5c9..d6b05d0a 100644 --- a/tests/apis/test_api_requests.py +++ b/tests/apis/test_api_requests.py @@ -156,6 +156,10 @@ async def serve_slowly(): assert 0.1 < timer.seconds < 0.2 + # Let the server request finish and release all resources (tasks). + # TODO: Remove when fixed: https://github.com/aio-libs/aiohttp/issues/7551 + await asyncio.sleep(1.0) + @pytest.mark.parametrize('fn, method', [ (get, 'get'), @@ -182,6 +186,10 @@ async def serve_slowly(): assert 0.1 < timer.seconds < 0.2 + # Let the server request finish and release all resources (tasks). + # TODO: Remove when fixed: https://github.com/aio-libs/aiohttp/issues/7551 + await asyncio.sleep(1.0) + @pytest.mark.parametrize('method', ['get']) # the only supported method at the moment async def test_direct_timeout_in_streams( @@ -204,6 +212,10 @@ async def serve_slowly(): assert 0.1 < timer.seconds < 0.2 + # Let the server request finish and release all resources (tasks). + # TODO: Remove when fixed: https://github.com/aio-libs/aiohttp/issues/7551 + await asyncio.sleep(1.0) + @pytest.mark.parametrize('method', ['get']) # the only supported method at the moment async def test_settings_timeout_in_streams( @@ -226,6 +238,10 @@ async def serve_slowly(): assert 0.1 < timer.seconds < 0.2 + # Let the server request finish and release all resources (tasks). + # TODO: Remove when fixed: https://github.com/aio-libs/aiohttp/issues/7551 + await asyncio.sleep(1.0) + @pytest.mark.parametrize('delay, expected', [ pytest.param(0.0, [], id='instant-none'), diff --git a/tests/conftest.py b/tests/conftest.py index f7625ca3..bfa2fba0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -411,8 +411,34 @@ def clean_kubernetes_client(): kubernetes.client.configuration.Configuration.set_default(None) +# Aresponses/aiohttp must be closed strictly after the vault. See the docstring. @pytest.fixture() -def fake_vault(mocker, hostname): +async def _fake_vault(mocker, hostname, aresponses): + """ + A hack around pytest's internal flaw in order to close the vault in the end. + + We cannot keep both the ContextVar and vault closing in the same fixture. + Pytest runs every async setup and every async teardown in a separate task + (a separate ``run_until_complete()``). The `vault_var` remains invisible + to tests (with API calls) and even to the fixture's finalizing part. + Sync (global) context vars do work and propagate fine — hence 2 fixtures. + + Without the proper vault finalization, the cached TCP sessions/connections + remain open, so the aresponses/aiohttp test server takes time before exiting + (15 seconds of keep-alive timeout by default). + """ + key = VaultKey('fixture') + info = ConnectionInfo(server=f'https://{hostname}') + vault = Vault({key: info}) + mocker.patch.object(vault._ready, 'wait_for') + try: + yield vault + finally: + await vault.close() + + +@pytest.fixture() +def fake_vault(_fake_vault): """ Provide a freshly created and populated authentication vault for every test. @@ -424,15 +450,10 @@ def fake_vault(mocker, hostname): """ from kopf._cogs.clients import auth - key = VaultKey('fixture') - info = ConnectionInfo(server=f'https://{hostname}') - vault = Vault({key: info}) - token = auth.vault_var.set(vault) - mocker.patch.object(vault._ready, 'wait_for') + token = auth.vault_var.set(_fake_vault) try: - yield vault + yield _fake_vault finally: - # await vault.close() # TODO: but it runs in a different loop, w/ wrong contextvar. auth.vault_var.reset(token) #