feat(phase-32): add automated tests V3 for data sources, scoring, campaigns and snapshots (T-235 to T-237)

This commit is contained in:
2026-02-10 09:07:43 +01:00
parent 02034d60f0
commit 35983de67e
11 changed files with 1676 additions and 12 deletions

View File

@@ -1,16 +1,45 @@
"""Pytest fixtures and configuration for backend tests."""
"""Pytest fixtures and configuration for backend tests.
The conftest intentionally avoids importing ``app.main`` at module level
because that triggers heavy side-effect imports (boto3, APScheduler, etc.)
which are NOT needed for unit tests. The ``client`` fixture lazily imports
the FastAPI app only when actually requested.
"""
import os
# Set DATABASE_URL to SQLite *before* any app module is imported so that
# the lazy engine in app.database never tries to connect to PostgreSQL.
os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:")
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy import JSON, String, Text, create_engine, event
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
from app.main import app
from app.database import Base, get_db
from app.database import Base
# ── Patch PostgreSQL-specific column types so SQLite can handle them ─────
# Must run BEFORE importing models, because column type objects are
# instantiated at class-definition time.
from sqlalchemy.dialects.postgresql import UUID as PG_UUID, JSONB as PG_JSONB
# Tell SQLAlchemy: when compiling for SQLite, render JSONB as plain JSON
# and PostgreSQL UUID as CHAR(32).
from sqlalchemy.dialects.sqlite.base import SQLiteTypeCompiler
if not hasattr(SQLiteTypeCompiler, "visit_JSONB"):
SQLiteTypeCompiler.visit_JSONB = lambda self, type_, **kw: "JSON"
if not hasattr(SQLiteTypeCompiler, "visit_UUID"):
SQLiteTypeCompiler.visit_UUID = lambda self, type_, **kw: "CHAR(32)"
from app.auth import hash_password
from app.models.user import User
# ── Import all models so Base.metadata knows about every table ──────────
import app.models # noqa: F401 — triggers model registration via __init__
# Use in-memory SQLite for tests
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
@@ -19,6 +48,14 @@ engine = create_engine(
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
# SQLite needs PRAGMA foreign_keys to enforce FK constraints
@event.listens_for(engine, "connect")
def _set_sqlite_pragma(dbapi_conn, connection_record):
cursor = dbapi_conn.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
@@ -43,13 +80,21 @@ def db():
@pytest.fixture(scope="function")
def client(db):
"""Create a test client with database override."""
"""Create a test client with database override.
Imports ``app.main`` lazily to avoid pulling in boto3 / APScheduler
when only the ``db`` fixture is needed.
"""
from app.main import app
from app.database import get_db
app.dependency_overrides[get_db] = override_get_db
Base.metadata.create_all(bind=engine)
from fastapi.testclient import TestClient
with TestClient(app) as test_client:
yield test_client
Base.metadata.drop_all(bind=engine)
app.dependency_overrides.clear()