registry_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package payment
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "testing"
  7. )
  8. // mockProvider implements the Provider interface for testing.
  9. type mockProvider struct {
  10. name string
  11. key string
  12. supportedTypes []PaymentType
  13. }
  14. func (m *mockProvider) Name() string { return m.name }
  15. func (m *mockProvider) ProviderKey() string { return m.key }
  16. func (m *mockProvider) SupportedTypes() []PaymentType { return m.supportedTypes }
  17. func (m *mockProvider) CreatePayment(_ context.Context, _ CreatePaymentRequest) (*CreatePaymentResponse, error) {
  18. return nil, nil
  19. }
  20. func (m *mockProvider) QueryOrder(_ context.Context, _ string) (*QueryOrderResponse, error) {
  21. return nil, nil
  22. }
  23. func (m *mockProvider) VerifyNotification(_ context.Context, _ string, _ map[string]string) (*PaymentNotification, error) {
  24. return nil, nil
  25. }
  26. func (m *mockProvider) Refund(_ context.Context, _ RefundRequest) (*RefundResponse, error) {
  27. return nil, nil
  28. }
  29. func TestRegistryRegisterAndGetProvider(t *testing.T) {
  30. t.Parallel()
  31. r := NewRegistry()
  32. p := &mockProvider{
  33. name: "TestPay",
  34. key: "testpay",
  35. supportedTypes: []PaymentType{TypeAlipay, TypeWxpay},
  36. }
  37. r.Register(p)
  38. got, err := r.GetProvider(TypeAlipay)
  39. if err != nil {
  40. t.Fatalf("GetProvider(alipay) error: %v", err)
  41. }
  42. if got.ProviderKey() != "testpay" {
  43. t.Fatalf("GetProvider(alipay) key = %q, want %q", got.ProviderKey(), "testpay")
  44. }
  45. got2, err := r.GetProvider(TypeWxpay)
  46. if err != nil {
  47. t.Fatalf("GetProvider(wxpay) error: %v", err)
  48. }
  49. if got2.ProviderKey() != "testpay" {
  50. t.Fatalf("GetProvider(wxpay) key = %q, want %q", got2.ProviderKey(), "testpay")
  51. }
  52. }
  53. func TestRegistryGetProviderNotFound(t *testing.T) {
  54. t.Parallel()
  55. r := NewRegistry()
  56. _, err := r.GetProvider("nonexistent")
  57. if err == nil {
  58. t.Fatal("GetProvider for unregistered type should return error")
  59. }
  60. }
  61. func TestRegistryGetProviderByKey(t *testing.T) {
  62. t.Parallel()
  63. r := NewRegistry()
  64. p := &mockProvider{
  65. name: "EasyPay",
  66. key: "easypay",
  67. supportedTypes: []PaymentType{TypeAlipay},
  68. }
  69. r.Register(p)
  70. got, err := r.GetProviderByKey("easypay")
  71. if err != nil {
  72. t.Fatalf("GetProviderByKey error: %v", err)
  73. }
  74. if got.Name() != "EasyPay" {
  75. t.Fatalf("GetProviderByKey name = %q, want %q", got.Name(), "EasyPay")
  76. }
  77. }
  78. func TestRegistryGetProviderByKeyNotFound(t *testing.T) {
  79. t.Parallel()
  80. r := NewRegistry()
  81. _, err := r.GetProviderByKey("nonexistent")
  82. if err == nil {
  83. t.Fatal("GetProviderByKey for unknown key should return error")
  84. }
  85. }
  86. func TestRegistryGetProviderKeyUnknownType(t *testing.T) {
  87. t.Parallel()
  88. r := NewRegistry()
  89. key := r.GetProviderKey("unknown_type")
  90. if key != "" {
  91. t.Fatalf("GetProviderKey for unknown type should return empty, got %q", key)
  92. }
  93. }
  94. func TestRegistryGetProviderKeyKnownType(t *testing.T) {
  95. t.Parallel()
  96. r := NewRegistry()
  97. p := &mockProvider{
  98. name: "Stripe",
  99. key: "stripe",
  100. supportedTypes: []PaymentType{TypeStripe},
  101. }
  102. r.Register(p)
  103. key := r.GetProviderKey(TypeStripe)
  104. if key != "stripe" {
  105. t.Fatalf("GetProviderKey(stripe) = %q, want %q", key, "stripe")
  106. }
  107. }
  108. func TestRegistrySupportedTypes(t *testing.T) {
  109. t.Parallel()
  110. r := NewRegistry()
  111. p1 := &mockProvider{
  112. name: "EasyPay",
  113. key: "easypay",
  114. supportedTypes: []PaymentType{TypeAlipay, TypeWxpay},
  115. }
  116. p2 := &mockProvider{
  117. name: "Stripe",
  118. key: "stripe",
  119. supportedTypes: []PaymentType{TypeStripe},
  120. }
  121. r.Register(p1)
  122. r.Register(p2)
  123. types := r.SupportedTypes()
  124. if len(types) != 3 {
  125. t.Fatalf("SupportedTypes() len = %d, want 3", len(types))
  126. }
  127. typeSet := make(map[PaymentType]bool)
  128. for _, tp := range types {
  129. typeSet[tp] = true
  130. }
  131. for _, expected := range []PaymentType{TypeAlipay, TypeWxpay, TypeStripe} {
  132. if !typeSet[expected] {
  133. t.Fatalf("SupportedTypes() missing %q", expected)
  134. }
  135. }
  136. }
  137. func TestRegistrySupportedTypesEmpty(t *testing.T) {
  138. t.Parallel()
  139. r := NewRegistry()
  140. types := r.SupportedTypes()
  141. if len(types) != 0 {
  142. t.Fatalf("SupportedTypes() on empty registry should be empty, got %d", len(types))
  143. }
  144. }
  145. func TestRegistryOverwriteExisting(t *testing.T) {
  146. t.Parallel()
  147. r := NewRegistry()
  148. p1 := &mockProvider{
  149. name: "OldPay",
  150. key: "old",
  151. supportedTypes: []PaymentType{TypeAlipay},
  152. }
  153. p2 := &mockProvider{
  154. name: "NewPay",
  155. key: "new",
  156. supportedTypes: []PaymentType{TypeAlipay},
  157. }
  158. r.Register(p1)
  159. r.Register(p2)
  160. got, err := r.GetProvider(TypeAlipay)
  161. if err != nil {
  162. t.Fatalf("GetProvider error: %v", err)
  163. }
  164. if got.Name() != "NewPay" {
  165. t.Fatalf("expected overwritten provider, got %q", got.Name())
  166. }
  167. }
  168. func TestRegistryConcurrentAccess(t *testing.T) {
  169. t.Parallel()
  170. r := NewRegistry()
  171. const goroutines = 50
  172. var wg sync.WaitGroup
  173. wg.Add(goroutines * 2)
  174. // Concurrent writers
  175. for i := 0; i < goroutines; i++ {
  176. go func(idx int) {
  177. defer wg.Done()
  178. p := &mockProvider{
  179. name: fmt.Sprintf("Provider-%d", idx),
  180. key: fmt.Sprintf("key-%d", idx),
  181. supportedTypes: []PaymentType{PaymentType(fmt.Sprintf("type-%d", idx))},
  182. }
  183. r.Register(p)
  184. }(i)
  185. }
  186. // Concurrent readers
  187. for i := 0; i < goroutines; i++ {
  188. go func() {
  189. defer wg.Done()
  190. _ = r.SupportedTypes()
  191. _, _ = r.GetProvider("some-type")
  192. _ = r.GetProviderKey("some-type")
  193. }()
  194. }
  195. wg.Wait()
  196. types := r.SupportedTypes()
  197. if len(types) != goroutines {
  198. t.Fatalf("after concurrent registration, expected %d types, got %d", goroutines, len(types))
  199. }
  200. }