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.
96 lines
3.4 KiB
Go
96 lines
3.4 KiB
Go
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")
|
|
}
|
|
}
|