136 lines
4.9 KiB
Go
136 lines
4.9 KiB
Go
package events
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"bd2server/internal/server/gamedata"
|
|
"bd2server/internal/server/stateio"
|
|
"bd2server/internal/server/wire"
|
|
)
|
|
|
|
func skinSetRequest(seq, costume, design uint64, set bool) []byte {
|
|
info := wire.AppendVarint(nil, 1, costume)
|
|
info = wire.AppendVarint(info, 2, design)
|
|
if set {
|
|
info = wire.AppendVarint(info, 3, 1)
|
|
}
|
|
return wire.AppendBytes(wire.AppendVarint(nil, 1, seq), 2, info)
|
|
}
|
|
|
|
func TestPrestigeSkinSelectionPersistsAndReplaysWithoutUndoingLaterChanges(t *testing.T) {
|
|
store := stateio.NewMemory()
|
|
eco, _, _ := economyFixture(t, store, &economyGraph{})
|
|
design := map[uint64]uint64{9901: 60601, 9902: 60601, 9903: 60602}
|
|
eco.AttachPrestigeSkins(design)
|
|
if _, err := eco.Apply("skins", nil, []gamedata.Reward{{Type: 45, ID: 9901, Count: 1}, {Type: 45, ID: 9902, Count: 1}, {Type: 45, ID: 9903, Count: 1}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
portrait := uint64(60601)
|
|
eco.AttachPrestigePortrait(func() uint64 { return portrait })
|
|
handler := SkinHandler{Economy: eco}
|
|
first := skinSetRequest(1, 60601, 9901, true)
|
|
code, original, handled, err := handler.HandleSession("/PrestigeSkinSet", first, "s1")
|
|
if err != nil || code != 426 || !handled {
|
|
t.Fatalf("set: %d %v %v", code, handled, err)
|
|
}
|
|
for _, req := range [][]byte{skinSetRequest(2, 60601, 9902, true), skinSetRequest(3, 60602, 9903, true), skinSetRequest(4, 60601, 9901, false)} {
|
|
_, out, _, callErr := handler.HandleSession("/PrestigeSkinSet", req, "s1")
|
|
if callErr != nil {
|
|
t.Fatal(callErr)
|
|
}
|
|
id, _, _ := wire.Varint(out, 1)
|
|
design, _, _ := wire.Varint(out, 2)
|
|
if id != 60601 || design != 9902 {
|
|
t.Fatalf("set changed unrelated portrait: %x", out)
|
|
}
|
|
}
|
|
// Disabling an older skin cannot clear the newer choice on the same costume.
|
|
sets, err := eco.PrestigeSkinSelections()
|
|
if err != nil || sets[60601] != 9902 || sets[60602] != 9903 {
|
|
t.Fatalf("selections: %v %v", sets, err)
|
|
}
|
|
portraitID, _, _ := wire.Varint(original, 1)
|
|
portraitDesign, _, _ := wire.Varint(original, 2)
|
|
if portraitID != 60601 || portraitDesign != 9901 {
|
|
t.Fatalf("portrait: %x", original)
|
|
}
|
|
_, _, _, err = handler.HandleSession("/PrestigeSkinSet", skinSetRequest(1, 60601, 9902, true), "s1")
|
|
if err == nil {
|
|
t.Fatal("sequence conflict accepted")
|
|
}
|
|
reopened, _, _ := economyFixture(t, store, &economyGraph{})
|
|
reopened.AttachPrestigeSkins(design)
|
|
_, replay, _, err := reopened.HandleSession("/PrestigeSkinSet", first, "s1")
|
|
if err != nil || !bytes.Equal(original, replay) {
|
|
t.Fatalf("restart replay %x %v", replay, err)
|
|
}
|
|
_, info, _, err := reopened.PrestigeSkinInfo("/PrestigeSkinInfo", wire.AppendVarint(nil, 1, 9))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
selected := map[uint64]bool{}
|
|
if err = wire.Walk(info, func(f wire.Field) error {
|
|
id, _, _ := wire.Varint(f.Value, 2)
|
|
set, _, _ := wire.Varint(f.Value, 3)
|
|
selected[id] = set == 1
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if selected[9901] || !selected[9902] || !selected[9903] {
|
|
t.Fatalf("info selection: %v", selected)
|
|
}
|
|
if _, _, _, err = reopened.HandleSession("/PrestigeSkinSet", skinSetRequest(1, 60601, 9902, false), "s2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sets, err = reopened.PrestigeSkinSelections()
|
|
if err != nil || sets[60601] != 0 || sets[60602] != 9903 {
|
|
t.Fatalf("unset disturbed another costume: %v %v", sets, err)
|
|
}
|
|
}
|
|
|
|
type failedSkinStore struct {
|
|
*stateio.Memory
|
|
fail bool
|
|
}
|
|
|
|
func (s *failedSkinStore) Save(name string, payload []byte) error {
|
|
if s.fail && name == "prestige_skin_sets" {
|
|
return fmt.Errorf("injected skin save failure")
|
|
}
|
|
return s.Memory.Save(name, payload)
|
|
}
|
|
|
|
func TestPrestigeSkinRejectsUnownedAndFailedSaveLeavesSelectionUnchanged(t *testing.T) {
|
|
store := &failedSkinStore{Memory: stateio.NewMemory()}
|
|
eco, _, _ := economyFixture(t, store, &economyGraph{})
|
|
eco.AttachPrestigeSkins(map[uint64]uint64{9901: 60601, 9902: 60601})
|
|
if _, err := eco.Apply("skin", nil, []gamedata.Reward{{Type: 45, ID: 9901, Count: 1}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, req := range [][]byte{skinSetRequest(1, 60601, 9902, true), skinSetRequest(1, 60602, 9901, true), wire.AppendBytes(wire.AppendVarint(nil, 1, 1), 2, wire.AppendBytes(wire.AppendVarint(wire.AppendVarint(nil, 1, 60601), 2, 9901), 3, nil))} {
|
|
if _, _, _, err := eco.HandleSession("/PrestigeSkinSet", req, "session"); err == nil {
|
|
t.Fatalf("invalid request accepted: %x", req)
|
|
}
|
|
}
|
|
req := skinSetRequest(1, 60601, 9901, true)
|
|
store.fail = true
|
|
if _, _, _, err := eco.HandleSession("/PrestigeSkinSet", req, "session"); err == nil {
|
|
t.Fatal("save failure succeeded")
|
|
}
|
|
sets, err := eco.PrestigeSkinSelections()
|
|
if err != nil || len(sets) != 0 {
|
|
t.Fatalf("failed selection leaked %v %v", sets, err)
|
|
}
|
|
store.fail = false
|
|
if _, _, _, err = eco.HandleSession("/PrestigeSkinSet", req, "session"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sets, err = eco.PrestigeSkinSelections()
|
|
if err != nil || sets[60601] != 9901 {
|
|
t.Fatalf("retry not committed: %v %v", sets, err)
|
|
}
|
|
}
|