package comm import ( "testing" "yunyan/pb" ) func TestComputeRates_Conversion(t *testing.T) { r := DefaultComputeRates() cases := []struct { name string got int64 want int64 }{ {"翻译 0 秒不计", r.ForTranslate(0), 0}, {"翻译 1 秒向上取整到 1 分钟", r.ForTranslate(1), 1}, {"翻译 60 秒 = 1", r.ForTranslate(60), 1}, {"翻译 61 秒 = 2", r.ForTranslate(61), 2}, {"会议 3600 秒 = 60", r.ForMeeting(3600), 60}, {"对话 1 字最低 1", r.ForAIChat(1), 1}, {"对话 100 字 = 1", r.ForAIChat(100), 1}, {"对话 101 字 = 2", r.ForAIChat(101), 2}, } for _, c := range cases { if c.got != c.want { t.Errorf("%s: got %d want %d", c.name, c.got, c.want) } } r2 := ComputeRates{Translate: 3, Meeting: 2, AIChat: 5} if got := r2.ForTranslate(90); got != 6 { t.Errorf("系数 3 × 2 分钟应为 6,got %d", got) } if got := r2.ForAIChat(250); got != 15 { t.Errorf("系数 5 × 3 段应为 15,got %d", got) } } func TestParseComputeRates_BadValuesFallBack(t *testing.T) { r := ParseComputeRates(map[string]string{ ConfigKeyComputeRateTranslate: "0", // 非法 → 默认 1 ConfigKeyComputeRateMeeting: "abc", // 非法 → 默认 1 ConfigKeyComputeRateAIChat: "4", ConfigKeyComputeGate: "1", }) if r.Translate != 1 || r.Meeting != 1 || r.AIChat != 4 || !r.Gate { t.Fatalf("unexpected %+v", r) } if r := ParseComputeRates(nil); r != DefaultComputeRates() { t.Fatalf("空配置应回默认,got %+v", r) } } func TestResolveVip(t *testing.T) { now := int64(2_000_000_000) // 2033 年,减几十天也不会跌成负数(Usedtime<=0 视为未激活) day := int64(86400) dev := func(used int64, days, level int32) *pb.DBAuthCode { return &pb.DBAuthCode{Code: "AA", Devicemac: "AA", Usedtime: used, Vipdays: days, Viplevel: level} } t.Run("无任何来源", func(t *testing.T) { v := ResolveVip(&pb.DBUser{}, nil, now) if v.Active(now) || v.Level != 0 { t.Fatalf("%+v", v) } }) t.Run("只有自购且有效", func(t *testing.T) { v := ResolveVip(&pb.DBUser{Viplv: 1, Vipexptime: now + day}, nil, now) if !v.Active(now) || v.FromDevice || v.ExpTime != now+day { t.Fatalf("%+v", v) } }) t.Run("自购过期、设备在期 → 来自设备", func(t *testing.T) { v := ResolveVip(&pb.DBUser{Vipexptime: now - day}, []*pb.DBAuthCode{dev(now-10*day, 30, 1)}, now) if !v.Active(now) || !v.FromDevice || v.ExpTime != now-10*day+30*day { t.Fatalf("%+v", v) } }) t.Run("设备未激活不算", func(t *testing.T) { v := ResolveVip(&pb.DBUser{}, []*pb.DBAuthCode{dev(0, 30, 1)}, now) if v.Active(now) { t.Fatalf("%+v", v) } }) t.Run("设备 VIP 期按日历天连续走,解绑不暂停:激活 40 天前送 30 天 → 已过期", func(t *testing.T) { v := ResolveVip(&pb.DBUser{}, []*pb.DBAuthCode{dev(now-40*day, 30, 1)}, now) if v.Active(now) { t.Fatalf("%+v", v) } if v.ExpTime != now-10*day { t.Fatalf("过期时仍应给出历史到期时间, %+v", v) } }) t.Run("两者都有效:等级高的赢;同级取最晚", func(t *testing.T) { v := ResolveVip(&pb.DBUser{Viplv: 1, Vipexptime: now + 100*day}, []*pb.DBAuthCode{dev(now-day, 10, 2)}, now) if v.Level != 2 || !v.FromDevice { t.Fatalf("设备是 VIP-Pro 应优先, %+v", v) } v = ResolveVip(&pb.DBUser{Viplv: 1, Vipexptime: now + 100*day}, []*pb.DBAuthCode{dev(now-day, 10, 1)}, now) if v.Level != 1 || v.FromDevice || v.ExpTime != now+100*day { t.Fatalf("同级取到期最晚的自购, %+v", v) } }) t.Run("设备配了天数没配等级视为 1", func(t *testing.T) { v := ResolveVip(&pb.DBUser{}, []*pb.DBAuthCode{dev(now-day, 10, 0)}, now) if v.Level != 1 { t.Fatalf("%+v", v) } }) } func TestPlanComputeDeduction(t *testing.T) { d := func(mac string, grant, used int64) *pb.DBAuthCode { return &pb.DBAuthCode{Code: mac, Devicemac: mac, Computegrant: grant, Computeused: used} } t.Run("先扣设备,剩余最少的先扣", func(t *testing.T) { cuts, user, over := planComputeDeduction(7, []*pb.DBAuthCode{d("big", 100, 0), d("small", 10, 7)}, 50) if len(cuts) != 2 || cuts[0].d.Code != "small" || cuts[0].n != 3 || cuts[1].n != 4 || user != 0 || over != 0 { t.Fatalf("cuts=%+v user=%d over=%d", cuts, user, over) } }) t.Run("设备不够扣用户", func(t *testing.T) { cuts, user, over := planComputeDeduction(10, []*pb.DBAuthCode{d("a", 4, 0)}, 50) if len(cuts) != 1 || cuts[0].n != 4 || user != 6 || over != 0 { t.Fatalf("cuts=%+v user=%d over=%d", cuts, user, over) } }) t.Run("都不够记超额", func(t *testing.T) { cuts, user, over := planComputeDeduction(10, []*pb.DBAuthCode{d("a", 4, 0)}, 2) if len(cuts) != 1 || user != 2 || over != 4 { t.Fatalf("cuts=%+v user=%d over=%d", cuts, user, over) } }) t.Run("用完的设备跳过", func(t *testing.T) { cuts, user, _ := planComputeDeduction(1, []*pb.DBAuthCode{d("a", 4, 4)}, 5) if len(cuts) != 0 || user != 1 { t.Fatalf("cuts=%+v user=%d", cuts, user) } }) } func TestParseOpsParams(t *testing.T) { t.Run("空配置回默认", func(t *testing.T) { if got := ParseOpsParams(nil); got != DefaultOpsParams() { t.Fatalf("got %+v", got) } }) t.Run("0 是合法值,不回落默认", func(t *testing.T) { got := ParseOpsParams(map[string]string{ ConfigKeyNewUserGiftVipDays: "0", ConfigKeyNewUserGiftCompute: "0", ConfigKeyVipWarnDays: "0", ConfigKeyComputeWarn: "0", }) if got.NewUserGiftVipDays != 0 || got.NewUserGiftCompute != 0 || got.VipWarnDays != 0 || got.ComputeWarn != 0 { t.Fatalf("配 0 应保持 0(= 不送 / 不提示),got %+v", got) } }) t.Run("非法值回默认", func(t *testing.T) { got := ParseOpsParams(map[string]string{ ConfigKeyNewUserGiftVipDays: "abc", ConfigKeyNewUserGiftCompute: "-5", }) if got.NewUserGiftVipDays != DefaultNewUserGiftVipDays || got.NewUserGiftCompute != DefaultNewUserGiftCompute { t.Fatalf("got %+v", got) } }) t.Run("往返一致", func(t *testing.T) { in := OpsParams{NewUserGiftVipDays: 15, NewUserGiftCompute: 250, VipWarnDays: 3, ComputeWarn: 50} if got := ParseOpsParams(in.ToKV()); got != in { t.Fatalf("got %+v want %+v", got, in) } }) }