191 lines
6.3 KiB
Go
191 lines
6.3 KiB
Go
package smashegg
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"chatapp3-golang/internal/config"
|
|
"chatapp3-golang/internal/integration"
|
|
"chatapp3-golang/internal/model"
|
|
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type fakeSmashEggGateway struct {
|
|
giftCalls []fakeGiftBackpackCall
|
|
propsCalls []integration.GivePropsBackpackRequest
|
|
switches int
|
|
changes []integration.GoldReceiptCommand
|
|
}
|
|
|
|
type fakeGiftBackpackCall struct {
|
|
userID int64
|
|
giftID int64
|
|
quantity int
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) ChangeGoldBalance(_ context.Context, cmd integration.GoldReceiptCommand) error {
|
|
g.changes = append(g.changes, cmd)
|
|
return nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) GivePropsBackpack(_ context.Context, req integration.GivePropsBackpackRequest) error {
|
|
g.propsCalls = append(g.propsCalls, req)
|
|
return nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) IncrGiftBackpack(_ context.Context, userID int64, giftID int64, quantity int) error {
|
|
g.giftCalls = append(g.giftCalls, fakeGiftBackpackCall{
|
|
userID: userID,
|
|
giftID: giftID,
|
|
quantity: quantity,
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) SwitchUseProps(context.Context, int64, int64) error {
|
|
g.switches++
|
|
return nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) ActivateTemporaryBadge(context.Context, int64, int64, int) error {
|
|
return nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) RemoveUserProfileCacheAll(context.Context, int64) error {
|
|
return nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) MapGoldBalance(context.Context, []int64) (map[int64]int64, error) {
|
|
return map[int64]int64{}, nil
|
|
}
|
|
|
|
func (g *fakeSmashEggGateway) MapUserTotalRecharge(context.Context, []int64) (map[int64][]integration.UserTotalRecharge, error) {
|
|
return map[int64][]integration.UserTotalRecharge{}, nil
|
|
}
|
|
|
|
func TestGrantResourceRewardRoutesGiftToGiftBackpack(t *testing.T) {
|
|
gateway := &fakeSmashEggGateway{}
|
|
service := &Service{java: gateway}
|
|
giftID := int64(2044086730826510337)
|
|
|
|
if err := service.grantResourceReward(context.Background(), &model.SmashEggDrawRecord{
|
|
UserID: 2042274349343506434,
|
|
RewardGroupID: &giftID,
|
|
ResourceType: resourceTypeGift,
|
|
DurationDays: 7,
|
|
}); err != nil {
|
|
t.Fatalf("grantResourceReward() error = %v", err)
|
|
}
|
|
|
|
if len(gateway.giftCalls) != 1 {
|
|
t.Fatalf("gift backpack calls = %d, want 1", len(gateway.giftCalls))
|
|
}
|
|
if got := gateway.giftCalls[0]; got.userID != 2042274349343506434 || got.giftID != giftID || got.quantity != 1 {
|
|
t.Fatalf("gift backpack call = %+v", got)
|
|
}
|
|
if len(gateway.propsCalls) != 0 {
|
|
t.Fatalf("props backpack calls = %d, want 0", len(gateway.propsCalls))
|
|
}
|
|
if gateway.switches != 0 {
|
|
t.Fatalf("switch use props calls = %d, want 0", gateway.switches)
|
|
}
|
|
}
|
|
|
|
func TestDrawIdempotencyReturnsOriginalResultWithoutSecondCharge(t *testing.T) {
|
|
service, gateway, db := newSmashEggDrawTestService(t)
|
|
seedSmashEggDrawConfig(t, db)
|
|
req := DrawRequest{Times: 1, IdempotencyKey: "egg-h5-key-1"}
|
|
|
|
first, err := service.Draw(context.Background(), AuthUser{UserID: 1001, SysOrigin: "LIKEI"}, req)
|
|
if err != nil {
|
|
t.Fatalf("Draw() first error = %v", err)
|
|
}
|
|
second, err := service.Draw(context.Background(), AuthUser{UserID: 1001, SysOrigin: "LIKEI"}, req)
|
|
if err != nil {
|
|
t.Fatalf("Draw() second error = %v", err)
|
|
}
|
|
if second.DrawNo != first.DrawNo {
|
|
t.Fatalf("second drawNo = %s, want %s", second.DrawNo, first.DrawNo)
|
|
}
|
|
if len(gateway.changes) != 2 {
|
|
t.Fatalf("wallet changes = %d, want one pay+reward", len(gateway.changes))
|
|
}
|
|
var recordCount int64
|
|
if err := db.Model(&model.SmashEggDrawRecord{}).Where("draw_no = ?", first.DrawNo).Count(&recordCount).Error; err != nil {
|
|
t.Fatalf("count records: %v", err)
|
|
}
|
|
if recordCount != 1 {
|
|
t.Fatalf("record count = %d, want 1", recordCount)
|
|
}
|
|
}
|
|
|
|
func TestDrawIdempotencyRejectsDifferentRequest(t *testing.T) {
|
|
service, gateway, db := newSmashEggDrawTestService(t)
|
|
seedSmashEggDrawConfig(t, db)
|
|
|
|
_, err := service.Draw(context.Background(), AuthUser{UserID: 1001, SysOrigin: "LIKEI"}, DrawRequest{Times: 1, IdempotencyKey: "egg-h5-key-2"})
|
|
if err != nil {
|
|
t.Fatalf("Draw() first error = %v", err)
|
|
}
|
|
_, err = service.Draw(context.Background(), AuthUser{UserID: 1001, SysOrigin: "LIKEI"}, DrawRequest{Times: 10, IdempotencyKey: "egg-h5-key-2"})
|
|
if err == nil {
|
|
t.Fatal("Draw() second expected idempotency conflict")
|
|
}
|
|
if len(gateway.changes) != 2 {
|
|
t.Fatalf("wallet changes = %d, want only first pay+reward", len(gateway.changes))
|
|
}
|
|
}
|
|
|
|
func newSmashEggDrawTestService(t *testing.T) (*Service, *fakeSmashEggGateway, *gorm.DB) {
|
|
t.Helper()
|
|
db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatalf("open sqlite: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(
|
|
&model.SmashEggConfig{},
|
|
&model.SmashEggDrawOptionConfig{},
|
|
&model.SmashEggRewardConfig{},
|
|
&model.SmashEggDrawRecord{},
|
|
&model.ActivityIdempotency{},
|
|
); err != nil {
|
|
t.Fatalf("migrate sqlite: %v", err)
|
|
}
|
|
gateway := &fakeSmashEggGateway{}
|
|
return NewService(config.Config{}, db, gateway), gateway, db
|
|
}
|
|
|
|
func seedSmashEggDrawConfig(t *testing.T, db *gorm.DB) {
|
|
t.Helper()
|
|
now := time.Now()
|
|
configRow := model.SmashEggConfig{
|
|
ID: 1,
|
|
SysOrigin: "LIKEI",
|
|
Enabled: true,
|
|
Timezone: defaultTimezone,
|
|
RTPBasisPoints: defaultRTPBasisPoints,
|
|
CreateTime: now,
|
|
UpdateTime: now,
|
|
}
|
|
options := []model.SmashEggDrawOptionConfig{
|
|
{ID: 2, ConfigID: 1, SysOrigin: "LIKEI", OptionKey: optionKeyOne, Label: "Smash 1", Times: 1, PriceGold: 100, Sort: 1, Enabled: true, CreateTime: now, UpdateTime: now},
|
|
{ID: 3, ConfigID: 1, SysOrigin: "LIKEI", OptionKey: optionKeyTen, Label: "Smash 10", Times: 10, PriceGold: 1000, Sort: 2, Enabled: true, CreateTime: now, UpdateTime: now},
|
|
}
|
|
rewards := []model.SmashEggRewardConfig{
|
|
{ID: 4, ConfigID: 1, SysOrigin: "LIKEI", PoolType: poolTypeGeneral, RewardType: rewardTypeGold, RewardGroupName: "50 Gold", GoldAmount: 50, RewardValueGold: 50, Sort: 1, Enabled: true, CreateTime: now, UpdateTime: now},
|
|
{ID: 5, ConfigID: 1, SysOrigin: "LIKEI", PoolType: poolTypeGeneral, RewardType: rewardTypeGold, RewardGroupName: "100 Gold", GoldAmount: 100, RewardValueGold: 100, Sort: 2, Enabled: true, CreateTime: now, UpdateTime: now},
|
|
}
|
|
if err := db.Create(&configRow).Error; err != nil {
|
|
t.Fatalf("seed config: %v", err)
|
|
}
|
|
if err := db.Create(&options).Error; err != nil {
|
|
t.Fatalf("seed options: %v", err)
|
|
}
|
|
if err := db.Create(&rewards).Error; err != nil {
|
|
t.Fatalf("seed rewards: %v", err)
|
|
}
|
|
}
|