# -*- 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)