scopedvr-map-editor/tests/server_sektion_e2e.gd
2026-11-01 19:34:05 +01:00

157 lines
7.9 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends SceneTree
## E2E Server-Sektion: das ECHTE Panel gegen einen ECHTEN Match-Server
## (tests/run_server_sektion_e2e.sh). Env: SRV_PORT, SRV_TOKEN, SRV_SVMAP.
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:
var port := int(OS.get_environment("SRV_PORT"))
var token := OS.get_environment("SRV_TOKEN")
var load_res := SvmapIO.load_from_file(OS.get_environment("SRV_SVMAP"))
if not bool(load_res["ok"]):
print("FAIL: Beispiel-Map nicht ladbar: ", load_res["errors"])
quit(1)
return
var good_doc: Dictionary = load_res["data"]
var fake := Control.new()
fake.set_script(load("res://tests/support_fake_main.gd"))
fake.doc = good_doc
root.add_child(fake)
var panel: Control = load("res://core/ui/panels/server_panel.gd").new()
panel.store_path = "user://test_e2e_store.dat"
DirAccess.remove_absolute(ProjectSettings.globalize_path(panel.store_path))
panel.setup(fake)
panel.build()
root.add_child(panel)
await process_frame
# Server anlegen (wie der Dialog) – erst mit FALSCHEM Token
var id: String = panel.store.upsert({"name": "E2E", "host": "127.0.0.1", "port": port, "token": "falsch"})
panel._refresh_selector(id)
var ok: bool = await panel.connect_selected()
_check(not ok and not panel.connected and "Token" in panel.last_notice + panel._conn_label.text, "falsches Token -> verständliche Meldung")
# Unerreichbarer Port
var bad_id: String = panel.store.upsert({"name": "tot", "host": "127.0.0.1", "port": 1, "token": "x"})
panel._refresh_selector(bad_id)
ok = await panel.connect_selected()
_check(not ok and "Keine Verbindung" in panel._conn_label.text, "unerreichbarer Server -> 'Keine Verbindung'")
# Richtig
panel.store.upsert({"id": id, "name": "E2E", "host": "127.0.0.1", "port": port, "token": token})
panel._refresh_selector(id)
ok = await panel.connect_selected()
_check(ok and panel.connected, "Verbinden mit richtigem Token")
_check("Admin E2E" in panel._status_label.text and "Spieler: 0" in panel._status_label.text, "Übersicht zeigt Servername/Spieler: " + panel._status_label.text.replace("\n", " | ").substr(0, 90))
# Einstellungen
_check(panel._settings_editors.has("team_size") and panel._settings_editors.has("password"), "Einstellungsformular aus der API-Spec gebaut")
(panel._settings_editors["team_size"] as SpinBox).value = 3
(panel._settings_editors["mode"] as OptionButton).select(3)
(panel._settings_editors["server_name"] as LineEdit).text = "Neuer Name"
(panel._settings_editors["password"] as LineEdit).text = "pw123"
var ch: Dictionary = panel.changed_settings()
_check(ch.keys().size() == 4 and ch["team_size"] == 3 and ch["mode"] == "dm", "nur geänderte Werte werden gesendet")
await panel.save_settings()
_check("Sofort aktiv" in panel._settings_result.text and "nächsten Map" in panel._settings_result.text and "Neustart" in panel._settings_result.text,
"Antwort zeigt sofort/nächste Map/Neustart: " + panel._settings_result.text.replace("\n", " | "))
_check(panel.changed_settings().is_empty(), "nach Speichern keine offenen Änderungen")
(panel._settings_editors["team_size"] as SpinBox).value = 9999 if false else 1
panel._fill_settings_editors()
_check(int((panel._settings_editors["team_size"] as SpinBox).value) == 3, "Zurücksetzen holt Serverwerte")
(panel._settings_editors["password"] as LineEdit).text = ""
# Push: gültige Map
panel._push_name.text = "editor_test"
var r: Dictionary = await panel.push_current_map()
_check(bool(r["ok"]) and "Hochgeladen" in r["text"], "Push gültige Map: " + str(r["text"]).substr(0, 80))
r = await panel.push_current_map()
_check(not bool(r["ok"]) and bool(r["exists"]), "zweiter Push -> 'existiert' (Nachfrage)")
r = await panel.push_current_map(true)
_check(bool(r["ok"]) and "ersetzt" in r["text"], "Push mit Ersetzen")
# Push: lokal ungültige Map (Spawns weg) -> gar nicht erst hochgeladen
var bad: Dictionary = good_doc.duplicate(true)
bad["spawn_zones"] = {}
fake.doc = bad
r = await panel.push_current_map()
_check(not bool(r["ok"]) and r["stage"] == "lokal" and "nicht hochgeladen" in r["text"], "lokal ungültig -> nicht hochgeladen: " + str(r["text"]).substr(0, 90))
# Server-422 (Editor-Prüfung umgangen): rohe Datei mit kaputter Prüfsumme
fake.doc = good_doc
var client: AdminClient = panel.client
var bytes := '{"format_version": 2, "info": {}}'.to_utf8_buffer()
var raw: Dictionary = await client.call_api("POST", "/maps", null, {"name": "kaputt"}, bytes)
var txt := AdminTexte.erklaere(raw)
_check(int(raw["status"]) == 422 and "abgelehnt" in txt and "•" in txt, "Server-422 -> deutsche Fehlerliste: " + txt.replace("\n", " | ").substr(0, 100))
# Rotation / Maps
await panel.refresh_maps()
var up_id := ""
for k in panel._rotation_checks.keys():
if str(k).ends_with("editor_test.svmap"):
up_id = k
_check(up_id != "", "hochgeladene Map in der Liste")
(panel._rotation_checks[up_id] as CheckBox).button_pressed = true
await panel.save_rotation()
_check("Rotation gespeichert" in panel.last_notice, "Rotation speichern")
await panel.load_map(up_id)
await create_timer(4.0).timeout
await panel.refresh_status()
_check("Example Valley" in panel._status_label.text or "editor_test" in panel._status_label.text, "Map laden: " + panel._status_label.text.split("\n")[1])
await panel.load_map("res://maps/testmap.tscn")
await create_timer(3.0).timeout
await panel.delete_map("editor_test")
_check("Map gelöscht" in panel.last_notice, "Map löschen")
await panel._do_restart()
_check("neu gestartet" in panel.last_notice, "Match neu starten")
# Spieler (leer) + Logs
await panel.refresh_players()
await process_frame
_check(panel._players_box.get_child_count() == 1, "Spielerliste leer-Hinweis")
await panel.kick(4242)
_check("nicht" in panel.last_notice and "Spieler" in panel.last_notice, "Kick unbekannter Spieler -> Meldung: " + panel.last_notice)
panel._log_filter.text = "Admin"
await panel.load_logs()
_check(panel._log_text.text.contains("Admin") and not panel._log_text.text.contains(token), "Logs geladen, Token nicht enthalten")
# Bots: Grenze kommt vom Server, 20 Bots brauchen Teamgröße 10
var bot_box: SpinBox = panel._settings_editors["bot_count"]
_check(bot_box.max_value >= 20.0, "Bot-Feld geht bis mindestens 20 (%d)" % int(bot_box.max_value))
(panel._settings_editors["bots_enabled"] as CheckBox).button_pressed = true
bot_box.value = 20
await panel.save_settings()
_check("⚠" in panel.last_notice and "Teamgröße" in panel.last_notice, "20 Bots bei kleiner Teamgröße -> Warnung: " + panel.last_notice.replace("\n", " | "))
(panel._settings_editors["team_size"] as SpinBox).value = 10
await panel.save_settings()
_check("⚠" not in panel.last_notice, "Teamgröße 10 -> keine Warnung")
await panel.refresh_status()
_check("+ 20 Bots" in panel._status_label.text, "Übersicht zeigt 20 Bots: " + panel._status_label.text.split("\n")[2])
# Server-Neustart über das Start-Skript
panel.restart_poll_s = 0.5
var restart_done := [false, false]
var restart_call := func() -> void:
restart_done[1] = await panel.restart_server()
restart_done[0] = true
restart_call.call()
while panel.connected:
await process_frame
_check("startet neu" in panel._conn_label.text, "Status zeigt: " + panel._conn_label.text)
var wait_end := Time.get_ticks_msec() + 60000
while not restart_done[0] and Time.get_ticks_msec() < wait_end:
await process_frame
_check(restart_done[1] and panel.connected and "neu gestartet" in panel.last_notice, "nach Neustart wieder verbunden: " + panel.last_notice)
_check("Läuft seit 0 h 0 min" in panel._status_label.text, "neuer Prozess läuft")
_check(int((panel._settings_editors["bot_count"] as SpinBox).value) == 20, "Einstellungen überleben den Neustart")
DirAccess.remove_absolute(ProjectSettings.globalize_path(panel.store_path))
print("CHECKS: %d FAILURES: %d" % [_checks, _failures.size()])
quit(0 if _failures.is_empty() else 1)