78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
import pytest
|
|
import subprocess
|
|
import time
|
|
import requests
|
|
import os
|
|
import signal
|
|
|
|
def kill_process_tree(pid):
|
|
"""Robustly kills a process and all its children."""
|
|
if pid is None:
|
|
return
|
|
try:
|
|
print(f"[Fixture] Attempting to kill process tree for PID {pid}...")
|
|
if os.name == 'nt':
|
|
# /F is force, /T is tree (includes children)
|
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(pid)],
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
check=False)
|
|
else:
|
|
# On Unix, kill the process group
|
|
os.killpg(os.getpgid(pid), signal.SIGKILL)
|
|
print(f"[Fixture] Process tree {pid} killed.")
|
|
except Exception as e:
|
|
print(f"[Fixture] Error killing process tree {pid}: {e}")
|
|
|
|
@pytest.fixture(scope="session")
|
|
def live_gui():
|
|
"""
|
|
Session-scoped fixture that starts gui.py with --enable-test-hooks.
|
|
Ensures the GUI is running before tests start and shuts it down after.
|
|
"""
|
|
print("\n[Fixture] Starting gui.py --enable-test-hooks...")
|
|
|
|
# Ensure logs directory exists
|
|
os.makedirs("logs", exist_ok=True)
|
|
log_file = open("logs/gui_test.log", "w", encoding="utf-8")
|
|
|
|
# Start gui.py as a subprocess.
|
|
process = subprocess.Popen(
|
|
["uv", "run", "python", "gui.py", "--enable-test-hooks"],
|
|
stdout=log_file,
|
|
stderr=log_file,
|
|
text=True,
|
|
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
|
|
)
|
|
|
|
# Wait for the hook server to be ready (Port 8999 per api_hooks.py)
|
|
max_retries = 5
|
|
ready = False
|
|
print(f"[Fixture] Waiting up to {max_retries}s for Hook Server on port 8999...")
|
|
|
|
start_time = time.time()
|
|
while time.time() - start_time < max_retries:
|
|
try:
|
|
# Using /status endpoint defined in HookHandler
|
|
response = requests.get("http://127.0.0.1:8999/status", timeout=0.5)
|
|
if response.status_code == 200:
|
|
ready = True
|
|
print(f"[Fixture] GUI Hook Server is ready after {round(time.time() - start_time, 2)}s.")
|
|
break
|
|
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout):
|
|
if process.poll() is not None:
|
|
print("[Fixture] Process died unexpectedly during startup.")
|
|
break
|
|
time.sleep(0.5)
|
|
|
|
if not ready:
|
|
print("[Fixture] TIMEOUT/FAILURE: Hook server failed to respond on port 8999 within 5s. Cleaning up...")
|
|
kill_process_tree(process.pid)
|
|
pytest.fail("Failed to start gui.py with test hooks within 5 seconds.")
|
|
|
|
try:
|
|
yield process
|
|
finally:
|
|
print("\n[Fixture] Finally block triggered: Shutting down gui.py...")
|
|
kill_process_tree(process.pid)
|