"""Tests für das Upload-Paket (scripts/build_deploy_zip.py). Prüft, dass das Paket vollständig ist, keine Geheimnisse oder Caches enthält, nur „/“ als Pfadtrenner nutzt und nach dem Entpacken wie auf cPanel startet. """ from __future__ import annotations import importlib.util import os import subprocess import sys import zipfile from pathlib import Path from types import ModuleType from app.config import PROJECT_ROOT def _load_builder() -> ModuleType: spec = importlib.util.spec_from_file_location( "build_deploy_zip", PROJECT_ROOT / "scripts" / "build_deploy_zip.py" ) assert spec is not None and spec.loader is not None module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def test_zip_contains_everything_the_server_needs(tmp_path: Path) -> None: target = tmp_path / "paket.zip" names = _load_builder().build_zip(target) with zipfile.ZipFile(target) as archive: archived = set(archive.namelist()) assert archived == set(names) for required in ( "passenger_wsgi.py", "requirements.txt", "app/__init__.py", "app/templates/index.html", "app/static/js/main.js", "app/static/js/lib/phaser.min.js", "app/static/assets/sprites/president.svg", ): assert required in archived, required def test_zip_has_no_secrets_caches_or_backslashes(tmp_path: Path) -> None: target = tmp_path / "paket.zip" names = _load_builder().build_zip(target) assert all("\\" not in name for name in names) assert not any(name == ".env" or name.startswith("instance/") for name in names) assert not any("__pycache__" in name or name.endswith(".pyc") for name in names) assert not any(name.startswith(("tests/", "node_modules/", ".venv/")) for name in names) def test_unpacked_zip_starts_like_on_cpanel(tmp_path: Path) -> None: """Das entpackte Paket allein reicht: passenger_wsgi importiert die App und liefert Seiten.""" target = tmp_path / "paket.zip" _load_builder().build_zip(target) deploy_root = tmp_path / "glory_defense" with zipfile.ZipFile(target) as archive: archive.extractall(deploy_root) env = {k: v for k, v in os.environ.items() if not k.startswith(("GLORY_", "SECRET_KEY"))} env["SECRET_KEY"] = "deploy-test" script = ( "import runpy\n" f"app = runpy.run_path({str(deploy_root / 'passenger_wsgi.py')!r})['application']\n" "c = app.test_client()\n" "print(c.get('/').status_code, c.get('/static/js/lib/phaser.min.js').status_code," " c.get('/api/highscores').status_code)\n" ) result = subprocess.run( [sys.executable, "-c", script], cwd=tmp_path, env=env, capture_output=True, text=True, timeout=60, check=False, ) assert result.returncode == 0, result.stderr assert result.stdout.strip() == "200 200 200" # Datenbank entsteht im entpackten Projekt, nicht im Arbeitsverzeichnis. assert (deploy_root / "instance" / "glory_defense.sqlite3").exists()