Files
bd2/go/internal/server/eventtasks/pass_reward_test.go
T

158 lines
6.3 KiB
Go

package eventtasks
import (
"bd2server/internal/server/gamedata"
"bd2server/internal/server/wire"
"bytes"
"testing"
)
func passClaimRequest(seq, rewardType uint64, all bool, level uint64) []byte {
b := req(seq)
if all {
b = wire.AppendVarint(b, 2, 1)
}
b = wire.AppendVarint(b, 3, 8)
if level != 0 {
b = wire.AppendVarint(b, 4, level)
}
if rewardType != 0 {
b = wire.AppendVarint(b, 5, rewardType)
}
return b
}
func claimPass(t *testing.T, s *Service, request []byte) []byte {
t.Helper()
code, response, handled, err := s.Handle("/PassReward", request)
if err != nil || code != 126 || !handled {
t.Fatalf("pass claim failed: code=%d handled=%t err=%v", code, handled, err)
}
if _, present, err := wire.Bytes(response, 1); err != nil || !present {
t.Fatalf("native receiver requires a non-null reward bundle: %x, %v", response, err)
}
return response
}
func TestPassRewardNativeOneClickAfterPurchaseAndRestart(t *testing.T) {
s, e, store := setup(t)
s.design.PassLevels[8] = []gamedata.EventPassLevel{
{ID: 1, NeedExp: 20, Basic: gamedata.Reward{Type: 3, Count: 1}, Premium: gamedata.Reward{Type: 4, Count: 10}},
{ID: 2, NeedExp: 30, Basic: gamedata.Reward{Type: 3, Count: 2}, Premium: gamedata.Reward{Type: 4, Count: 20}},
{ID: 3, NeedExp: 40, Basic: gamedata.Reward{Type: 3, Count: 3}, Premium: gamedata.Reward{Type: 4, Count: 30}},
{ID: 4, Basic: gamedata.Reward{Type: 3, Count: 4}, Premium: gamedata.Reward{Type: 4, Count: 40}},
}
s.design.PassBuys = map[uint64][]gamedata.EventPassBuy{8: {{ID: 1, Type: 1, LevelsGranted: 3, Cost: gamedata.Reward{Type: 3, Count: 1000}}}}
buy := wire.AppendVarint(req(1), 2, 8)
buy = wire.AppendVarint(buy, 3, 1)
if _, _, _, err := s.Handle("/PassBuy", buy); err != nil {
t.Fatal(err)
}
// PassRootUI.ReceiveAllReward sends BASIC first, then PREMIUM_1 in its callback.
basic := passClaimRequest(2, 0, true, 0)
basicReply := claimPass(t, s, basic)
for _, lv := range s.design.PassLevels[8] {
p := s.pass(s.registry.List()[2])
if !p.Claimed[key(lv.ID, 0)] || p.Claimed[key(lv.ID, 1)] {
t.Fatalf("basic phase incorrectly claimed premium at level %d", lv.ID)
}
}
if len(e.rewards) != 4 || e.rewards[0].Type != 3 || e.rewards[3].Count != 4 {
t.Fatalf("basic phase granted wrong rewards: %+v", e.rewards)
}
reopened, err := Open(store, s.design, s.registry, e)
if err != nil {
t.Fatal(err)
}
reopened.now = s.now
reopened.SetSession("test")
if replay := claimPass(t, reopened, basic); !bytes.Equal(replay, basicReply) || e.calls != 2 {
t.Fatal("restart replay repeated basic grants")
}
premium := passClaimRequest(3, 1, true, 0)
premiumReply := claimPass(t, reopened, premium)
if len(e.rewards) != 8 || e.rewards[4].Type != 4 || e.rewards[7].Count != 40 || e.calls != 3 {
t.Fatalf("premium phase granted wrong rewards: %+v", e.rewards)
}
for _, lv := range reopened.design.PassLevels[8] {
p := reopened.pass(reopened.registry.List()[2])
if !p.Claimed[key(lv.ID, 0)] || !p.Claimed[key(lv.ID, 1)] {
t.Fatalf("claim state incomplete at level %d", lv.ID)
}
}
if replay := claimPass(t, reopened, premium); !bytes.Equal(replay, premiumReply) || e.calls != 3 {
t.Fatal("premium replay repeated grants")
}
// A new one-click request after claiming must complete without granting again.
for typ := uint64(0); typ <= 1; typ++ {
response := claimPass(t, reopened, passClaimRequest(4+typ, typ, true, 0))
bundle, _, _ := wire.Bytes(response, 1)
if len(bundle) != 0 || e.calls != 3 || len(e.rewards) != 8 {
t.Fatal("already-claimed all request repeated rewards")
}
}
}
func TestPassRewardBasicAlreadyClaimedBeforePremiumPurchase(t *testing.T) {
s, e, _ := setup(t)
s.design.PassLevels[8] = []gamedata.EventPassLevel{{ID: 1, Basic: gamedata.Reward{Type: 3, Count: 5}, Premium: gamedata.Reward{Type: 4, Count: 50}}}
claimPass(t, s, passClaimRequest(1, 0, true, 0))
s.design.PassBuys = map[uint64][]gamedata.EventPassBuy{8: {{ID: 1, Type: 1, Cost: gamedata.Reward{Type: 3, Count: 1000}}}}
buy := wire.AppendVarint(req(2), 2, 8)
buy = wire.AppendVarint(buy, 3, 1)
if _, _, _, err := s.Handle("/PassBuy", buy); err != nil {
t.Fatal(err)
}
claimPass(t, s, passClaimRequest(3, 0, true, 0))
if len(e.rewards) != 1 || e.calls != 2 {
t.Fatal("empty basic phase granted again")
}
claimPass(t, s, passClaimRequest(4, 1, true, 0))
if len(e.rewards) != 2 || e.rewards[1].Type != 4 || e.rewards[1].Count != 50 || e.calls != 3 {
t.Fatalf("empty basic phase prevented premium claim: %+v", e.rewards)
}
}
func TestPassRewardSingleClaimsAndLockedLevels(t *testing.T) {
s, e, _ := setup(t)
s.design.PassLevels[8] = []gamedata.EventPassLevel{
{ID: 1, NeedExp: 20, Basic: gamedata.Reward{Type: 3, Count: 5}, Premium: gamedata.Reward{Type: 4, Count: 50}},
{ID: 2, Basic: gamedata.Reward{Type: 3, Count: 6}, Premium: gamedata.Reward{Type: 4, Count: 60}},
}
if _, _, _, err := s.Handle("/PassReward", passClaimRequest(1, 1, true, 0)); err == nil || e.calls != 0 {
t.Fatal("premium reward granted without purchase")
}
claimPass(t, s, passClaimRequest(2, 0, false, 1))
if len(e.rewards) != 1 || e.rewards[0].Count != 5 {
t.Fatal("single basic reward incorrect")
}
for _, request := range [][]byte{passClaimRequest(3, 0, false, 1), passClaimRequest(4, 0, false, 2), passClaimRequest(5, 0, false, 99), passClaimRequest(6, 2, true, 0)} {
if _, _, _, err := s.Handle("/PassReward", request); err == nil || e.calls != 1 {
t.Fatal("duplicate, locked or fabricated reward accepted")
}
}
s.pass(s.registry.List()[2]).Premium = true
claimPass(t, s, passClaimRequest(7, 1, false, 1))
if len(e.rewards) != 2 || e.rewards[1].Count != 50 || s.pass(s.registry.List()[2]).Claimed[key(2, 1)] {
t.Fatal("single premium claim changed another level")
}
}
func TestPassRewardKeepsCurrentNewbieStepInEveryResponse(t *testing.T) {
s, _, _ := setup(t)
d := s.design.Passes[8]
d.NewbieStep = 1
s.design.Passes[8] = d
s.state.NewbieStep = 1
s.design.PassLevels[8] = []gamedata.EventPassLevel{{ID: 1, NeedExp: 20, Basic: gamedata.Reward{Type: 3, Count: 5}}, {ID: 2, Basic: gamedata.Reward{Type: 3, Count: 6}}}
response := claimPass(t, s, passClaimRequest(1, 0, true, 0))
if scalar(response, 2) != 1 || s.state.NewbieStep != 1 {
t.Fatal("partial claim resets native guide step")
}
response = claimPass(t, s, passClaimRequest(2, 0, true, 0))
if scalar(response, 2) != 1 {
t.Fatal("empty phase resets native guide step")
}
}