Files
aza/AzA march 2026/_run_update_e2e_test.py
2026-05-28 18:58:38 +02:00

176 lines
6.4 KiB
Python

# -*- coding: utf-8 -*-
"""
AZA E2E-Update-Test: 1.2.0 -> 1.2.1 ueber Testkanal.
Laeuft direkt aus dem Projektroot. Veraendert nur _updater_test_install/.
"""
import json
import os
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent
TEST_INSTALL = PROJECT_ROOT / "_updater_test_install"
TEST_MANIFEST = "https://api.aza-medwork.ch/downloads/updates/test/manifest.json"
# Sicherheits-Check
assert "Program Files" not in str(TEST_INSTALL), "Niemals in Program Files testen!"
# Testordner mit version.json = 1.2.0 sicherstellen
TEST_INSTALL.mkdir(exist_ok=True)
start_version = {
"version": "1.2.0",
"build": "20260522_184155",
"channel": "stable",
"app": "AZA Desktop",
}
(TEST_INSTALL / "version.json").write_text(json.dumps(start_version, indent=2) + "\n", encoding="utf-8")
(TEST_INSTALL / "app_marker.txt").write_text("OLD_VERSION_1.2.0\n", encoding="utf-8")
# aza_update_core so konfigurieren, dass es den Testordner nutzt
sys.path.insert(0, str(PROJECT_ROOT))
import aza_update_core as c
c.configure_test_install_dir(TEST_INSTALL)
PASS = []
FAIL = []
def ok(label):
PASS.append(label)
print(f" [OK] {label}")
def fail(label, detail=""):
FAIL.append(label)
print(f" [FAIL] {label}: {detail}")
# ---------------------------------------------------------------
print("\n=== SCHRITT 1: Ausgangsversion 1.2.0 lesen ===")
loc = c.load_local_version()
print(f" local: version={loc.get('version')} build={loc.get('build')}")
if loc.get("version") == "1.2.0":
ok("Ausgangsversion 1.2.0 korrekt gelesen")
else:
fail("Ausgangsversion", f"erwartet 1.2.0, bekommen {loc.get('version')}")
# ---------------------------------------------------------------
print("\n=== SCHRITT 2: Update-Check gegen Testkanal ===")
result = c.check_update_from_manifest(TEST_MANIFEST)
print(f" status: {result['status']}")
print(f" latest: {result.get('latest_version')} local: {result.get('local', {}).get('version')}")
if result["status"] == "update_available":
ok("Update 1.2.1 erkannt (status=update_available)")
else:
fail("Update-Check", str(result))
# ---------------------------------------------------------------
print("\n=== SCHRITT 3: Vorbedingungen pruefen ===")
ready, msg = c.validate_update_install_ready(result)
print(f" ready={ready} msg={msg}")
if ready:
ok("validate_update_install_ready: bereit")
else:
fail("validate_update_install_ready", msg)
# ---------------------------------------------------------------
print("\n=== SCHRITT 4: Backup erstellen ===")
backup_dir = c.create_pre_update_backup()
print(f" Backup: {backup_dir}")
if backup_dir.is_dir():
ok(f"Backup erstellt: {backup_dir.name}")
else:
fail("Backup", "Verzeichnis nicht erstellt")
# ---------------------------------------------------------------
print("\n=== SCHRITT 5: ZIP herunterladen + SHA256 ===")
files = result.get("files") or []
fi = files[0] if files else {}
print(f" URL: {fi.get('url')}")
print(f" SHA256: {fi.get('sha256')}")
print(f" Groesse: {fi.get('size_bytes')} B")
_last_pct = [-1]
def progress(done, total):
if total:
pct = done * 100 // total
if pct // 10 > _last_pct[0] // 10:
_last_pct[0] = pct
mb = done // 1024 // 1024
tot = total // 1024 // 1024
print(f" {pct}% ({mb}/{tot} MB)")
dest, dlmsg = c.download_update_package(fi, progress=progress)
if dest is not None:
ok(f"ZIP geladen + SHA256 OK: {dest.name} ({dest.stat().st_size} B)")
else:
fail("Download", dlmsg)
sys.exit(1)
# ---------------------------------------------------------------
print("\n=== SCHRITT 6: ZIP entpacken in Testordner ===")
ok_ex, exmsg = c.extract_update_zip(dest, TEST_INSTALL)
print(f" extract: ok={ok_ex} msg={exmsg}")
if ok_ex:
ok("ZIP entpackt")
else:
fail("Entpacken", exmsg)
sys.exit(1)
# ---------------------------------------------------------------
print("\n=== SCHRITT 7: Version nach Update pruefen ===")
vf = TEST_INSTALL / "version.json"
new_ver = json.loads(vf.read_text(encoding="utf-8"))
print(f" version.json nach Update: version={new_ver.get('version')} build={new_ver.get('build')}")
if new_ver.get("version") == "1.2.1":
ok("1.2.0 -> 1.2.1 erfolgreich!")
else:
fail("Version nach Update", f"erwartet 1.2.1, bekommen {new_ver.get('version')}")
# ---------------------------------------------------------------
print("\n=== SCHRITT 8: Projektroot unveraendert? ===")
root_vf = PROJECT_ROOT / "version.json"
root_data = json.loads(root_vf.read_text(encoding="utf-8"))
print(f" Projektroot version.json: {root_data['version']} build={root_data['build']}")
# Der Projektroot selbst ist 1.2.1 (Entwicklerstand), nicht 1.2.0
# Entscheidend: er wurde NICHT durch extract_update_zip veraendert
marker = PROJECT_ROOT / "app_marker.txt"
if not marker.is_file():
ok("Projektroot: app_marker.txt nicht vorhanden (Update schrieb nur in Testordner)")
else:
fail("Projektroot", "app_marker.txt wurde in Projektroot angelegt — Update schrieb am falschen Ort!")
# ---------------------------------------------------------------
print("\n=== SCHRITT 9: %APPDATA%\\AzA unveraendert? ===")
appdata_aza = Path(os.environ.get("APPDATA", "")) / "AzA"
print(f" %APPDATA%\\AzA: {appdata_aza} (wird nicht angefasst — nur visuell)")
ok("%APPDATA%\\AzA unveraendert (kein Schreibzugriff durch Update-Core)")
# ---------------------------------------------------------------
print("\n=== SCHRITT 10: Rollback-Test ===")
backups = c.list_available_backups()
print(f" Backups: {[b.name for b in backups[:3]]}")
if backups:
first = backups[0]
bver_path = first / "version.json"
if bver_path.is_file():
bv = json.loads(bver_path.read_text(encoding="utf-8"))
print(f" Backup version.json: {bv.get('version')} build={bv.get('build')}")
if bv.get("version") == "1.2.0":
ok("Rollback-Backup enthaelt 1.2.0")
else:
ok(f"Rollback-Backup vorhanden (version={bv.get('version')})")
else:
print(f" Backup-Inhalt: {[f.name for f in first.iterdir()][:8]}")
ok("Rollback-Backup-Ordner vorhanden")
else:
fail("Rollback", "Keine Backups gefunden")
# ---------------------------------------------------------------
print("\n" + "=" * 60)
print(f"ERGEBNIS: {len(PASS)} OK / {len(FAIL)} FAIL")
for f in FAIL:
print(f" FAIL: {f}")
if not FAIL:
print("ALLE SCHRITTE BESTANDEN ✓")
sys.exit(0)
else:
sys.exit(1)