"""E2E test fixtures: live uvicorn server for Playwright.""" from __future__ import annotations import os import socket import threading import time import httpx import pytest import uvicorn def _free_port() -> int: with socket.socket() as s: s.bind(("127.0.0.1", 0)) return s.getsockname()[1] @pytest.fixture(scope="session") def live_server(tmp_path_factory): """Start the FastAPI app on a random port in a background thread.""" # Isolated data dir for E2E session data_dir = tmp_path_factory.mktemp("imptune_e2e_data") # Patch config module so the app uses the temp dir import imptune.config as cfg cfg.DATA_DIR = str(data_dir) cfg.DB_PATH = str(data_dir / "imptune.db") cfg.DRIVERS_DIR = str(data_dir / "drivers") cfg.ICONS_DIR = str(data_dir / "icons") os.makedirs(cfg.DRIVERS_DIR, exist_ok=True) os.makedirs(cfg.ICONS_DIR, exist_ok=True) # Also set env var so lifespan handler picks up correct dirs os.environ["DATA_DIR"] = str(data_dir) # Initialize DB against the tmp dir from imptune.db.database import init_db init_db() from imptune.main import app port = _free_port() config = uvicorn.Config(app, host="127.0.0.1", port=port, log_level="error") server = uvicorn.Server(config) thread = threading.Thread(target=server.run, daemon=True) thread.start() base_url = f"http://127.0.0.1:{port}" # Readiness poll via /health (up to 5 s) deadline = time.time() + 5.0 while time.time() < deadline: try: r = httpx.get(f"{base_url}/health", timeout=0.5) if r.status_code == 200: break except Exception: pass time.sleep(0.1) else: raise RuntimeError("live_server did not become ready within 5 s") yield base_url server.should_exit = True thread.join(timeout=2.0)