extends SceneTree ## P07-01 F7, writer phase. Plays the minute script, writes ordinary save files ## mid-rain, just before and after the rain end and just before and after the ## day 1 draw, and hands the exact save packages to the reader suite ## (test_p07_weather_restart_2_read.gd), which runs as a separate engine process. ## The handoff is the declared generated report res://artifacts/p07-01/restart-handoff.json ## (tools/regression/suite-policy.json fixed_generated_report_routes). const Fixture := preload("res://tests/helpers/p07_weather_restart_fixture.gd") var _checks := 0 var _failures := 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: print("P07-01: restart writer") var fixtures := Fixture.new(_expect) var straight := fixtures.new_fixture() var straight_runtime: Variant = straight[&"runtime"] fixtures.play(straight, Fixture.FIRST_MINUTE, Fixture.LAST_MINUTE, Callable()) _expect(straight_runtime.weather.get_rain_hold(Fixture.HELD_GUEST) == {"original_exit": 362, "extended_to": 602} or straight_runtime.guest_service.get_guest(Fixture.HELD_GUEST) == null, "the guest due at 06:02 was held to 10:02 (or has left since)") _expect(straight[&"draws"][&"count"] == Fixture.DRAW_MINUTES.size() and straight_runtime.weather.get_last_draw_day() == 1, "the uninterrupted script draws day 1 once") var saving := fixtures.new_fixture() var saving_runtime: Variant = saving[&"runtime"] var saved_states := {} var saved_paths := {} fixtures.play(saving, Fixture.FIRST_MINUTE, Fixture.LAST_MINUTE, func(minute: int) -> void: if minute in Fixture.SAVE_MINUTES: if minute == 500: var held_present: bool = saving_runtime.guest_service.get_guest(Fixture.HELD_GUEST) != null _expect(saving_runtime.weather.get_kind() == &"rain" and (not held_present or not saving_runtime.weather.get_rain_hold(Fixture.HELD_GUEST).is_empty()), "minute 500 saves mid-rain with the hold of a present guest") var path := Fixture.WRITER_SAVE % minute saved_states[minute] = fixtures.state_bytes(saving_runtime) _expect(bool(saving_runtime.save_to_path(path).get(&"ok", false)), "save file at minute %d" % minute) saved_paths[minute] = path) _expect(fixtures.state_bytes(saving_runtime) == fixtures.state_bytes(straight_runtime), "writing the save files leaves the weather state as without saving") var saves: Array = [] for minute: int in Fixture.SAVE_MINUTES: var directory := ProjectSettings.globalize_path(str(saved_paths.get(minute, Fixture.WRITER_SAVE % minute))) _expect(DirAccess.dir_exists_absolute(directory) and DirAccess.get_directories_at(directory).is_empty(), "save package at minute %d holds only files" % minute) var files := {} for name: String in DirAccess.get_files_at(directory): var bytes := FileAccess.get_file_as_bytes(directory.path_join(name)) files[name] = {"sha256": Fixture.sha256(bytes), "bytes": bytes.size(), "base64": Marshalls.raw_to_base64(bytes)} _expect(files.has("manifest.json") and files.has("world.bin"), "save package at minute %d has its manifest and world" % minute) var state: PackedByteArray = saved_states.get(minute, PackedByteArray()) saves.append({"minute": minute, "files": files, "state_sha256": Fixture.sha256(state), "state_base64": Marshalls.raw_to_base64(state)}) var final_state := fixtures.state_bytes(straight_runtime) var handoff := { "schema": Fixture.HANDOFF_SCHEMA, "writer_pid": OS.get_process_id(), "writer_source_sha256": FileAccess.get_sha256(Fixture.WRITER_SOURCE), "seed": Fixture.SEED, "last_minute": Fixture.LAST_MINUTE, "straight_final_state_sha256": Fixture.sha256(final_state), "straight_final_state_base64": Marshalls.raw_to_base64(final_state), "saves": saves, } DirAccess.make_dir_recursive_absolute(Fixture.HANDOFF_PATH.get_base_dir()) var file := FileAccess.open(Fixture.HANDOFF_PATH, FileAccess.WRITE) _expect(file != null, "handoff file opens for writing") if file != null: file.store_string(JSON.stringify(handoff, "\t") + "\n") file.close() print("P07_RESTART_WRITER pid=%d handoff_sha256=%s" % [OS.get_process_id(), FileAccess.get_sha256(Fixture.HANDOFF_PATH)]) fixtures.free_fixture(straight) fixtures.free_fixture(saving) await process_frame if _failures == 0: print("PASS: %d checks" % _checks) else: push_error("FAIL: %d of %d checks failed" % [_failures, _checks]) quit(_failures) func _expect(condition: bool, message: String) -> void: _checks += 1 if not condition: _failures += 1 push_error(message)