64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package store_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/wangjia/pay/internal/model"
|
|
"github.com/wangjia/pay/internal/store"
|
|
)
|
|
|
|
func seedOrder(t *testing.T, s *store.OrderStore, no string) {
|
|
t.Helper()
|
|
if err := s.CreateOrder(&model.OrderV2{
|
|
OutTradeNo: no, BizSystem: "pangolin", BizRef: "u-1", ProductID: 3,
|
|
AmountMinor: 29990000, Currency: "USDT", Status: model.OrderPendingV2,
|
|
}); err != nil {
|
|
t.Fatalf("create order: %v", err)
|
|
}
|
|
if err := s.CreateAttempt(&model.Attempt{
|
|
OutTradeNo: no, Channel: "crypto", AccountID: "usdt-a1", ProviderRef: "P-" + no,
|
|
RenderType: "crypto_address", AmountMinor: 29990000, Currency: "USDT",
|
|
Status: model.AttemptPending, ExpiresAt: ptr(time.Now().Add(15 * time.Minute)),
|
|
}); err != nil {
|
|
t.Fatalf("create attempt: %v", err)
|
|
}
|
|
}
|
|
func ptr(t time.Time) *time.Time { return &t }
|
|
|
|
func TestMarkPaidIdempotentAndCancel(t *testing.T) {
|
|
s := store.NewOrderStore(model.OpenTestDB(t))
|
|
seedOrder(t, s, "PAY-1")
|
|
|
|
ok, err := s.MarkAttemptPaid("PAY-1", "crypto", "P-PAY-1", time.Now())
|
|
if err != nil || !ok {
|
|
t.Fatalf("mark#1 ok=%v err=%v", ok, err)
|
|
}
|
|
// 幂等:再标 → false
|
|
ok2, _ := s.MarkAttemptPaid("PAY-1", "crypto", "P-PAY-1", time.Now())
|
|
if ok2 {
|
|
t.Fatalf("第二次 MarkAttemptPaid 应 false")
|
|
}
|
|
|
|
// paid 后不能取消
|
|
if okc, _ := s.CancelOrder("PAY-1"); okc {
|
|
t.Fatalf("paid 单不应可取消")
|
|
}
|
|
|
|
// 另一单可取消,且列表可见
|
|
seedOrder(t, s, "PAY-2")
|
|
if okc, err := s.CancelOrder("PAY-2"); err != nil || !okc {
|
|
t.Fatalf("cancel PAY-2 ok=%v err=%v", okc, err)
|
|
}
|
|
list, _ := s.ListOrders("pangolin", "u-1", 20)
|
|
var sawCanceled bool
|
|
for _, o := range list {
|
|
if o.OutTradeNo == "PAY-2" && o.Status == model.OrderCanceledV2 {
|
|
sawCanceled = true
|
|
}
|
|
}
|
|
if !sawCanceled {
|
|
t.Fatalf("canceled 单应出现在列表")
|
|
}
|
|
}
|