From e3febd256cdf1e30649d9c7d134d61edacfeb022 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 23 Oct 2026 15:04:17 +0100 Subject: [PATCH] test(cloudxr): clean up test_background's stand-in on failure Follow-up to the terminate-race fix in test_background.py. Now that the stand-in service really sleeps for 30 s, a failure before terminate() succeeds left it running; kill it in a finally, as the sibling spawn tests already do. On success the child is an unreaped zombie by then, so the kill is a no-op. Also prepend the stand-in's directory to PYTHONPATH instead of replacing it, so the child keeps the inherited path. Signed-off-by: Jakob Bornecrantz --- tests/python/core/cloudxr/test_background.py | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/python/core/cloudxr/test_background.py b/tests/python/core/cloudxr/test_background.py index d135ce1334..92fd0185fe 100644 --- a/tests/python/core/cloudxr/test_background.py +++ b/tests/python/core/cloudxr/test_background.py @@ -29,7 +29,7 @@ def stand_in_service(tmp_path, monkeypatch): (tmp_path / "stand_in_service.py").write_text( "import sys, time\ntime.sleep(float(sys.argv[-1]))\n" ) - monkeypatch.setenv("PYTHONPATH", str(tmp_path)) + monkeypatch.setenv("PYTHONPATH", str(tmp_path), prepend=os.pathsep) monkeypatch.setattr(background, "_MODULE", "stand_in_service") @@ -218,15 +218,18 @@ def test_sigterm_and_clears_the_pid_file(self, tmp_path, stand_in_service): logs_dir = tmp_path / "logs" pid, _ = background.spawn(["30"], run_dir, logs_dir) - assert _poll_read_pid(run_dir) == pid - - assert background.terminate(run_dir, timeout_sec=10) is True - assert not background.pid_path(run_dir).exists() - # Not `os.kill(pid, 0)`: this process is still the child's parent and - # has not reaped it, so the pid survives as a zombie and signalling it - # succeeds. A zombie's /proc//cmdline is empty, which is why the - # liveness check reports it gone — that is the contract that matters. - assert background._is_our_service(pid) is False + try: + assert _poll_read_pid(run_dir) == pid + + assert background.terminate(run_dir, timeout_sec=10) is True + assert not background.pid_path(run_dir).exists() + # Not `os.kill(pid, 0)`: this process is still the child's parent and + # has not reaped it, so the pid survives as a zombie and signalling it + # succeeds. A zombie's /proc//cmdline is empty, which is why the + # liveness check reports it gone — that is the contract that matters. + assert background._is_our_service(pid) is False + finally: + os.kill(pid, signal.SIGKILL) def test_never_escalates_to_sigkill(self, tmp_path, monkeypatch): """SIGKILL would orphan the runtime, which leads its own session."""