easypay_query_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package provider
  2. import (
  3. "context"
  4. "net/http"
  5. "net/http/httptest"
  6. "net/url"
  7. "testing"
  8. "github.com/Wei-Shaw/sub2api/internal/payment"
  9. )
  10. func TestEasyPayQueryOrderStatusMapping(t *testing.T) {
  11. t.Parallel()
  12. const orderID = "order-123"
  13. tests := []struct {
  14. name string
  15. body string
  16. wantStatus string
  17. wantTradeNo string
  18. wantAmount float64
  19. }{
  20. {
  21. name: "top level trade success is paid",
  22. body: `{"code":1,"trade_status":"TRADE_SUCCESS","status":0,"money":"12.34","trade_no":"gateway-123"}`,
  23. wantStatus: payment.ProviderStatusPaid,
  24. wantTradeNo: "gateway-123",
  25. wantAmount: 12.34,
  26. },
  27. {
  28. name: "waiting trade status with paid numeric status stays pending",
  29. body: `{"code":1,"trade_status":"WAITING","status":1,"money":"12.34","trade_no":"gateway-123"}`,
  30. wantStatus: payment.ProviderStatusPending,
  31. wantTradeNo: "gateway-123",
  32. wantAmount: 12.34,
  33. },
  34. {
  35. name: "empty trade status with paid numeric status stays pending",
  36. body: `{"code":1,"trade_status":"","status":1,"money":"12.34"}`,
  37. wantStatus: payment.ProviderStatusPending,
  38. wantTradeNo: orderID,
  39. wantAmount: 12.34,
  40. },
  41. {
  42. name: "nested data trade success is paid",
  43. body: `{"code":1,"data":{"trade_status":"TRADE_SUCCESS","status":0,"money":"9.99","trade_no":"data-456"}}`,
  44. wantStatus: payment.ProviderStatusPaid,
  45. wantTradeNo: "data-456",
  46. wantAmount: 9.99,
  47. },
  48. {
  49. name: "legacy numeric paid status remains compatible",
  50. body: `{"code":1,"status":1,"money":"3.21"}`,
  51. wantStatus: payment.ProviderStatusPaid,
  52. wantTradeNo: orderID,
  53. wantAmount: 3.21,
  54. },
  55. {
  56. name: "legacy numeric non paid status is pending",
  57. body: `{"code":1,"status":0,"money":"3.21"}`,
  58. wantStatus: payment.ProviderStatusPending,
  59. wantTradeNo: orderID,
  60. wantAmount: 3.21,
  61. },
  62. {
  63. name: "query failure with missing status is pending",
  64. body: `{"code":0,"msg":"订单不存在"}`,
  65. wantStatus: payment.ProviderStatusPending,
  66. wantTradeNo: orderID,
  67. },
  68. {
  69. name: "missing fields are pending",
  70. body: `{}`,
  71. wantStatus: payment.ProviderStatusPending,
  72. wantTradeNo: orderID,
  73. },
  74. }
  75. for _, tt := range tests {
  76. tt := tt
  77. t.Run(tt.name, func(t *testing.T) {
  78. t.Parallel()
  79. var gotForm url.Values
  80. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  81. if r.Method != http.MethodPost {
  82. t.Errorf("method = %q, want %q", r.Method, http.MethodPost)
  83. }
  84. if r.URL.Path != "/api.php" {
  85. t.Errorf("path = %q, want /api.php", r.URL.Path)
  86. }
  87. if err := r.ParseForm(); err != nil {
  88. t.Errorf("ParseForm: %v", err)
  89. }
  90. gotForm = make(url.Values, len(r.PostForm))
  91. for key, values := range r.PostForm {
  92. gotForm[key] = append([]string(nil), values...)
  93. }
  94. w.Header().Set("Content-Type", "application/json")
  95. _, _ = w.Write([]byte(tt.body))
  96. }))
  97. defer server.Close()
  98. provider := newTestEasyPay(t, server.URL)
  99. resp, err := provider.QueryOrder(context.Background(), orderID)
  100. if err != nil {
  101. t.Fatalf("QueryOrder returned error: %v", err)
  102. }
  103. if resp.Status != tt.wantStatus {
  104. t.Fatalf("status = %q, want %q (response=%+v)", resp.Status, tt.wantStatus, resp)
  105. }
  106. if resp.TradeNo != tt.wantTradeNo {
  107. t.Fatalf("trade_no = %q, want %q", resp.TradeNo, tt.wantTradeNo)
  108. }
  109. if resp.Amount != tt.wantAmount {
  110. t.Fatalf("amount = %v, want %v", resp.Amount, tt.wantAmount)
  111. }
  112. for key, want := range map[string]string{
  113. "act": "order",
  114. "pid": "pid-1",
  115. "key": "pkey-1",
  116. "out_trade_no": orderID,
  117. } {
  118. if got := gotForm.Get(key); got != want {
  119. t.Fatalf("form[%s] = %q, want %q (form=%v)", key, got, want, gotForm)
  120. }
  121. }
  122. })
  123. }
  124. }