import os import secrets import sys from pathlib import Path os.environ.setdefault("JUMPHOST_ENV", "development") os.environ.setdefault("JUMPHOST_DEV_KEK", secrets.token_hex(32)) os.environ.setdefault("JUMPHOST_DEV_SESSION_SECRET", secrets.token_hex(32)) sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) import pytest # noqa: E402 from httpx import ASGITransport, AsyncClient # noqa: E402 @pytest.fixture() def tmp_data_dir(tmp_path, monkeypatch): monkeypatch.setenv("JUMPHOST_DATA_DIR", str(tmp_path)) return tmp_path @pytest.fixture(autouse=True) def _reset_rate_limiter(): """login_rate_limiter (app/security/rate_limit.py) ist bewusst ein Prozess-weiter In-Memory-Singleton (siehe Konzept/Docstring dort) -- genau das wird hier durch die Tests bestaetigt (test_source_ip_rate_limit_*). Damit sich einzelne Tests nicht gegenseitig ueber ihr Kontingent beeinflussen, wird der Zustand vor JEDEM Test zurueckgesetzt.""" from app.security.rate_limit import login_rate_limiter login_rate_limiter._events.clear() yield login_rate_limiter._events.clear() @pytest.fixture() async def client(tmp_data_dir): # app.config.settings ist ein Modul-Singleton, der beim ERSTEN Import des # Prozesses einmalig aus der Umgebung gelesen wird (siehe app/config.py) -- # spaetere Aenderungen von JUMPHOST_DATA_DIR je Test wirken sich darauf # nicht mehr aus. Fuer Testisolation wird daher die (immer gleiche) # DB-Datei vor jedem Test explizit zurueckgesetzt statt sich auf einen # neuen Datenpfad pro Test zu verlassen. from app.main import app from app.config import settings for suffix in ("", "-wal", "-shm"): p = settings.data_dir / f"jumphost.db{suffix}" if p.exists(): p.unlink() transport = ASGITransport(app=app) # https:// Base-URL, da unsere Session-Cookies "Secure" gesetzt haben # (Konzept 6.2) und httpx' Cookie-Jar dies wie ein Browser respektiert. async with AsyncClient(transport=transport, base_url="https://testserver") as ac: async with app.router.lifespan_context(app): yield ac