90 lines
5.5 KiB
GDScript
90 lines
5.5 KiB
GDScript
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")
|
|
|
|
# Neustart: Server kommt nicht zurück -> verständliche Meldung statt ewig warten
|
|
var fake_src := GDScript.new()
|
|
fake_src.source_code = "extends AdminClient\nfunc call_api(method: String, _path: String, _body: Variant = null, _query: Dictionary = {}, _raw: PackedByteArray = PackedByteArray()) -> Dictionary:\n\tawait get_tree().process_frame\n\tif method == \"POST\":\n\t\treturn {\"ok\": true, \"status\": 202, \"body\": {\"ok\": true}, \"transport_error\": \"\"}\n\treturn _transport_fail(\"weg\")\n"
|
|
fake_src.reload()
|
|
var fake_client: Node = fake_src.new()
|
|
panel.add_child(fake_client)
|
|
panel.client = fake_client
|
|
panel.restart_wait_s = 0.3
|
|
panel.restart_poll_s = 0.1
|
|
var ok_restart: bool = await panel.restart_server()
|
|
_check(not ok_restart and not panel.connected and "nicht zurück" in panel._conn_label.text, "Zeitüberschreitung: " + panel._conn_label.text)
|
|
|
|
print("CHECKS: %d FAILURES: %d" % [_checks, _failures.size()])
|
|
quit(0 if _failures.is_empty() else 1)
|