修改支付相关
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPaymentLifecycleLogsDoNotIncludeProviderErrorsOrPayloads(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
logger := slog.New(slog.NewJSONHandler(&output, nil))
|
||||
repo := &paymentRepoStub{createErr: errors.New("provider response: secret-token"), callbackErr: errors.New("callback body: secret-token")}
|
||||
orders := &paymentOrderRepoStub{}
|
||||
sources := NewPaymentOrderSourceRegistry()
|
||||
if err := sources.Register(&paymentSourceStub{intent: &PaymentIntent{
|
||||
Provider: PaymentAlipay, TradeNo: "order-1", BusinessType: "game_item", BusinessID: "item-1",
|
||||
Subject: "test item", Amount: 100, Currency: "CNY",
|
||||
}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
uc := NewPaymentUsecase(repo, orders, nil, sources, nil, logger)
|
||||
_, _ = uc.Create(context.Background(), &PaymentRequest{
|
||||
Provider: PaymentAlipay, TradeNo: "order-1", BusinessType: "game_item", BusinessID: "item-1",
|
||||
Extra: map[string]any{"api_key": "secret-token"},
|
||||
})
|
||||
_, _ = uc.Callback(context.Background(), &PaymentCallback{Provider: PaymentAlipay, Body: []byte("secret-token")})
|
||||
|
||||
text := output.String()
|
||||
if strings.Contains(text, "secret-token") {
|
||||
t.Fatal("provider error or request payload leaked to payment log")
|
||||
}
|
||||
for _, stage := range []string{
|
||||
"payment.create.started", "payment.order.prepared", "payment.order.persisted",
|
||||
"payment.provider.create.started", "payment.create.failed",
|
||||
"payment.callback.received", "payment.callback.verify_failed", "payment.callback.failed",
|
||||
} {
|
||||
if !strings.Contains(text, stage) {
|
||||
t.Errorf("missing lifecycle stage %s", stage)
|
||||
}
|
||||
}
|
||||
for _, line := range strings.Split(strings.TrimSpace(text), "\n") {
|
||||
var entry map[string]any
|
||||
if err := json.Unmarshal([]byte(line), &entry); err != nil {
|
||||
t.Fatalf("invalid structured log %q: %v", line, err)
|
||||
}
|
||||
if entry["mod"] != "payment" {
|
||||
t.Fatalf("payment log module = %v", entry["mod"])
|
||||
}
|
||||
if entry["msg"] == "payment.create.failed" && entry["duration_ms"] == nil {
|
||||
t.Fatal("create failure did not record duration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaymentLogErrorUsesStableReasonWithoutOriginalMessage(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
logger := NewPaymentLogger(slog.New(slog.NewJSONHandler(&output, nil)))
|
||||
logger.Error(context.Background(), "payment.test.failed", "error", PaymentRejected(errors.New("secret-token")))
|
||||
if strings.Contains(output.String(), "secret-token") || !strings.Contains(output.String(), `"error_code":"provider_rejected"`) {
|
||||
t.Fatalf("unsafe or missing error code in %s", output.String())
|
||||
}
|
||||
if got := paymentErrorCode(context.DeadlineExceeded); got != "timeout" {
|
||||
t.Fatalf("deadline error code = %q, want timeout", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaymentLogCorrelatesQueryFulfillmentAndRefund(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
logger := slog.New(slog.NewJSONHandler(&output, nil))
|
||||
pending := successPaymentResult()
|
||||
pending.Status = "pending"
|
||||
repo := &paymentRepoStub{query: pending, refund: &PaymentResult{
|
||||
Provider: PaymentAlipay, TradeNo: "order-1", Status: "pending", Amount: 40, Currency: "CNY",
|
||||
}}
|
||||
orders := &paymentOrderRepoStub{order: testBizPaymentOrder()}
|
||||
registry := NewPaymentFulfillmentRegistry()
|
||||
if err := registry.Register(&paymentFulfillmentStub{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
uc := NewPaymentUsecase(repo, orders, nil, nil, registry, logger)
|
||||
if _, err := uc.Query(context.Background(), PaymentAlipay, "order-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
orders.order.PaymentStatus = PaymentStatusPaid
|
||||
if _, err := uc.Fulfill(context.Background(), PaymentAlipay, "order-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := uc.Refund(context.Background(), PaymentAlipay, "order-1", 40); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := uc.ConfirmRefund(context.Background(), PaymentAlipay, "order-1", "refund-1", 40, true, "confirmed"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, stage := range []string{
|
||||
"payment.provider.query.checked", "payment.order.reconciled", "payment.query.completed",
|
||||
"payment.fulfillment.started", "payment.fulfillment.completed",
|
||||
"payment.refund.reserved", "payment.provider.refund.checked",
|
||||
"payment.refund.completed", "payment.refund_confirmation.completed",
|
||||
} {
|
||||
if !strings.Contains(output.String(), stage) {
|
||||
t.Errorf("missing lifecycle stage %s", stage)
|
||||
}
|
||||
}
|
||||
for _, line := range strings.Split(strings.TrimSpace(output.String()), "\n") {
|
||||
var entry map[string]any
|
||||
if err := json.Unmarshal([]byte(line), &entry); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entry["trade_no"] != "order-1" {
|
||||
t.Fatalf("uncorrelated payment log: %s", line)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user