feat(all): add hunting and events, commerce and rewards, binary calendars, GameData caching and login diagnostics
Implement hunting AP and progress, event tasks, exchanges, games, stories and actions; connect battle and reward handling. Add CashShop plugin and installation, server purchases and entitlements, recharge rules and plugin version metadata. Distribute binary calendars independently; cache GameData in memory and fix single-connection query deadlocks. Improve automatic login and recovery diagnostics; document configuration and release flows.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package commerce
|
||||
|
||||
import (
|
||||
"bd2server/internal/server/gameconfig"
|
||||
"bd2server/internal/server/gamedata"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testDesign() *gamedata.CashCatalog {
|
||||
return &gamedata.CashCatalog{Products: []gamedata.CashProductDesign{
|
||||
{Key: gamedata.CashProductKey{GroupID: 1, ProductID: 1, SaleGroup: 1}, GoogleSKU: "recharge", AppleSKU: "recharge-ios", PriceType: 1, PriceCount: 2200, Recharge: true, NominalPaidDiamonds: 100},
|
||||
{Key: gamedata.CashProductKey{GroupID: 1, ProductID: 2, SaleGroup: 1}, GoogleSKU: "recharge", AppleSKU: "recharge-ios", PriceType: 1, PriceCount: 2200, Recharge: true, NominalPaidDiamonds: 100},
|
||||
{Key: gamedata.CashProductKey{GroupID: 2, ProductID: 1, SaleGroup: 1}, GoogleSKU: "skin", AppleSKU: "skin-ios", PriceType: 1, PriceCount: 5501},
|
||||
{Key: gamedata.CashProductKey{GroupID: 3, ProductID: 1}, GoogleSKU: "native", PriceType: 2, PriceCount: 100},
|
||||
}}
|
||||
}
|
||||
func TestCashPricesAliasesAndIsolation(t *testing.T) {
|
||||
for _, currency := range []string{"free", "gold", "diamonds", "ban", ""} {
|
||||
cfg := gameconfig.Default().Purchases
|
||||
cfg.DiamondRecharge.Currency = currency
|
||||
c, err := NewCatalog("test", testDesign(), cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m := c.Manifest()
|
||||
if m.SchemaVersion != 1 || len(m.Products) != 6 {
|
||||
t.Fatalf("manifest %+v", m)
|
||||
}
|
||||
skin, err := c.Quote(gamedata.CashProductKey{GroupID: 2, ProductID: 1, SaleGroup: 1}, 2)
|
||||
if err != nil || skin.Cost != 502 || skin.ItemType != 2 || skin.Currency != "paid_diamonds" {
|
||||
t.Fatalf("ordinary goods affected by %q: %+v %v", currency, skin, err)
|
||||
}
|
||||
recharge, err := c.Quote(gamedata.CashProductKey{GroupID: 1, ProductID: 1, SaleGroup: 1}, 1)
|
||||
if currency == "ban" || currency == "" {
|
||||
if err == nil {
|
||||
t.Fatal("disabled recharge accepted")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := uint64(0)
|
||||
if currency == "gold" {
|
||||
want = 100000
|
||||
}
|
||||
if currency == "diamonds" {
|
||||
want = 100
|
||||
}
|
||||
if recharge.Cost != want {
|
||||
t.Fatalf("currency %s cost=%d", currency, recharge.Cost)
|
||||
}
|
||||
second, _ := c.Quote(gamedata.CashProductKey{GroupID: 1, ProductID: 2, SaleGroup: 1}, 1)
|
||||
if second.Cost != recharge.Cost {
|
||||
t.Fatal("first purchase incorrectly doubled cost")
|
||||
}
|
||||
m.Products[0].SKU = "changed"
|
||||
if c.Manifest().Products[0].SKU == "changed" {
|
||||
t.Fatal("manifest mutable through caller")
|
||||
}
|
||||
if _, err = c.Quote(gamedata.CashProductKey{GroupID: 3, ProductID: 1}, 1); err == nil {
|
||||
t.Fatal("native wallet item intercepted")
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestMonetaryBoundsAndBaseline(t *testing.T) {
|
||||
for _, v := range [][3]uint64{{math.MaxUint64, 2, 1}, {1, 0, 1}, {1, 1, 0}, {math.MaxInt32 + 1, 1, 1}} {
|
||||
if _, err := ceilRatio(v[0], v[1], v[2]); err == nil {
|
||||
t.Fatalf("accepted %v", v)
|
||||
}
|
||||
}
|
||||
d := testDesign()
|
||||
d.Products[0].PriceCount = 2000
|
||||
d.Products[1].PriceCount = 2000
|
||||
c, err := NewCatalog("test", d, gameconfig.Default().Purchases)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p, _ := c.Quote(d.Products[2].Key, 1)
|
||||
if p.Cost != 276 {
|
||||
t.Fatalf("baseline not derived dynamically: %+v", p)
|
||||
}
|
||||
if _, err = c.Quote(d.Products[2].Key, math.MaxInt32); err == nil {
|
||||
t.Fatal("overflow accepted")
|
||||
}
|
||||
if _, err = c.Quote(d.Products[2].Key, 0); err == nil {
|
||||
t.Fatal("zero purchase accepted")
|
||||
}
|
||||
d.Products[0].Recharge = false
|
||||
d.Products[1].Recharge = false
|
||||
if _, err = NewCatalog("test", d, gameconfig.Default().Purchases); err == nil {
|
||||
t.Fatal("missing baseline accepted")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user