""" conftest.py — shared fixtures for the ExCALIBR test suite. Sets EXCALIBR_JOBS_DIR to a temporary directory before any module is imported, so api.py never touches the real /jobs directory during tests. """ import os import shutil import tempfile from pathlib import Path import pytest # ── Set env var BEFORE api.py is imported ───────────────────────────────────── # pytest collects conftest.py first, so this runs before any test module import. _tmp_jobs_root = Path(__file__).parent / "tmp_jobs" def pytest_configure(config): """Create the temp jobs directory and point the app at it.""" _tmp_jobs_root.mkdir(exist_ok=True) os.environ["EXCALIBR_JOBS_DIR"] = str(_tmp_jobs_root) def pytest_unconfigure(config): """Remove the temp jobs directory after the full test run.""" shutil.rmtree(_tmp_jobs_root, ignore_errors=True) @pytest.fixture(autouse=True) def clean_jobs_dir(): """Wipe tmp_jobs before each test so tests don't bleed into each other.""" shutil.rmtree(_tmp_jobs_root, ignore_errors=True) _tmp_jobs_root.mkdir() yield # Leave cleanup to pytest_unconfigure at session end @pytest.fixture def client(): """FastAPI TestClient — fresh per test with rate limit cleared.""" from fastapi.testclient import TestClient import backend.api as api_module # Reset in-memory rate limit state between tests api_module._rate_limit.clear() api_module.jobs.clear() with TestClient(api_module.app) as c: yield c @pytest.fixture def minimal_csv(tmp_path) -> Path: """A minimal valid CSV with enough rows to pass basic validation.""" content = "score,sample_assignments\n" # 10 pathogenic, 10 benign, 5 synonymous for _ in range(10): content += "1.5,0\n" for _ in range(10): content += "-1.5,1\n" for _ in range(5): content += "0.1,3\n" p = tmp_path / "test.csv" p.write_text(content) return p @pytest.fixture def default_params() -> str: import json return json.dumps({ "components": [2, 3], "nBootstraps": 10, "fitsPerBootstrap": 5, "benignMethod": "avg", "conservativeMonotonicity": True, })