from collections.abc import Generator import pytest from fastapi.testclient import TestClient from sqlalchemy import create_engine, text from sqlalchemy.engine import make_url from sqlmodel import Session, SQLModel from app.core.config import settings from app.core.db import engine, init_db from app.main import app from tests.utils.user import authentication_token_from_email from tests.utils.utils import get_superuser_token_headers @pytest.fixture(scope="session", autouse=True) def flow_data(tmp_path_factory: pytest.TempPathFactory) -> Generator[None, None, None]: """Keep flows and secrets written by tests out of the real store.""" root = tmp_path_factory.mktemp("flow-data") settings.FLOWS_DIR = root / "flows" settings.SECRETS_FILE = root / "secrets.enc" yield @pytest.fixture(scope="session", autouse=True) def db() -> Generator[Session, None, None]: """Create the throwaway database `tests/__init__.py` points at, drop it after.""" url = make_url(str(settings.SQLALCHEMY_DATABASE_URI)) # The teardown drops this database, so refuse to run against anything but # the dedicated test one. assert url.database and url.database.endswith("_test"), url.database maintenance = create_engine( url.set(database="postgres"), isolation_level="AUTOCOMMIT" ) drop = text(f'DROP DATABASE IF EXISTS "{url.database}" WITH (FORCE)') with maintenance.connect() as connection: connection.execute(drop) connection.execute(text(f'CREATE DATABASE "{url.database}"')) SQLModel.metadata.create_all(engine) with Session(engine) as session: init_db(session) yield session engine.dispose() with maintenance.connect() as connection: connection.execute(drop) maintenance.dispose() @pytest.fixture(scope="module") def client() -> Generator[TestClient, None, None]: with TestClient(app) as c: yield c @pytest.fixture(scope="module") def superuser_token_headers(client: TestClient) -> dict[str, str]: return get_superuser_token_headers(client) @pytest.fixture(scope="module") def normal_user_token_headers(client: TestClient, db: Session) -> dict[str, str]: return authentication_token_from_email( client=client, email=settings.EMAIL_TEST_USER, db=db )