aboutsummaryrefslogtreecommitdiff
path: root/internal/game/economy_recovery_identity_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/economy_recovery_identity_test.go')
-rw-r--r--internal/game/economy_recovery_identity_test.go128
1 files changed, 0 insertions, 128 deletions
diff --git a/internal/game/economy_recovery_identity_test.go b/internal/game/economy_recovery_identity_test.go
deleted file mode 100644
index 04d6fed..0000000
--- a/internal/game/economy_recovery_identity_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package game
-
-// Identity-resolution regressions for economy recovery: a record carrying a
-// stable character ID must never be resolved — paid or resolved — through a
-// display name that a different character later reused, and money recovery
-// must run only AFTER lifecycle-journal rollback (a rolled-back rename
-// restores an older character before-image that must not erase compensation
-// already applied).
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "thehouseoficarus/internal/persistence"
-)
-
-// TestRecoveryDoesNotPayReusedCharacterName: an owed payout journaled for
-// identity A (named "alice") must not be paid to identity B after B reuses
-// the name, and A's unresolved liability must stay open for operator
-// inspection instead of being silently settled against B's balance.
-func TestRecoveryDoesNotPayReusedCharacterName(t *testing.T) {
- h := newHarness(t)
- h.seedAccount("alice")
- p := h.seedCharacter("alice", "alice")
- h.g.RunOnOwner(func() {
- p.ID = "original-character"
- p.Credits = 90
- if err := h.g.AccountStore.SaveCharacter(p); err != nil {
- t.Error(err)
- return
- }
- // A failed payout save left the owed money journaled for recovery.
- if _, err := h.g.Economy.start("payout", p, 0, 20, 90, 110, 0, 0); err != nil {
- t.Error(err)
- return
- }
- // Delete the original character, then reuse its name for a
- // different identity.
- p.ID = "replacement-character"
- if err := h.g.AccountStore.SaveCharacter(p); err != nil {
- t.Error(err)
- return
- }
- h.g.recoverEconomy()
- })
- loaded, err := h.g.AccountStore.LoadCharacter("alice")
- if err != nil {
- t.Fatal(err)
- }
- if loaded.Credits != 90 {
- t.Errorf("replacement identity received someone else's payout: credits=%d, want 90", loaded.Credits)
- }
- if open := h.g.Economy.mustLoadOpen(t); len(open) != 1 {
- t.Errorf("original identity's unresolved liability was discarded: open records=%d", len(open))
- }
-}
-
-// TestEconomyRecoveryRunsAfterLifecycleRollback: a leftover lifecycle
-// transaction (a rename that never reached its commit point) restores the
-// character's before-image at startup, and must do so BEFORE money
-// compensation — otherwise the compensation's settled/compacted records are
-// gone and the rollback silently erases a payout that was already applied.
-func TestEconomyRecoveryRunsAfterLifecycleRollback(t *testing.T) {
- h := newHarness(t)
- h.seedAccount("alice")
- p := h.seedCharacter("alice", "alice")
- h.g.RunOnOwner(func() {
- p.ID = "stable-character"
- p.Credits = 90
- if err := h.g.AccountStore.SaveCharacter(p); err != nil {
- t.Error(err)
- return
- }
- // A failed payout save left the owed money journaled for recovery.
- if _, err := h.g.Economy.start("payout", p, 0, 20, 90, 110, 0, 0); err != nil {
- t.Error(err)
- return
- }
- // Simulate a crash mid-rename: apply the move and the renamed
- // character file directly, then leave the lifecycle journal on
- // disk so the next startup rolls it back.
- oldPath := h.g.AccountStore.CharPath("alice")
- newPath := h.g.AccountStore.CharPath("renamed")
- txn := persistence.NewTransaction(h.g.journalDir())
- if err := txn.Move(oldPath, newPath); err != nil {
- t.Error(err)
- return
- }
- p.Name = "renamed"
- data, err := h.g.AccountStore.MarshalCharacter(p)
- if err != nil {
- t.Error(err)
- return
- }
- if err := txn.Replace(newPath, data, 0600); err != nil {
- t.Error(err)
- return
- }
- journal, err := txn.MarshalJournal()
- if err != nil {
- t.Error(err)
- return
- }
- if err := os.WriteFile(filepath.Join(h.g.journalDir(), "txn-audit.json"), journal, 0600); err != nil {
- t.Error(err)
- return
- }
- if err := os.Rename(oldPath, newPath); err != nil {
- t.Error(err)
- return
- }
- if err := h.g.AccountStore.SaveCharacter(p); err != nil {
- t.Error(err)
- return
- }
- })
- // A fresh Game over the saved files simulates the restart.
- restarted := harnessFromDir(t, h.dir)
- loaded, err := restarted.g.AccountStore.LoadCharacter("alice")
- if err != nil {
- t.Fatal(err)
- }
- if loaded.Credits != 110 {
- t.Errorf("lifecycle rollback erased recovered payout: credits=%d, want 110; open liabilities=%d",
- loaded.Credits, len(restarted.g.Economy.mustLoadOpen(t)))
- }
-}