"""Shared pytest fixtures. Uses SQLite for speed (see ARCHITECTURE.md §4.8). Tests exercise the framework against an in-memory Postgres-shaped SQLAlchemy Base — no Alembic migrations in the test path; models create their tables from metadata. Environment defaults are set at *module import* time (not via fixture) so they are in place before pytest collects any test module that transitively imports `ypms.main` (which instantiates the FastAPI app at import time). """ from __future__ import annotations import os from collections.abc import Iterator os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:") os.environ.setdefault("JWT_SECRET", "test-secret") os.environ.setdefault( "COLUMN_ENCRYPTION_KEY", "test-col-enc-key-32bytes-______________" ) os.environ.setdefault("ENV", "test") import pytest # noqa: E402 from fastapi.testclient import TestClient # noqa: E402 from sqlalchemy import create_engine # noqa: E402 from sqlalchemy.orm import Session, sessionmaker # noqa: E402 from sqlalchemy.pool import StaticPool # noqa: E402 @pytest.fixture def db() -> Iterator[Session]: """Fresh in-memory SQLite DB per test with all model tables created. Import happens inside the fixture so the model modules register themselves on Base.metadata before create_all runs. """ import ypms.audit.models # noqa: F401 import ypms.framework.version_history # noqa: F401 import ypms.security.models # noqa: F401 import ypms.users.models # noqa: F401 import ypms.youth.models # noqa: F401 from ypms.db import Base # StaticPool + check_same_thread=False share the same in-memory DB across # threads. TestClient runs handlers in a worker thread, so without this # the fixture-scoped session and the request-scoped session see different # empty databases (SADeprecationWarning: SQLite objects created in a # thread can only be used in that same thread). engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, future=True, ) Base.metadata.create_all(engine) SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True) session = SessionLocal() try: yield session finally: session.close() engine.dispose() @pytest.fixture def client() -> Iterator[TestClient]: from ypms.main import create_app app = create_app() with TestClient(app) as c: yield c