264 lines
8.9 KiB
Go
264 lines
8.9 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"bindbox-game/configs"
|
||
"bindbox-game/internal/pkg/logger"
|
||
"bindbox-game/internal/repository/mysql"
|
||
"bindbox-game/internal/repository/mysql/dao"
|
||
"bindbox-game/internal/repository/mysql/model"
|
||
tcmodel "bindbox-game/internal/repository/mysql/task_center"
|
||
tasksvc "bindbox-game/internal/service/task_center"
|
||
"bindbox-game/internal/service/title"
|
||
"bindbox-game/internal/service/user"
|
||
|
||
"github.com/redis/go-redis/v9"
|
||
)
|
||
|
||
// IntegrationTest 运行集成测试流
|
||
func IntegrationTest(repo mysql.Repo) error {
|
||
ctx := context.Background()
|
||
cfg := configs.Get()
|
||
|
||
// 1. 初始化日志(自定义)
|
||
l, err := logger.NewCustomLogger(dao.Use(repo.GetDbW()))
|
||
if err != nil {
|
||
return fmt.Errorf("初始化日志失败: %v", err)
|
||
}
|
||
|
||
// 2. 初始化 Redis
|
||
rdb := redis.NewClient(&redis.Options{
|
||
Addr: cfg.Redis.Addr,
|
||
Password: cfg.Redis.Pass,
|
||
DB: cfg.Redis.DB,
|
||
})
|
||
if err := rdb.Ping(ctx).Err(); err != nil {
|
||
return fmt.Errorf("连接 Redis 失败: %v", err)
|
||
}
|
||
|
||
// 3. 初始化依赖服务
|
||
userSvc := user.New(l, repo)
|
||
titleSvc := title.New(l, repo)
|
||
taskSvc := tasksvc.New(l, repo, rdb, userSvc, titleSvc)
|
||
|
||
// 3.5 清理缓存以确保能加载最新配置
|
||
if err := rdb.Del(ctx, "task_center:active_tasks").Err(); err != nil {
|
||
fmt.Printf("⚠️ 清理缓存失败: %v\n", err)
|
||
}
|
||
|
||
// 4. 选择一个测试用户和任务
|
||
// ... (代码逻辑不变)
|
||
userID := int64(8888)
|
||
|
||
// 搜索一个首单任务(满足 lifetime 窗口,奖励为点数)
|
||
var task tcmodel.Task
|
||
db := repo.GetDbW()
|
||
if err := db.Joins("JOIN task_center_task_tiers ON task_center_task_tiers.task_id = task_center_tasks.id").
|
||
Joins("JOIN task_center_task_rewards ON task_center_task_rewards.task_id = task_center_tasks.id").
|
||
Where("task_center_task_tiers.metric = ? AND task_center_task_tiers.window = ? AND task_center_task_rewards.reward_type = ?", "first_order", "lifetime", "points").
|
||
First(&task).Error; err != nil {
|
||
return fmt.Errorf("未找到符合条件的集成测试任务: %v", err)
|
||
}
|
||
|
||
fmt.Printf("--- 开始集成测试 ---\n")
|
||
fmt.Printf("用户ID: %d, 任务ID: %d (%s)\n", userID, task.ID, task.Name)
|
||
|
||
// 5. 创建一个模拟订单
|
||
orderNo := fmt.Sprintf("TEST_ORDER_%d", time.Now().Unix())
|
||
order := &model.Orders{
|
||
UserID: userID,
|
||
OrderNo: orderNo,
|
||
TotalAmount: 100,
|
||
ActualAmount: 100,
|
||
Status: 2, // 已支付
|
||
PaidAt: time.Now(),
|
||
}
|
||
if err := db.Omit("cancelled_at").Create(order).Error; err != nil {
|
||
return fmt.Errorf("创建测试订单失败: %v", err)
|
||
}
|
||
fmt.Printf("创建测试订单: %s (ID: %d)\n", orderNo, order.ID)
|
||
|
||
// 6. 触发 OnOrderPaid
|
||
fmt.Println("触发 OnOrderPaid 事件...")
|
||
if err := taskSvc.OnOrderPaid(ctx, userID, order.ID); err != nil {
|
||
return fmt.Errorf("OnOrderPaid 失败: %v", err)
|
||
}
|
||
|
||
// 7. 验证结果
|
||
// A. 检查进度是否更新
|
||
var progress tcmodel.UserTaskProgress
|
||
if err := db.Where("user_id = ? AND task_id = ?", userID, task.ID).First(&progress).Error; err != nil {
|
||
fmt.Printf("❌ 进度记录未找到: %v\n", err)
|
||
} else {
|
||
fmt.Printf("✅ 进度记录已更新: first_order=%d\n", progress.FirstOrder)
|
||
}
|
||
|
||
// B. 检查奖励日志
|
||
time.Sleep(1 * time.Second)
|
||
|
||
var eventLog tcmodel.TaskEventLog
|
||
if err := db.Where("user_id = ? AND task_id = ?", userID, task.ID).Order("id desc").First(&eventLog).Error; err != nil {
|
||
fmt.Printf("❌ 奖励日志未找到: %v\n", err)
|
||
} else {
|
||
fmt.Printf("✅ 奖励日志已找到: Status=%s, Result=%s\n", eventLog.Status, eventLog.Result)
|
||
if eventLog.Status == "granted" {
|
||
fmt.Printf("🎉 集成测试通过!奖励已成功发放。\n")
|
||
} else {
|
||
fmt.Printf("⚠️ 奖励发放状态异常: %s\n", eventLog.Status)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// InviteAndTaskIntegrationTest 运行邀请与任务全链路集成测试
|
||
func InviteAndTaskIntegrationTest(repo mysql.Repo) error {
|
||
ctx := context.Background()
|
||
cfg := configs.Get()
|
||
db := repo.GetDbW()
|
||
|
||
// 1. 初始化
|
||
l, _ := logger.NewCustomLogger(dao.Use(db))
|
||
rdb := redis.NewClient(&redis.Options{Addr: cfg.Redis.Addr, Password: cfg.Redis.Pass, DB: cfg.Redis.DB})
|
||
userSvc := user.New(l, repo)
|
||
titleSvc := title.New(l, repo)
|
||
taskSvc := tasksvc.New(l, repo, rdb, userSvc, titleSvc)
|
||
|
||
// 2. 准备角色
|
||
inviterID := int64(9001)
|
||
inviteeID := int64(9002)
|
||
_ = ensureUserExists(repo, inviterID, "老司机(邀请者)")
|
||
_ = ensureUserExists(repo, inviteeID, "萌新(被邀请者)")
|
||
|
||
// 3. 建立邀请关系
|
||
if err := ensureInviteRelationship(repo, inviterID, inviteeID); err != nil {
|
||
return fmt.Errorf("建立邀请关系失败: %v", err)
|
||
}
|
||
|
||
// 4. 清理 Redis 缓存
|
||
_ = rdb.Del(ctx, "task_center:active_tasks").Err()
|
||
|
||
// 5. 查找测试任务
|
||
var inviteTask tcmodel.Task
|
||
if err := db.Joins("JOIN task_center_task_tiers ON task_center_task_tiers.task_id = task_center_tasks.id").
|
||
Where("task_center_task_tiers.metric = ? AND task_center_task_tiers.window = ?", "invite_count", "lifetime").
|
||
First(&inviteTask).Error; err != nil {
|
||
return fmt.Errorf("未找到邀请任务: %v", err)
|
||
}
|
||
|
||
var firstOrderTask tcmodel.Task
|
||
if err := db.Joins("JOIN task_center_task_tiers ON task_center_task_tiers.task_id = task_center_tasks.id").
|
||
Where("task_center_task_tiers.metric = ? AND task_center_task_tiers.window = ?", "first_order", "lifetime").
|
||
First(&firstOrderTask).Error; err != nil {
|
||
return fmt.Errorf("未找到首单任务: %v", err)
|
||
}
|
||
|
||
fmt.Printf("--- 开始邀请全链路测试 ---\n")
|
||
fmt.Printf("邀请人: %d, 被邀请人: %d\n", inviterID, inviteeID)
|
||
|
||
// 6. 模拟邀请成功事件 (触发两次以确保达到默认阈值 2)
|
||
fmt.Println("触发 OnInviteSuccess 事件 (第1次)...")
|
||
if err := taskSvc.OnInviteSuccess(ctx, inviterID, inviteeID); err != nil {
|
||
return fmt.Errorf("OnInviteSuccess 失败: %v", err)
|
||
}
|
||
fmt.Println("触发 OnInviteSuccess 事件 (第2次, 换个用户ID)...")
|
||
if err := taskSvc.OnInviteSuccess(ctx, inviterID, 9999); err != nil {
|
||
return fmt.Errorf("OnInviteSuccess 失败: %v", err)
|
||
}
|
||
|
||
// 7. 模拟被邀请者下单
|
||
orderNo := fmt.Sprintf("INVITE_ORDER_%d", time.Now().Unix())
|
||
order := &model.Orders{
|
||
UserID: inviteeID,
|
||
OrderNo: orderNo,
|
||
TotalAmount: 100,
|
||
ActualAmount: 100,
|
||
Status: 2, // 已支付
|
||
PaidAt: time.Now(),
|
||
}
|
||
if err := db.Omit("cancelled_at").Create(order).Error; err != nil {
|
||
return fmt.Errorf("创建被邀请者订单失败: %v", err)
|
||
}
|
||
fmt.Printf("被邀请者下单成功: %s (ID: %d)\n", orderNo, order.ID)
|
||
|
||
fmt.Println("触发 OnOrderPaid 事件 (被邀请者)...")
|
||
if err := taskSvc.OnOrderPaid(ctx, inviteeID, order.ID); err != nil {
|
||
return fmt.Errorf("OnOrderPaid 失败: %v", err)
|
||
}
|
||
|
||
// 8. 验证
|
||
time.Sleep(1 * time.Second)
|
||
|
||
fmt.Println("\n--- 数据库进度核查 ---")
|
||
var allProgress []tcmodel.UserTaskProgress
|
||
db.Where("user_id IN (?)", []int64{inviterID, inviteeID}).Find(&allProgress)
|
||
if len(allProgress) == 0 {
|
||
fmt.Println("⚠️ 数据库中未找到任何进度记录!")
|
||
}
|
||
for _, p := range allProgress {
|
||
userLabel := "邀请人"
|
||
if p.UserID == inviteeID {
|
||
userLabel = "被邀请人"
|
||
}
|
||
fmt.Printf("[%s] 用户:%d 任务:%d | Invite=%d, OrderCount=%d, FirstOrder=%d\n",
|
||
userLabel, p.UserID, p.TaskID, p.InviteCount, p.OrderCount, p.FirstOrder)
|
||
}
|
||
|
||
fmt.Println("\n--- 奖励发放核查 ---")
|
||
var logs []tcmodel.TaskEventLog
|
||
db.Where("user_id IN (?) AND status = ?", []int64{inviterID, inviteeID}, "granted").Find(&logs)
|
||
fmt.Printf("✅ 累计发放奖励次数: %d\n", len(logs))
|
||
for _, l := range logs {
|
||
fmt.Printf(" - 用户 %d 触发任务 %d 奖励 | Source:%s\n", l.UserID, l.TaskID, l.SourceType)
|
||
}
|
||
|
||
if len(logs) >= 2 {
|
||
fmt.Println("\n🎉 邀请全链路集成测试通过!邀请人和被邀请人都获得了奖励。")
|
||
} else {
|
||
fmt.Printf("\n⚠️ 测试部分完成,奖励次数(%d)少于预期(2)\n", len(logs))
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 模拟创建用户的方法(如果不存在)
|
||
func ensureUserExists(repo mysql.Repo, userID int64, nickname string) error {
|
||
db := repo.GetDbW()
|
||
var user model.Users
|
||
if err := db.Where("id = ?", userID).First(&user).Error; err != nil {
|
||
user = model.Users{
|
||
ID: userID,
|
||
Nickname: nickname,
|
||
Avatar: "http://example.com/a.png",
|
||
Status: 1,
|
||
InviteCode: fmt.Sprintf("CODE%d", userID),
|
||
}
|
||
if err := db.Create(&user).Error; err != nil {
|
||
return err
|
||
}
|
||
fmt.Printf("已确保测试用户存在: %d (%s)\n", userID, nickname)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 建立邀请关系
|
||
func ensureInviteRelationship(repo mysql.Repo, inviterID, inviteeID int64) error {
|
||
db := repo.GetDbW()
|
||
var rel model.UserInvites
|
||
if err := db.Where("invitee_id = ?", inviteeID).First(&rel).Error; err != nil {
|
||
rel = model.UserInvites{
|
||
InviterID: inviterID,
|
||
InviteeID: inviteeID,
|
||
InviteCode: fmt.Sprintf("CODE%d", inviterID),
|
||
}
|
||
return db.Omit("rewarded_at").Create(&rel).Error
|
||
}
|
||
// 如果已存在但邀请人不对,修正它
|
||
if rel.InviterID != inviterID {
|
||
return db.Model(&rel).Update("inviter_id", inviterID).Error
|
||
}
|
||
return nil
|
||
}
|