From 02cd712b22fd6df27404110ab56fc9c80263ea4f Mon Sep 17 00:00:00 2001 From: David Leong <116610336+leongdl@users.noreply.github.com> Date: Thu, 15 Oct 2026 15:36:20 -0700 Subject: [PATCH] test: Warm PowerShell before Windows round trips TestReprPwshWindowsValidation fails intermittently on windows-latest with subprocess.TimeoutExpired after 10 seconds. The first PowerShell launch on a fresh hosted runner pays a one-time cold start that can exceed the 10-second per-call timeout in _pwsh_eval, so whichever test launches PowerShell first is killed, and a killed launch can leave the next one cold too. Run 38812686088 (PR #379, a CHANGELOG-only change) lost the first four tests of the class this way, each at about 10.1 s, while the other nine passed. The same timeout appears in 8 of the last 60 Code Quality runs, on Python 3.10, 3.12, 3.13 and 3.14, and run 35389550086 passed on rerun at the same SHA. Add a class-scoped autouse fixture that pays the cold start once, with a 120-second deadline, through the same _pwsh_eval path the tests use: a .ps1 file run with -File that calls Write-Output. It asserts the output, so a broken PowerShell still fails the class instead of being skipped. The per-call timeout stays at 10 seconds and no test assertion changes. Mark the class timeout(180), because pytest-timeout counts class-scoped fixture setup against the first test and the project-wide --timeout=30 would otherwise cut a long warm-up short. Verified on macOS with PowerShell 7.6.7 behind a shim that simulates the cold start. The class is Windows-only, so this is a simulation, not a Windows reproduction. Without the fix, a 41 s cold start fails the same four tests as run 38812686088, at 10.01 s each, and a 12 s cold start fails test_pwsh_string_simple_roundtrip alone. With the fix both pass 13/13, and the cold start lands in the first test's setup. Each of these mutants fails the class under a 41 s cold start: no warm-up, a 10 s warm-up deadline, and no timeout marker. Only repeated green Code Quality runs on real Windows runners prove the fix. At roughly one failure in 50 Windows jobs, one green run is weak evidence. Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com> --- test/openjd/expr/test_strings.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/openjd/expr/test_strings.py b/test/openjd/expr/test_strings.py index 1a6abd82..f50d69f5 100644 --- a/test/openjd/expr/test_strings.py +++ b/test/openjd/expr/test_strings.py @@ -650,10 +650,21 @@ def test_pwsh_range_expr_as_list(self) -> None: @pytest.mark.skipif(os.name != "nt", reason="PowerShell validation only on Windows") +# pytest-timeout counts the class-scoped warm-up below against the first test. +@pytest.mark.timeout(180) class TestReprPwshWindowsValidation: """Validate repr_pwsh output by running PowerShell subprocess on Windows.""" - def _pwsh_eval(self, expr: str) -> str: + @staticmethod + @pytest.fixture(scope="class", autouse=True) + def _warm_powershell() -> None: + # The first PowerShell launch on a fresh Windows runner can exceed the + # per-call timeout. Pay that once here, with a deadline sized for it. + ready = TestReprPwshWindowsValidation._pwsh_eval("Write-Output ready", timeout=120) + assert ready == "ready" + + @staticmethod + def _pwsh_eval(expr: str, *, timeout: float = 10) -> str: """Write expr to a temporary .ps1 file and execute it, so PowerShell interprets the repr_pwsh output exactly once (no argument-layer parsing).""" import subprocess @@ -667,7 +678,7 @@ def _pwsh_eval(self, expr: str) -> str: ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", ps1_path], capture_output=True, text=True, - timeout=10, + timeout=timeout, ) return result.stdout.strip() finally: