# Import all models so Base.metadata knows every table import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool import app.models.alert # noqa: F401 # pylint: disable=unused-import import app.models.api_token # noqa: F401 # pylint: disable=unused-import import app.models.dns_cache # noqa: F401 # pylint: disable=unused-import import app.models.domain # noqa: F401 # pylint: disable=unused-import import app.models.mail_source as _mail_source_model # noqa: F401 # pylint: disable=unused-import import app.models.mail_source_import # noqa: F401 # pylint: disable=unused-import import app.models.report # noqa: F401 # pylint: disable=unused-import import app.models.setting # noqa: F401 # pylint: disable=unused-import import app.models.user # noqa: F401 # pylint: disable=unused-import from app.core.database import Base, get_db from app.core.security import require_admin_auth from app.main import create_app from app.services.report_store import ReportStore @pytest.fixture() def test_app() -> FastAPI: """Create a fresh FastAPI application instance for testing.""" application = create_app() return application @pytest.fixture() def db_session(): """Create a fresh in-memory SQLite database session per test. ``StaticPool`` ensures every SQLAlchemy operation reuses the same underlying DBAPI connection so the in-memory database (and its tables) persist for the full duration of the test, even across commits. """ engine = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) db = TestingSessionLocal() try: yield db finally: db.close() Base.metadata.drop_all(engine) engine.dispose() @pytest.fixture() def client(test_app: FastAPI, db_session): # pylint: disable=redefined-outer-name """Create a TestClient with a DB override for the test app.""" def override_get_db(): try: yield db_session finally: pass test_app.dependency_overrides[get_db] = override_get_db with TestClient(test_app) as test_client: yield test_client test_app.dependency_overrides.clear() @pytest.fixture(autouse=True) def _reset_report_store(): """Reset the ReportStore singleton between tests to avoid state leakage.""" store = ReportStore.get_instance() store.clear() yield store.clear() @pytest.fixture() def authed_client(test_app: FastAPI, db_session): # pylint: disable=redefined-outer-name """ TestClient with both DB and admin-auth dependency overrides. Bypasses ``require_admin_auth`` so tests can call admin-only endpoints without needing a real API key or JWT token. """ async def mock_admin_auth(): return {"auth_type": "api_key"} def override_get_db(): try: yield db_session finally: pass test_app.dependency_overrides[get_db] = override_get_db test_app.dependency_overrides[require_admin_auth] = mock_admin_auth with TestClient(test_app) as test_client: yield test_client test_app.dependency_overrides.clear()