"""Testet UsersConfig gegen eine realistische users.cfg."""
import shutil, sys, tempfile
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from kerio_users_config import UsersConfig, validate_login
from kerio_common import AbortedError
SAMPLE = '''
Admin
local.lan
1
CDE8D0A3-929B-4AC6-8197-4C39D58C8A64
D3S:0faed6fd
Administrator
max.mustermann
local.lan
1
94480090-4C04-4FE2-9126-0DBDAEC85F5F
D3S:b6a11602
Max Mustermann
max.mustermann
andere.lan
1
AAAAAAAA-0000-0000-0000-000000000000
D3S:anders
Max in anderer Domain
ldap.user
local.lan
1
BBBBBBBB-0000-0000-0000-000000000000
LDAP Benutzer
testgruppe
local.lan
E78FEFAB-2C65-4D08-946B-76E3989EEF9D
max.mustermann
local.lan
1
SHA:28108e32
ldap.user
local.lan
0
'''
tmp = Path(tempfile.mkdtemp())
cfg_path = tmp / "users.cfg"
cfg_path.write_text(SAMPLE, encoding="utf-8")
ok = True
def check(label, cond):
global ok
print(f" {'ok ' if cond else 'FEHLER'} {label}")
if not cond: ok = False
print("== 1. Lesen ==")
c = UsersConfig(cfg_path)
check("Domains gefunden", set(c.domains()) == {"local.lan", "andere.lan"})
check("4 Benutzer gesamt", len(c.users()) == 4)
check("3 in local.lan", len(c.users("local.lan")) == 3)
u = c.find_user("max.mustermann", "local.lan")
check("Benutzer gefunden", u is not None and u["guid"].startswith("94480090"))
check("fullName gelesen", u["fullName"] == "Max Mustermann")
check("Domain-Trennung: andere.lan hat eigenen Eintrag",
c.find_user("max.mustermann", "andere.lan")["guid"].startswith("AAAA"))
print("\n== 2. Verzeichnisdienst erkennen ==")
check("max.mustermann ist intern", c.is_internal("max.mustermann", "local.lan"))
check("ldap.user ist NICHT intern", not c.is_internal("ldap.user", "local.lan"))
print("\n== 3. Login-Namen validieren ==")
for good in ("anna.schmidt", "a", "a-b_c.d", "user123"):
try:
validate_login(good); check(f"{good!r} erlaubt", True)
except AbortedError:
check(f"{good!r} erlaubt", False)
for bad in ("", ".anfang", "ende.", "mit leerzeichen", "boes", "a"*100, "a&b"):
try:
validate_login(bad); check(f"{bad!r} abgelehnt", False)
except AbortedError:
check(f"{bad!r} abgelehnt", True)
print("\n== 4. Umbenennen ==")
c2 = UsersConfig(cfg_path)
n = c2.rename_user("max.mustermann", "maxi.musterfrau", "local.lan", "Maxi Musterfrau")
check("2 Bloecke geaendert (User + UserAdditionalData)", n == 2)
c2.save()
c3 = UsersConfig(cfg_path)
check("neuer Name da", c3.find_user("maxi.musterfrau", "local.lan") is not None)
check("alter Name weg in local.lan", c3.find_user("max.mustermann", "local.lan") is None)
check("fullName geaendert", c3.find_user("maxi.musterfrau","local.lan")["fullName"] == "Maxi Musterfrau")
check("Guid unveraendert", c3.find_user("maxi.musterfrau","local.lan")["guid"].startswith("94480090"))
check("ANDERE DOMAIN unberuehrt",
c3.find_user("max.mustermann", "andere.lan") is not None)
check("Passworthistorie mitgewandert", c3.is_internal("maxi.musterfrau", "local.lan"))
txt = cfg_path.read_text(encoding="utf-8")
check("Passwort-Hash erhalten", "D3S:b6a11602" in txt)
check("PasswordHistory erhalten", "SHA:28108e32" in txt)
check("Admin unberuehrt", "Admin" in txt)
check("Gruppe unberuehrt", "testgruppe" in txt)
check("kein max.mustermann mehr in UserAdditionalData/local.lan",
txt.count("max.mustermann") == 1) # nur noch andere.lan
print("\n== 5. other_occurrences ==")
c4 = UsersConfig(cfg_path)
hits = c4.other_occurrences("testgruppe", "local.lan")
check("findet Treffer in Group-Liste", any("Group" in h for h in hits))
check("keine Treffer fuer unbekannten Namen",
c4.other_occurrences("gibtsnicht", "local.lan") == [])
print("\n== 6. Abgelehnter Login-Name aendert nichts ==")
c5 = UsersConfig(cfg_path)
before = c5.text
try:
c5.rename_user("maxi.musterfrau", "boes", "local.lan")
check("haette ablehnen muessen", False)
except AbortedError:
check("ungueltiger Zielname abgelehnt", True)
check("Text unveraendert", c5.text == before)
print("\n" + ("ALLE TESTS BESTANDEN" if ok else "FEHLGESCHLAGEN"))
sys.exit(0 if ok else 1)