159 lines
5.0 KiB
Go
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)
|
|
}
|
|
}
|