补充兑换码开通会员集成测试场景
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
membershipmodel "wx_service/internal/membership/model"
|
||||
usermodel "wx_service/internal/model"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func setupRedeemTestDB(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("open sqlite: %v", err)
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(
|
||||
&membershipmodel.MembershipRedeemCode{},
|
||||
&membershipmodel.MembershipRedemption{},
|
||||
&usermodel.UserMembership{},
|
||||
); err != nil {
|
||||
t.Fatalf("auto migrate: %v", err)
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func seedRedeemCode(t *testing.T, db *gorm.DB, plainCode string, durationDays int, expiresAt *time.Time, maxUses int, status string) membershipmodel.MembershipRedeemCode {
|
||||
t.Helper()
|
||||
|
||||
code := normalizeCode(plainCode)
|
||||
record := membershipmodel.MembershipRedeemCode{
|
||||
CodeHash: hashCode(code),
|
||||
CodeSuffix: suffixOf(code, 6),
|
||||
Plan: "month",
|
||||
DurationDays: durationDays,
|
||||
ExpiresAt: expiresAt,
|
||||
MaxUses: maxUses,
|
||||
UsedUses: 0,
|
||||
Status: status,
|
||||
}
|
||||
if err := db.Create(&record).Error; err != nil {
|
||||
t.Fatalf("seed redeem code: %v", err)
|
||||
}
|
||||
return record
|
||||
}
|
||||
|
||||
func TestRedeemCodeServiceRedeemSuccessAndRepeat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := setupRedeemTestDB(t)
|
||||
svc := NewRedeemCodeService(db, "")
|
||||
user := &usermodel.User{ID: 1, MiniProgramID: 10}
|
||||
|
||||
code := "TEST-CODE-001"
|
||||
seedRedeemCode(t, db, code, 30, nil, 1, "active")
|
||||
|
||||
res, err := svc.Redeem(context.Background(), user, code, "127.0.0.1", "ut")
|
||||
if err != nil {
|
||||
t.Fatalf("redeem success: %v", err)
|
||||
}
|
||||
if res == nil || res.Extended {
|
||||
t.Fatalf("first redeem should create membership and extended=false")
|
||||
}
|
||||
|
||||
var membership usermodel.UserMembership
|
||||
if err := db.Where("mini_program_id = ? AND user_id = ?", user.MiniProgramID, user.ID).First(&membership).Error; err != nil {
|
||||
t.Fatalf("query membership: %v", err)
|
||||
}
|
||||
if membership.Status != "active" {
|
||||
t.Fatalf("membership status=%s, want=active", membership.Status)
|
||||
}
|
||||
|
||||
var storedCode membershipmodel.MembershipRedeemCode
|
||||
if err := db.Where("code_hash = ?", hashCode(normalizeCode(code))).First(&storedCode).Error; err != nil {
|
||||
t.Fatalf("query redeem code: %v", err)
|
||||
}
|
||||
if storedCode.UsedUses != 1 {
|
||||
t.Fatalf("used_uses=%d, want=1", storedCode.UsedUses)
|
||||
}
|
||||
|
||||
_, err = svc.Redeem(context.Background(), user, code, "127.0.0.1", "ut")
|
||||
if !errors.Is(err, ErrRedeemCodeUsedUp) {
|
||||
t.Fatalf("repeat redeem err=%v, want ErrRedeemCodeUsedUp", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedeemCodeServiceRedeemExpiredCode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := setupRedeemTestDB(t)
|
||||
svc := NewRedeemCodeService(db, "")
|
||||
user := &usermodel.User{ID: 2, MiniProgramID: 10}
|
||||
|
||||
expired := time.Now().Add(-1 * time.Hour)
|
||||
code := "TEST-CODE-EXPIRED"
|
||||
seedRedeemCode(t, db, code, 30, &expired, 1, "active")
|
||||
|
||||
_, err := svc.Redeem(context.Background(), user, code, "127.0.0.1", "ut")
|
||||
if !errors.Is(err, ErrRedeemCodeExpired) {
|
||||
t.Fatalf("redeem expired err=%v, want ErrRedeemCodeExpired", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedeemCodeServiceRedeemInvalidCode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := setupRedeemTestDB(t)
|
||||
svc := NewRedeemCodeService(db, "")
|
||||
user := &usermodel.User{ID: 3, MiniProgramID: 10}
|
||||
|
||||
_, err := svc.Redeem(context.Background(), user, "NOT-FOUND-CODE", "127.0.0.1", "ut")
|
||||
if !errors.Is(err, ErrRedeemCodeInvalid) {
|
||||
t.Fatalf("redeem invalid err=%v, want ErrRedeemCodeInvalid", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedeemCodeServiceRedeemExtendsActiveMembership(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := setupRedeemTestDB(t)
|
||||
svc := NewRedeemCodeService(db, "")
|
||||
user := &usermodel.User{ID: 4, MiniProgramID: 10}
|
||||
|
||||
firstCode := "TEST-CODE-A"
|
||||
secondCode := "TEST-CODE-B"
|
||||
seedRedeemCode(t, db, firstCode, 10, nil, 1, "active")
|
||||
seedRedeemCode(t, db, secondCode, 15, nil, 1, "active")
|
||||
|
||||
firstRes, err := svc.Redeem(context.Background(), user, firstCode, "127.0.0.1", "ut")
|
||||
if err != nil {
|
||||
t.Fatalf("first redeem: %v", err)
|
||||
}
|
||||
secondRes, err := svc.Redeem(context.Background(), user, secondCode, "127.0.0.1", "ut")
|
||||
if err != nil {
|
||||
t.Fatalf("second redeem: %v", err)
|
||||
}
|
||||
if secondRes == nil || !secondRes.Extended {
|
||||
t.Fatalf("second redeem should extend existing membership")
|
||||
}
|
||||
if !secondRes.EndsAt.After(firstRes.EndsAt) {
|
||||
t.Fatalf("second ends_at=%s should be after first ends_at=%s", secondRes.EndsAt, firstRes.EndsAt)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user