stripe 4.9.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +10 -0
  3. data/.rubocop.yml +28 -4
  4. data/.rubocop_todo.yml +11 -22
  5. data/.travis.yml +3 -6
  6. data/.vscode/extensions.json +7 -0
  7. data/.vscode/settings.json +8 -0
  8. data/CHANGELOG.md +102 -2
  9. data/Gemfile +2 -10
  10. data/README.md +96 -40
  11. data/Rakefile +8 -7
  12. data/VERSION +1 -1
  13. data/lib/stripe.rb +64 -85
  14. data/lib/stripe/api_operations/delete.rb +23 -1
  15. data/lib/stripe/api_operations/list.rb +0 -6
  16. data/lib/stripe/api_operations/nested_resource.rb +14 -7
  17. data/lib/stripe/api_operations/request.rb +3 -7
  18. data/lib/stripe/api_operations/save.rb +1 -3
  19. data/lib/stripe/api_resource.rb +50 -2
  20. data/lib/stripe/connection_manager.rb +141 -0
  21. data/lib/stripe/error_object.rb +94 -0
  22. data/lib/stripe/errors.rb +22 -9
  23. data/lib/stripe/list_object.rb +11 -5
  24. data/lib/stripe/multipart_encoder.rb +131 -0
  25. data/lib/stripe/object_types.rb +94 -0
  26. data/lib/stripe/resources.rb +77 -0
  27. data/lib/stripe/{account.rb → resources/account.rb} +49 -27
  28. data/lib/stripe/{account_link.rb → resources/account_link.rb} +1 -1
  29. data/lib/stripe/resources/alipay_account.rb +34 -0
  30. data/lib/stripe/{apple_pay_domain.rb → resources/apple_pay_domain.rb} +1 -1
  31. data/lib/stripe/resources/application_fee.rb +13 -0
  32. data/lib/stripe/resources/application_fee_refund.rb +30 -0
  33. data/lib/stripe/{balance.rb → resources/balance.rb} +1 -1
  34. data/lib/stripe/{balance_transaction.rb → resources/balance_transaction.rb} +1 -5
  35. data/lib/stripe/{bank_account.rb → resources/bank_account.rb} +14 -4
  36. data/lib/stripe/{bitcoin_receiver.rb → resources/bitcoin_receiver.rb} +3 -3
  37. data/lib/stripe/{bitcoin_transaction.rb → resources/bitcoin_transaction.rb} +1 -1
  38. data/lib/stripe/resources/capability.rb +33 -0
  39. data/lib/stripe/{card.rb → resources/card.rb} +12 -4
  40. data/lib/stripe/resources/charge.rb +22 -0
  41. data/lib/stripe/{checkout → resources/checkout}/session.rb +2 -2
  42. data/lib/stripe/{country_spec.rb → resources/country_spec.rb} +1 -1
  43. data/lib/stripe/{coupon.rb → resources/coupon.rb} +2 -2
  44. data/lib/stripe/resources/credit_note.rb +22 -0
  45. data/lib/stripe/resources/customer.rb +35 -0
  46. data/lib/stripe/resources/customer_balance_transaction.rb +30 -0
  47. data/lib/stripe/resources/discount.rb +7 -0
  48. data/lib/stripe/{dispute.rb → resources/dispute.rb} +9 -7
  49. data/lib/stripe/{ephemeral_key.rb → resources/ephemeral_key.rb} +5 -2
  50. data/lib/stripe/{event.rb → resources/event.rb} +1 -1
  51. data/lib/stripe/{exchange_rate.rb → resources/exchange_rate.rb} +1 -1
  52. data/lib/stripe/{file.rb → resources/file.rb} +8 -11
  53. data/lib/stripe/{file_link.rb → resources/file_link.rb} +2 -2
  54. data/lib/stripe/resources/invoice.rb +73 -0
  55. data/lib/stripe/{invoice_item.rb → resources/invoice_item.rb} +2 -2
  56. data/lib/stripe/{invoice_line_item.rb → resources/invoice_line_item.rb} +1 -1
  57. data/lib/stripe/resources/issuing/authorization.rb +33 -0
  58. data/lib/stripe/resources/issuing/card.rb +24 -0
  59. data/lib/stripe/{issuing → resources/issuing}/card_details.rb +1 -1
  60. data/lib/stripe/{issuing → resources/issuing}/cardholder.rb +2 -2
  61. data/lib/stripe/{issuing → resources/issuing}/dispute.rb +2 -2
  62. data/lib/stripe/{issuing → resources/issuing}/transaction.rb +2 -2
  63. data/lib/stripe/resources/login_link.rb +14 -0
  64. data/lib/stripe/resources/order.rb +32 -0
  65. data/lib/stripe/{order_return.rb → resources/order_return.rb} +1 -1
  66. data/lib/stripe/resources/payment_intent.rb +42 -0
  67. data/lib/stripe/resources/payment_method.rb +32 -0
  68. data/lib/stripe/resources/payout.rb +22 -0
  69. data/lib/stripe/{person.rb → resources/person.rb} +8 -3
  70. data/lib/stripe/{plan.rb → resources/plan.rb} +1 -1
  71. data/lib/stripe/{product.rb → resources/product.rb} +3 -3
  72. data/lib/stripe/resources/radar/early_fraud_warning.rb +11 -0
  73. data/lib/stripe/{radar → resources/radar}/value_list.rb +2 -2
  74. data/lib/stripe/{radar → resources/radar}/value_list_item.rb +2 -2
  75. data/lib/stripe/{recipient.rb → resources/recipient.rb} +2 -6
  76. data/lib/stripe/{recipient_transfer.rb → resources/recipient_transfer.rb} +1 -1
  77. data/lib/stripe/{refund.rb → resources/refund.rb} +1 -1
  78. data/lib/stripe/{reporting → resources/reporting}/report_run.rb +2 -2
  79. data/lib/stripe/{reporting → resources/reporting}/report_type.rb +2 -2
  80. data/lib/stripe/resources/reversal.rb +29 -0
  81. data/lib/stripe/resources/review.rb +20 -0
  82. data/lib/stripe/resources/setup_intent.rb +32 -0
  83. data/lib/stripe/{sigma → resources/sigma}/scheduled_query_run.rb +2 -2
  84. data/lib/stripe/{sku.rb → resources/sku.rb} +3 -3
  85. data/lib/stripe/{source.rb → resources/source.rb} +17 -15
  86. data/lib/stripe/{source_transaction.rb → resources/source_transaction.rb} +1 -1
  87. data/lib/stripe/resources/subscription.rb +25 -0
  88. data/lib/stripe/{subscription_item.rb → resources/subscription_item.rb} +5 -2
  89. data/lib/stripe/resources/subscription_schedule.rb +32 -0
  90. data/lib/stripe/resources/tax_id.rb +26 -0
  91. data/lib/stripe/resources/tax_rate.rb +11 -0
  92. data/lib/stripe/{terminal → resources/terminal}/connection_token.rb +2 -2
  93. data/lib/stripe/{terminal → resources/terminal}/location.rb +3 -2
  94. data/lib/stripe/{terminal → resources/terminal}/reader.rb +3 -2
  95. data/lib/stripe/{three_d_secure.rb → resources/three_d_secure.rb} +1 -1
  96. data/lib/stripe/{token.rb → resources/token.rb} +1 -1
  97. data/lib/stripe/resources/topup.rb +22 -0
  98. data/lib/stripe/resources/transfer.rb +26 -0
  99. data/lib/stripe/resources/usage_record.rb +7 -0
  100. data/lib/stripe/{usage_record_summary.rb → resources/usage_record_summary.rb} +1 -1
  101. data/lib/stripe/{webhook_endpoint.rb → resources/webhook_endpoint.rb} +2 -2
  102. data/lib/stripe/singleton_api_resource.rb +3 -1
  103. data/lib/stripe/stripe_client.rb +347 -218
  104. data/lib/stripe/stripe_object.rb +72 -59
  105. data/lib/stripe/stripe_response.rb +53 -21
  106. data/lib/stripe/util.rb +54 -109
  107. data/lib/stripe/version.rb +1 -1
  108. data/lib/stripe/webhook.rb +5 -3
  109. data/stripe.gemspec +14 -5
  110. data/test/stripe/account_link_test.rb +1 -1
  111. data/test/stripe/account_test.rb +193 -32
  112. data/test/stripe/alipay_account_test.rb +1 -1
  113. data/test/stripe/api_operations_test.rb +3 -4
  114. data/test/stripe/api_resource_test.rb +119 -30
  115. data/test/stripe/apple_pay_domain_test.rb +18 -5
  116. data/test/stripe/application_fee_refund_test.rb +1 -1
  117. data/test/stripe/application_fee_test.rb +45 -1
  118. data/test/stripe/balance_test.rb +1 -1
  119. data/test/stripe/balance_transaction_test.rb +20 -0
  120. data/test/stripe/bank_account_test.rb +1 -1
  121. data/test/stripe/capability_test.rb +45 -0
  122. data/test/stripe/charge_test.rb +13 -8
  123. data/test/stripe/checkout/session_test.rb +7 -1
  124. data/test/stripe/connection_manager_test.rb +138 -0
  125. data/test/stripe/country_spec_test.rb +1 -1
  126. data/test/stripe/coupon_test.rb +16 -6
  127. data/test/stripe/credit_note_test.rb +61 -0
  128. data/test/stripe/customer_balance_transaction_test.rb +37 -0
  129. data/test/stripe/customer_card_test.rb +1 -1
  130. data/test/stripe/customer_test.rb +151 -40
  131. data/test/stripe/dispute_test.rb +10 -1
  132. data/test/stripe/ephemeral_key_test.rb +8 -1
  133. data/test/stripe/errors_test.rb +30 -9
  134. data/test/stripe/exchange_rate_test.rb +1 -1
  135. data/test/stripe/file_link_test.rb +1 -1
  136. data/test/stripe/file_test.rb +19 -5
  137. data/test/stripe/invoice_item_test.rb +18 -7
  138. data/test/stripe/invoice_line_item_test.rb +1 -1
  139. data/test/stripe/invoice_test.rb +77 -9
  140. data/test/stripe/issuing/authorization_test.rb +33 -11
  141. data/test/stripe/issuing/card_test.rb +15 -6
  142. data/test/stripe/issuing/cardholder_test.rb +1 -1
  143. data/test/stripe/issuing/dispute_test.rb +1 -1
  144. data/test/stripe/issuing/transaction_test.rb +1 -1
  145. data/test/stripe/list_object_test.rb +1 -17
  146. data/test/stripe/login_link_test.rb +2 -2
  147. data/test/stripe/multipart_encoder_test.rb +130 -0
  148. data/test/stripe/oauth_test.rb +1 -1
  149. data/test/stripe/order_return_test.rb +1 -1
  150. data/test/stripe/order_test.rb +28 -3
  151. data/test/stripe/payment_intent_test.rb +31 -4
  152. data/test/stripe/payment_method_test.rb +84 -0
  153. data/test/stripe/payout_test.rb +8 -1
  154. data/test/stripe/person_test.rb +1 -1
  155. data/test/stripe/plan_test.rb +26 -20
  156. data/test/stripe/product_test.rb +16 -6
  157. data/test/stripe/radar/early_fraud_warning_test.rb +22 -0
  158. data/test/stripe/radar/value_list_item_test.rb +16 -6
  159. data/test/stripe/radar/value_list_test.rb +16 -6
  160. data/test/stripe/recipient_test.rb +18 -5
  161. data/test/stripe/refund_test.rb +1 -1
  162. data/test/stripe/reporting/report_run_test.rb +1 -1
  163. data/test/stripe/reporting/report_type_test.rb +1 -1
  164. data/test/stripe/reversal_test.rb +1 -1
  165. data/test/stripe/review_test.rb +1 -1
  166. data/test/stripe/setup_intent_test.rb +84 -0
  167. data/test/stripe/sigma/scheduled_query_run_test.rb +1 -1
  168. data/test/stripe/sku_test.rb +16 -6
  169. data/test/stripe/source_test.rb +14 -19
  170. data/test/stripe/source_transaction_test.rb +1 -1
  171. data/test/stripe/stripe_client_test.rb +242 -26
  172. data/test/stripe/stripe_object_test.rb +8 -36
  173. data/test/stripe/stripe_response_test.rb +71 -25
  174. data/test/stripe/subscription_item_test.rb +28 -6
  175. data/test/stripe/subscription_schedule_test.rb +19 -1
  176. data/test/stripe/subscription_test.rb +29 -9
  177. data/test/stripe/tax_id_test.rb +31 -0
  178. data/test/stripe/tax_rate_test.rb +43 -0
  179. data/test/stripe/terminal/connection_token_test.rb +1 -1
  180. data/test/stripe/terminal/location_test.rb +18 -1
  181. data/test/stripe/terminal/reader_test.rb +18 -1
  182. data/test/stripe/three_d_secure_test.rb +1 -1
  183. data/test/stripe/topup_test.rb +9 -1
  184. data/test/stripe/transfer_test.rb +46 -1
  185. data/test/stripe/usage_record_summary_test.rb +1 -1
  186. data/test/stripe/util_test.rb +1 -1
  187. data/test/stripe/webhook_endpoint_test.rb +18 -1
  188. data/test/stripe/webhook_test.rb +4 -4
  189. data/test/stripe_mock.rb +4 -3
  190. data/test/stripe_test.rb +1 -14
  191. data/test/test_helper.rb +14 -11
  192. metadata +117 -125
  193. data/lib/stripe/alipay_account.rb +0 -27
  194. data/lib/stripe/application_fee.rb +0 -23
  195. data/lib/stripe/application_fee_refund.rb +0 -22
  196. data/lib/stripe/charge.rb +0 -84
  197. data/lib/stripe/customer.rb +0 -90
  198. data/lib/stripe/invoice.rb +0 -48
  199. data/lib/stripe/issuer_fraud_record.rb +0 -9
  200. data/lib/stripe/issuing/authorization.rb +0 -22
  201. data/lib/stripe/issuing/card.rb +0 -18
  202. data/lib/stripe/login_link.rb +0 -11
  203. data/lib/stripe/order.rb +0 -31
  204. data/lib/stripe/payment_intent.rb +0 -26
  205. data/lib/stripe/payout.rb +0 -20
  206. data/lib/stripe/reversal.rb +0 -22
  207. data/lib/stripe/review.rb +0 -14
  208. data/lib/stripe/subscription.rb +0 -25
  209. data/lib/stripe/subscription_schedule.rb +0 -32
  210. data/lib/stripe/subscription_schedule_revision.rb +0 -25
  211. data/lib/stripe/topup.rb +0 -16
  212. data/lib/stripe/transfer.rb +0 -23
  213. data/lib/stripe/usage_record.rb +0 -14
  214. data/test/stripe/account_external_accounts_operations_test.rb +0 -69
  215. data/test/stripe/account_login_links_operations_test.rb +0 -21
  216. data/test/stripe/account_persons_operations_test.rb +0 -70
  217. data/test/stripe/application_fee_refunds_operations_test.rb +0 -56
  218. data/test/stripe/customer_sources_operations_test.rb +0 -64
  219. data/test/stripe/file_upload_test.rb +0 -76
  220. data/test/stripe/issuer_fraud_record_test.rb +0 -20
  221. data/test/stripe/subscription_schedule_revision_test.rb +0 -37
  222. data/test/stripe/subscription_schedule_revisions_operations_test.rb +0 -35
  223. data/test/stripe/transfer_reversals_operations_test.rb +0 -57
  224. data/test/stripe/usage_record_test.rb +0 -28
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class RecipientTest < Test::Unit::TestCase
@@ -40,10 +40,23 @@ module Stripe
40
40
  end
41
41
 
42
42
  should "be deletable" do
43
- recipient = Stripe::Recipient.retrieve("rp_123")
44
- recipient = recipient.delete
45
- assert_requested :delete, "#{Stripe.api_base}/v1/recipients/#{recipient.id}"
46
- assert recipient.is_a?(Stripe::Recipient)
43
+ end
44
+
45
+ context "#delete" do
46
+ should "be deletable" do
47
+ recipient = Stripe::Recipient.retrieve("rp_123")
48
+ recipient = recipient.delete
49
+ assert_requested :delete, "#{Stripe.api_base}/v1/recipients/#{recipient.id}"
50
+ assert recipient.is_a?(Stripe::Recipient)
51
+ end
52
+ end
53
+
54
+ context ".delete" do
55
+ should "be deletable" do
56
+ recipient = Stripe::Recipient.delete("rp_123")
57
+ assert_requested :delete, "#{Stripe.api_base}/v1/recipients/rp_123"
58
+ assert recipient.is_a?(Stripe::Recipient)
59
+ end
47
60
  end
48
61
  end
49
62
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class RefundTest < Test::Unit::TestCase
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../../test_helper", __FILE__)
3
+ require ::File.expand_path("../../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  module Reporting
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../../test_helper", __FILE__)
3
+ require ::File.expand_path("../../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  module Reporting
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class ReversalTest < Test::Unit::TestCase
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class ReviewTest < Test::Unit::TestCase
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class SetupIntentTest < Test::Unit::TestCase
7
+ TEST_RESOURCE_ID = "seti_123"
8
+
9
+ should "be listable" do
10
+ setup_intents = Stripe::SetupIntent.list
11
+ assert_requested :get, "#{Stripe.api_base}/v1/setup_intents"
12
+ assert setup_intents.data.is_a?(Array)
13
+ assert setup_intents.data[0].is_a?(Stripe::SetupIntent)
14
+ end
15
+
16
+ should "be retrievable" do
17
+ setup_intent = Stripe::SetupIntent.retrieve("seti_123")
18
+ assert_requested :get, "#{Stripe.api_base}/v1/setup_intents/seti_123"
19
+ assert setup_intent.is_a?(Stripe::SetupIntent)
20
+ end
21
+
22
+ should "be creatable" do
23
+ setup_intent = Stripe::SetupIntent.create(
24
+ payment_method_types: ["card"]
25
+ )
26
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents"
27
+ assert setup_intent.is_a?(Stripe::SetupIntent)
28
+ end
29
+
30
+ should "be saveable" do
31
+ setup_intent = Stripe::SetupIntent.construct_from(id: "seti_123", object: "setup_intent", metadata: {})
32
+ setup_intent.metadata["key"] = "value"
33
+ setup_intent.save
34
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/#{setup_intent.id}"
35
+ end
36
+
37
+ should "be updateable" do
38
+ setup_intent = Stripe::SetupIntent.update("seti_123", metadata: { foo: "bar" })
39
+
40
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123"
41
+ assert setup_intent.is_a?(Stripe::SetupIntent)
42
+ end
43
+
44
+ context "#cancel" do
45
+ should "cancel a setup_intent" do
46
+ setup_intent = Stripe::SetupIntent.construct_from(id: "seti_123", object: "setup_intent")
47
+ setup_intent = setup_intent.cancel
48
+
49
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/cancel"
50
+ assert setup_intent.is_a?(Stripe::SetupIntent)
51
+ end
52
+ end
53
+
54
+ context ".cancel" do
55
+ should "cancel a setup_intent" do
56
+ setup_intent = Stripe::SetupIntent.cancel("seti_123")
57
+
58
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/cancel"
59
+ assert setup_intent.is_a?(Stripe::SetupIntent)
60
+ end
61
+ end
62
+
63
+ context "#confirm" do
64
+ should "confirm a setup_intent" do
65
+ setup_intent = Stripe::SetupIntent.construct_from(id: "seti_123", object: "setup_intent")
66
+ setup_intent = setup_intent.confirm(
67
+ payment_method: "pm_123"
68
+ )
69
+
70
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/confirm"
71
+ assert setup_intent.is_a?(Stripe::SetupIntent)
72
+ end
73
+ end
74
+
75
+ context ".confirm" do
76
+ should "confirm a setup_intent" do
77
+ setup_intent = Stripe::SetupIntent.confirm("seti_123", payment_method: "pm_123")
78
+
79
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/confirm"
80
+ assert setup_intent.is_a?(Stripe::SetupIntent)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../../test_helper", __FILE__)
3
+ require ::File.expand_path("../../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  module Issuing
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class SKUTest < Test::Unit::TestCase
@@ -40,11 +40,21 @@ module Stripe
40
40
  assert sku.is_a?(Stripe::SKU)
41
41
  end
42
42
 
43
- should "be deletable" do
44
- sku = Stripe::SKU.retrieve("sku_123")
45
- sku = sku.delete
46
- assert_requested :delete, "#{Stripe.api_base}/v1/skus/#{sku.id}"
47
- assert sku.is_a?(Stripe::SKU)
43
+ context "#delete" do
44
+ should "be deletable" do
45
+ sku = Stripe::SKU.retrieve("sku_123")
46
+ sku = sku.delete
47
+ assert_requested :delete, "#{Stripe.api_base}/v1/skus/#{sku.id}"
48
+ assert sku.is_a?(Stripe::SKU)
49
+ end
50
+ end
51
+
52
+ context ".delete" do
53
+ should "be deletable" do
54
+ sku = Stripe::SKU.delete("sku_123")
55
+ assert_requested :delete, "#{Stripe.api_base}/v1/skus/sku_123"
56
+ assert sku.is_a?(Stripe::SKU)
57
+ end
48
58
  end
49
59
  end
50
60
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class SourceTest < Test::Unit::TestCase
@@ -51,24 +51,6 @@ module Stripe
51
51
  end
52
52
  end
53
53
 
54
- context "#delete" do
55
- should "warn that #delete is deprecated" do
56
- old_stderr = $stderr
57
- $stderr = StringIO.new
58
- begin
59
- source = Stripe::Source.construct_from(customer: "cus_123",
60
- id: "src_123",
61
- object: "source")
62
- source.delete
63
- message = "NOTE: Stripe::Source#delete is " \
64
- "deprecated; use #detach instead"
65
- assert_match Regexp.new(message), $stderr.string
66
- ensure
67
- $stderr = old_stderr
68
- end
69
- end
70
- end
71
-
72
54
  should "not be listable" do
73
55
  assert_raises NoMethodError do
74
56
  Stripe::Source.list
@@ -79,6 +61,19 @@ module Stripe
79
61
  should "verify the source" do
80
62
  source = Stripe::Source.retrieve("src_123")
81
63
  source = source.verify(values: [1, 2])
64
+ assert_requested :post,
65
+ "#{Stripe.api_base}/v1/sources/#{source.id}/verify",
66
+ body: { values: [1, 2] }
67
+ assert source.is_a?(Stripe::Source)
68
+ end
69
+ end
70
+
71
+ context ".verify" do
72
+ should "verify the source" do
73
+ source = Stripe::Source.verify("src_123", values: [1, 2])
74
+ assert_requested :post,
75
+ "#{Stripe.api_base}/v1/sources/src_123/verify",
76
+ body: { values: [1, 2] }
82
77
  assert source.is_a?(Stripe::Source)
83
78
  end
84
79
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class SourceTransactionTest < Test::Unit::TestCase
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require ::File.expand_path("../../test_helper", __FILE__)
3
+ require ::File.expand_path("../test_helper", __dir__)
4
4
 
5
5
  module Stripe
6
6
  class StripeClientTest < Test::Unit::TestCase
@@ -17,6 +17,50 @@ module Stripe
17
17
  end
18
18
  end
19
19
 
20
+ context ".clear_all_connection_managers" do
21
+ should "clear connection managers across all threads" do
22
+ stub_request(:post, "#{Stripe.api_base}/path")
23
+ .to_return(body: JSON.generate(object: "account"))
24
+
25
+ num_threads = 3
26
+
27
+ # Poorly named class -- note this is actually a concurrent queue.
28
+ recv_queue = Queue.new
29
+ send_queue = Queue.new
30
+
31
+ threads = num_threads.times.map do |_|
32
+ Thread.start do
33
+ # Causes a connection manager to be created on this thread and a
34
+ # connection within that manager to be created for API access.
35
+ manager = StripeClient.default_connection_manager
36
+ manager.execute_request(:post, "#{Stripe.api_base}/path")
37
+
38
+ # Signal to the main thread we're ready.
39
+ recv_queue << true
40
+
41
+ # Wait for the main thread to signal continue.
42
+ send_queue.pop
43
+
44
+ # This check isn't great, but it's otherwise difficult to tell that
45
+ # anything happened with just the public-facing API.
46
+ assert_equal({}, manager.instance_variable_get(:@active_connections))
47
+ end
48
+ end
49
+
50
+ # Wait for threads to start up.
51
+ threads.each { recv_queue.pop }
52
+
53
+ # Do the clear (the method we're actually trying to test).
54
+ StripeClient.clear_all_connection_managers
55
+
56
+ # Tell threads to run their check.
57
+ threads.each { send_queue << true }
58
+
59
+ # And finally, give all threads time to perform their check.
60
+ threads.each(&:join)
61
+ end
62
+ end
63
+
20
64
  context ".default_client" do
21
65
  should "be a StripeClient" do
22
66
  assert_kind_of StripeClient, StripeClient.default_client
@@ -32,18 +76,19 @@ module Stripe
32
76
  end
33
77
  end
34
78
 
35
- context ".default_conn" do
36
- should "be a Faraday::Connection" do
37
- assert_kind_of Faraday::Connection, StripeClient.default_conn
79
+ context ".default_connection_manager" do
80
+ should "be a ConnectionManager" do
81
+ assert_kind_of ConnectionManager,
82
+ StripeClient.default_connection_manager
38
83
  end
39
84
 
40
85
  should "be a different connection on each thread" do
41
- other_thread_conn = nil
86
+ other_thread_manager = nil
42
87
  thread = Thread.new do
43
- other_thread_conn = StripeClient.default_conn
88
+ other_thread_manager = StripeClient.default_connection_manager
44
89
  end
45
90
  thread.join
46
- refute_equal StripeClient.default_conn, other_thread_conn
91
+ refute_equal StripeClient.default_connection_manager, other_thread_manager
47
92
  end
48
93
  end
49
94
 
@@ -52,26 +97,66 @@ module Stripe
52
97
  Stripe.stubs(:max_network_retries).returns(2)
53
98
  end
54
99
 
55
- should "retry on timeout" do
56
- assert StripeClient.should_retry?(Faraday::TimeoutError.new(""), 0)
100
+ should "retry on Errno::ECONNREFUSED" do
101
+ assert StripeClient.should_retry?(Errno::ECONNREFUSED.new,
102
+ method: :post, num_retries: 0)
103
+ end
104
+
105
+ should "retry on Net::OpenTimeout" do
106
+ assert StripeClient.should_retry?(Net::OpenTimeout.new,
107
+ method: :post, num_retries: 0)
108
+ end
109
+
110
+ should "retry on Net::ReadTimeout" do
111
+ assert StripeClient.should_retry?(Net::ReadTimeout.new,
112
+ method: :post, num_retries: 0)
113
+ end
114
+
115
+ should "retry on SocketError" do
116
+ assert StripeClient.should_retry?(SocketError.new,
117
+ method: :post, num_retries: 0)
118
+ end
119
+
120
+ should "retry on a 409 Conflict" do
121
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 409),
122
+ method: :post, num_retries: 0)
123
+ end
124
+
125
+ should "retry on a 429 Too Many Requests when lock timeout" do
126
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 429,
127
+ code: "lock_timeout"),
128
+ method: :post, num_retries: 0)
57
129
  end
58
130
 
59
- should "retry on a failed connection" do
60
- assert StripeClient.should_retry?(Faraday::ConnectionFailed.new(""), 0)
131
+ should "retry on a 500 Internal Server Error when non-POST" do
132
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500),
133
+ method: :get, num_retries: 0)
61
134
  end
62
135
 
63
- should "retry on a conflict" do
64
- error = make_rate_limit_error
65
- e = Faraday::ClientError.new(error[:error][:message], status: 409)
66
- assert StripeClient.should_retry?(e, 0)
136
+ should "retry on a 503 Service Unavailable" do
137
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 503),
138
+ method: :post, num_retries: 0)
67
139
  end
68
140
 
69
141
  should "not retry at maximum count" do
70
- refute StripeClient.should_retry?(RuntimeError.new, Stripe.max_network_retries)
142
+ refute StripeClient.should_retry?(RuntimeError.new,
143
+ method: :post, num_retries: Stripe.max_network_retries)
71
144
  end
72
145
 
73
146
  should "not retry on a certificate validation error" do
74
- refute StripeClient.should_retry?(Faraday::SSLError.new(""), 0)
147
+ refute StripeClient.should_retry?(OpenSSL::SSL::SSLError.new,
148
+ method: :post, num_retries: 0)
149
+ end
150
+
151
+ should "not retry on a 429 Too Many Requests when not lock timeout" do
152
+ refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 429,
153
+ code: "rate_limited"),
154
+ method: :post, num_retries: 0)
155
+ end
156
+
157
+ should "not retry on a 500 Internal Server Error when POST" do
158
+ refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500),
159
+ method: :post, num_retries: 0)
75
160
  end
