"""SQLite in-memory fixtures for API tests.""" import os # Must be set before app.database imports create_engine os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:") os.environ.setdefault("SAC_BOOTSTRAP_API_KEY", "sac_test_key_for_pytest_only") import pytest from fastapi.testclient import TestClient from sqlalchemy import JSON, create_engine, event from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool from app.auth.api_key import hash_api_key from app.auth.jwt_auth import create_access_token from app.database import Base, get_db from app.main import app as fastapi_app import app.models # noqa: F401 — register all tables on Base.metadata from app.models import ApiKey, User from app.models.user import USER_ROLE_ADMIN, USER_ROLE_MONITOR from app.services.user_auth import hash_password TEST_API_KEY = os.environ["SAC_BOOTSTRAP_API_KEY"] @event.listens_for(Base.metadata, "before_create") def _sqlite_jsonb_as_json(metadata, connection, **_kwargs) -> None: if connection.dialect.name != "sqlite": return for table in metadata.tables.values(): for column in table.columns: if isinstance(column.type, JSONB): column.type = JSON() @pytest.fixture def db_engine(): engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) yield engine engine.dispose() @pytest.fixture def db_session(db_engine): Session = sessionmaker(bind=db_engine, autocommit=False, autoflush=False) session = Session() session.add( ApiKey( name="test", key_prefix=TEST_API_KEY[:12], key_hash=hash_api_key(TEST_API_KEY), is_active=True, ) ) session.add( User( username="test-admin", password_hash=hash_password("test-admin-password"), role=USER_ROLE_ADMIN, is_active=True, ) ) session.add( User( username="test-monitor", password_hash=hash_password("test-monitor-password"), role=USER_ROLE_MONITOR, is_active=True, ) ) session.commit() yield session session.close() @pytest.fixture def client(db_session, monkeypatch): monkeypatch.setattr("app.main.bootstrap_api_key", lambda: None) monkeypatch.setattr("app.main.bootstrap_users", lambda: None) def override_get_db(): try: yield db_session finally: pass fastapi_app.dependency_overrides[get_db] = override_get_db with TestClient(fastapi_app) as c: yield c fastapi_app.dependency_overrides.clear() @pytest.fixture def auth_headers(): return {"Authorization": f"Bearer {TEST_API_KEY}"} @pytest.fixture def jwt_headers(): token = create_access_token("test-admin", USER_ROLE_ADMIN) return {"Authorization": f"Bearer {token}"} @pytest.fixture def jwt_monitor_headers(): token = create_access_token("test-monitor", USER_ROLE_MONITOR) return {"Authorization": f"Bearer {token}"}