66 lines
2.1 KiB
Go
66 lines
2.1 KiB
Go
package store_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/wangjia/pay/internal/model"
|
|
"github.com/wangjia/pay/internal/store"
|
|
)
|
|
|
|
func newSubStore(t *testing.T) *store.SubscriptionStore {
|
|
return store.NewSubscriptionStore(model.OpenTestDB(t))
|
|
}
|
|
|
|
func TestSubscriptionCreateIdempotent(t *testing.T) {
|
|
s := newSubStore(t)
|
|
sub := &model.Subscription{SubID: "SUB-1", Channel: "stripe", ProviderSubRef: "sub_x",
|
|
OutTradeNo: "PAY-1", BizSystem: "pangolin", BizRef: "u-1", BizCode: "pro_month",
|
|
AmountMinor: 2999, Currency: "USD", Status: model.SubActive}
|
|
created, err := s.Create(sub)
|
|
if err != nil || !created {
|
|
t.Fatalf("first create: created=%v err=%v", created, err)
|
|
}
|
|
// 同 provider_sub_ref 再建 → 幂等 no-op(Stripe 重投 checkout.completed)
|
|
again, err := s.Create(&model.Subscription{SubID: "SUB-2", Channel: "stripe", ProviderSubRef: "sub_x",
|
|
OutTradeNo: "PAY-1", AmountMinor: 2999, Currency: "USD", Status: model.SubActive})
|
|
if err != nil || again {
|
|
t.Fatalf("dup create: again=%v err=%v", again, err)
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionStateMachine(t *testing.T) {
|
|
s := newSubStore(t)
|
|
end := time.Now().Add(30 * 24 * time.Hour)
|
|
if _, err := s.Create(&model.Subscription{SubID: "SUB-9", Channel: "stripe", ProviderSubRef: "sub_9",
|
|
OutTradeNo: "PAY-9", AmountMinor: 2999, Currency: "USD", Status: model.SubActive}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// active → past_due
|
|
ok, _ := s.MarkPastDue("stripe", "sub_9")
|
|
if !ok {
|
|
t.Fatal("MarkPastDue should flip active→past_due")
|
|
}
|
|
// past_due → active(续费恢复)
|
|
ok, _ = s.Activate("SUB-9", &end)
|
|
if !ok {
|
|
t.Fatal("Activate should recover past_due→active")
|
|
}
|
|
// → canceled(终态)
|
|
ok, _ = s.MarkCanceled("SUB-9")
|
|
if !ok {
|
|
t.Fatal("MarkCanceled should flip →canceled")
|
|
}
|
|
// canceled 后不可复活
|
|
if ok, _ := s.Activate("SUB-9", &end); ok {
|
|
t.Fatal("canceled sub must not be re-activated")
|
|
}
|
|
if ok, _ := s.MarkPastDue("stripe", "sub_9"); ok {
|
|
t.Fatal("canceled sub must not go past_due")
|
|
}
|
|
got, err := s.GetBySubID("SUB-9")
|
|
if err != nil || got.Status != model.SubCanceled {
|
|
t.Fatalf("final status = %v err=%v", got.Status, err)
|
|
}
|
|
}
|