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://src/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") 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)