From 8ad814b422d68e5b8add2a8a5bb1777cbc3deda1 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 7 Jun 2026 12:22:24 -0400 Subject: [PATCH] fix(tests): live_gui fixture kills stale process on port 8999 before spawn The fixture detected stale processes on port 8999 but only issued a soft btn_reset POST (which doesn't reset the provider). When a previous batch left a sloppy.py subprocess running, the new subprocess failed to bind port 8999 and the wait loop connected to the stale process instead, leading to cross-batch state pollution (e.g., test_change_provider_via_hook seeing current_provider='gemini' after setting 'anthropic'). Fix: when port 8999 is found LISTENING, parse netstat -ano for the PID, taskkill /F /PID it, sleep 1s, then proceed with the fresh subprocess.Popen. Verified: tests/test_conftest_watchdog.py 3/3 still pass (the watchdog from e1c8730f is independent of this fix). --- tests/conftest.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6bee7ab7..8a5efe8d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -356,15 +356,30 @@ def live_gui() -> Generator[tuple[subprocess.Popen, str], None, None]: else: os.symlink(src_assets, temp_workspace / "assets") - # Check if already running (shouldn't be) + # Check if already running (shouldn't be). If stale, kill the old process + # before spawning a new one — otherwise the new subprocess fails to bind + # port 8999 and the wait loop connects to the stale process instead, + # leading to state pollution across batches. try: resp = requests.get("http://127.0.0.1:8999/status", timeout=0.5) if resp.status_code == 200: - print("[Fixture] WARNING: Hook Server already up on port 8999. Test state might be polluted.") - # Optionally try to reset it - try: requests.post("http://127.0.0.1:8999/api/gui", json={"action": "click", "item": "btn_reset"}, timeout=1) - except: pass - except: pass + print("[Fixture] WARNING: Hook Server already up on port 8999. Killing stale process...") + netstat = subprocess.run(["netstat", "-ano"], capture_output=True, text=True, timeout=5) + stale_pids: set[int] = set() + for line in netstat.stdout.splitlines(): + if ":8999" in line and "LISTENING" in line: + parts = line.split() + if parts: + try: stale_pids.add(int(parts[-1])) + except ValueError: pass + for pid in stale_pids: + try: + subprocess.run(["taskkill", "/F", "/PID", str(pid)], capture_output=True, timeout=5) + print(f"[Fixture] Killed stale PID {pid}") + except Exception: pass + time.sleep(1.0) + print("[Fixture] Proceeding with fresh sloppy.py spawn") + except Exception: pass print(f"\n[Fixture] Starting {gui_script} --enable-test-hooks in {temp_workspace}...") os.makedirs("logs", exist_ok=True)