diff options
Diffstat (limited to 'internal/game/economy_recovery_regression_test.go')
| -rw-r--r-- | internal/game/economy_recovery_regression_test.go | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/internal/game/economy_recovery_regression_test.go b/internal/game/economy_recovery_regression_test.go index 1bb3293..241b235 100644 --- a/internal/game/economy_recovery_regression_test.go +++ b/internal/game/economy_recovery_regression_test.go @@ -479,3 +479,59 @@ func TestCapBlockedPayoutIsJournaled(t *testing.T) { t.Fatalf("recovery mutated a capped balance: %d", loaded.Credits) } } + +// TestRecoveryReappliesPartiallyPaidIdenticalPayouts: two identical payout +// records were open and an earlier recovery run re-applied (and settled) +// only the FIRST before crashing again — the second save failed transiently +// (see TestRecoverySaveFailureRetriesOnNextStartup for the single-record +// case). The next recovery must NOT settle the remaining record as +// "already durable" merely because the balance now sits at its +// post-payout checkpoint: the settled sibling explains that balance, and +// the open record is still owed. +func TestRecoveryReappliesPartiallyPaidIdenticalPayouts(t *testing.T) { + h := newHarness(t) + h.seedAccount("alice", "pw", false) + p := h.seedCharacter("alice", "alice") + h.g.RunOnOwner(func() { + p.Credits = 90 + if err := h.g.AccountStore.SaveCharacter(p); err != nil { + t.Error(err) + return + } + // Two identical owed payouts were journaled against balance 90. + if _, err := h.g.Economy.start("payout", p, 0, 20, 90, 110, 0, 0); err != nil { + t.Error(err) + return + } + second, err := h.g.Economy.start("payout", p, 0, 20, 90, 110, 0, 0) + if err != nil { + t.Error(err) + return + } + // Simulate the prior recovery run: the first record was re-applied + // and settled durably; the second's save failed transiently. + if err := h.g.payCreditsDurable(p, 20); err != nil { + t.Error(err) + return + } + first := h.g.Economy.loadOpen()[0] + if first.ID == second.ID { + t.Fatal("setup: expected two distinct records") + } + h.g.Economy.settle(first) + // Recovery over this state: the remaining owed payout must be + // re-applied, never settled as "already durable". + h.g.recoverEconomy() + loaded, err := h.g.AccountStore.LoadCharacter("alice") + if err != nil { + t.Error(err) + return + } + if loaded.Credits != 130 { + t.Errorf("recovered balance = %d, want 130 (remaining owed payout re-applied)", loaded.Credits) + } + if open := h.g.Economy.loadOpen(); len(open) != 0 { + t.Errorf("records left open after recovery: %+v", open) + } + }) +} |
