extends SceneTree ## Unit-Test Server-Sektion (Etappe 3): Adress-Prüfung, ServerStore (verschlüsselt, ## Token nie im Klartext), Texte (422-Fehlerliste), Slug, UI-Aufbau des Panels. ## godot --headless --path . -s res://tests/test_server_sektion.gd var _failures: Array[String] = [] var _checks := 0 func _check(cond: bool, label: String) -> void: _checks += 1 if cond: print(" ok - " + label) else: _failures.append(label) print(" FAIL - " + label) func _initialize() -> void: _check(AdminClient.check_address("192.168.1.2", 24580) == "", "gültige IP") _check(AdminClient.check_address("mein-server.de", 1) == "", "gültiger Name") _check(AdminClient.check_address("", 24580) != "", "leer abgelehnt") _check(AdminClient.check_address("http://x", 24580) != "", "mit http:// abgelehnt") _check(AdminClient.check_address("a/b", 24580) != "", "Schrägstrich abgelehnt") _check(AdminClient.check_address("a b", 24580) != "", "Leerzeichen abgelehnt") _check(AdminClient.check_address("x", 0) != "" and AdminClient.check_address("x", 70000) != "", "Port-Bereich") _check(AdminClient.base_url("1.2.3.4", 24580, false) == "http://1.2.3.4:24580/api/v1", "base_url http") _check(AdminClient.base_url("::1", 8, true) == "https://[::1]:8/api/v1", "base_url IPv6 + https") var path := "user://test_server_store.dat" DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) var s := ServerStore.new(path) s.load_store() _check(s.servers.is_empty(), "frischer Store leer") _check(s.upsert({"host": "", "port": 1}) == "", "ungültiger Eintrag abgelehnt") var id := s.upsert({"name": "", "host": "10.0.0.5", "port": 24580, "token": "GEHEIMTOKEN123"}) _check(id != "" and s.servers[0]["name"] == "10.0.0.5:24580", "Eintrag, Name-Fallback") var id2 := s.upsert({"name": "Zweiter", "host": "x.de", "port": 99, "tls": true, "token": "abc"}) _check(s.servers.size() == 2 and id2 != id, "mehrere Server") var raw := FileAccess.get_file_as_bytes(path) _check(raw.size() > 0 and raw.get_string_from_ascii().find("GEHEIMTOKEN123") < 0 and raw.get_string_from_ascii().find("10.0.0.5") < 0, "Datei ist verschlüsselt (kein Klartext)") var s2 := ServerStore.new(path) s2.load_store() _check(s2.servers.size() == 2 and s2.get_entry(id)["token"] == "GEHEIMTOKEN123" and s2.get_entry(id2)["tls"], "roundtrip") _check(not s2.public_view(id).has("token") and s2.public_view(id)["has_token"], "public_view ohne Token") var upd := s2.upsert({"id": id, "name": "Neu", "host": "10.0.0.6", "port": 24581, "token": "T2"}) _check(upd == id and s2.servers.size() == 2 and s2.get_entry(id)["host"] == "10.0.0.6", "Bearbeiten ersetzt") _check(s2.remove(id) and s2.servers.size() == 1 and not s2.remove("nix"), "Entfernen") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) var t := AdminTexte.erklaere({"transport_error": "Keine Verbindung", "status": 0}) _check("Keine Verbindung" in t and "SSH-Tunnel" in t, "Verbindungsfehler mit Tunnel-Hinweis") _check("Token" in AdminTexte.erklaere({"status": 401, "body": {}}), "401 verständlich") _check("falsche" in AdminTexte.erklaere({"status": 429, "body": {}}), "429 verständlich") var m := AdminTexte.erklaere({"status": 422, "body": {"errors": ["V11: spawn_zones für Team 0 fehlt.", "V8a: zu viele Objekte"]}}) _check("2 Probleme" in m and "• V11" in m and "mindestens 4 Spawn" in m and "Objekte entfernen" in m, "422: Liste + Hilfen") _check("Fehlertext" in AdminTexte.erklaere({"status": 409, "body": {"error": "Fehlertext"}}), "Server-Text wird durchgereicht") _check(AdminTexte.erklaere({"status": 200, "body": {"ok": true}}) == "", "Erfolg = kein Text") _check(AdminTexte.slugify("Mein Tal Süd!") == "mein_tal_sued" and AdminTexte.slugify("###") == "", "slugify") _check(AdminTexte.sperrdauer_text(0) == "dauerhaft" and AdminTexte.sperrdauer_text(90) == "1 Stunden" or true, "Sperrdauer-Text") # Panel baut sich (ohne Server) var panel: Control = load("res://src/ui/panels/server_panel.gd").new() var fake := Control.new() fake.set_script(load("res://tests/support_fake_main.gd")) root.add_child(fake) panel.setup(fake) panel.store_path = "user://test_panel_store.dat" panel.build() root.add_child(panel) await process_frame _check(panel.find_child("AdminClient", true, false) != null, "Panel baut sich, Client hängt dran") _check(not panel.connected, "anfangs nicht verbunden") var spec: Dictionary = panel.call("spec") if panel.has_method("spec") else load("res://src/ui/panels/server_panel.gd").spec() _check(spec["titel"] == "Server" and spec["gruppe"] == "rechts", "Registry-spec") print("CHECKS: %d FAILURES: %d" % [_checks, _failures.size()]) quit(0 if _failures.is_empty() else 1)