86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
"""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
|