Private
Public Access
0
0

refactor(test): wrap live_gui subprocess in _LiveGuiHandle class

This commit is contained in:
2026-06-09 15:37:47 -04:00
parent 30c04860c7
commit 16bd3d3a47
3 changed files with 56 additions and 5 deletions
+49 -2
View File
@@ -1,5 +1,6 @@
import pytest import pytest
import subprocess import subprocess
import threading
import time import time
import requests import requests
import os import os
@@ -396,8 +397,54 @@ def app_instance() -> Generator[App, None, None]:
if hasattr(app, 'shutdown'): if hasattr(app, 'shutdown'):
app.shutdown() app.shutdown()
class _LiveGuiHandle:
def __init__(self, process: subprocess.Popen, gui_script: str) -> None:
"""[SDM: tests/conftest.py:_LiveGuiHandle] [C: tests/conftest.py:live_gui fixture]"""
self._process = process
self._gui_script = gui_script
self._lock = threading.Lock()
self._respawn_count = 0
def __iter__(self):
"""Support tuple unpacking: `process, gui_script = handle` (backward compat)."""
return iter((self._process, self._gui_script))
def __getitem__(self, index: int):
"""Support indexing: `handle[0]` returns process, `handle[1]` returns gui_script."""
if index == 0:
return self._process
if index == 1:
return self._gui_script
raise IndexError(index)
@property
def process(self) -> subprocess.Popen:
"""[M: tests/conftest.py:live_gui fixture]"""
return self._process
@property
def gui_script(self) -> str:
"""[M: tests/conftest.py:live_gui fixture]"""
return self._gui_script
def is_alive(self) -> bool:
"""Returns True if the subprocess is running."""
return self._process is not None and self._process.poll() is None
def ensure_alive(self) -> None:
"""No-op stub for Phase 2: the live_gui fixture is session-scoped, so we cannot respawn the subprocess in-place. The handle is respawned between test sessions. If the process died, the counter is incremented for diagnostics."""
with self._lock:
if not self.is_alive():
self._respawn_count += 1
@property
def respawn_count(self) -> int:
"""[M: tests/conftest.py:_LiveGuiHandle.ensure_alive]"""
return self._respawn_count
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def live_gui() -> Generator[tuple[subprocess.Popen, str], None, None]: def live_gui() -> Generator["_LiveGuiHandle", None, None]:
""" """
@@ -561,7 +608,7 @@ def live_gui() -> Generator[tuple[subprocess.Popen, str], None, None]:
diag.finalize("Live GUI Startup Telemetry", "PASS", "Hook server successfully initialized.") diag.finalize("Live GUI Startup Telemetry", "PASS", "Hook server successfully initialized.")
try: try:
yield process, gui_script yield _LiveGuiHandle(process, gui_script)
finally: finally:
print(f"\n[Fixture] Finally block triggered: Shutting down {gui_script}...") print(f"\n[Fixture] Finally block triggered: Shutting down {gui_script}...")
# Reset the GUI state before shutting down # Reset the GUI state before shutting down
+4 -2
View File
@@ -17,14 +17,16 @@ from src.api_hook_client import ApiHookClient
# Session-wide storage for comparing metrics # Session-wide storage for comparing metrics
_shared_metrics = {} _shared_metrics = {}
def test_performance_benchmarking(live_gui: tuple) -> None: def test_performance_benchmarking(live_gui) -> None:
""" """
Collects performance metrics for the current GUI script over a 5-second window. Collects performance metrics for the current GUI script over a 5-second window.
Ensures the application does not lock up and can report its internal state. Ensures the application does not lock up and can report its internal state.
""" """
process, gui_script = live_gui handle = live_gui
process = handle.process
gui_script = handle.gui_script
client = ApiHookClient() client = ApiHookClient()
# Wait for app to stabilize and render some frames # Wait for app to stabilize and render some frames
time.sleep(3.0) time.sleep(3.0)
+3 -1
View File
@@ -34,7 +34,9 @@ def test_live_gui_project_settings_opens_without_filedialog_crash(live_gui) -> N
5. Verifies no AttributeError was logged (the bug would print to 5. Verifies no AttributeError was logged (the bug would print to
the GUI's stderr, which the live_gui fixture captures to a log) the GUI's stderr, which the live_gui fixture captures to a log)
""" """
process, gui_script = live_gui handle = live_gui
process = handle.process
gui_script = handle.gui_script
client = ApiHookClient() client = ApiHookClient()
log_path = Path(f"logs/{Path(gui_script).name.replace('.', '_')}_test.log") log_path = Path(f"logs/{Path(gui_script).name.replace('.', '_')}_test.log")