"""Tests für das Laden der Konfiguration aus Umgebungsvariablen.""" from __future__ import annotations from pathlib import Path import pytest from app import config as config_module from app import create_app from app.config import ( PROJECT_ROOT, ensure_secret_key, env_bool, env_int, load_config, load_or_create_secret_key, resolve_project_path, ) def test_relative_paths_are_anchored_at_project_root() -> None: assert resolve_project_path("instance/x.sqlite3") == PROJECT_ROOT / "instance" / "x.sqlite3" def test_absolute_paths_stay_unchanged(tmp_path: Path) -> None: assert resolve_project_path(tmp_path / "db.sqlite3") == tmp_path / "db.sqlite3" def test_env_int(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.delenv("GD_TEST_INT", raising=False) assert env_int("GD_TEST_INT", 7) == 7 monkeypatch.setenv("GD_TEST_INT", " 12 ") assert env_int("GD_TEST_INT", 7) == 12 monkeypatch.setenv("GD_TEST_INT", "zwölf") with pytest.raises(ValueError, match="ganze Zahl"): env_int("GD_TEST_INT", 7) monkeypatch.setenv("GD_TEST_INT", "0") with pytest.raises(ValueError, match="mindestens"): env_int("GD_TEST_INT", 7, minimum=1) @pytest.mark.parametrize( ("raw", "expected"), [("1", True), ("ja", True), ("0", False), ("", False)] ) def test_env_bool(monkeypatch: pytest.MonkeyPatch, raw: str, expected: bool) -> None: monkeypatch.setenv("GD_TEST_BOOL", raw) assert env_bool("GD_TEST_BOOL", default=False) is expected def test_secret_key_file_is_created_once(tmp_path: Path) -> None: key_file = tmp_path / "instance" / "secret_key" first = load_or_create_secret_key(key_file) second = load_or_create_secret_key(key_file) assert first == second assert len(first) == 64 def test_load_config_reads_environment(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: monkeypatch.setenv("SECRET_KEY", "aus-der-umgebung") monkeypatch.setenv("GLORY_DB_PATH", str(tmp_path / "x.sqlite3")) monkeypatch.setenv("GLORY_RATE_LIMIT_MAX", "9") monkeypatch.setenv("GLORY_RATE_LIMIT_WINDOW", "30") config = load_config() assert config["SECRET_KEY"] == "aus-der-umgebung" assert config["DATABASE_PATH"] == str(tmp_path / "x.sqlite3") assert config["RATE_LIMIT_MAX_SUBMISSIONS"] == 9 assert config["RATE_LIMIT_WINDOW_SECONDS"] == 30 def test_generated_secret_is_created_only_when_needed( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: """Ohne SECRET_KEY entsteht die Schlüsseldatei erst beim ersten Bedarf. Befehle im cPanel-Terminal (Datenbank anlegen, Ehrentafel moderieren) dürfen keine überflüssige Schlüsseldatei erzeugen. """ monkeypatch.delenv("SECRET_KEY", raising=False) key_file = tmp_path / "secret_key" monkeypatch.setattr(config_module, "SECRET_KEY_FILE", key_file) config = load_config() assert config["SECRET_KEY"] is None assert not key_file.exists() key = ensure_secret_key(config) assert key == key_file.read_text(encoding="utf-8") assert config["SECRET_KEY"] == key assert ensure_secret_key(config) == key def test_app_without_secret_creates_key_on_first_token( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: monkeypatch.delenv("SECRET_KEY", raising=False) key_file = tmp_path / "secret_key" monkeypatch.setattr(config_module, "SECRET_KEY_FILE", key_file) app = create_app({"DATABASE_PATH": str(tmp_path / "db.sqlite3")}) client = app.test_client() assert client.get("/").status_code == 200 assert client.get("/healthz").status_code == 200 assert app.test_cli_runner().invoke(args=["scores", "list"]).exit_code == 0 assert not key_file.exists() assert client.post("/api/runs").status_code == 201 assert key_file.exists() assert app.config["SECRET_KEY"] == key_file.read_text(encoding="utf-8") def test_blocklist_path_from_environment(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: monkeypatch.setenv("GLORY_NAME_BLOCKLIST", str(tmp_path / "sperre.txt")) assert load_config()["NAME_BLOCKLIST_PATH"] == str(tmp_path / "sperre.txt") monkeypatch.delenv("GLORY_NAME_BLOCKLIST") assert load_config()["NAME_BLOCKLIST_PATH"] == str( PROJECT_ROOT / "instance" / "name_blocklist.txt" ) def test_overrides_take_precedence(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("SECRET_KEY", "aus-der-umgebung") assert load_config({"SECRET_KEY": "override"})["SECRET_KEY"] == "override"