From a0e2c081197b79846e323c2897a9c8efe231d00b Mon Sep 17 00:00:00 2001 From: goodboy Date: Tue, 9 Jun 2026 20:19:11 -0400 Subject: [PATCH] Wall-cap `test_stale_entry_is_deleted` via `pytest-timeout` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a hard process-level wall-clock bound on a test known to wedge un-Ctrl-C-ably under an in-dev spawn backend, so an unattended suite run can't hang indefinitely. Deats, - New `testing` dep: `pytest-timeout>=2.3`. - `test_stale_entry_is_deleted`: `@pytest.mark.timeout(3, method='thread')`. The `method='thread'` choice is deliberate — `method='signal'` routes via `SIGALRM` which can be starved by the same GIL-hostage path that drops `SIGINT`, so it'd never actually fire in the starvation case. At timeout, `pytest-timeout` hard-kills the pytest process itself — that's the intended behavior here; the alternative is the suite never returning. (this commit msg was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code (cherry picked from commit 189f4e3f72e9f1eda5d24bcbab5743f7e35bd913) (factored: kept pyproject + tests/discovery/test_registrar.py parts of "Wall-cap `subint` audit tests via `pytest-timeout`"; dropped tests/test_subint_cancellation.py) --- pyproject.toml | 5 +++++ tests/discovery/test_registrar.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 169bc7ad..4a0e5828 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,6 +85,11 @@ testing = [ # interactions stay predictable across dev installs). "pytest>=9.0", "pexpect>=4.9.0,<5", + # per-test wall-clock bound (used via + # `@pytest.mark.timeout(..., method='thread')` on the + # known-hanging `subint`-backend audit tests; see + # `ai/conc-anal/subint_*_issue.md`). + "pytest-timeout>=2.3", ] repl = [ "pyperclip>=1.9.0", diff --git a/tests/discovery/test_registrar.py b/tests/discovery/test_registrar.py index 60b2b10c..362c4549 100644 --- a/tests/discovery/test_registrar.py +++ b/tests/discovery/test_registrar.py @@ -516,6 +516,22 @@ async def kill_transport( # @pytest.mark.parametrize('use_signal', [False, True]) +# +# Wall-clock bound via `pytest-timeout` (`method='thread'`). +# Under `--spawn-backend=subint` this test can wedge in an +# un-Ctrl-C-able state (abandoned-subint + shared-GIL +# starvation → signal-wakeup-fd pipe fills → SIGINT silently +# dropped; see `ai/conc-anal/subint_sigint_starvation_issue.md`). +# `method='thread'` is specifically required because `signal`- +# method SIGALRM suffers the same GIL-starvation path and +# wouldn't fire the Python-level handler. +# At timeout the plugin hard-kills the pytest process — that's +# the intended behavior here; the alternative is an unattended +# suite run that never returns. +@pytest.mark.timeout( + 3, # NOTE should be a 2.1s happy path. + method='thread', +) def test_stale_entry_is_deleted( debug_mode: bool, daemon: subprocess.Popen,