Skip to content

fix(tests): give the _as cleanup guards a runtime-local token client - #109

Merged
olavgg merged 1 commit into
mainfrom
fix/cleanup-guard-own-config
Sep 2, 2026
Merged

fix(tests): give the _as cleanup guards a runtime-local token client#109
olavgg merged 1 commit into
mainfrom
fix/cleanup-guard-own-config

Conversation

@JosteinGj

Copy link
Copy Markdown
Contributor

The teardown guard already knew it must not reuse the test's HTTP client - its connection-pool tasks belong to the test's runtime - and builds its own ApiService inside the teardown runtime for exactly that reason. What the module doc missed is that there are two clients. A DataHubConfig carries one of its own for the token endpoint, and the _as guards take a config from the test, so building an ApiService from it replaced the REST client and left the token one pointing at the test's runtime.

That deadlocks rather than erroring, because the test's runtime is not busy but blocked: drop parks in thread::scope until teardown returns, so the one thread that could drive the connection is waiting for the thread waiting for it. A valid cached token hides it - get_api_token returns without touching the network - so it only surfaces once the token has been invalidated (a 401 clears it) or has expired. That is how one failing ACL test wedged the whole suite for 19 minutes with no output.

Measured, driving the same teardown three ways: after the test runtime is dropped, ~6ms; while it is blocked, never returns; while it is blocked but with a runtime-local client, ~74ms.

The regression test reproduces the blocked-runtime half faithfully (the drop runs on its own thread while the test blocks waiting for it) so a deadlock fails an assertion in 30s instead of stalling the suite silently. Verified both ways: it fails without the fix and passes with it.

The teardown guard already knew it must not reuse the test's HTTP client -
its connection-pool tasks belong to the test's runtime - and builds its own
ApiService inside the teardown runtime for exactly that reason. What the
module doc missed is that there are *two* clients. A DataHubConfig carries
one of its own for the token endpoint, and the `_as` guards take a config
from the test, so building an ApiService from it replaced the REST client
and left the token one pointing at the test's runtime.

That deadlocks rather than erroring, because the test's runtime is not busy
but *blocked*: drop parks in thread::scope until teardown returns, so the one
thread that could drive the connection is waiting for the thread waiting for
it. A valid cached token hides it - get_api_token returns without touching
the network - so it only surfaces once the token has been invalidated (a 401
clears it) or has expired. That is how one failing ACL test wedged the whole
suite for 19 minutes with no output.

Measured, driving the same teardown three ways: after the test runtime is
dropped, ~6ms; while it is blocked, never returns; while it is blocked but
with a runtime-local client, ~74ms.

The regression test reproduces the blocked-runtime half faithfully (the drop
runs on its own thread while the test blocks waiting for it) so a deadlock
fails an assertion in 30s instead of stalling the suite silently. Verified
both ways: it fails without the fix and passes with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JosteinGj
JosteinGj requested a review from olavgg September 2, 2026 10:45
@olavgg
olavgg merged commit 71769e4 into main Sep 2, 2026
18 checks passed
@olavgg
olavgg deleted the fix/cleanup-guard-own-config branch September 2, 2026 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants