"""Test fixtures. Runs the real Alembic migrations once per session against a real SQLite file (never mocked — see CLAUDE.md's test policy — and never `:memory:`, which gives each separate connection its own isolated database rather than one shared one), then deletes all rows between tests for isolation. This deliberately exercises the exact same migration path CI's `migrations` job and a real deploy use, not a parallel test-only schema-creation shortcut. """ import os import tempfile from collections.abc import AsyncIterator from pathlib import Path import pytest from alembic.config import Config from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncSession from alembic import command os.environ.setdefault("VELODROME_ENVIRONMENT", "test") _tmp_dir = tempfile.mkdtemp(prefix="velodrome-test-") _db_path = Path(_tmp_dir) / "test.db" os.environ.setdefault("VELODROME_DATABASE_URL", f"sqlite+aiosqlite:///{_db_path}") # Settings/engines must not be constructed before the env var above is set, so these imports are # deliberately below it, not at module top. import httpx # noqa: E402 from velodrome.app import app # noqa: E402 from velodrome.db import auth_session # noqa: E402 @pytest.fixture(scope="session", autouse=True) def _run_migrations() -> None: cfg = Config(os.path.join(os.path.dirname(__file__), "..", "alembic.ini")) cfg.set_main_option("script_location", os.path.join(os.path.dirname(__file__), "..", "alembic")) command.upgrade(cfg, "head") @pytest.fixture(autouse=True) async def _clean_tables() -> AsyncIterator[None]: yield async with auth_session() as db: async with db.begin(): # Children before parents for the FK constraints. for table in ("sessions", "api_tokens", "invites", "users"): await db.execute(text(f"DELETE FROM {table}")) @pytest.fixture async def db_auth() -> AsyncIterator[AsyncSession]: async with auth_session() as db: yield db @pytest.fixture async def client() -> AsyncIterator[httpx.AsyncClient]: transport = httpx.ASGITransport(app=app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as c: yield c