Files
kerio-connect-rename-user/tests/test_store.py
T
duffyduckandClaude Opus 5 5011491067 Umbenennung ueber users.cfg statt Administration API
Der Test gegen einen echten Server (Kerio Connect 10.0.9 patch 2) hat
gezeigt, dass Users.set das Feld loginName stillschweigend ignoriert -
kein Fehler, keine Wirkung, waehrend fullName im selben Aufruf sauber
uebernommen wird. Vier Varianten geprueft (nur loginName, mit domainId,
mit leeren emailAddresses, vollstaendiges User-Objekt): alle wirkungslos.
Der bisherige Ansatz konnte also gar nicht funktionieren.

Der Login-Name steht in users.cfg, und zwar in zwei Listen: User und
UserAdditionalData. Beide verweisen ueber Name+Domain statt ueber die
Guid, beide muessen mit, sonst verliert der Benutzer seine
Passworthistorie. Geaendert wird der Rohtext, damit Formatierung und
unbekannte Felder unangetastet bleiben.

users.cfg und Store-Verzeichnis wandern jetzt in EINEM Stopp-Fenster.
Laeuft Kerio zwischendurch mit nur einer Haelfte, legt es die
vermeintlich fehlende Mailbox sofort neu an - beim Entwickeln genau so
passiert. Damit entfaellt auch der Admin-Zugang: das Script braucht
keine Zugangsdaten mehr, --list zeigt die Benutzer aus der Datei.

Ausserdem gefunden: itemSource heisst 'DSInternalSource', nicht
'Internal' wie angenommen - die alte Pruefung haette bei jedem lokalen
Benutzer faelschlich abgebrochen. Die Erkennung laeuft jetzt ueber
InternalDb in users.cfg.

Tests fuer beide Haelften unter tests/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 13:44:31 +02:00

80 lines
2.9 KiB
Python

"""Testet die Store-Logik gegen einen nachgebauten Kerio-Store."""
import sys, tempfile, os
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from kerio_rename_user import (
plan_store_renames, check_rename_targets, apply_store_renames,
find_dir_ci, AbortedError, revert_store_renames,
)
root = Path(tempfile.mkdtemp())
store = root / "store"
# Kerio-Store nachbauen: mail/ und archive/, Verzeichnisse klein geschrieben
for sub in ("mail", "archive"):
d = store / sub / "firma.de" / "anna.mueller"
d.mkdir(parents=True)
(d / "INBOX").mkdir()
(d / "INBOX" / "msg.eml").write_text("hallo")
# ein anderer Benutzer, der nicht angefasst werden darf
(store / "mail" / "firma.de" / "bob").mkdir(parents=True)
print("== 1. Planung ==")
renames = plan_store_renames(store, "firma.de", "anna.mueller", "anna.schmidt")
for s, t in renames:
print(f" {s.relative_to(store)} -> {t.relative_to(store)}")
assert len(renames) == 2, renames
check_rename_targets(renames)
print("\n== 2. Domain case-insensitiv (FIRMA.DE) ==")
r2 = plan_store_renames(store, "FIRMA.DE", "Anna.Mueller", "anna.schmidt")
assert len(r2) == 2, r2
print(" ok, findet trotz Gross-/Kleinschreibung")
print("\n== 3. Zielverzeichnis belegt -> Abbruch ==")
(store / "mail" / "firma.de" / "anna.schmidt").mkdir()
try:
check_rename_targets(renames)
print(" FEHLER: haette abbrechen muessen")
sys.exit(1)
except AbortedError as e:
print(f" ok: {e}")
(store / "mail" / "firma.de" / "anna.schmidt").rmdir()
print("\n== 4. Benutzer ohne Verzeichnis -> leere Liste, kein Abbruch ==")
r4 = plan_store_renames(store, "firma.de", "gibtsnicht", "neu")
assert r4 == [], r4
print(" ok, leere Liste (users.cfg wird dann trotzdem geaendert)")
print("\n== 5. (dry-run wird jetzt im Aufrufer behandelt) ==")
pass # dry-run liegt jetzt im Aufrufer
assert (store / "mail" / "firma.de" / "anna.mueller").is_dir()
print(" ok, Quelle noch da")
print("\n== 6. Tatsaechliches Verschieben ==")
done = apply_store_renames(renames)
assert len(done) == 2
for sub in ("mail", "archive"):
neu = store / sub / "firma.de" / "anna.schmidt"
assert neu.is_dir(), neu
assert (neu / "INBOX" / "msg.eml").read_text() == "hallo"
assert not (store / sub / "firma.de" / "anna.mueller").exists()
assert (store / "mail" / "firma.de" / "bob").is_dir(), "anderer Benutzer angefasst!"
print(" ok, Inhalte erhalten, Fremdbenutzer unberuehrt")
print("\n== 7. Rollback ==")
revert_store_renames(done)
for sub in ("mail", "archive"):
assert (store / sub / "firma.de" / "anna.mueller" / "INBOX" / "msg.eml").read_text() == "hallo"
print(" ok, alles zurueck")
print("\n== 8. Store-Pfad falsch -> klare Meldung ==")
try:
plan_store_renames(root / "gibtsnicht", "firma.de", "a", "b")
sys.exit(1)
except AbortedError as e:
print(f" ok: {str(e)[:70]}...")
print("\nALLE TESTS BESTANDEN")