76
161
  end
77
162
 
@@ -115,15 +200,16 @@ module Stripe
115
200
  end
116
201
 
117
202
  context "#initialize" do
118
- should "set Stripe.default_conn" do
203
+ should "set Stripe.default_connection_manager" do
119
204
  client = StripeClient.new
120
- assert_equal StripeClient.default_conn, client.conn
205
+ assert_equal StripeClient.default_connection_manager,
206
+ client.connection_manager
121
207
  end
122
208
 
123
209
  should "set a different connection if one was specified" do
124
- conn = Faraday.new
125
- client = StripeClient.new(conn)
126
- assert_equal conn, client.conn
210
+ connection_manager = ConnectionManager.new
211
+ client = StripeClient.new(connection_manager)
212
+ assert_equal connection_manager, client.connection_manager
127
213
  end
128
214
  end
129
215
 
@@ -178,7 +264,7 @@ module Stripe
178
264
  Util.expects(:log_debug).with("Request details",
179
265
  body: "",
180
266
  idempotency_key: "abc",
181
- query_params: nil)
267
+ query: nil)
182
268
 
183
269
  Util.expects(:log_info).with("Response from Stripe API",
184
270
  account: "acct_123",
@@ -403,6 +489,20 @@ module Stripe
403
489
  assert_equal 'Invalid response object from API: "" (HTTP response code was 200)', e.message
404
490
  end
405
491
 
492
+ should "handle low level error" do
493
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
494
+ .to_raise(Errno::ECONNREFUSED.new)
495
+
496
+ client = StripeClient.new
497
+ e = assert_raises Stripe::APIConnectionError do
498
+ client.execute_request(:post, "/v1/charges")
499
+ end
500
+
501
+ assert_equal StripeClient::ERROR_MESSAGE_CONNECTION % Stripe.api_base +
502
+ "\n\n(Network error: Connection refused)",
503
+ e.message
504
+ end
505
+
406
506
  should "handle error response with unknown value" do
407
507
  stub_request(:post, "#{Stripe.api_base}/v1/charges")
408
508
  .to_return(body: JSON.generate(bar: "foo"), status: 500)
@@ -738,14 +838,130 @@ module Stripe
738
838
 
739
839
  should "reset local thread state after a call" do
740
840
  begin
741
- Thread.current[:stripe_client] = :stripe_client
841
+ StripeClient.current_thread_context.active_client = :stripe_client
842
+
843
+ client = StripeClient.new
844
+ client.request {}
845
+
846
+ assert_equal :stripe_client,
847
+ StripeClient.current_thread_context.active_client
848
+ ensure
849
+ StripeClient.current_thread_context.active_client = nil
850
+ end
851
+ end
852
+
853
+ should "correctly return last responses despite multiple clients" do
854
+ charge_resp = { object: "charge" }
855
+ coupon_resp = { object: "coupon" }
856
+
857
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
858
+ .to_return(body: JSON.generate(charge_resp))
859
+ stub_request(:post, "#{Stripe.api_base}/v1/coupons")
860
+ .to_return(body: JSON.generate(coupon_resp))
861
+
862
+ client1 = StripeClient.new
863
+ client2 = StripeClient.new
864
+
865
+ client2_resp = nil
866
+ _charge, client1_resp = client1.request do
867
+ Charge.create
868
+
869
+ # This is contrived, but we run one client nested in the `request`
870
+ # block of another one just to ensure that the parent is still
871
+ # unwinding when this goes through. If the parent's last response
872
+ # were to be overridden by this client (through a bug), then it would
873
+ # happen here.
874
+ _coupon, client2_resp = client2.request do
875
+ Coupon.create
876
+ end
877
+ end
878
+
879
+ assert_equal charge_resp, client1_resp.data
880
+ assert_equal coupon_resp, client2_resp.data
881
+ end
882
+
883
+ should "correctly return last responses despite multiple threads" do
884
+ charge_resp = { object: "charge" }
885
+ coupon_resp = { object: "coupon" }
886
+
887
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
888
+ .to_return(body: JSON.generate(charge_resp))
889
+ stub_request(:post, "#{Stripe.api_base}/v1/coupons")
890
+ .to_return(body: JSON.generate(coupon_resp))
891
+
892
+ client = StripeClient.new
893
+
894
+ # Poorly named class -- note this is actually a concurrent queue.
895
+ recv_queue = Queue.new
896
+ send_queue = Queue.new
897
+
898
+ # Start a thread, make an API request, but then idle in the `request`
899
+ # block until the main thread has been able to make its own API request
900
+ # and signal that it's done. If this thread's last response were to be
901
+ # overridden by the main thread (through a bug), then this routine
902
+ # should suss it out.
903
+ resp1 = nil
904
+ thread = Thread.start do
905
+ _charge, resp1 = client.request do
906
+ Charge.create
907
+
908
+ # Idle in `request` block until main thread signals.
909
+ send_queue.pop
910
+ end
911
+
912
+ # Signal main thread that we're done and it can run its checks.
913
+ recv_queue << true
914
+ end
915
+
916
+ # Make an API request.
917
+ _coupon, resp2 = client.request do
918
+ Coupon.create
919
+ end
920
+
921
+ # Tell background thread to finish `request`, then wait for it to
922
+ # signal back to us that it's ready.
923
+ send_queue << true
924
+ recv_queue.pop
925
+
926
+ assert_equal charge_resp, resp1.data
927
+ assert_equal coupon_resp, resp2.data
928
+
929
+ # And for maximum hygiene, make sure that our thread rejoins.
930
+ thread.join
931
+ end
932
+
933
+ should "error if calls to #request are nested on the same thread" do
934
+ client = StripeClient.new
935
+ client.request do
936
+ e = assert_raises(RuntimeError) do
937
+ client.request {}
938
+ end
939
+ assert_equal "calls to StripeClient#request cannot be nested within a thread",
940
+ e.message
941
+ end
942
+ end
943
+ end
944
+
945
+ context "#proxy" do
946
+ should "run the request through the proxy" do
947
+ begin
948
+ StripeClient.current_thread_context.default_connection_manager = nil
949
+
950
+ Stripe.proxy = "http://user:pass@localhost:8080"
742
951
 
743
952
  client = StripeClient.new
744
953
  client.request {}
745
954
 
746
- assert_equal :stripe_client, Thread.current[:stripe_client]
955
+ connection = Stripe::StripeClient.default_connection_manager.connection_for(Stripe.api_base)
956
+
957
+ assert_equal "localhost", connection.proxy_address
958
+ assert_equal 8080, connection.proxy_port
959
+ assert_equal "user", connection.proxy_user
960
+ assert_equal "pass", connection.proxy_pass
747
961
  ensure
748
- Thread.current[:stripe_client] = nil
962
+ Stripe.proxy = nil
963
+
964
+ StripeClient.current_thread_context.default_connection_manager = nil
749
965
  end
750
966
  end
751
967
  end