118 lines
3.3 KiB
Go
118 lines
3.3 KiB
Go
package refundretry
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"hfb_sys/backend/internal/model"
|
|
|
|
"go.uber.org/zap"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
func setupRefundRetryTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("创建测试数据库失败: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(&model.PaymentOrder{}, &model.RentalOrder{}); err != nil {
|
|
t.Fatalf("数据库迁移失败: %v", err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func TestRetryBackoffCapsAtOneHour(t *testing.T) {
|
|
cases := []struct {
|
|
retryCount int
|
|
want time.Duration
|
|
}{
|
|
{retryCount: 1, want: 5 * time.Minute},
|
|
{retryCount: 2, want: 10 * time.Minute},
|
|
{retryCount: 3, want: 20 * time.Minute},
|
|
{retryCount: 4, want: 40 * time.Minute},
|
|
{retryCount: 5, want: time.Hour},
|
|
{retryCount: 10, want: time.Hour},
|
|
}
|
|
for _, tc := range cases {
|
|
if got := retryBackoff(tc.retryCount); got != tc.want {
|
|
t.Fatalf("retryBackoff(%d) = %s, want %s", tc.retryCount, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarkRetryFailedStopsAtMaxCount(t *testing.T) {
|
|
db := setupRefundRetryTestDB(t)
|
|
job := New(db, nil, zap.NewNop(), nil)
|
|
now := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC)
|
|
row := model.PaymentOrder{
|
|
PaymentNo: "PAY202606140101",
|
|
OrderID: 1,
|
|
OrderNo: "ORD202606140101",
|
|
UserID: 2,
|
|
Provider: "mock",
|
|
ThirdOrderID: "REF202606140101",
|
|
BizType: "admin_refund",
|
|
Status: "failed",
|
|
RetryCount: maxRetryCount - 1,
|
|
}
|
|
if err := db.Create(&row).Error; err != nil {
|
|
t.Fatalf("创建退款单失败: %v", err)
|
|
}
|
|
|
|
if err := job.markRetryFailed(t.Context(), row, now); err != nil {
|
|
t.Fatalf("markRetryFailed() error = %v", err)
|
|
}
|
|
var latest model.PaymentOrder
|
|
if err := db.First(&latest, row.ID).Error; err != nil {
|
|
t.Fatalf("查询退款单失败: %v", err)
|
|
}
|
|
if latest.RetryCount != maxRetryCount {
|
|
t.Fatalf("RetryCount = %d, want %d", latest.RetryCount, maxRetryCount)
|
|
}
|
|
if latest.LastRetryAt == nil || !latest.LastRetryAt.Equal(now) {
|
|
t.Fatalf("LastRetryAt = %v, want %v", latest.LastRetryAt, now)
|
|
}
|
|
if latest.NextRetryAt != nil {
|
|
t.Fatalf("NextRetryAt = %v, want nil after max retry", latest.NextRetryAt)
|
|
}
|
|
}
|
|
|
|
func TestResetRetryClearsRetryFields(t *testing.T) {
|
|
db := setupRefundRetryTestDB(t)
|
|
job := New(db, nil, zap.NewNop(), nil)
|
|
now := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC)
|
|
next := now.Add(time.Hour)
|
|
row := model.PaymentOrder{
|
|
PaymentNo: "PAY202606140102",
|
|
OrderID: 1,
|
|
OrderNo: "ORD202606140102",
|
|
UserID: 2,
|
|
Provider: "mock",
|
|
ThirdOrderID: "REF202606140102",
|
|
BizType: "admin_refund",
|
|
Status: "refunded",
|
|
RetryCount: 3,
|
|
LastRetryAt: &now,
|
|
NextRetryAt: &next,
|
|
}
|
|
if err := db.Create(&row).Error; err != nil {
|
|
t.Fatalf("创建退款单失败: %v", err)
|
|
}
|
|
|
|
if err := job.resetRetry(t.Context(), row.ID); err != nil {
|
|
t.Fatalf("resetRetry() error = %v", err)
|
|
}
|
|
var latest model.PaymentOrder
|
|
if err := db.First(&latest, row.ID).Error; err != nil {
|
|
t.Fatalf("查询退款单失败: %v", err)
|
|
}
|
|
if latest.RetryCount != 0 || latest.LastRetryAt != nil || latest.NextRetryAt != nil {
|
|
t.Fatalf("retry fields = count:%d last:%v next:%v, want zero/nil", latest.RetryCount, latest.LastRetryAt, latest.NextRetryAt)
|
|
}
|
|
}
|