test(plugins): stop the update check reaching the live registry mid-suite - #61
Merged
Merged
Conversation
…uite Semantic Release has been failing intermittently on master with exit 139: `uv run pytest` segfaulted partway through tests/ui, so the version/tag step never ran. The release job is fine — the suite was crashing. test_plugin_window_rows.py calls build_plugin_ui with the default settings, which arms the post-launch plugin update check on a 12 s QTimer. Six tests, six timers, none of them cancelled when the test that created them ended. They fired a quarter-minute later, inside whatever was running by then, each starting a daemon thread that fetched the real registry over HTTPS. CI's fault traceback caught it exactly there: five live threads in socket.getaddrinfo while the main thread was in tests/ui/test_pluginmanager.py's fixture, garbage-collecting the previous test's Qt objects. Sockets crossing another test's teardown is what segfaulted; whether it lands depends on suite timing, which is why this only started biting as the suite grew. Two changes, both in tests: - that helper turns update_check off, since the file is about window rows and never wanted the check; - tests/conftest.py grows a session-scoped guard that refuses any fetch_https_bytes call arriving without a transport. Session-scoped because the gap between tests is precisely where a leaked timer fires, and a function-scoped patch would already be unwound. The transport seam stays open, so patch_default_transport and the redirect/size tests are untouched. No product code changes. Full suite green offscreen (1994 passed) and ~20 s faster, since it no longer waits on live DNS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was failing
Semantic Release has been failing intermittently on
masterwith exit code 139 — theVerify release candidatestep (uv run pytest) segfaults partway throughtests/ui, soCalculate version, update changelog, commit, tag, and pushnever runs. Two of the last four runs died this way (31349283155, 31349817083). The release tooling is fine; the test suite was crashing.Why
tests/ui/test_plugin_window_rows.py::make_uicallsbuild_plugin_uiwith default settings, which arms the post-launch plugin update check on a 12 sQTimer. Six tests, six timers, and nothing cancels them when the test that created them ends. They fire a quarter-minute later — inside whatever test is running by then — each starting a daemon thread that fetches the real registry over HTTPS.CI's fault traceback caught it precisely there: five live threads in
socket.getaddrinfowhile the main thread sat intests/ui/test_pluginmanager.py's fixture, garbage-collecting the previous test's Qt objects.Live sockets crossing another test's Qt teardown is what segfaults. Whether it lands depends on suite timing, which is why this only started biting as the suite grew —
tests/uinow runs long enough for the timers to fire inside the session rather than after it.Reproduced locally by running
test_plugin_window_rows.pyfollowed by a test that spins the event loop for 16 s:plugin-update-checkthreads appear after the tests that armed them have finished. With this change, zero.The fix (tests only)
test_plugin_window_rows.pyturnsupdate_checkoff — the file is about Settings > Windows rows and never wanted the check.tests/conftest.pygrows a session-scoped guard that refuses anyfetch_https_bytescall arriving without a transport. Session-scoped because the gap between tests is exactly where a leaked timer fires, and a function-scoped patch would already be unwound. The transport seam stays open, sopatch_default_transportand the redirect/size-limit tests are untouched.Tests
QT_QPA_PLATFORM=offscreen uv run pytest→ 1994 passed, 2 deselected, and ~20 s faster (56 s vs 78 s) now that it no longer waits on live DNS.uv run ruff check ./ruff format --check .clean.tests/now raisescould not reach the registry: the test suite must not fetch … for real. Before this branch, that same call fetched the live index successfully — the suite really was talking to the internet.Risk / notes
No product code changes, so
test:— correctly no version bump. Merge with a merge commit so the commit survives for versioning.