Files
affiliate_dash/backend/internal/service/rock_using_at_test.go
T

159 lines
5.0 KiB
Go

package service
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"affiliate_dash/internal/model"
"affiliate_dash/internal/pkg/timeutil"
)
func TestAssignTokenForOrder_SetsUsingAtAndReleaseClears(t *testing.T) {
db := newRockTestDB(t)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch {
case strings.HasPrefix(r.URL.Path, "/api/redeem/"):
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"id": 151153,
"redeem_code": "CODE-USING-1",
"bind_url": "https://gp.qq.com/cp/mock_bind",
})
case strings.HasSuffix(r.URL.Path, "/refresh"):
_ = json.NewEncoder(w).Encode(map[string]interface{}{})
default:
w.WriteHeader(http.StatusNotFound)
}
}))
defer server.Close()
svc := NewRockService(db, NewRockClient(server.URL))
setRockTestBearer(t, svc, "bearer-test")
token := model.RockToken{
UpstreamTokenID: "88001",
Token: "jwt-using",
RedeemCode: "CODE-USING-1",
Color: model.RockColorBlack,
Status: model.RockStatusAvailable,
}
if err := db.Create(&token).Error; err != nil {
t.Fatalf("创建可用 Token 失败: %v", err)
}
assigned, _, err := svc.AssignTokenForOrder(context.Background(), "ORDER-USING-1", "12345678")
if err != nil {
t.Fatalf("分配 Token 失败: %v", err)
}
if assigned.Status != model.RockStatusUsing {
t.Fatalf("分配后状态应为 using,实际 %s", assigned.Status)
}
if assigned.UsingAt == nil {
t.Fatalf("分配后 using_at 必须写入")
}
var stored model.RockToken
if err := db.First(&stored, assigned.ID).Error; err != nil {
t.Fatalf("重新读取 Token 失败: %v", err)
}
if stored.UsingAt == nil {
t.Fatalf("数据库中 using_at 未写入")
}
if err := svc.ReleaseUnboundUsingToken(context.Background(), assigned.ID); err != nil {
t.Fatalf("释放未绑定 Token 失败: %v", err)
}
var released model.RockToken
if err := db.First(&released, assigned.ID).Error; err != nil {
t.Fatalf("读取释放后的 Token 失败: %v", err)
}
if released.Status != model.RockStatusAvailable {
t.Fatalf("释放后状态应为 available,实际 %s", released.Status)
}
if released.UsingAt != nil {
t.Fatalf("释放回库存后 using_at 必须清空,实际 %v", released.UsingAt)
}
}
func TestImportPackageDetail_SetsUsingAtFromClaimedAt(t *testing.T) {
db := newRockTestDB(t)
svc := NewRockService(db, NewRockClient("https://example.com"))
var detail RockPackageDetailResponse
raw := `{
"package": {"id": 9001, "share_code": "share-using"},
"tokens": [
{"id": 30001, "token": "t1", "redeem_code": "c1", "color": "black", "status": "using", "created_at": "2026-10-27 23:31:59"}
]
}`
if err := json.Unmarshal([]byte(raw), &detail); err != nil {
t.Fatalf("解析包详情失败: %v", err)
}
inserted, _, _, err := svc.importPackageDetail(context.Background(), &detail, nil)
if err != nil {
t.Fatalf("导入包详情失败: %v", err)
}
if inserted != 1 {
t.Fatalf("期望新增 1 条,实际 %d", inserted)
}
var row model.RockToken
if err := db.Where("upstream_token_id = ?", "30001").First(&row).Error; err != nil {
t.Fatalf("查询导入 Token 失败: %v", err)
}
if row.Status != model.RockStatusUsing {
t.Fatalf("期望状态 using,实际 %s", row.Status)
}
if row.UsingAt == nil {
t.Fatalf("上游状态为 using 时必须写入 using_at")
}
expected := time.Date(2026, 10, 27, 23, 31, 59, 0, timeutil.Location())
if !row.UsingAt.Equal(expected) {
t.Fatalf("using_at 应取上游 claimed_at,实际 %v", row.UsingAt)
}
}
func TestUpdateConfig_UsingWarningDaysValidation(t *testing.T) {
db := newRockTestDB(t)
svc := NewRockService(db, NewRockClient("https://example.com"))
ctx := context.Background()
cfg, err := svc.GetConfig(ctx)
if err != nil {
t.Fatalf("获取配置失败: %v", err)
}
if cfg.UsingWarnDays != 3 || cfg.UsingDangerDays != 5 {
t.Fatalf("默认阈值应为 3/5,实际 %d/%d", cfg.UsingWarnDays, cfg.UsingDangerDays)
}
warnSix := 6
if _, err := svc.UpdateConfig(ctx, UpdateRockConfigReq{UsingWarnDays: &warnSix}); err == nil {
t.Fatalf("橙色预警 6 天大于默认红色 5 天时必须报错")
}
warnFour, dangerFour := 4, 4
if _, err := svc.UpdateConfig(ctx, UpdateRockConfigReq{UsingWarnDays: &warnFour, UsingDangerDays: &dangerFour}); err == nil {
t.Fatalf("红色预警不大于橙色预警时必须报错")
}
warnZero := 0
if _, err := svc.UpdateConfig(ctx, UpdateRockConfigReq{UsingWarnDays: &warnZero}); err == nil {
t.Fatalf("预警天数小于 1 时必须报错")
}
warnTwo, dangerFourAgain := 2, 4
updated, err := svc.UpdateConfig(ctx, UpdateRockConfigReq{UsingWarnDays: &warnTwo, UsingDangerDays: &dangerFourAgain})
if err != nil {
t.Fatalf("合法阈值保存失败: %v", err)
}
if updated.UsingWarnDays != 2 || updated.UsingDangerDays != 4 {
t.Fatalf("阈值未保存,实际 %d/%d", updated.UsingWarnDays, updated.UsingDangerDays)
}
}