diff options
| author | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
| commit | 153acb7f644d755c45533b7c5311e3ffa47e8973 (patch) | |
| tree | 7645e6f7b65bc3830b078e3b9336d2e6b199d584 /internal/game/hardening_shutdown_save_error_test.go | |
| parent | 87d08f0151e643951769e323995f1c5ed89ee200 (diff) | |
| download | thehouseoficarus-153acb7f644d755c45533b7c5311e3ffa47e8973.tar.gz | |
fix: harden engine across casino, economy, concurrency, security, and content
Diffstat (limited to 'internal/game/hardening_shutdown_save_error_test.go')
| -rw-r--r-- | internal/game/hardening_shutdown_save_error_test.go | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/internal/game/hardening_shutdown_save_error_test.go b/internal/game/hardening_shutdown_save_error_test.go new file mode 100644 index 0000000..c75f6fc --- /dev/null +++ b/internal/game/hardening_shutdown_save_error_test.go @@ -0,0 +1,63 @@ +package game + +// Regression coverage for the shutdown final-save report: runShutdown records +// a failed saveAllOnlineCharacters on the Game, and ShutdownSaveError exposes +// it so main can exit non-zero instead of losing online state silently. + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +// TestShutdownSaveErrorReportsFailedFinalSave makes the character save fail +// (the character file is replaced by a directory, so the atomic replace cannot +// land) and requires the shutdown sequence to record the failure on the Game. +func TestShutdownSaveErrorReportsFailedFinalSave(t *testing.T) { + h := newHarness(t) + h.seedAccount("alice") + h.seedCharacter("alice", "alice") + h.connect("alice") + + charPath := filepath.Join(h.dir, "players", "characters", "alice.yaml") + if err := os.Remove(charPath); err != nil { + t.Fatalf("remove character file: %v", err) + } + if err := os.Mkdir(charPath, 0o755); err != nil { + t.Fatalf("block character path: %v", err) + } + + h.g.runShutdown() + + err := h.g.ShutdownSaveError() + if err == nil { + t.Fatal("a failed final save was not recorded") + } + if !strings.Contains(err.Error(), "alice") { + t.Fatalf("shutdown save error does not name the unsaved character: %v", err) + } +} + +// TestShutdownSaveErrorNilWhenFinalSaveSucceeds pins the other direction: +// nothing is reported when every online character was persisted, so main does +// not exit non-zero on a clean shutdown. +func TestShutdownSaveErrorNilWhenFinalSaveSucceeds(t *testing.T) { + h := newHarness(t) + h.seedAccount("alice") + h.seedCharacter("alice", "alice") + h.connect("alice") + + if err := h.g.ShutdownSaveError(); err != nil { + t.Fatalf("ShutdownSaveError before any shutdown = %v, want nil", err) + } + + h.g.runShutdown() + + if err := h.g.ShutdownSaveError(); err != nil { + t.Fatalf("clean shutdown recorded a save failure: %v", err) + } + if _, err := h.g.AccountStore.LoadCharacter("alice"); err != nil { + t.Fatalf("online character was not saved: %v", err) + } +} |
