Zwei-Instanzen-Test unabhängig von der Startzeit, Bot endet immer

Die Uhr des Hosts wartet jetzt auf den Gast. So kann ein langsamer Start
des zweiten Prozesses die Takte bis zum Vergleich nicht mehr verbrauchen.
Der Bot endet auch dann, wenn er seinen Bericht nicht schreiben kann,
und überlebt den Test nie. Ein leeres --storage= führt ihn nicht mehr in
den Ordner des Spielers. Ein neuer Test prüft, dass der Bot ohne
schreibbaren Bericht mit Exit-Code 1 endet.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Steven Wroblewski
2026-10-01 23:24:10 +02:00
parent acce1ed435
commit 84e786e531
2 changed files with 43 additions and 5 deletions
+30
View File
@@ -18,6 +18,9 @@ func test_a_guest_in_another_process_stays_in_lockstep() -> void:
host.options.port = 0 host.options.port = 0
host.listen_address = "127.0.0.1" host.listen_address = "127.0.0.1"
check(host.play(true), "the world opens") check(host.play(true), "the world opens")
# The host's clock waits for the guest, so that a slow start of the second
# process cannot use up the ticks before UNTIL.
host.clock.paused = true
var report_path := directory.path_join("guest.json") var report_path := directory.path_join("guest.json")
var arguments := PackedStringArray([ var arguments := PackedStringArray([
@@ -63,3 +66,30 @@ func test_a_guest_in_another_process_stays_in_lockstep() -> void:
host.link.link.close() host.link.link.close()
host.free() host.free()
TestFiles.remove_dir(directory) TestFiles.remove_dir(directory)
func test_a_guest_bot_that_cannot_write_its_report_still_ends() -> void:
var directory := TestFiles.temporary_dir("bot-report")
var arguments := PackedStringArray([
"--headless",
"--path", ProjectSettings.globalize_path("res://"),
"--log-file", ProjectSettings.globalize_path(directory.path_join("bot.log")),
"-s", "res://tools/guest_bot.gd",
"--",
# An address that cannot be read ends the session at once.
"--join=host:port",
"--storage=" + directory.path_join("bot"),
# A folder cannot be opened as the report file.
"--out=" + ProjectSettings.globalize_path(directory),
])
var process := OS.create_process(OS.get_executable_path(), arguments)
check(process > 0, "the bot starts")
var started := Time.get_ticks_msec()
while OS.is_process_running(process) and Time.get_ticks_msec() - started < PATIENCE_MSEC:
await tree.process_frame
var ended := not OS.is_process_running(process)
if not ended:
OS.kill(process)
check(ended, "the bot ends")
check_eq(OS.get_process_exit_code(process), 1, "and reports a failure")
TestFiles.remove_dir(directory)
+11 -3
View File
@@ -24,7 +24,9 @@ func _run() -> void:
var report := {"error": "the host did not answer"} var report := {"error": "the host did not answer"}
var main: Node = load("res://main.tscn").instantiate() var main: Node = load("res://main.tscn").instantiate()
main.storage_dir = settings.get("--storage", "user://bot") # Never the player's own folder, even for an empty --storage=.
var storage: String = settings.get("--storage", "")
main.storage_dir = storage if not storage.is_empty() else "user://bot"
main.command_line = PackedStringArray(["--join=" + settings.get("--join", ""), "--name=Bot"]) main.command_line = PackedStringArray(["--join=" + settings.get("--join", ""), "--name=Bot"])
root.add_child(main) root.add_child(main)
@@ -50,10 +52,16 @@ func _run() -> void:
} }
break break
var file := FileAccess.open(settings.get("--out", "user://bot.json"), FileAccess.WRITE) # The bot ends in every case, even if the report cannot be written, so that
# it never outlives the test that started it.
var path: String = settings.get("--out", "user://bot.json")
var file := FileAccess.open(path, FileAccess.WRITE)
if file == null:
push_error("the report cannot be written to %s: %s" % [path, error_string(FileAccess.get_open_error())])
else:
file.store_string(JSON.stringify(report)) file.store_string(JSON.stringify(report))
file.close() file.close()
main.notification(Node.NOTIFICATION_WM_CLOSE_REQUEST) main.notification(Node.NOTIFICATION_WM_CLOSE_REQUEST)
root.remove_child(main) root.remove_child(main)
main.free() main.free()
quit(0 if not report.has("error") else 1) quit(0 if file != null and not report.has("error") else 1)