Erster Stand des öffentlichen Ausschnitts aus dem Vault. Die .gitignore arbeitet als Positivliste: ausgeschlossen ist alles, eingeschlossen nur, was ausdrücklich wieder aufgenommen wird. Notizen, Projekte, Finanzen, das Sitzungsgedächtnis und settings.local.json bleiben damit außen vor. Der Kundenname in AI/Regelwerk/seo.md ist durch eine neutrale Bezeichnung ersetzt; die Regeln selbst sind unverändert. Co-Authored-By: Claude Opus 5 <[email protected]>
116 lines
4.3 KiB
Python
116 lines
4.3 KiB
Python
"""Wiederaufbau-Test im Browser: Backend weg, Backend wieder da -- ohne Neuladen der Seite.
|
|
|
|
Koordinator-Pruefskript (Windows-Python mit Playwright), nicht fuers Repo.
|
|
Frage: Zeigt die Kopfzeile "Backend getrennt", wenn das Backend stirbt, und von selbst wieder
|
|
"Backend verbunden", wenn es zurueck ist? Herkunft: Projektvorgabe (Spec, Abschnitt Frontend).
|
|
Statustexte aus dashboard/src/components/Kopfzeile.tsx (abgeschrieben am 2026-09-17).
|
|
Was es nicht sieht: die Wartezeiten 1/2/5/10 s im Einzelnen (dafuer api.test.ts), andere Browser als Chromium.
|
|
Regressionsnachweis: --ohne-neustart laesst das Backend unten; der Lauf muss dann mit Exit 2 am Schritt
|
|
"wieder verbunden" enden.
|
|
Aufruf: python -X utf8 wiederaufbau.py [--ohne-neustart]
|
|
"""
|
|
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
from playwright.sync_api import TimeoutError as PlaywrightTimeout
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
PORT = 8146
|
|
BASIS = f"http://localhost:{PORT}"
|
|
HIER = Path(__file__).parent
|
|
|
|
|
|
def starte_backend() -> subprocess.Popen:
|
|
skript = open(HIER / "start_probe.sh", "rb")
|
|
return subprocess.Popen(
|
|
["wsl", "-d", "Debian", "--", "bash", "-s", str(PORT), "1.0"],
|
|
stdin=skript, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
|
)
|
|
|
|
|
|
def beende_backend() -> None:
|
|
subprocess.run(["wsl", "-d", "Debian", "--", "pkill", "-f", f"start_probe_backend.py {PORT}"],
|
|
stdin=subprocess.DEVNULL, capture_output=True)
|
|
|
|
|
|
def warte_auf_backend(sekunden: float) -> bool:
|
|
ende = time.time() + sekunden
|
|
while time.time() < ende:
|
|
try:
|
|
with urllib.request.urlopen(BASIS + "/api/uebersicht", timeout=1) as antwort:
|
|
if antwort.status == 200:
|
|
return True
|
|
except OSError:
|
|
time.sleep(0.5)
|
|
return False
|
|
|
|
|
|
def main() -> int:
|
|
ohne_neustart = "--ohne-neustart" in sys.argv
|
|
beende_backend()
|
|
prozess = starte_backend()
|
|
schritte: list[str] = []
|
|
try:
|
|
if not warte_auf_backend(40):
|
|
print("BEFUND: Probe-Backend kommt nicht hoch -- der Lauf misst nichts")
|
|
return 2
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch()
|
|
seite = browser.new_page(viewport={"width": 1280, "height": 800})
|
|
fehler: list[str] = []
|
|
seite.on("pageerror", lambda e: fehler.append(str(e)))
|
|
seite.goto(BASIS + "/", wait_until="domcontentloaded")
|
|
seite.evaluate("() => { window.__marke = 'nicht neu geladen'; }")
|
|
|
|
def erwarte(text: str, sekunden: float, name: str) -> bool:
|
|
start = time.time()
|
|
try:
|
|
seite.get_by_text(text, exact=True).first.wait_for(timeout=sekunden * 1000)
|
|
except PlaywrightTimeout:
|
|
print(f"BEFUND: Schritt '{name}': '{text}' erscheint nicht binnen {sekunden} s")
|
|
return False
|
|
schritte.append(f"{name}: '{text}' nach {time.time() - start:.1f} s")
|
|
return True
|
|
|
|
if not erwarte("Backend verbunden", 20, "erste Verbindung"):
|
|
return 2
|
|
beende_backend()
|
|
prozess.wait(timeout=20)
|
|
if not erwarte("Backend getrennt", 20, "nach dem Ende des Backends"):
|
|
return 2
|
|
if not ohne_neustart:
|
|
prozess = starte_backend()
|
|
if not warte_auf_backend(40):
|
|
print("BEFUND: Probe-Backend kommt nach dem Neustart nicht hoch")
|
|
return 2
|
|
if not erwarte("Backend verbunden", 30, "wieder verbunden"):
|
|
return 2
|
|
marke = seite.evaluate("() => window.__marke")
|
|
if marke != "nicht neu geladen":
|
|
print(f"BEFUND: Die Seite wurde neu geladen (Marke {marke!r})")
|
|
return 2
|
|
if fehler:
|
|
print(f"BEFUND: Seitenfehler: {fehler[:3]}")
|
|
return 2
|
|
browser.close()
|
|
for schritt in schritte:
|
|
print("ok " + schritt)
|
|
print("Kein Befund: Wiederaufbau ohne Neuladen.")
|
|
return 0
|
|
finally:
|
|
for schritt in schritte:
|
|
pass
|
|
beende_backend()
|
|
try:
|
|
prozess.wait(timeout=10)
|
|
except subprocess.TimeoutExpired:
|
|
prozess.kill()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|