176 lines
6.4 KiB
Python
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)
|