Skip to content

fix: propagate the serial test runner's exit code on Windows - #4771

Open
MohammedAlkindi wants to merge 1 commit into
openai:mainfrom
MohammedAlkindi:fix/serial-runner-exit-code
Open

fix: propagate the serial test runner's exit code on Windows#4771
MohammedAlkindi wants to merge 1 commit into
openai:mainfrom
MohammedAlkindi:fix/serial-runner-exit-code

Conversation

@MohammedAlkindi

Copy link
Copy Markdown

make tests-serial exits 0 on Windows whether the serial tests pass or fail.

.github/scripts/run_serial_tests.py ends in os.execv. Windows has no process replacement: the
CRT spawns a child and terminates the caller with 0. The caller returns in about 100 ms while pytest
keeps running orphaned, so make tests and make check report success, and pytest's output arrives
afterwards, interleaved into whatever runs next. AGENTS.md lists make tests in the mandatory
local run order.

run_integration_tests.py already handles this at lines 103-106, added in 21a1f9b4. This applies
the same guarded shape to the serial runner, plus a unit test mirroring
test_windows_bootstrap_uses_subprocess_and_propagates_exit_code.

POSIX is unchanged: os.execv still runs there, so pytest keeps owning the terminal and its own
signal handling.

CI is unaffected. make tests runs on ubuntu-latest, and the windows-latest job invokes
uv run pytest directly, so serial tests already propagate there.

verification
base 2b81a9e3 (2026-08-28), Python 3.13.13, win32 x64, uv 0.12.5

mechanism, isolated (re-run by hand):
  child sys.exit(7) direct  -> shell saw 7
  same child via os.execv   -> shell saw 0

new unit tests, source reverted:
  FAILED test_windows_runner_uses_subprocess_and_propagates_exit_code
  Failed: Windows serial runner must not call os.execv
    .github/scripts/run_serial_tests.py:49: in main
        os.execv(sys.executable, _serial_args(...))

with the fix: 6 passed
ruff check: All checks passed    ruff format: unchanged
staged blobs: run_serial_tests.py CR=0, test_run_serial_tests.py CR=0

run_serial_tests.py ends in os.execv. Windows has no process
replacement, so the CRT spawns a child and terminates the caller with 0.
make tests-serial returns in about 100 ms reporting success while pytest
keeps running orphaned, and its output arrives afterwards, interleaved
into whatever the shell runs next.

run_integration_tests.py already handles this at lines 103-106, added in
21a1f9b. Apply the same win32-guarded shape here: subprocess.run with
check=False, then raise SystemExit on the child's return code.

POSIX is unchanged. os.execv still runs there, so pytest keeps owning the
terminal and its own signal handling.

Adds two tests mirroring the precedent's
test_windows_bootstrap_uses_subprocess_and_propagates_exit_code: the
win32 case asserts the code propagates, that check is False, and that
os.execv is never called; the POSIX case asserts execv is still used and
subprocess.run is not.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants