package main import ( "fmt" "time" "91porn-server/common/timeutil" "91porn-server/models/v/checkinconfigmod" "91porn-server/models/v/checkinprizemod" "91porn-server/models/v/usercheckinmod" fw "git.ruishengces.com/pub_tool/autotest" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type CheckinSuite struct { env *Env url string // AppBaseURL prizeIds []primitive.ObjectID } func (s *CheckinSuite) Name() string { return "签到功能" } func (s *CheckinSuite) Setup(ctx *fw.TestContext) error { // 确保签到功能已启用 cfg, _ := checkinconfigmod.FindOne(bson.M{}) if cfg == nil { if err := checkinconfigmod.InsertOne(&checkinconfigmod.CheckinConfig{ Enable: true, Description: "测试签到", }); err != nil { return err } } else if !cfg.Enable { if err := checkinconfigmod.UpdateOne(bson.M{"_id": cfg.ID}, bson.M{"$set": bson.M{"enable": true}}); err != nil { return err } } // 创建测试用签到奖品配置(连续签到第1~3天) s.prizeIds = make([]primitive.ObjectID, 3) for i := 0; i < 3; i++ { id := primitive.NewObjectID() s.prizeIds[i] = id if err := checkinprizemod.InsertOne(&checkinprizemod.CheckinPrize{ ID: id, Title: fmt.Sprintf("测试奖品第%d天", i+1), CheckinDays: int64(i + 1), CheckinType: checkinprizemod.CheckinTypeContinuously, PrizeId: primitive.NewObjectID(), // 故意用不存在的奖品ID PrizeName: fmt.Sprintf("测试奖品%d", i+1), Status: true, BigPrize: false, }); err != nil { return err } } return nil } func (s *CheckinSuite) Teardown(ctx *fw.TestContext) { s.cleanCheckins() s.cleanPrizes() } func (s *CheckinSuite) cleanCheckins() { for { n, _ := usercheckinmod.DeleteOne(bson.M{"userId": s.env.TestUID}) if n == 0 { break } } } func (s *CheckinSuite) cleanPrizes() { for _, id := range s.prizeIds { checkinprizemod.DeleteOne(bson.M{"_id": id}) } } func (s *CheckinSuite) insertRecord(date time.Time, contDays, cumDays int64) { s.insertRecordWithGave(date, contDays, cumDays, true) } func (s *CheckinSuite) insertRecordWithGave(date time.Time, contDays, cumDays int64, gave bool) { _ = usercheckinmod.InsertOne(&usercheckinmod.UserCheckin{ ID: primitive.NewObjectID(), Date: timeutil.BeginOfTime(date), UserId: s.env.TestUID, Gave: gave, ContinuouslyDays: contDays, CumulativeDays: cumDays, CreatedAt: date, }) } func (s *CheckinSuite) headers() map[string]string { return map[string]string{ "Authorization": s.env.AppToken, "User-Agent": "91porn/3.8.0 (Android; test)", "X-User-Agent": "ver=3.8.0&sysType=android&devType=test&devId=checkin-test-001", } } func (s *CheckinSuite) getPrize() *fw.Resp { return fw.DoWithHeaders("POST", s.url+"/api/app/checkin/prize", map[string]interface{}{}, s.headers()) } func (s *CheckinSuite) Run(ctx *fw.TestContext) { s.testQueryEmpty(ctx) s.testContinuous3Days(ctx) s.testBrokenStreak(ctx) s.testBrokenStreakOneDayGap(ctx) s.testCrossMonthContinuous(ctx) s.testTodayChecked(ctx) s.testDoubleReward(ctx) s.testCheckinAfterBroken(ctx) s.testIsCheckedIn(ctx) } // 空数据查询 func (s *CheckinSuite) testQueryEmpty(ctx *fw.TestContext) { s.cleanCheckins() resp := s.getPrize() ctx.CodeEqual("空数据查询-code=200", resp, 200) data := resp.Data() if data != nil { checkin, _ := data["checkin"].(map[string]interface{}) if checkin != nil { ctx.Equal("空数据-todayChecked=false", checkin["todayChecked"], false) ctx.Equal("空数据-连续=0", fw.Num(checkin, "continuouslyDays"), float64(0)) ctx.Equal("空数据-累计=0", fw.Num(checkin, "cumulativeDays"), float64(0)) } } } // 连续签到3天 func (s *CheckinSuite) testContinuous3Days(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) s.insertRecord(today.Add(-3*24*time.Hour), 1, 1) s.insertRecord(today.Add(-2*24*time.Hour), 2, 2) s.insertRecord(today.Add(-1*24*time.Hour), 3, 3) resp := s.getPrize() ctx.CodeEqual("连续3天-code=200", resp, 200) data := resp.Data() checkin, _ := data["checkin"].(map[string]interface{}) ctx.Equal("连续3天-todayChecked=false", checkin["todayChecked"], false) ctx.Equal("连续3天-continuously=3", fw.Num(checkin, "continuouslyDays"), float64(3)) ctx.Equal("连续3天-cumulative=3", fw.Num(checkin, "cumulativeDays"), float64(3)) } // 断签:4天前、3天前签到,昨天和前天没签 func (s *CheckinSuite) testBrokenStreak(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) s.insertRecord(today.Add(-4*24*time.Hour), 1, 1) s.insertRecord(today.Add(-3*24*time.Hour), 2, 2) resp := s.getPrize() ctx.CodeEqual("断签-code=200", resp, 200) checkin, _ := resp.Data()["checkin"].(map[string]interface{}) ctx.Equal("断签-continuously=0", fw.Num(checkin, "continuouslyDays"), float64(0)) ctx.Equal("断签-cumulative=2", fw.Num(checkin, "cumulativeDays"), float64(2)) } // 中间断一天:3天前签,2天前没签,昨天签 func (s *CheckinSuite) testBrokenStreakOneDayGap(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) s.insertRecord(today.Add(-3*24*time.Hour), 1, 1) s.insertRecord(today.Add(-1*24*time.Hour), 1, 2) resp := s.getPrize() ctx.CodeEqual("断一天-code=200", resp, 200) checkin, _ := resp.Data()["checkin"].(map[string]interface{}) ctx.Equal("断一天-continuously=1", fw.Num(checkin, "continuouslyDays"), float64(1)) ctx.Equal("断一天-cumulative=2", fw.Num(checkin, "cumulativeDays"), float64(2)) } // 跨月:上月记录不计入连续 func (s *CheckinSuite) testCrossMonthContinuous(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() beginOfMonth := timeutil.BeginningOfMonth(now) s.insertRecord(beginOfMonth.Add(-3*24*time.Hour), 1, 1) s.insertRecord(beginOfMonth.Add(-2*24*time.Hour), 2, 2) s.insertRecord(beginOfMonth.Add(-1*24*time.Hour), 3, 3) resp := s.getPrize() ctx.CodeEqual("跨月-code=200", resp, 200) checkin, _ := resp.Data()["checkin"].(map[string]interface{}) ctx.Equal("跨月-continuously=0", fw.Num(checkin, "continuouslyDays"), float64(0)) ctx.Info(fmt.Sprintf("跨月-cumulative=%v (含上月记录,原版行为)", fw.Num(checkin, "cumulativeDays"))) } // 今天已签到 func (s *CheckinSuite) testTodayChecked(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) if now.Day() < 3 { ctx.Info("月初不足3天,跳过今天已签到测试") return } s.insertRecord(today.Add(-2*24*time.Hour), 1, 1) s.insertRecord(today.Add(-1*24*time.Hour), 2, 2) s.insertRecord(today, 3, 3) resp := s.getPrize() ctx.CodeEqual("今天已签到-code=200", resp, 200) checkin, _ := resp.Data()["checkin"].(map[string]interface{}) ctx.Equal("今天已签到-todayChecked=true", checkin["todayChecked"], true) ctx.Equal("今天已签到-continuously=3", fw.Num(checkin, "continuouslyDays"), float64(3)) } // 第7天双倍奖励 func (s *CheckinSuite) testDoubleReward(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) if now.Day() < 7 { ctx.Info("本月不足7天,跳过双倍奖励测试") return } for i := 6; i >= 1; i-- { d := today.Add(time.Duration(-i) * 24 * time.Hour) s.insertRecord(d, int64(7-i), int64(7-i)) } resp := s.getPrize() ctx.CodeEqual("双倍奖励-code=200", resp, 200) checkin, _ := resp.Data()["checkin"].(map[string]interface{}) ctx.Equal("6天连续+未签到-doubleReward=true", checkin["doubleReward"], true) ctx.Equal("6天连续-continuously=6", fw.Num(checkin, "continuouslyDays"), float64(6)) } // 断签后恢复 func (s *CheckinSuite) testCheckinAfterBroken(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) if now.Day() < 5 { ctx.Info("月初不足5天,跳过断签恢复测试") return } s.insertRecord(today.Add(-5*24*time.Hour), 1, 1) s.insertRecord(today.Add(-4*24*time.Hour), 2, 2) // 3天前和2天前断签 s.insertRecord(today.Add(-1*24*time.Hour), 1, 3) resp := s.getPrize() ctx.CodeEqual("断签恢复-code=200", resp, 200) checkin, _ := resp.Data()["checkin"].(map[string]interface{}) ctx.Equal("断签恢复-continuously=1", fw.Num(checkin, "continuouslyDays"), float64(1)) ctx.Equal("断签恢复-cumulative=3", fw.Num(checkin, "cumulativeDays"), float64(3)) } // isCheckedIn字段:签到但未发奖时isCheckedIn=true,isReceive=false func (s *CheckinSuite) testIsCheckedIn(ctx *fw.TestContext) { s.cleanCheckins() now := time.Now().Local() today := timeutil.BeginOfTime(now) if now.Day() < 3 { ctx.Info("月初不足3天,跳过isCheckedIn测试") return } // 第1天正常发奖,第2天签到但未发奖(Gave=false),第3天正常发奖 s.insertRecord(today.Add(-2*24*time.Hour), 1, 1) s.insertRecordWithGave(today.Add(-1*24*time.Hour), 2, 2, false) // 签到了但奖品未发放 s.insertRecord(today, 3, 3) resp := s.getPrize() ctx.CodeEqual("isCheckedIn-code=200", resp, 200) data := resp.Data() prizes, _ := data["prizes"].([]interface{}) if len(prizes) < 3 { ctx.Info(fmt.Sprintf("prizes数量不足3个(got=%d),跳过isCheckedIn断言", len(prizes))) return } // 第1天:isCheckedIn=true, isReceive=true p1, _ := prizes[0].(map[string]interface{}) ctx.Equal("第1天-isCheckedIn=true", p1["isCheckedIn"], true) ctx.Equal("第1天-isReceive=true", p1["isReceive"], true) // 第2天:签到了但未发奖 → isCheckedIn=true, isReceive=false p2, _ := prizes[1].(map[string]interface{}) ctx.Equal("第2天-isCheckedIn=true(签到未发奖)", p2["isCheckedIn"], true) ctx.Equal("第2天-isReceive=false(奖品未发放)", p2["isReceive"], false) // 第3天:isCheckedIn=true, isReceive=true p3, _ := prizes[2].(map[string]interface{}) ctx.Equal("第3天-isCheckedIn=true", p3["isCheckedIn"], true) ctx.Equal("第3天-isReceive=true", p3["isReceive"], true) }