aboutsummaryrefslogtreecommitdiff
path: root/internal/game/economy_rollback_regression_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/economy_rollback_regression_test.go')
-rw-r--r--internal/game/economy_rollback_regression_test.go89
1 files changed, 0 insertions, 89 deletions
diff --git a/internal/game/economy_rollback_regression_test.go b/internal/game/economy_rollback_regression_test.go
deleted file mode 100644
index bceb351..0000000
--- a/internal/game/economy_rollback_regression_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package game
-
-// Rollback-failure regressions for the durable money journal. When a journal
-// append fails, the invariant was historically "append failed means no record
-// bytes remain". A failed rollback (the truncate, or the sync that makes it
-// durable) breaks that invariant: the record can survive while the caller
-// believes the append failed. The wallet's journal-unavailable payout fallback
-// must then still record the attempted record's ID as open-payout evidence, or
-// recovery re-applies the surviving payout and pays the player twice.
-
-import (
- "encoding/json"
- "errors"
- "os"
- "path/filepath"
- "testing"
-)
-
-// TestAppendRollbackFailureIsUncertain: /dev/full accepts the open but fails
-// the write with ENOSPC and the rollback truncate with EINVAL, so the append
-// must report that the record MAY have survived.
-func TestAppendRollbackFailureIsUncertain(t *testing.T) {
- if _, err := os.Stat("/dev/full"); err != nil {
- t.Skipf("/dev/full is not available: %v", err)
- }
- j := newEconomyJournal(t.TempDir())
- j.path = "/dev/full"
-
- err := j.append(economyRecord{ID: "uncertain", Kind: "payout", Status: "open"})
- if !errors.Is(err, errJournalAppendUncertain) {
- t.Fatalf("append rollback failure = %v, want errJournalAppendUncertain", err)
- }
-}
-
-// TestFallbackPayoutRecordsEvidenceForSurvivingRecord: a payout whose journal
-// append fails and whose rollback cannot be proven must leave open-payout
-// evidence in the character file. A surviving record is then settled from that
-// evidence at the next startup instead of being re-applied.
-func TestFallbackPayoutRecordsEvidenceForSurvivingRecord(t *testing.T) {
- g, p := newEvidenceHarness(t)
-
- // Break the journal append: point it at its own directory, which cannot
- // be opened for append or truncation. The wallet takes the file-only
- // fallback.
- journalPath := g.Economy.path
- g.Economy.path = filepath.Dir(journalPath)
- w := casinoWallet{g: g, p: p}
- if err := w.PayCredits(20); err != nil {
- t.Fatalf("fallback payout failed: %v", err)
- }
- if p.Credits != 110 {
- t.Fatalf("fallback payout not applied: credits=%d, want 110", p.Credits)
- }
- if len(p.OpenPayouts) != 1 {
- t.Fatalf("fallback payout recorded %d open-payout evidence IDs, want 1: %v",
- len(p.OpenPayouts), p.OpenPayouts)
- }
- id := p.OpenPayouts[0]
-
- // Simulate the failed append having survived in the journal (the exact
- // state a failed rollback produces). Recovery must use the file evidence
- // and settle it, not re-apply it.
- g.Economy.path = journalPath
- rec := economyRecord{
- ID: id, Player: p.Name, PlayerID: p.ID, Kind: "payout", Tracked: true,
- Credit: 20, Status: "open", CreditsBefore: 90, CreditsAfter: 110,
- }
- line, err := json.Marshal(rec)
- if err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(journalPath, append(line, '\n'), 0o600); err != nil {
- t.Fatal(err)
- }
-
- g.recoverEconomy()
-
- loaded, err := g.AccountStore.LoadCharacter(p.Name)
- if err != nil {
- t.Fatal(err)
- }
- if loaded.Credits != 110 {
- t.Fatalf("balance after recovery = %d, want 110 (surviving payout settled from evidence, not re-applied)",
- loaded.Credits)
- }
- if open := g.Economy.mustLoadOpen(t); len(open) != 0 {
- t.Fatalf("records left open after recovery: %+v", open)
- }
-}