"""Pytest configuration shared across the suite. Skips tests that require external services (Supabase, NVIDIA integrate) unless the right env vars are set. """ from __future__ import annotations import os from pathlib import Path import pytest def _truthy(v: str | None) -> bool: return v is not None and v not in ("", "0", "false", "False") @pytest.fixture(scope="session") def has_supabase() -> bool: return _truthy(os.environ.get("SUPABASE_URL")) and _truthy( os.environ.get("SUPABASE_SECRET_KEY") or os.environ.get("SUPABASE_KEY") ) @pytest.fixture(scope="session") def has_nvidia() -> bool: return _truthy(os.environ.get("NVIDIA_API_KEY")) or _truthy( os.environ.get("LLM_API_KEY") ) @pytest.fixture(scope="session") def fastapi_client(): """Starlette TestClient for the FastAPI app. Only constructed when no external network is needed (e.g. /health, /, /documents/templates). """ from fastapi.testclient import TestClient # type: ignore # Provides query/key so supabase init doesn't blow up os.environ.setdefault("SUPABASE_URL", "") os.environ.setdefault("SUPABASE_SECRET_KEY", "") os.environ.setdefault("NVIDIA_API_KEY", "test") from app.main import app return TestClient(app) @pytest.fixture(scope="session") def minimal_app_client(): """Lightweight TestClient that mounts ONLY /uploads/blueprint*. Use this when the canonical app depends on packages (PIL etc.) the local Termux env can't build — this fixture isolates the new router so we can run its smoke tests in this env without breaking CI runs that already exercise the full app elsewhere. """ from fastapi import FastAPI # type: ignore from fastapi.middleware.cors import CORSMiddleware # type: ignore from fastapi.testclient import TestClient # type: ignore # Load the uploads router module directly — bypass app.routers.__init__ # which transitively imports the legacy blueprint service (depends on # Pillow, missing on Termux). The router file itself only imports # Pydantic models and the canonical services it owns. import importlib.util as _util import sys as _sys _spec = _util.spec_from_file_location( "vf_uploads_isolated", str(Path(__file__).parent.parent / "app" / "routers" / "uploads.py"), ) _mod = _util.module_from_spec(_spec) _spec.loader.exec_module(_mod) uploads_router = _mod.router os.environ.setdefault("SUPABASE_URL", "") os.environ.setdefault("SUPABASE_SECRET_KEY", "") os.environ.setdefault("NVIDIA_API_KEY", "test") app = FastAPI(title="VF uploads (minimal)") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["GET", "POST", "OPTIONS"], allow_headers=["*"], ) app.include_router(uploads_router) return TestClient(app) def pytest_collection_modifyitems(config, items): """Mark tests that hit external services with a skip marker when the required env var is missing. """ skip_no_sb = pytest.mark.skip(reason="Supabase credentials required") skip_no_nv = pytest.mark.skip(reason="NVIDIA API key required") has_sb = _truthy(os.environ.get("SUPABASE_URL")) and _truthy( os.environ.get("SUPABASE_SECRET_KEY") or os.environ.get("SUPABASE_KEY") ) has_nv = _truthy(os.environ.get("NVIDIA_API_KEY")) or _truthy( os.environ.get("LLM_API_KEY") ) for item in items: if "supabase" in item.keywords and not has_sb: item.add_marker(skip_no_sb) if "nvidia" in item.keywords and not has_nv: item.add_marker(skip_no_nv)