109 lines
3.2 KiB
Go
109 lines
3.2 KiB
Go
package world
|
|
|
|
import (
|
|
"bd2server/internal/server/accountstate"
|
|
"bd2server/internal/server/gamedata"
|
|
"bd2server/internal/server/player"
|
|
"bd2server/internal/server/stateio"
|
|
"bd2server/internal/server/wire"
|
|
"errors"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
type purchaseFailStore struct {
|
|
*accountstate.Repository
|
|
fail bool
|
|
}
|
|
|
|
func (s *purchaseFailStore) SaveWithEntries(domain string, core []byte, changes []stateio.EntryMutation) error {
|
|
if s.fail && domain == "collection" {
|
|
return errors.New("forced purchase marker failure")
|
|
}
|
|
return s.Repository.SaveWithEntries(domain, core, changes)
|
|
}
|
|
|
|
func TestPackPurchaseFailureRollsBackSQLiteCurrencyTicketAndMarker(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "state.db")
|
|
repo, err := accountstate.Open(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { repo.Close() }()
|
|
storage := &purchaseFailStore{Repository: repo}
|
|
s := testService()
|
|
s.seed.PackID = 709
|
|
s.inventory, err = player.OpenInventory(storage, &player.Starter{Version: "2.35.10"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s.wallet, err = player.OpenWallet(storage, player.Currency{Catalyst: 5})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s.collection, err = player.OpenCollectionStore(storage, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.wallet.GrantQuestOnce("test:baseline", nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s.storyCatalog = &gamedata.StoryCatalog{Packs: map[int]gamedata.StoryPack{709: {ID: 709, BuyRewards: []gamedata.Reward{{Type: 12, Count: 17}, {Type: 19, ID: 88, Count: 1}}}}}
|
|
op, err := repo.BeginOperation()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
storage.fail = true
|
|
request := wire.AppendVarint(wire.AppendVarint(nil, 1, 1), 2, 709)
|
|
if _, _, _, err := s.Handle("/PackBuy", request); err == nil {
|
|
t.Fatal("forced collection failure returned success")
|
|
}
|
|
if err := op.Rollback(); err != nil && !errors.Is(err, stateio.ErrStateRecoveryRequired) {
|
|
t.Fatal(err)
|
|
}
|
|
if err := repo.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
repo, err = accountstate.Open(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
storage.Repository = repo
|
|
storage.fail = false
|
|
// Requests reconstruct domains following a rollback; in-memory snapshots
|
|
// that participated in the aborted operation must not be reused.
|
|
wallet, err := player.OpenWallet(storage, player.Currency{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
inventory, err := player.OpenInventory(storage, &player.Starter{Version: "2.35.10"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
collection, err := player.OpenCollectionStore(storage, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if wallet.CatalystBalance() != 5 || wallet.WasGranted("pack-purchase:709:currency") || len(inventory.All()) != 0 {
|
|
t.Fatal("aborted purchase persisted partial awards")
|
|
}
|
|
if _, found := collection.Grant("pack-purchase:709"); found {
|
|
t.Fatal("aborted purchase persisted marker")
|
|
}
|
|
s.wallet, s.inventory, s.collection = wallet, inventory, collection
|
|
op, err = repo.BeginOperation()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, _, _, err := s.Handle("/PackBuy", request); err != nil {
|
|
op.Rollback()
|
|
t.Fatal(err)
|
|
}
|
|
if err := op.Commit(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if wallet.CatalystBalance() != 22 || len(inventory.All()) != 1 {
|
|
t.Fatal("retried purchase did not grant exactly once")
|
|
}
|
|
}
|