"""Runner stall handling check (2026-10-12). 1. start_timeout=3 s with 1 retry: Rhino cannot start a script that fast -> both attempts are killed, RhinoJobError lists 2 attempts with the window title, and no Rhino process from this test is left running. 2. normal run: result returned and no Rhino left behind (exit mode exited / killed after result is recorded). """ import subprocess import sys import tempfile from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from runner import RhinoJobError, run_job # noqa: E402 step = Path(tempfile.mkdtemp()) / "noop.py" step.write_text("print('noop')\n", encoding="utf-8") def rhino_count(): out = subprocess.run(["tasklist", "/FI", "IMAGENAME eq Rhino.exe", "/FO", "CSV", "/NH"], capture_output=True, text=True) return out.stdout.count("Rhino.exe") ok = True before = rhino_count() try: run_job([{"name": "noop", "script": step}], start_timeout=3, retries=1) print("FAIL stall: no error raised") ok = False except RhinoJobError as e: n = str(e).count("did not start the job within 3s") print("PASS" if n == 2 else "FAIL", "stall: attempts reported", n, "|", str(e)[:200]) ok &= n == 2 left = rhino_count() - before print("PASS" if left == 0 else "FAIL", "stall: Rhino processes left", left) ok &= left == 0 r = run_job([{"name": "noop", "script": step}]) good = r["ok"] and r["steps"][0]["stdout"].strip() == "noop" print("PASS" if good else "FAIL", "normal run returns the result:", r["wall_secs"], "s") # How Rhino ended is recorded, not judged: since 2026-10-12 13:00 Rhino on this PC often stays alive after # _-Exit (cause not identified); the runner then kills it after the grace period, the result is already safe. print("INFO rhino exit:", r["rhino_exit"]) left = rhino_count() - before print("PASS" if left == 0 else "FAIL", "normal run: Rhino processes left", left) ok &= good and left == 0 sys.exit(0 if ok else 1)