7370b17bd9
CreateSubscription/applySubscription 加 source 参数(兑换路径传 "code" 零行为变化);新导出 GrantPaidSubscriptionTx(ctx, tx, ...) 供 pay 侧在 调用方事务内以 source='pay' 复用同一段叠加语义(同 plan 活跃订阅原地 延长,否则新建行),写 pay_grant 审计。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
83 lines
2.3 KiB
Go
83 lines
2.3 KiB
Go
package codes_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/wangjia/pangolin/server/internal/codes"
|
|
)
|
|
|
|
// 新用户:GrantPaidSubscriptionTx 新建一行 source='pay',到期 = now+days。
|
|
func TestGrantPaidSubscription_NewRow(t *testing.T) {
|
|
db := openMigratedSQLite(t)
|
|
seedUser(t, db, 1)
|
|
store := codes.NewStore(db)
|
|
svc := codes.NewService(store, nil, 5, time.Hour)
|
|
ctx := context.Background()
|
|
|
|
tx, err := store.BeginTx(ctx)
|
|
if err != nil {
|
|
t.Fatalf("BeginTx: %v", err)
|
|
}
|
|
subID, expiresAt, err := svc.GrantPaidSubscriptionTx(ctx, tx, 1, codes.PlanPro, 31, "order:test001")
|
|
if err != nil {
|
|
t.Fatalf("GrantPaidSubscriptionTx: %v", err)
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
t.Fatalf("commit: %v", err)
|
|
}
|
|
if subID == 0 {
|
|
t.Fatal("subID = 0")
|
|
}
|
|
want := time.Now().UTC().AddDate(0, 0, 31)
|
|
if d := expiresAt.Sub(want); d > time.Minute || d < -time.Minute {
|
|
t.Errorf("expiresAt = %v, want ≈ %v", expiresAt, want)
|
|
}
|
|
var source string
|
|
if err := db.QueryRow(`SELECT source FROM subscriptions WHERE id = ?`, subID).Scan(&source); err != nil {
|
|
t.Fatalf("query source: %v", err)
|
|
}
|
|
if source != "pay" {
|
|
t.Errorf("source = %q, want pay", source)
|
|
}
|
|
}
|
|
|
|
// 已有同 plan 活跃订阅:原地延长(行数不变,expires 累加),复用兑换码同一段叠加语义。
|
|
func TestGrantPaidSubscription_StacksOnActive(t *testing.T) {
|
|
db := openMigratedSQLite(t)
|
|
seedUser(t, db, 1)
|
|
store := codes.NewStore(db)
|
|
svc := codes.NewService(store, nil, 5, time.Hour)
|
|
ctx := context.Background()
|
|
|
|
grant := func(days int) time.Time {
|
|
tx, err := store.BeginTx(ctx)
|
|
if err != nil {
|
|
t.Fatalf("BeginTx: %v", err)
|
|
}
|
|
_, exp, err := svc.GrantPaidSubscriptionTx(ctx, tx, 1, codes.PlanPro, days, "order:test002")
|
|
if err != nil {
|
|
t.Fatalf("grant: %v", err)
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
t.Fatalf("commit: %v", err)
|
|
}
|
|
return exp
|
|
}
|
|
first := grant(31)
|
|
second := grant(92)
|
|
|
|
want := first.AddDate(0, 0, 92)
|
|
if d := second.Sub(want); d > time.Minute || d < -time.Minute {
|
|
t.Errorf("stacked expiresAt = %v, want ≈ %v", second, want)
|
|
}
|
|
var n int
|
|
if err := db.QueryRow(`SELECT COUNT(*) FROM subscriptions WHERE user_id = 1`).Scan(&n); err != nil {
|
|
t.Fatalf("count: %v", err)
|
|
}
|
|
if n != 1 {
|
|
t.Errorf("subscription rows = %d, want 1(原地延长)", n)
|
|
}
|
|
}
|