yumi-golang/internal/service/taskcenter/taskcenter_test.go
2026-05-08 18:55:47 +08:00

235 lines
6.3 KiB
Go

package taskcenter
import (
"context"
"testing"
"chatapp3-golang/internal/common"
"chatapp3-golang/internal/config"
"chatapp3-golang/internal/integration"
"chatapp3-golang/internal/model"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func newTestService(t *testing.T, java taskCenterJavaGateway) (*Service, *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.TaskCenterConfig{},
&model.TaskCenterTaskConfig{},
&model.TaskCenterUserProgress{},
&model.TaskCenterEvent{},
&model.TaskCenterClaimRecord{},
); err != nil {
t.Fatalf("auto migrate: %v", err)
}
service := NewService(config.Config{
TaskCenter: config.TaskCenterConfig{
DefaultSysOrigin: "LIKEI",
Timezone: "Asia/Riyadh",
},
}, db, java)
return service, db
}
func TestDailyTaskConfigEventListAndClaim(t *testing.T) {
java := &taskCenterTestGateway{events: map[string]bool{}}
service, _ := newTestService(t, java)
ctx := context.Background()
configResp, err := service.SaveConfig(ctx, SaveConfigRequest{
SysOrigin: "likei",
Enabled: true,
Timezone: "Asia/Riyadh",
TaskCategory: TaskCategoryDaily,
Tasks: []SaveTaskConfigInput{
{
TaskCode: "daily_mic_duration",
Enabled: true,
TaskName: "使用麦克风 %d 分钟。",
TaskDesc: "进度 / 目标",
ConditionType: "mic_duration_seconds",
TargetValue: 60,
TargetUnit: "second",
RewardGold: 1100,
JumpType: "ROOM_RANDOM_WITH_MIC",
SortOrder: 10,
},
},
})
if err != nil {
t.Fatalf("SaveConfig() error = %v", err)
}
if !configResp.Configured || !configResp.Enabled || len(configResp.Tasks) != 1 {
t.Fatalf("SaveConfig() resp = %+v", configResp)
}
user := common.AuthUser{UserID: 1001, SysOrigin: "LIKEI"}
tasks, err := service.ListTasks(ctx, user)
if err != nil {
t.Fatalf("ListTasks() error = %v", err)
}
if len(tasks) != 1 || tasks[0].TaskStatus != 0 || tasks[0].CompletedValue != 0 {
t.Fatalf("initial tasks = %+v", tasks)
}
eventResp, err := service.ReceiveEvent(ctx, EventRequest{
SysOrigin: "LIKEI",
EventID: "event-1",
EventType: "MIC_DURATION_SECONDS",
UserID: flexibleInt64(user.UserID),
DeltaValue: 60,
})
if err != nil {
t.Fatalf("ReceiveEvent() error = %v", err)
}
if !eventResp.Processed || eventResp.Updated != 1 {
t.Fatalf("ReceiveEvent() resp = %+v", eventResp)
}
tasks, err = service.ListTasks(ctx, user)
if err != nil {
t.Fatalf("ListTasks() after event error = %v", err)
}
if len(tasks) != 1 || tasks[0].TaskStatus != 1 || tasks[0].CompletedValue != 60 {
t.Fatalf("completed tasks = %+v", tasks)
}
ok, err := service.Claim(ctx, user, tasks[0].TaskID)
if err != nil {
t.Fatalf("Claim() error = %v", err)
}
if !ok {
t.Fatalf("Claim() = false, want true")
}
if len(java.changedEvents) != 1 {
t.Fatalf("wallet changes = %d, want 1", len(java.changedEvents))
}
if len(java.changedEvents[0]) > 50 {
t.Fatalf("wallet event id length = %d, want <= 50: %s", len(java.changedEvents[0]), java.changedEvents[0])
}
ok, err = service.Claim(ctx, user, tasks[0].TaskID)
if err != nil {
t.Fatalf("Claim() duplicate error = %v", err)
}
if !ok || len(java.changedEvents) != 1 {
t.Fatalf("duplicate claim ok=%v changes=%d, want true/1", ok, len(java.changedEvents))
}
}
func TestExclusiveTaskConfigUsesLifetimeCycleAndHidesAfterClaim(t *testing.T) {
java := &taskCenterTestGateway{events: map[string]bool{}}
service, _ := newTestService(t, java)
ctx := context.Background()
_, err := service.SaveConfig(ctx, SaveConfigRequest{
SysOrigin: "LIKEI",
Enabled: true,
Timezone: "Asia/Riyadh",
TaskCategory: TaskCategoryNewbie,
Tasks: []SaveTaskConfigInput{
{
TaskCode: "EXCLUSIVE_RECHARGE",
Enabled: true,
TaskName: "专属充值任务",
ConditionType: "RECHARGE_GOLD",
TargetValue: 10,
TargetUnit: "gold",
RewardGold: 100,
},
},
})
if err != nil {
t.Fatalf("SaveConfig() error = %v", err)
}
user := common.AuthUser{UserID: 2001, SysOrigin: "LIKEI"}
tasks, err := service.ListTasks(ctx, user)
if err != nil {
t.Fatalf("ListTasks() error = %v", err)
}
if len(tasks) != 1 || tasks[0].TaskType != 1 {
t.Fatalf("exclusive tasks = %+v, want one taskType=1", tasks)
}
eventResp, err := service.ReceiveEvent(ctx, EventRequest{
SysOrigin: "LIKEI",
EventID: "recharge-1",
EventType: "RECHARGE_GOLD",
UserID: flexibleInt64(user.UserID),
DeltaValue: 10,
})
if err != nil {
t.Fatalf("ReceiveEvent() error = %v", err)
}
if !eventResp.Processed || eventResp.Updated != 1 {
t.Fatalf("ReceiveEvent() resp = %+v", eventResp)
}
ok, err := service.Claim(ctx, user, tasks[0].TaskID)
if err != nil {
t.Fatalf("Claim() error = %v", err)
}
if !ok {
t.Fatalf("Claim() = false, want true")
}
tasks, err = service.ListTasks(ctx, user)
if err != nil {
t.Fatalf("ListTasks() after claim error = %v", err)
}
if len(tasks) != 0 {
t.Fatalf("exclusive tasks after claim = %+v, want hidden", tasks)
}
}
func TestTaskConfigRejectsRemovedConditionTypes(t *testing.T) {
service, _ := newTestService(t, nil)
for _, conditionType := range []string{"POST_MOOD_COUNT", "INTERACTIVE_GAME_COUNT", "CP_BIND_COUNT"} {
t.Run(conditionType, func(t *testing.T) {
_, err := service.SaveConfig(context.Background(), SaveConfigRequest{
SysOrigin: "LIKEI",
Enabled: true,
Timezone: "Asia/Riyadh",
TaskCategory: TaskCategoryDaily,
Tasks: []SaveTaskConfigInput{
{
TaskCode: "REMOVED_" + conditionType,
Enabled: true,
TaskName: "Removed condition",
ConditionType: conditionType,
TargetValue: 1,
TargetUnit: "count",
RewardGold: 100,
},
},
})
if err == nil {
t.Fatalf("SaveConfig() error = nil, want invalid condition")
}
})
}
}
type taskCenterTestGateway struct {
changedEvents []string
events map[string]bool
}
func (g *taskCenterTestGateway) ExistsGoldEvent(_ context.Context, eventID string) (bool, error) {
return g.events[eventID], nil
}
func (g *taskCenterTestGateway) ChangeGoldBalance(_ context.Context, cmd integration.GoldReceiptCommand) error {
g.changedEvents = append(g.changedEvents, cmd.EventID)
g.events[cmd.EventID] = true
return nil
}