"""Tests für den Passenger-Einstiegspunkt (cPanel „Setup Python App“).""" from __future__ import annotations import importlib.util import os import subprocess import sys from collections.abc import Iterator from pathlib import Path import pytest from flask import Flask from app.config import PROJECT_ROOT PASSENGER_FILE = PROJECT_ROOT / "passenger_wsgi.py" def _clean_env(tmp_path: Path) -> dict[str, str]: env = {k: v for k, v in os.environ.items() if not k.startswith(("GLORY_", "SECRET_KEY"))} env["SECRET_KEY"] = "passenger-test" env["GLORY_DB_PATH"] = str(tmp_path / "passenger.sqlite3") return env @pytest.fixture() def isolated_environ() -> Iterator[None]: """Stellt os.environ nach dem Test wieder her. passenger_wsgi.py lädt eine vorhandene .env-Datei in os.environ. Ohne diese Isolation würden deren Werte (z. B. GLORY_RATE_LIMIT_MAX) in spätere Tests durchsickern. """ saved = dict(os.environ) yield os.environ.clear() os.environ.update(saved) @pytest.mark.usefixtures("isolated_environ") def test_passenger_file_exposes_wsgi_application( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: monkeypatch.setenv("SECRET_KEY", "passenger-test") monkeypatch.setenv("GLORY_DB_PATH", str(tmp_path / "passenger.sqlite3")) spec = importlib.util.spec_from_file_location("passenger_wsgi_under_test", PASSENGER_FILE) assert spec is not None and spec.loader is not None module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) application = module.application assert isinstance(application, Flask) client = application.test_client() assert client.get("/").status_code == 200 assert client.get("/healthz").get_json() == {"status": "ok"} def test_passenger_import_works_from_foreign_working_directory(tmp_path: Path) -> None: """Passenger startet nicht zwingend im Projektordner – der Import muss trotzdem klappen.""" script = ( "import runpy, sys\n" f"ns = runpy.run_path({str(PASSENGER_FILE)!r})\n" "app = ns['application']\n" "print(type(app).__name__, app.test_client().get('/healthz').status_code)\n" ) result = subprocess.run( [sys.executable, "-c", script], cwd=tmp_path, env=_clean_env(tmp_path), capture_output=True, text=True, timeout=60, check=False, ) assert result.returncode == 0, result.stderr assert result.stdout.strip() == "Flask 200" assert (tmp_path / "passenger.sqlite3").exists() def test_passenger_file_uses_only_relative_project_paths() -> None: source = PASSENGER_FILE.read_text(encoding="utf-8") assert "application = create_app()" in source # Keine fest verdrahteten Pfade (z. B. /home/user/...), sonst bricht es beim Umzug. assert "/home/" not in source assert "C:\\" not in source