P08-03: 配置の通常操作受入
This commit is contained in:
Vendored
+74
-3
@@ -20,6 +20,7 @@ var input_method := "handler"
|
||||
var observed_cell: Variant = null
|
||||
var save_serial := 0
|
||||
var save_records: Array = []
|
||||
var operation_results: Array[Dictionary] = []
|
||||
const INITIAL_SAVE := "user://saves/p08_initial"
|
||||
|
||||
func annotate(row: Dictionary) -> void:
|
||||
@@ -43,8 +44,10 @@ func json_file(name: String, data: Variant) -> void:
|
||||
file.close()
|
||||
|
||||
func capture(label: String) -> String:
|
||||
return capture_model(label, runtime.create_snapshot())
|
||||
|
||||
func capture_model(label: String, snapshot: Dictionary) -> String:
|
||||
var name := role + "-" + label
|
||||
var snapshot: Dictionary = runtime.create_snapshot()
|
||||
json_file(name + ".json", Codec.new().typed(snapshot))
|
||||
var file := FileAccess.open(directory.path_join(name + ".var"), FileAccess.WRITE)
|
||||
if file != null:
|
||||
@@ -226,10 +229,15 @@ func writer() -> void:
|
||||
await demolish(target, "demolition")
|
||||
await build(&"reception", target, "rebuild")
|
||||
await camera()
|
||||
capture("presave")
|
||||
await button(main.find_child("ManualSaveButton", true, false))
|
||||
expect(main.build_status_label.text == "手動セーブを保存しました。", "normal save")
|
||||
capture("checkpoint")
|
||||
await archive_formal()
|
||||
var formal := inspect_formal()
|
||||
var presave: Dictionary = bytes_to_var(FileAccess.get_file_as_bytes(directory.path_join("writer-presave.var")))
|
||||
expect(var_to_bytes(presave) == var_to_bytes(formal), "whole presave formal model")
|
||||
verify_operation(formal, operation_results.back(), &"SAVE_CHECKPOINT_SUCCEEDED")
|
||||
var members := {}
|
||||
for member: String in MEMBERS:
|
||||
members[member] = FileAccess.get_sha256(directory.path_join("formal/" + member))
|
||||
@@ -245,8 +253,10 @@ func reader(distinct: bool) -> void:
|
||||
await frames()
|
||||
expect(main.build_status_label.text == "手動セーブを読み込みました。", "normal resume")
|
||||
capture("checkpoint")
|
||||
var original := FileAccess.get_file_as_bytes(directory.path_join("writer-checkpoint.var"))
|
||||
expect(original == var_to_bytes(runtime.create_snapshot()), "whole formal resume model")
|
||||
var formal := inspect_formal()
|
||||
var original := FileAccess.get_file_as_bytes(directory.path_join("writer-formal-model.var"))
|
||||
expect(original == var_to_bytes(formal), "whole formal resume model")
|
||||
verify_operation(formal, operation_results.back(), &"SAVE_RECOVERY_LOADED")
|
||||
expect(String(runtime.world_service.get_occupant(target)) == saved.instance_id, "same resumed instance/cell")
|
||||
for member: String in MEMBERS:
|
||||
expect(FileAccess.get_sha256(directory.path_join("formal/" + member)) == saved.members[member], "reader preserves formal member " + member)
|
||||
@@ -325,7 +335,68 @@ func save_initial_fixture() -> void:
|
||||
func archive_formal() -> void:
|
||||
export_package(String(main.manual_save_path), "formal")
|
||||
|
||||
func inspect_formal() -> Dictionary:
|
||||
var stored := SaveService.inspect_snapshot(String(main.manual_save_path))
|
||||
record_save_result("formal_inspect", String(main.manual_save_path), stored)
|
||||
expect(bool(stored.get(&"ok", false)), "read-only formal inspection")
|
||||
var formal: Dictionary = stored.get(&"snapshot", {})
|
||||
capture_model("formal-model", formal)
|
||||
return formal
|
||||
|
||||
func verify_operation(formal: Dictionary, result: Dictionary, event_type: StringName) -> void:
|
||||
var expected := formal.duplicate(true)
|
||||
var model: Dictionary = expected[&"systems"][&"runtime"]
|
||||
var counters: Dictionary = model[&"id_generator"]["counters"]
|
||||
var next: int = int(counters.get("domain_event", 0)) + 1
|
||||
counters["domain_event"] = next
|
||||
var event_id := "domain_event.%012d" % next
|
||||
var payload := {
|
||||
&"ok": bool(result.get(&"ok", false)),
|
||||
&"code": StringName(result.get(&"code", &"UNKNOWN")),
|
||||
&"message": str(result.get(&"message", "")),
|
||||
&"operation": StringName(result.get(&"operation", &"unknown")),
|
||||
&"save_path": str(result.get(&"save_path", result.get(&"path", ""))),
|
||||
&"reason": StringName(result.get(&"reason", &"")),
|
||||
&"request_id": int(result.get(&"request_id", 0)),
|
||||
&"checkpoint_absolute_minute": int(result.get(&"checkpoint_absolute_minute", formal[&"clock"][&"absolute_minute"])),
|
||||
&"duration_us": int(result.get(&"duration_us", 0)),
|
||||
&"runtime_duration_us": int(result.get(&"runtime_duration_us", 0)),
|
||||
}
|
||||
if result.get(&"selected") is Dictionary:
|
||||
var selected: Dictionary = result[&"selected"]
|
||||
payload[&"selected_candidate_id"] = StringName(selected.get(&"id", &""))
|
||||
payload[&"selected_candidate_kind"] = StringName(selected.get(&"kind", &""))
|
||||
payload[&"selected_generation"] = int(selected.get(&"generation", -1))
|
||||
if result.get(&"manifest") is Dictionary:
|
||||
var manifest: Dictionary = result[&"manifest"]
|
||||
payload[&"save_id"] = str(manifest.get("save_id", ""))
|
||||
payload[&"saved_absolute_minute"] = int(manifest.get("absolute_minute", -1))
|
||||
var stream: Dictionary = model[&"domain_events"]
|
||||
stream["published_ids"].append(event_id)
|
||||
stream["published_ids"].sort()
|
||||
var notification := SimulationDomainEvent.new(StringName(event_id), event_type,
|
||||
int(formal[&"clock"][&"absolute_minute"]), &"save_service", [], payload, 0)
|
||||
stream["recent_events"].append(notification.to_dictionary())
|
||||
if stream["recent_events"].size() > DomainEventStream.RECENT_EVENT_LIMIT:
|
||||
stream["recent_events"].pop_front()
|
||||
capture_model("expected-operation", expected)
|
||||
capture("operation-actual")
|
||||
var actual: Dictionary = bytes_to_var(FileAccess.get_file_as_bytes(directory.path_join(role + "-checkpoint.var")))
|
||||
json_file(role + "-operation-comparison.json", {
|
||||
"pid": OS.get_process_id(), "delta_kind": "source_defined_notification",
|
||||
"formal_model": role + "-formal-model", "actual_model": role + "-checkpoint",
|
||||
"expected_model": role + "-expected-operation", "returned_result": Codec.new().typed(result),
|
||||
"saved_recent_count": formal[&"systems"][&"runtime"][&"domain_events"]["recent_events"].size(),
|
||||
"expected_recent_count": stream["recent_events"].size(),
|
||||
"actual_recent_count": actual[&"systems"][&"runtime"][&"domain_events"]["recent_events"].size(),
|
||||
"whole_raw_equal": var_to_bytes(expected) == var_to_bytes(actual),
|
||||
})
|
||||
# Complete raw actual/expected snapshots remain available on unknown drift.
|
||||
expect(var_to_bytes(expected) == var_to_bytes(actual), "whole source-defined save operation model; see " + role + "-operation-comparison.json")
|
||||
expect(var_to_bytes(actual) == var_to_bytes(runtime.create_snapshot()), "read-only inspection preserves live model")
|
||||
|
||||
func record_save_operation(result: Dictionary) -> void:
|
||||
operation_results.append(result.duplicate(true))
|
||||
record_save_result("runtime_operation", String(main.manual_save_path), result)
|
||||
|
||||
func record_save_result(operation: String, path: String, result: Dictionary) -> void:
|
||||
|
||||
Reference in New Issue
Block a user