"""Test environment bootstrap. Cauldron's server module instantiates a DB + OAuth client + Mealie client at import time, so tests must stub those before importing cauldron.server. This module performs that stubbing exactly once (idempotent — safe to import multiple times). Both pytest's conftest.py and direct `unittest discover` runs route through here. """ import os from unittest.mock import MagicMock, patch from cryptography.fernet import Fernet _BOOTSTRAPPED = False def _stub_env() -> None: os.environ.setdefault("SECRET_KEY", "test-secret") os.environ.setdefault("MEALIE_BASE_URL", "http://mealie.test") os.environ.setdefault("MEALIE_API_TOKEN", "mealie-test-token") os.environ.setdefault("CLAWDFORGE_URL", "http://forge.test") os.environ.setdefault("CLAWDFORGE_TOKEN", "forge-test-token") os.environ.setdefault("ADMIN_BEARER", "admin-test-bearer") os.environ.setdefault("OIDC_ISSUER", "http://authentik.test/application/o/cauldron") os.environ.setdefault("OIDC_CLIENT_ID", "test-client") os.environ.setdefault("OIDC_CLIENT_SECRET", "test-secret-client") os.environ.setdefault("OIDC_REDIRECT_URI", "http://localhost/auth/callback") os.environ.setdefault("DB_HOST", "localhost") os.environ.setdefault("DB_NAME", "cauldron_test") os.environ.setdefault("DB_USER", "cauldron") os.environ.setdefault("DB_PASSWORD", "test") os.environ.setdefault("CAULDRON_FERNET_KEY", Fernet.generate_key().decode()) class _FakeCursor: def __init__(self): self.lastrowid = 0 self.rowcount = 0 def execute(self, *a, **kw): pass def fetchone(self): return None def fetchall(self): return [] def __enter__(self): return self def __exit__(self, *a): return False class _FakeConn: def __init__(self, *a, **kw): pass def cursor(self): return _FakeCursor() def commit(self): pass def rollback(self): pass def close(self): pass def bootstrap() -> None: """Apply env + import-time monkey patches. Idempotent.""" global _BOOTSTRAPPED if _BOOTSTRAPPED: return _stub_env() # pymysql.connect → no-op fake patch("pymysql.connect", _FakeConn).start() # Pre-import dotted modules so the next patches resolve import cauldron.db # noqa: F401 import cauldron.oidc # noqa: F401 import cauldron.foods # noqa: F401 # Skip migrations patch("cauldron.db.DB.migrate", lambda self: []).start() # Skip OIDC metadata fetch oauth_obj = MagicMock() oauth_obj.cauldron = MagicMock() patch("cauldron.oidc.init_oauth", lambda *a, **kw: oauth_obj).start() # Skip foods seed loader patch("cauldron.foods.load_seed_if_empty", lambda db: 0).start() _BOOTSTRAPPED = True bootstrap()