stripe 3.2.0 → 5.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (230) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +10 -0
  3. data/.gitignore +3 -0
  4. data/.rubocop.yml +80 -0
  5. data/.rubocop_todo.yml +33 -0
  6. data/.travis.yml +9 -7
  7. data/.vscode/extensions.json +7 -0
  8. data/.vscode/settings.json +8 -0
  9. data/CHANGELOG.md +876 -0
  10. data/CODE_OF_CONDUCT.md +77 -0
  11. data/Gemfile +21 -21
  12. data/History.txt +1 -678
  13. data/README.md +195 -53
  14. data/Rakefile +18 -12
  15. data/VERSION +1 -1
  16. data/bin/stripe-console +5 -3
  17. data/lib/stripe/api_operations/create.rb +3 -1
  18. data/lib/stripe/api_operations/delete.rb +26 -2
  19. data/lib/stripe/api_operations/list.rb +3 -12
  20. data/lib/stripe/api_operations/nested_resource.rb +72 -0
  21. data/lib/stripe/api_operations/request.rb +33 -15
  22. data/lib/stripe/api_operations/save.rb +18 -9
  23. data/lib/stripe/api_resource.rb +60 -10
  24. data/lib/stripe/connection_manager.rb +159 -0
  25. data/lib/stripe/error_object.rb +94 -0
  26. data/lib/stripe/errors.rb +39 -19
  27. data/lib/stripe/instrumentation.rb +82 -0
  28. data/lib/stripe/list_object.rb +54 -22
  29. data/lib/stripe/multipart_encoder.rb +131 -0
  30. data/lib/stripe/oauth.rb +22 -14
  31. data/lib/stripe/object_types.rb +96 -0
  32. data/lib/stripe/{account.rb → resources/account.rb} +72 -34
  33. data/lib/stripe/resources/account_link.rb +9 -0
  34. data/lib/stripe/resources/alipay_account.rb +34 -0
  35. data/lib/stripe/{apple_pay_domain.rb → resources/apple_pay_domain.rb} +4 -2
  36. data/lib/stripe/resources/application_fee.rb +13 -0
  37. data/lib/stripe/resources/application_fee_refund.rb +30 -0
  38. data/lib/stripe/{balance.rb → resources/balance.rb} +3 -1
  39. data/lib/stripe/{balance_transaction.rb → resources/balance_transaction.rb} +3 -5
  40. data/lib/stripe/resources/bank_account.rb +42 -0
  41. data/lib/stripe/{bitcoin_receiver.rb → resources/bitcoin_receiver.rb} +6 -5
  42. data/lib/stripe/resources/bitcoin_transaction.rb +15 -0
  43. data/lib/stripe/resources/capability.rb +33 -0
  44. data/lib/stripe/resources/card.rb +37 -0
  45. data/lib/stripe/resources/charge.rb +22 -0
  46. data/lib/stripe/resources/checkout/session.rb +12 -0
  47. data/lib/stripe/{country_spec.rb → resources/country_spec.rb} +3 -5
  48. data/lib/stripe/{coupon.rb → resources/coupon.rb} +4 -2
  49. data/lib/stripe/resources/credit_note.rb +32 -0
  50. data/lib/stripe/resources/credit_note_line_item.rb +7 -0
  51. data/lib/stripe/resources/customer.rb +35 -0
  52. data/lib/stripe/resources/customer_balance_transaction.rb +30 -0
  53. data/lib/stripe/resources/discount.rb +7 -0
  54. data/lib/stripe/resources/dispute.rb +21 -0
  55. data/lib/stripe/resources/ephemeral_key.rb +19 -0
  56. data/lib/stripe/{event.rb → resources/event.rb} +3 -1
  57. data/lib/stripe/resources/exchange_rate.rb +9 -0
  58. data/lib/stripe/resources/file.rb +34 -0
  59. data/lib/stripe/resources/file_link.rb +11 -0
  60. data/lib/stripe/resources/invoice.rb +73 -0
  61. data/lib/stripe/{invoice_item.rb → resources/invoice_item.rb} +4 -2
  62. data/lib/stripe/{invoice_line_item.rb → resources/invoice_line_item.rb} +3 -1
  63. data/lib/stripe/resources/issuing/authorization.rb +33 -0
  64. data/lib/stripe/resources/issuing/card.rb +24 -0
  65. data/lib/stripe/resources/issuing/card_details.rb +9 -0
  66. data/lib/stripe/resources/issuing/cardholder.rb +13 -0
  67. data/lib/stripe/resources/issuing/dispute.rb +13 -0
  68. data/lib/stripe/resources/issuing/transaction.rb +12 -0
  69. data/lib/stripe/resources/login_link.rb +14 -0
  70. data/lib/stripe/resources/mandate.rb +7 -0
  71. data/lib/stripe/resources/order.rb +32 -0
  72. data/lib/stripe/{order_return.rb → resources/order_return.rb} +3 -5
  73. data/lib/stripe/resources/payment_intent.rb +42 -0
  74. data/lib/stripe/resources/payment_method.rb +32 -0
  75. data/lib/stripe/resources/payout.rb +22 -0
  76. data/lib/stripe/resources/person.rb +31 -0
  77. data/lib/stripe/{plan.rb → resources/plan.rb} +3 -1
  78. data/lib/stripe/{product.rb → resources/product.rb} +5 -3
  79. data/lib/stripe/resources/radar/early_fraud_warning.rb +11 -0
  80. data/lib/stripe/resources/radar/value_list.rb +14 -0
  81. data/lib/stripe/resources/radar/value_list_item.rb +13 -0
  82. data/lib/stripe/{recipient.rb → resources/recipient.rb} +5 -6
  83. data/lib/stripe/resources/recipient_transfer.rb +7 -0
  84. data/lib/stripe/{refund.rb → resources/refund.rb} +3 -1
  85. data/lib/stripe/resources/reporting/report_run.rb +12 -0
  86. data/lib/stripe/resources/reporting/report_type.rb +12 -0
  87. data/lib/stripe/resources/reversal.rb +29 -0
  88. data/lib/stripe/resources/review.rb +20 -0
  89. data/lib/stripe/resources/setup_intent.rb +32 -0
  90. data/lib/stripe/resources/sigma/scheduled_query_run.rb +15 -0
  91. data/lib/stripe/{sku.rb → resources/sku.rb} +5 -3
  92. data/lib/stripe/resources/source.rb +46 -0
  93. data/lib/stripe/resources/source_transaction.rb +7 -0
  94. data/lib/stripe/resources/subscription.rb +25 -0
  95. data/lib/stripe/resources/subscription_item.rb +25 -0
  96. data/lib/stripe/resources/subscription_schedule.rb +32 -0
  97. data/lib/stripe/resources/tax_id.rb +26 -0
  98. data/lib/stripe/resources/tax_rate.rb +11 -0
  99. data/lib/stripe/resources/terminal/connection_token.rb +11 -0
  100. data/lib/stripe/resources/terminal/location.rb +14 -0
  101. data/lib/stripe/resources/terminal/reader.rb +14 -0
  102. data/lib/stripe/{three_d_secure.rb → resources/three_d_secure.rb} +3 -1
  103. data/lib/stripe/{token.rb → resources/token.rb} +3 -1
  104. data/lib/stripe/resources/topup.rb +22 -0
  105. data/lib/stripe/resources/transfer.rb +26 -0
  106. data/lib/stripe/resources/usage_record.rb +7 -0
  107. data/lib/stripe/resources/usage_record_summary.rb +7 -0
  108. data/lib/stripe/resources/webhook_endpoint.rb +12 -0
  109. data/lib/stripe/resources.rb +79 -0
  110. data/lib/stripe/singleton_api_resource.rb +10 -4
  111. data/lib/stripe/stripe_client.rb +658 -337
  112. data/lib/stripe/stripe_object.rb +248 -126
  113. data/lib/stripe/stripe_response.rb +55 -21
  114. data/lib/stripe/util.rb +145 -187
  115. data/lib/stripe/version.rb +3 -1
  116. data/lib/stripe/webhook.rb +27 -16
  117. data/lib/stripe.rb +139 -90
  118. data/stripe.gemspec +26 -14
  119. data/test/openapi/README.md +9 -0
  120. data/test/stripe/account_link_test.rb +18 -0
  121. data/test/stripe/account_test.rb +311 -101
  122. data/test/stripe/alipay_account_test.rb +21 -1
  123. data/test/stripe/api_operations_test.rb +57 -8
  124. data/test/stripe/api_resource_test.rb +359 -271
  125. data/test/stripe/apple_pay_domain_test.rb +26 -11
  126. data/test/stripe/application_fee_refund_test.rb +10 -8
  127. data/test/stripe/application_fee_test.rb +49 -3
  128. data/test/stripe/balance_test.rb +4 -2
  129. data/test/stripe/balance_transaction_test.rb +20 -0
  130. data/test/stripe/bank_account_test.rb +11 -11
  131. data/test/stripe/capability_test.rb +45 -0
  132. data/test/stripe/charge_test.rb +25 -18
  133. data/test/stripe/checkout/session_test.rb +41 -0
  134. data/test/stripe/connection_manager_test.rb +163 -0
  135. data/test/stripe/country_spec_test.rb +6 -4
  136. data/test/stripe/coupon_test.rb +29 -10
  137. data/test/stripe/credit_note_test.rb +90 -0
  138. data/test/stripe/customer_balance_transaction_test.rb +37 -0
  139. data/test/stripe/customer_card_test.rb +13 -17
  140. data/test/stripe/customer_test.rb +161 -49
  141. data/test/stripe/dispute_test.rb +19 -8
  142. data/test/stripe/ephemeral_key_test.rb +23 -14
  143. data/test/stripe/errors_test.rb +32 -9
  144. data/test/stripe/exchange_rate_test.rb +20 -0
  145. data/test/stripe/file_link_test.rb +41 -0
  146. data/test/stripe/file_test.rb +87 -0
  147. data/test/stripe/instrumentation_test.rb +74 -0
  148. data/test/stripe/invoice_item_test.rb +31 -18
  149. data/test/stripe/invoice_line_item_test.rb +3 -1
  150. data/test/stripe/invoice_test.rb +158 -39
  151. data/test/stripe/issuing/authorization_test.rb +72 -0
  152. data/test/stripe/issuing/card_test.rb +62 -0
  153. data/test/stripe/issuing/cardholder_test.rb +53 -0
  154. data/test/stripe/issuing/dispute_test.rb +45 -0
  155. data/test/stripe/issuing/transaction_test.rb +48 -0
  156. data/test/stripe/list_object_test.rb +120 -88
  157. data/test/stripe/login_link_test.rb +16 -14
  158. data/test/stripe/mandate_test.rb +14 -0
  159. data/test/stripe/multipart_encoder_test.rb +130 -0
  160. data/test/stripe/oauth_test.rb +69 -50
  161. data/test/stripe/order_return_test.rb +7 -5
  162. data/test/stripe/order_test.rb +39 -14
  163. data/test/stripe/payment_intent_test.rb +107 -0
  164. data/test/stripe/payment_method_test.rb +84 -0
  165. data/test/stripe/payout_test.rb +18 -9
  166. data/test/stripe/person_test.rb +46 -0
  167. data/test/stripe/plan_test.rb +67 -19
  168. data/test/stripe/product_test.rb +28 -14
  169. data/test/stripe/radar/early_fraud_warning_test.rb +22 -0
  170. data/test/stripe/radar/value_list_item_test.rb +48 -0
  171. data/test/stripe/radar/value_list_test.rb +61 -0
  172. data/test/stripe/recipient_test.rb +27 -13
  173. data/test/stripe/refund_test.rb +11 -9
  174. data/test/stripe/reporting/report_run_test.rb +33 -0
  175. data/test/stripe/reporting/report_type_test.rb +22 -0
  176. data/test/stripe/reversal_test.rb +12 -10
  177. data/test/stripe/review_test.rb +27 -0
  178. data/test/stripe/setup_intent_test.rb +84 -0
  179. data/test/stripe/sigma/scheduled_query_run_test.rb +22 -0
  180. data/test/stripe/sku_test.rb +24 -12
  181. data/test/stripe/source_test.rb +70 -19
  182. data/test/stripe/stripe_client_test.rb +867 -326
  183. data/test/stripe/stripe_object_test.rb +284 -182
  184. data/test/stripe/stripe_response_test.rb +73 -24
  185. data/test/stripe/subscription_item_test.rb +47 -15
  186. data/test/stripe/subscription_schedule_test.rb +82 -0
  187. data/test/stripe/subscription_test.rb +41 -19
  188. data/test/stripe/tax_id_test.rb +31 -0
  189. data/test/stripe/tax_rate_test.rb +43 -0
  190. data/test/stripe/terminal/connection_token_test.rb +16 -0
  191. data/test/stripe/terminal/location_test.rb +68 -0
  192. data/test/stripe/terminal/reader_test.rb +62 -0
  193. data/test/stripe/three_d_secure_test.rb +4 -2
  194. data/test/stripe/topup_test.rb +62 -0
  195. data/test/stripe/transfer_test.rb +55 -8
  196. data/test/stripe/usage_record_summary_test.rb +29 -0
  197. data/test/stripe/util_test.rb +173 -84
  198. data/test/stripe/webhook_endpoint_test.rb +59 -0
  199. data/test/stripe/webhook_test.rb +21 -17
  200. data/test/stripe_mock.rb +78 -0
  201. data/test/stripe_test.rb +6 -15
  202. data/test/test_data.rb +28 -26
  203. data/test/test_helper.rb +48 -29
  204. metadata +183 -70
  205. data/lib/stripe/alipay_account.rb +0 -22
  206. data/lib/stripe/application_fee.rb +0 -22
  207. data/lib/stripe/application_fee_refund.rb +0 -20
  208. data/lib/stripe/bank_account.rb +0 -30
  209. data/lib/stripe/bitcoin_transaction.rb +0 -11
  210. data/lib/stripe/card.rb +0 -27
  211. data/lib/stripe/charge.rb +0 -82
  212. data/lib/stripe/customer.rb +0 -79
  213. data/lib/stripe/dispute.rb +0 -17
  214. data/lib/stripe/ephemeral_key.rb +0 -18
  215. data/lib/stripe/file_upload.rb +0 -33
  216. data/lib/stripe/invoice.rb +0 -29
  217. data/lib/stripe/login_link.rb +0 -9
  218. data/lib/stripe/order.rb +0 -29
  219. data/lib/stripe/payout.rb +0 -18
  220. data/lib/stripe/recipient_transfer.rb +0 -6
  221. data/lib/stripe/reversal.rb +0 -20
  222. data/lib/stripe/source.rb +0 -23
  223. data/lib/stripe/subscription.rb +0 -33
  224. data/lib/stripe/subscription_item.rb +0 -14
  225. data/lib/stripe/transfer.rb +0 -18
  226. data/test/api_stub_helpers.rb +0 -0
  227. data/test/stripe/bitcoin_receiver_test.rb +0 -67
  228. data/test/stripe/bitcoin_transaction_test.rb +0 -19
  229. data/test/stripe/file_upload_test.rb +0 -66
  230. data/test/stripe/recipient_card_test.rb +0 -44
@@ -1,4 +1,6 @@
1
- require File.expand_path('../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
2
4
 
3
5
  module Stripe
4
6
  class StripeClientTest < Test::Unit::TestCase
@@ -15,24 +17,148 @@ module Stripe
15
17
  end
16
18
  end
17
19
 
20
+ context ".maybe_gc_connection_managers" do
21
+ should "garbage collect old connection managers when appropriate" do
22
+ stub_request(:post, "#{Stripe.api_base}/v1/path")
23
+ .to_return(body: JSON.generate(object: "account"))
24
+
25
+ # Make sure we start with a blank slate (state may have been left in
26
+ # place by other tests).
27
+ StripeClient.clear_all_connection_managers
28
+
29
+ # Establish a base time.
30
+ t = 0.0
31
+
32
+ # And pretend that `StripeClient` was just initialized for the first
33
+ # time. (Don't access instance variables like this, but it's tricky to
34
+ # test properly otherwise.)
35
+ StripeClient.instance_variable_set(:@last_connection_manager_gc, t)
36
+
37
+ #
38
+ # t
39
+ #
40
+ Util.stubs(:monotonic_time).returns(t)
41
+
42
+ # Execute an initial request to ensure that a connection manager was
43
+ # created.
44
+ client = StripeClient.new
45
+ client.execute_request(:post, "/v1/path")
46
+
47
+ # The GC shouldn't run yet (a `nil` return indicates that GC didn't run).
48
+ assert_equal nil, StripeClient.maybe_gc_connection_managers
49
+
50
+ #
51
+ # t + StripeClient::CONNECTION_MANAGER_GC_PERIOD - 1
52
+ #
53
+ # Move time to just *before* garbage collection is eligible to run.
54
+ # Nothing should happen.
55
+ #
56
+ Util.stubs(:monotonic_time).returns(t + StripeClient::CONNECTION_MANAGER_GC_PERIOD - 1)
57
+
58
+ assert_equal nil, StripeClient.maybe_gc_connection_managers
59
+
60
+ #
61
+ # t + StripeClient::CONNECTION_MANAGER_GC_PERIOD + 1
62
+ #
63
+ # Move time to just *after* garbage collection is eligible to run.
64
+ # Garbage collection will run, but because the connection manager is
65
+ # not passed its expiry age, it will not be collected. Zero is returned
66
+ # to indicate so.
67
+ #
68
+ Util.stubs(:monotonic_time).returns(t + StripeClient::CONNECTION_MANAGER_GC_PERIOD + 1)
69
+
70
+ assert_equal 0, StripeClient.maybe_gc_connection_managers
71
+
72
+ #
73
+ # t + StripeClient::CONNECTION_MANAGER_GC_LAST_USED_EXPIRY + 1
74
+ #
75
+ # Move us far enough into the future that we're passed the horizons for
76
+ # both a GC run as well as well as the expiry age of a connection
77
+ # manager. That means the GC will run and collect the connection
78
+ # manager that we created above.
79
+ #
80
+ Util.stubs(:monotonic_time).returns(t + StripeClient::CONNECTION_MANAGER_GC_LAST_USED_EXPIRY + 1)
81
+
82
+ assert_equal 1, StripeClient.maybe_gc_connection_managers
83
+
84
+ # And as an additional check, the connection manager of the current
85
+ # thread context should have been set to `nil` as it was GCed.
86
+ assert_nil StripeClient.current_thread_context.default_connection_manager
87
+ end
88
+ end
89
+
90
+ context ".clear_all_connection_managers" do
91
+ should "clear connection managers across all threads" do
92
+ stub_request(:post, "#{Stripe.api_base}/path")
93
+ .to_return(body: JSON.generate(object: "account"))
94
+
95
+ num_threads = 3
96
+
97
+ # Poorly named class -- note this is actually a concurrent queue.
98
+ recv_queue = Queue.new
99
+ send_queue = Queue.new
100
+
101
+ threads = num_threads.times.map do |_|
102
+ Thread.start do
103
+ # Causes a connection manager to be created on this thread and a
104
+ # connection within that manager to be created for API access.
105
+ manager = StripeClient.default_connection_manager
106
+ manager.execute_request(:post, "#{Stripe.api_base}/path")
107
+
108
+ # Signal to the main thread we're ready.
109
+ recv_queue << true
110
+
111
+ # Wait for the main thread to signal continue.
112
+ send_queue.pop
113
+
114
+ # This check isn't great, but it's otherwise difficult to tell that
115
+ # anything happened with just the public-facing API.
116
+ assert_equal({}, manager.instance_variable_get(:@active_connections))
117
+ end
118
+ end
119
+
120
+ # Wait for threads to start up.
121
+ threads.each { recv_queue.pop }
122
+
123
+ # Do the clear (the method we're actually trying to test).
124
+ StripeClient.clear_all_connection_managers
125
+
126
+ # Tell threads to run their check.
127
+ threads.each { send_queue << true }
128
+
129
+ # And finally, give all threads time to perform their check.
130
+ threads.each(&:join)
131
+ end
132
+ end
133
+
18
134
  context ".default_client" do
19
135
  should "be a StripeClient" do
20
136
  assert_kind_of StripeClient, StripeClient.default_client
21
137
  end
138
+
139
+ should "be a different client on each thread" do
140
+ other_thread_client = nil
141
+ thread = Thread.new do
142
+ other_thread_client = StripeClient.default_client
143
+ end
144
+ thread.join
145
+ refute_equal StripeClient.default_client, other_thread_client
146
+ end
22
147
  end
23
148
 
24
- context ".default_conn" do
25
- should "be a Faraday::Connection" do
26
- assert_kind_of Faraday::Connection, StripeClient.default_conn
149
+ context ".default_connection_manager" do
150
+ should "be a ConnectionManager" do
151
+ assert_kind_of ConnectionManager,
152
+ StripeClient.default_connection_manager
27
153
  end
28
154
 
29
155
  should "be a different connection on each thread" do
30
- other_thread_conn = nil
156
+ other_thread_manager = nil
31
157
  thread = Thread.new do
32
- other_thread_conn = StripeClient.default_conn
158
+ other_thread_manager = StripeClient.default_connection_manager
33
159
  end
34
160
  thread.join
35
- refute_equal StripeClient.default_conn, other_thread_conn
161
+ refute_equal StripeClient.default_connection_manager, other_thread_manager
36
162
  end
37
163
  end
38
164
 
@@ -41,26 +167,108 @@ module Stripe
41
167
  Stripe.stubs(:max_network_retries).returns(2)
42
168
  end
43
169
 
44
- should 'retry on timeout' do
45
- assert StripeClient.should_retry?(Faraday::TimeoutError.new(""), 0)
170
+ should "retry on Errno::ECONNREFUSED" do
171
+ assert StripeClient.should_retry?(Errno::ECONNREFUSED.new,
172
+ method: :post, num_retries: 0)
173
+ end
174
+
175
+ should "retry on EOFError" do
176
+ assert StripeClient.should_retry?(EOFError.new,
177
+ method: :post, num_retries: 0)
178
+ end
179
+
180
+ should "retry on Errno::ECONNRESET" do
181
+ assert StripeClient.should_retry?(Errno::ECONNRESET.new,
182
+ method: :post, num_retries: 0)
183
+ end
184
+
185
+ should "retry on Errno::ETIMEDOUT" do
186
+ assert StripeClient.should_retry?(Errno::ETIMEDOUT.new,
187
+ method: :post, num_retries: 0)
188
+ end
189
+
190
+ should "retry on Errno::EHOSTUNREACH" do
191
+ assert StripeClient.should_retry?(Errno::EHOSTUNREACH.new,
192
+ method: :post, num_retries: 0)
193
+ end
194
+
195
+ should "retry on Net::OpenTimeout" do
196
+ assert StripeClient.should_retry?(Net::OpenTimeout.new,
197
+ method: :post, num_retries: 0)
198
+ end
199
+
200
+ should "retry on Net::ReadTimeout" do
201
+ assert StripeClient.should_retry?(Net::ReadTimeout.new,
202
+ method: :post, num_retries: 0)
203
+ end
204
+
205
+ should "retry on SocketError" do
206
+ assert StripeClient.should_retry?(SocketError.new,
207
+ method: :post, num_retries: 0)
46
208
  end
47
209
 
48
- should 'retry on a failed connection' do
49
- assert StripeClient.should_retry?(Faraday::ConnectionFailed.new(""), 0)
210
+ should "retry when the `Stripe-Should-Retry` header is `true`" do
211
+ headers = StripeResponse::Headers.new(
212
+ "Stripe-Should-Retry" => ["true"]
213
+ )
214
+
215
+ # Note we send status 400 here, which would normally not be retried.
216
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_headers: headers,
217
+ http_status: 400),
218
+ method: :post, num_retries: 0)
50
219
  end
51
220
 
52
- should 'retry on a conflict' do
53
- error = make_rate_limit_error
54
- e = Faraday::ClientError.new(error[:error][:message], { status: 409 })
55
- assert StripeClient.should_retry?(e, 0)
221
+ should "not retry when the `Stripe-Should-Retry` header is `false`" do
222
+ headers = StripeResponse::Headers.new(
223
+ "Stripe-Should-Retry" => ["false"]
224
+ )
225
+
226
+ # Note we send status 409 here, which would normally be retried.
227
+ refute StripeClient.should_retry?(Stripe::StripeError.new(http_headers: headers,
228
+ http_status: 409),
229
+ method: :post, num_retries: 0)
56
230
  end
57
231
 
58
- should 'not retry at maximum count' do
59
- refute StripeClient.should_retry?(RuntimeError.new, Stripe.max_network_retries)
232
+ should "retry on a 409 Conflict" do
233
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 409),
234
+ method: :post, num_retries: 0)
60
235
  end
61
236
 
62
- should 'not retry on a certificate validation error' do
63
- refute StripeClient.should_retry?(Faraday::SSLError.new(""), 0)
237
+ should "retry on a 429 Too Many Requests when lock timeout" do
238
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 429,
239
+ code: "lock_timeout"),
240
+ method: :post, num_retries: 0)
241
+ end
242
+
243
+ should "retry on a 500 Internal Server Error when non-POST" do
244
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500),
245
+ method: :get, num_retries: 0)
246
+ end
247
+
248
+ should "retry on a 503 Service Unavailable" do
249
+ assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 503),
250
+ method: :post, num_retries: 0)
251
+ end
252
+
253
+ should "not retry at maximum count" do
254
+ refute StripeClient.should_retry?(RuntimeError.new,
255
+ method: :post, num_retries: Stripe.max_network_retries)
256
+ end
257
+
258
+ should "not retry on a certificate validation error" do
259
+ refute StripeClient.should_retry?(OpenSSL::SSL::SSLError.new,
260
+ method: :post, num_retries: 0)
261
+ end
262
+
263
+ should "not retry on a 429 Too Many Requests when not lock timeout" do
264
+ refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 429,
265
+ code: "rate_limited"),
266
+ method: :post, num_retries: 0)
267
+ end
268
+
269
+ should "not retry on a 500 Internal Server Error when POST" do
270
+ refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500),
271
+ method: :post, num_retries: 0)
64
272
  end
65
273
  end
66
274
 
@@ -103,203 +311,170 @@ module Stripe
103
311
  end
104
312
  end
105
313
 
106
- context "#initialize" do
107
- should "set Stripe.default_conn" do
108
- client = StripeClient.new
109
- assert_equal StripeClient.default_conn, client.conn
110
- end
111
-
112
- should "set a different connection if one was specified" do
113
- conn = Faraday.new
114
- client = StripeClient.new(conn)
115
- assert_equal conn, client.conn
116
- end
117
- end
118
-
119
314
  context "#execute_request" do
120
315
  context "headers" do
121
316
  should "support literal headers" do
122
- stub_request(:post, "#{Stripe.api_base}/v1/account").
123
- with(headers: { "Stripe-Account" => "bar" }).
124
- to_return(body: JSON.generate({ object: "account" }))
317
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
318
+ .with(headers: { "Stripe-Account" => "bar" })
319
+ .to_return(body: JSON.generate(object: "account"))
125
320
 
126
321
  client = StripeClient.new
127
- client.execute_request(:post, '/v1/account',
128
- headers: { "Stripe-Account" => "bar" }
129
- )
322
+ client.execute_request(:post, "/v1/account",
323
+ headers: { "Stripe-Account" => "bar" })
130
324
  end
131
325
 
132
326
  should "support RestClient-style header keys" do
133
- stub_request(:post, "#{Stripe.api_base}/v1/account").
134
- with(headers: { "Stripe-Account" => "bar" }).
135
- to_return(body: JSON.generate({ object: "account" }))
327
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
328
+ .with(headers: { "Stripe-Account" => "bar" })
329
+ .to_return(body: JSON.generate(object: "account"))
136
330
 
137
331
  client = StripeClient.new
138
- client.execute_request(:post, '/v1/account',
139
- headers: { :stripe_account => "bar" }
140
- )
332
+ client.execute_request(:post, "/v1/account",
333
+ headers: { stripe_account: "bar" })
141
334
  end
142
335
  end
143
336
 
144
337
  context "logging" do
145
338
  setup do
146
339
  # Freeze time for the purposes of the `elapsed` parameter that we
147
- # emit for responses. I didn't want to bring in a new dependency for
148
- # this, but Mocha's `anything` parameter can't match inside of a hash
149
- # and is therefore not useful for this purpose. If we switch over to
150
- # rspec-mocks at some point, we can probably remove Timecop from the
151
- # project.
152
- Timecop.freeze(Time.local(1990))
153
- end
154
-
155
- teardown do
156
- Timecop.return
340
+ # emit for responses. Mocha's `anything` parameter can't match inside
341
+ # of a hash and is therefore not useful for this purpose. If we
342
+ # switch over to rspec-mocks at some point, we can probably remove
343
+ # this.
344
+ Util.stubs(:monotonic_time).returns(0.0)
157
345
  end
158
346
 
159
347
  should "produce appropriate logging" do
160
- body = JSON.generate({ object: "account" })
348
+ body = JSON.generate(object: "account")
161
349
 
162
350
  Util.expects(:log_info).with("Request to Stripe API",
163
- account: "acct_123",
164
- api_version: '2010-11-12',
165
- idempotency_key: "abc",
166
- method: :post,
167
- num_retries: 0,
168
- path: "/v1/account"
169
- )
351
+ account: "acct_123",
352
+ api_version: "2010-11-12",
353
+ idempotency_key: "abc",
354
+ method: :post,
355
+ num_retries: 0,
356
+ path: "/v1/account")
170
357
  Util.expects(:log_debug).with("Request details",
171
- body: '',
172
- idempotency_key: "abc"
173
- )
358
+ body: "",
359
+ idempotency_key: "abc",
360
+ query: nil)
174
361
 
175
362
  Util.expects(:log_info).with("Response from Stripe API",
176
- account: "acct_123",
177
- api_version: '2010-11-12',
178
- elapsed: 0.0,
179
- idempotency_key: "abc",
180
- method: :post,
181
- path: "/v1/account",
182
- request_id: "req_123",
183
- status: 200
184
- )
363
+ account: "acct_123",
364
+ api_version: "2010-11-12",
365
+ elapsed: 0.0,
366
+ idempotency_key: "abc",
367
+ method: :post,
368
+ path: "/v1/account",
369
+ request_id: "req_123",
370
+ status: 200)
185
371
  Util.expects(:log_debug).with("Response details",
186
- body: body,
187
- idempotency_key: "abc",
188
- request_id: "req_123"
189
- )
372
+ body: body,
373
+ idempotency_key: "abc",
374
+ request_id: "req_123")
190
375
  Util.expects(:log_debug).with("Dashboard link for request",
191
- idempotency_key: "abc",
192
- request_id: "req_123",
193
- url: Util.request_id_dashboard_url("req_123", Stripe.api_key)
194
- )
376
+ idempotency_key: "abc",
377
+ request_id: "req_123",
378
+ url: Util.request_id_dashboard_url("req_123", Stripe.api_key))
195
379
 
196
- stub_request(:post, "#{Stripe.api_base}/v1/account").
197
- to_return(
380
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
381
+ .to_return(
198
382
  body: body,
199
383
  headers: {
200
384
  "Idempotency-Key" => "abc",
201
385
  "Request-Id" => "req_123",
202
386
  "Stripe-Account" => "acct_123",
203
- "Stripe-Version" => "2010-11-12"
387
+ "Stripe-Version" => "2010-11-12",
204
388
  }
205
389
  )
206
390
 
207
391
  client = StripeClient.new
208
- client.execute_request(:post, '/v1/account',
209
- headers: {
210
- "Idempotency-Key" => "abc",
211
- "Stripe-Account" => "acct_123",
212
- "Stripe-Version" => "2010-11-12"
213
- }
214
- )
392
+ client.execute_request(:post, "/v1/account",
393
+ headers: {
394
+ "Idempotency-Key" => "abc",
395
+ "Stripe-Account" => "acct_123",
396
+ "Stripe-Version" => "2010-11-12",
397
+ })
215
398
  end
216
399
 
217
400
  should "produce logging on API error" do
218
401
  Util.expects(:log_info).with("Request to Stripe API",
219
- account: nil,
220
- api_version: nil,
221
- idempotency_key: nil,
222
- method: :post,
223
- num_retries: 0,
224
- path: "/v1/account"
225
- )
402
+ account: nil,
403
+ api_version: nil,
404
+ idempotency_key: nil,
405
+ method: :post,
406
+ num_retries: 0,
407
+ path: "/v1/account")
226
408
  Util.expects(:log_info).with("Response from Stripe API",
227
- account: nil,
228
- api_version: nil,
229
- elapsed: 0.0,
230
- idempotency_key: nil,
231
- method: :post,
232
- path: "/v1/account",
233
- request_id: nil,
234
- status: 500
235
- )
409
+ account: nil,
410
+ api_version: nil,
411
+ elapsed: 0.0,
412
+ idempotency_key: nil,
413
+ method: :post,
414
+ path: "/v1/account",
415
+ request_id: nil,
416
+ status: 500)
236
417
 
237
418
  error = {
238
- code: 'code',
239
- message: 'message',
240
- param: 'param',
241
- type: 'type',
419
+ code: "code",
420
+ message: "message",
421
+ param: "param",
422
+ type: "type",
242
423
  }
243
- Util.expects(:log_info).with('Stripe API error',
244
- status: 500,
245
- error_code: error['code'],
246
- error_message: error['message'],
247
- error_param: error['param'],
248
- error_type: error['type'],
249
- idempotency_key: nil,
250
- request_id: nil
251
- )
252
-
253
- stub_request(:post, "#{Stripe.api_base}/v1/account").
254
- to_return(
255
- body: JSON.generate({ :error => error }),
424
+ Util.expects(:log_error).with("Stripe API error",
425
+ status: 500,
426
+ error_code: error[:code],
427
+ error_message: error[:message],
428
+ error_param: error[:param],
429
+ error_type: error[:type],
430
+ idempotency_key: nil,
431
+ request_id: nil)
432
+
433
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
434
+ .to_return(
435
+ body: JSON.generate(error: error),
256
436
  status: 500
257
437
  )
258
438
 
259
439
  client = StripeClient.new
260
440
  assert_raises Stripe::APIError do
261
- client.execute_request(:post, '/v1/account')
441
+ client.execute_request(:post, "/v1/account")
262
442
  end
263
443
  end
264
444
 
265
445
  should "produce logging on OAuth error" do
266
446
  Util.expects(:log_info).with("Request to Stripe API",
267
- account: nil,
268
- api_version: nil,
269
- idempotency_key: nil,
270
- method: :post,
271
- num_retries: 0,
272
- path: "/oauth/token"
273
- )
447
+ account: nil,
448
+ api_version: nil,
449
+ idempotency_key: nil,
450
+ method: :post,
451
+ num_retries: 0,
452
+ path: "/oauth/token")
274
453
  Util.expects(:log_info).with("Response from Stripe API",
275
- account: nil,
276
- api_version: nil,
277
- elapsed: 0.0,
278
- idempotency_key: nil,
279
- method: :post,
280
- path: "/oauth/token",
281
- request_id: nil,
282
- status: 400
283
- )
284
-
285
- Util.expects(:log_info).with('Stripe OAuth error',
286
- status: 400,
287
- error_code: "invalid_request",
288
- error_description: "No grant type specified",
289
- idempotency_key: nil,
290
- request_id: nil
291
- )
292
-
293
- stub_request(:post, "#{Stripe.connect_base}/oauth/token").
294
- to_return(body: JSON.generate({
295
- error: "invalid_request",
296
- error_description: "No grant type specified",
297
- }), status: 400)
454
+ account: nil,
455
+ api_version: nil,
456
+ elapsed: 0.0,
457
+ idempotency_key: nil,
458
+ method: :post,
459
+ path: "/oauth/token",
460
+ request_id: nil,
461
+ status: 400)
462
+
463
+ Util.expects(:log_error).with("Stripe OAuth error",
464
+ status: 400,
465
+ error_code: "invalid_request",
466
+ error_description: "No grant type specified",
467
+ idempotency_key: nil,
468
+ request_id: nil)
469
+
470
+ stub_request(:post, "#{Stripe.connect_base}/oauth/token")
471
+ .to_return(body: JSON.generate(error: "invalid_request",
472
+ error_description: "No grant type specified"), status: 400)
298
473
 
299
474
  client = StripeClient.new
300
- opts = {api_base: Stripe.connect_base}
475
+ opts = { api_base: Stripe.connect_base }
301
476
  assert_raises Stripe::OAuth::InvalidRequestError do
302
- client.execute_request(:post, '/oauth/token', opts)
477
+ client.execute_request(:post, "/oauth/token", **opts)
303
478
  end
304
479
  end
305
480
  end
@@ -308,14 +483,14 @@ module Stripe
308
483
  should "use a globally set header" do
309
484
  begin
310
485
  old = Stripe.stripe_account
311
- Stripe.stripe_account = 'acct_1234'
486
+ Stripe.stripe_account = "acct_1234"
312
487
 
313
- stub_request(:post, "#{Stripe.api_base}/v1/account").
314
- with(headers: {"Stripe-Account" => Stripe.stripe_account}).
315
- to_return(body: JSON.generate({ object: "account" }))
488
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
489
+ .with(headers: { "Stripe-Account" => Stripe.stripe_account })
490
+ .to_return(body: JSON.generate(object: "account"))
316
491
 
317
492
  client = StripeClient.new
318
- client.execute_request(:post, '/v1/account')
493
+ client.execute_request(:post, "/v1/account")
319
494
  ensure
320
495
  Stripe.stripe_account = old
321
496
  end
@@ -323,24 +498,23 @@ module Stripe
323
498
 
324
499
  should "use a locally set header" do
325
500
  stripe_account = "acct_0000"
326
- stub_request(:post, "#{Stripe.api_base}/v1/account").
327
- with(headers: {"Stripe-Account" => stripe_account}).
328
- to_return(body: JSON.generate({ object: "account" }))
501
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
502
+ .with(headers: { "Stripe-Account" => stripe_account })
503
+ .to_return(body: JSON.generate(object: "account"))
329
504
 
330
505
  client = StripeClient.new
331
- client.execute_request(:post, '/v1/account',
332
- headers: { :stripe_account => stripe_account }
333
- )
506
+ client.execute_request(:post, "/v1/account",
507
+ headers: { stripe_account: stripe_account })
334
508
  end
335
509
 
336
510
  should "not send it otherwise" do
337
- stub_request(:post, "#{Stripe.api_base}/v1/account").
338
- with { |req|
511
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
512
+ .with do |req|
339
513
  req.headers["Stripe-Account"].nil?
340
- }.to_return(body: JSON.generate({ object: "account" }))
514
+ end.to_return(body: JSON.generate(object: "account"))
341
515
 
342
516
  client = StripeClient.new
343
- client.execute_request(:post, '/v1/account')
517
+ client.execute_request(:post, "/v1/account")
344
518
  end
345
519
  end
346
520
 
@@ -350,31 +524,33 @@ module Stripe
350
524
  old = Stripe.app_info
351
525
  Stripe.set_app_info(
352
526
  "MyAwesomePlugin",
527
+ partner_id: "partner_1234",
353
528
  url: "https://myawesomeplugin.info",
354
529
  version: "1.2.34"
355
530
  )
356
531
 
357
- stub_request(:post, "#{Stripe.api_base}/v1/account").
358
- with { |req|
532
+ stub_request(:post, "#{Stripe.api_base}/v1/account")
533
+ .with do |req|
359
534
  assert_equal \
360
535
  "Stripe/v1 RubyBindings/#{Stripe::VERSION} " \
361
536
  "MyAwesomePlugin/1.2.34 (https://myawesomeplugin.info)",
362
537
  req.headers["User-Agent"]
363
538
 
364
539
  data = JSON.parse(req.headers["X-Stripe-Client-User-Agent"],
365
- symbolize_names: true)
540
+ symbolize_names: true)
366
541
 
367
542
  assert_equal({
368
543
  name: "MyAwesomePlugin",
544
+ partner_id: "partner_1234",
369
545
  url: "https://myawesomeplugin.info",
370
- version: "1.2.34"
546
+ version: "1.2.34",
371
547
  }, data[:application])
372
548
 
373
549
  true
374
- }.to_return(body: JSON.generate({ object: "account" }))
550
+ end.to_return(body: JSON.generate(object: "account"))
375
551
 
376
552
  client = StripeClient.new
377
- client.execute_request(:post, '/v1/account')
553
+ client.execute_request(:post, "/v1/account")
378
554
  ensure
379
555
  Stripe.app_info = old
380
556
  end
@@ -383,184 +559,225 @@ module Stripe
383
559
 
384
560
  context "error handling" do
385
561
  should "handle error response with empty body" do
386
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
387
- to_return(body: '', status: 500)
562
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
563
+ .to_return(body: "", status: 500)
388
564
 
389
565
  client = StripeClient.new
566
+
390
567
  e = assert_raises Stripe::APIError do
391
- client.execute_request(:post, '/v1/charges')
568
+ client.execute_request(:post, "/v1/charges")
392
569
  end
393
-
394
570
  assert_equal 'Invalid response object from API: "" (HTTP response code was 500)', e.message
395
571
  end
396
572
 
397
573
  should "handle success response with empty body" do
398
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
399
- to_return(body: '', status: 200)
574
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
575
+ .to_return(body: "", status: 200)
400
576
 
401
577
  client = StripeClient.new
578
+
402
579
  e = assert_raises Stripe::APIError do
403
- client.execute_request(:post, '/v1/charges')
580
+ client.execute_request(:post, "/v1/charges")
404
581
  end
405
-
406
582
  assert_equal 'Invalid response object from API: "" (HTTP response code was 200)', e.message
407
583
  end
408
584
 
585
+ should "feed a request ID through to the error object" do
586
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
587
+ .to_return(body: JSON.generate(make_missing_id_error),
588
+ headers: { "Request-ID": "req_123" },
589
+ status: 400)
590
+
591
+ client = StripeClient.new
592
+
593
+ e = assert_raises Stripe::InvalidRequestError do
594
+ client.execute_request(:post, "/v1/charges")
595
+ end
596
+ assert_equal("req_123", e.request_id)
597
+ end
598
+
599
+ should "handle low level error" do
600
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
601
+ .to_raise(Errno::ECONNREFUSED.new)
602
+
603
+ client = StripeClient.new
604
+
605
+ e = assert_raises Stripe::APIConnectionError do
606
+ client.execute_request(:post, "/v1/charges")
607
+ end
608
+ assert_equal StripeClient::ERROR_MESSAGE_CONNECTION % Stripe.api_base +
609
+ "\n\n(Network error: Connection refused)",
610
+ e.message
611
+ end
612
+
409
613
  should "handle error response with unknown value" do
410
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
411
- to_return(body: JSON.generate({ bar: "foo" }), status: 500)
614
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
615
+ .to_return(body: JSON.generate(bar: "foo"), status: 500)
412
616
 
413
617
  client = StripeClient.new
618
+
414
619
  e = assert_raises Stripe::APIError do
415
- client.execute_request(:post, '/v1/charges')
620
+ client.execute_request(:post, "/v1/charges")
416
621
  end
417
-
418
622
  assert_equal 'Invalid response object from API: "{\"bar\":\"foo\"}" (HTTP response code was 500)', e.message
419
623
  end
420
624
 
421
- should "raise InvalidRequestError on 400" do
422
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
423
- to_return(body: JSON.generate(make_missing_id_error), status: 400)
625
+ should "raise IdempotencyError on 400 of type idempotency_error" do
626
+ data = make_missing_id_error
627
+ data[:error][:type] = "idempotency_error"
628
+
629
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
630
+ .to_return(body: JSON.generate(data), status: 400)
631
+
424
632
  client = StripeClient.new
425
- begin
426
- client.execute_request(:post, '/v1/charges')
427
- rescue Stripe::InvalidRequestError => e
428
- assert_equal(400, e.http_status)
429
- assert_equal(true, !!e.http_body)
430
- assert_equal(true, e.json_body.kind_of?(Hash))
633
+
634
+ e = assert_raises Stripe::IdempotencyError do
635
+ client.execute_request(:post, "/v1/charges")
431
636
  end
637
+ assert_equal(400, e.http_status)
638
+ assert_equal(true, e.json_body.is_a?(Hash))
639
+ end
640
+
641
+ should "raise InvalidRequestError on other 400s" do
642
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
643
+ .to_return(body: JSON.generate(make_missing_id_error), status: 400)
644
+
645
+ client = StripeClient.new
646
+
647
+ e = assert_raises Stripe::InvalidRequestError do
648
+ client.execute_request(:post, "/v1/charges")
649
+ end
650
+ assert_equal(400, e.http_status)
651
+ assert_equal(true, e.json_body.is_a?(Hash))
432
652
  end
433
653
 
434
654
  should "raise AuthenticationError on 401" do
435
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
436
- to_return(body: JSON.generate(make_missing_id_error), status: 401)
655
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
656
+ .to_return(body: JSON.generate(make_missing_id_error), status: 401)
657
+
437
658
  client = StripeClient.new
438
- begin
439
- client.execute_request(:post, '/v1/charges')
440
- rescue Stripe::AuthenticationError => e
441
- assert_equal(401, e.http_status)
442
- assert_equal(true, !!e.http_body)
443
- assert_equal(true, e.json_body.kind_of?(Hash))
659
+
660
+ e = assert_raises Stripe::AuthenticationError do
661
+ client.execute_request(:post, "/v1/charges")
444
662
  end
663
+ assert_equal(401, e.http_status)
664
+ assert_equal(true, e.json_body.is_a?(Hash))
445
665
  end
446
666
 
447
667
  should "raise CardError on 402" do
448
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
449
- to_return(body: JSON.generate(make_missing_id_error), status: 402)
668
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
669
+ .to_return(body: JSON.generate(make_invalid_exp_year_error), status: 402)
670
+
450
671
  client = StripeClient.new
451
- begin
452
- client.execute_request(:post, '/v1/charges')
453
- rescue Stripe::CardError => e
454
- assert_equal(402, e.http_status)
455
- assert_equal(true, !!e.http_body)
456
- assert_equal(true, e.json_body.kind_of?(Hash))
672
+
673
+ e = assert_raises Stripe::CardError do
674
+ client.execute_request(:post, "/v1/charges")
457
675
  end
676
+ assert_equal(402, e.http_status)
677
+ assert_equal(true, e.json_body.is_a?(Hash))
678
+ assert_equal("invalid_expiry_year", e.code)
679
+ assert_equal("exp_year", e.param)
458
680
  end
459
681
 
460
682
  should "raise PermissionError on 403" do
461
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
462
- to_return(body: JSON.generate(make_missing_id_error), status: 403)
683
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
684
+ .to_return(body: JSON.generate(make_missing_id_error), status: 403)
685
+
463
686
  client = StripeClient.new
464
- begin
465
- client.execute_request(:post, '/v1/charges')
466
- rescue Stripe::PermissionError => e
467
- assert_equal(403, e.http_status)
468
- assert_equal(true, !!e.http_body)
469
- assert_equal(true, e.json_body.kind_of?(Hash))
687
+
688
+ e = assert_raises Stripe::PermissionError do
689
+ client.execute_request(:post, "/v1/charges")
470
690
  end
691
+ assert_equal(403, e.http_status)
692
+ assert_equal(true, e.json_body.is_a?(Hash))
471
693
  end
472
694
 
473
695
  should "raise InvalidRequestError on 404" do
474
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
475
- to_return(body: JSON.generate(make_missing_id_error), status: 404)
696
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
697
+ .to_return(body: JSON.generate(make_missing_id_error), status: 404)
698
+
476
699
  client = StripeClient.new
477
- begin
478
- client.execute_request(:post, '/v1/charges')
479
- rescue Stripe::InvalidRequestError => e
480
- assert_equal(404, e.http_status)
481
- assert_equal(true, !!e.http_body)
482
- assert_equal(true, e.json_body.kind_of?(Hash))
700
+
701
+ e = assert_raises Stripe::InvalidRequestError do
702
+ client.execute_request(:post, "/v1/charges")
483
703
  end
704
+ assert_equal(404, e.http_status)
705
+ assert_equal(true, e.json_body.is_a?(Hash))
484
706
  end
485
707
 
486
708
  should "raise RateLimitError on 429" do
487
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
488
- to_return(body: JSON.generate(make_rate_limit_error), status: 429)
709
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
710
+ .to_return(body: JSON.generate(make_rate_limit_error), status: 429)
711
+
489
712
  client = StripeClient.new
490
- begin
491
- client.execute_request(:post, '/v1/charges')
492
- rescue Stripe::RateLimitError => e
493
- assert_equal(429, e.http_status)
494
- assert_equal(true, !!e.http_body)
495
- assert_equal(true, e.json_body.kind_of?(Hash))
713
+
714
+ e = assert_raises Stripe::RateLimitError do
715
+ client.execute_request(:post, "/v1/charges")
496
716
  end
717
+ assert_equal(429, e.http_status)
718
+ assert_equal(true, e.json_body.is_a?(Hash))
497
719
  end
498
720
 
499
721
  should "raise OAuth::InvalidRequestError when error is a string with value 'invalid_request'" do
500
- stub_request(:post, "#{Stripe.connect_base}/oauth/token").
501
- to_return(body: JSON.generate({
502
- error: "invalid_request",
503
- error_description: "No grant type specified",
504
- }), status: 400)
722
+ stub_request(:post, "#{Stripe.connect_base}/oauth/token")
723
+ .to_return(body: JSON.generate(error: "invalid_request",
724
+ error_description: "No grant type specified"), status: 400)
505
725
 
506
726
  client = StripeClient.new
507
- opts = {api_base: Stripe.connect_base}
727
+
728
+ opts = { api_base: Stripe.connect_base }
508
729
  e = assert_raises Stripe::OAuth::InvalidRequestError do
509
- client.execute_request(:post, '/oauth/token', opts)
730
+ client.execute_request(:post, "/oauth/token", **opts)
510
731
  end
511
732
 
512
733
  assert_equal(400, e.http_status)
513
- assert_equal(true, !!e.http_body)
514
- assert_equal('No grant type specified', e.message)
734
+ assert_equal("No grant type specified", e.message)
515
735
  end
516
736
 
517
737
  should "raise OAuth::InvalidGrantError when error is a string with value 'invalid_grant'" do
518
- stub_request(:post, "#{Stripe.connect_base}/oauth/token").
519
- to_return(body: JSON.generate({
520
- error: "invalid_grant",
521
- error_description: "This authorization code has already been used. All tokens issued with this code have been revoked.",
522
- }), status: 400)
738
+ stub_request(:post, "#{Stripe.connect_base}/oauth/token")
739
+ .to_return(body: JSON.generate(error: "invalid_grant",
740
+ error_description: "This authorization code has already been used. All tokens issued with this code have been revoked."), status: 400)
523
741
 
524
742
  client = StripeClient.new
525
- opts = {api_base: Stripe.connect_base}
743
+
744
+ opts = { api_base: Stripe.connect_base }
526
745
  e = assert_raises Stripe::OAuth::InvalidGrantError do
527
- client.execute_request(:post, '/oauth/token', opts)
746
+ client.execute_request(:post, "/oauth/token", **opts)
528
747
  end
529
748
 
530
749
  assert_equal(400, e.http_status)
531
- assert_equal('invalid_grant', e.code)
532
- assert_equal('This authorization code has already been used. All tokens issued with this code have been revoked.', e.message)
750
+ assert_equal("invalid_grant", e.code)
751
+ assert_equal("This authorization code has already been used. All tokens issued with this code have been revoked.", e.message)
533
752
  end
534
753
 
535
754
  should "raise OAuth::InvalidClientError when error is a string with value 'invalid_client'" do
536
- stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize").
537
- to_return(body: JSON.generate({
538
- error: "invalid_client",
539
- error_description: "This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist.",
540
- }), status: 401)
755
+ stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize")
756
+ .to_return(body: JSON.generate(error: "invalid_client",
757
+ error_description: "This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist."), status: 401)
541
758
 
542
759
  client = StripeClient.new
543
- opts = {api_base: Stripe.connect_base}
760
+
761
+ opts = { api_base: Stripe.connect_base }
544
762
  e = assert_raises Stripe::OAuth::InvalidClientError do
545
- client.execute_request(:post, '/oauth/deauthorize', opts)
763
+ client.execute_request(:post, "/oauth/deauthorize", **opts)
546
764
  end
547
765
 
548
766
  assert_equal(401, e.http_status)
549
- assert_equal('invalid_client', e.code)
550
- assert_equal('This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist.', e.message)
767
+ assert_equal("invalid_client", e.code)
768
+ assert_equal("This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist.", e.message)
551
769
  end
552
770
 
553
771
  should "raise Stripe::OAuthError on indeterminate OAuth error" do
554
- stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize").
555
- to_return(body: JSON.generate({
556
- error: "new_code_not_recognized",
557
- error_description: "Something.",
558
- }), status: 401)
772
+ stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize")
773
+ .to_return(body: JSON.generate(error: "new_code_not_recognized",
774
+ error_description: "Something."), status: 401)
559
775
 
560
776
  client = StripeClient.new
561
- opts = {api_base: Stripe.connect_base}
777
+
778
+ opts = { api_base: Stripe.connect_base }
562
779
  e = assert_raises Stripe::OAuth::OAuthError do
563
- client.execute_request(:post, '/oauth/deauthorize', opts)
780
+ client.execute_request(:post, "/oauth/deauthorize", **opts)
564
781
  end
565
782
 
566
783
  assert_equal(401, e.http_status)
@@ -574,48 +791,48 @@ module Stripe
574
791
  Stripe.stubs(:max_network_retries).returns(2)
575
792
  end
576
793
 
577
- should 'not add an idempotency key to GET requests' do
794
+ should "not add an idempotency key to GET requests" do
578
795
  SecureRandom.expects(:uuid).times(0)
579
- stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123").
580
- with { |req|
581
- req.headers['Idempotency-Key'].nil?
582
- }.to_return(body: JSON.generate({ object: "charge" }))
796
+ stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123")
797
+ .with do |req|
798
+ req.headers["Idempotency-Key"].nil?
799
+ end.to_return(body: JSON.generate(object: "charge"))
583
800
  client = StripeClient.new
584
801
  client.execute_request(:get, "/v1/charges/ch_123")
585
802
  end
586
803
 
587
- should 'ensure there is always an idempotency_key on POST requests' do
804
+ should "ensure there is always an idempotency_key on POST requests" do
588
805
  SecureRandom.expects(:uuid).at_least_once.returns("random_key")
589
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
590
- with(headers: {"Idempotency-Key" => "random_key"}).
591
- to_return(body: JSON.generate({ object: "charge" }))
806
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
807
+ .with(headers: { "Idempotency-Key" => "random_key" })
808
+ .to_return(body: JSON.generate(object: "charge"))
592
809
  client = StripeClient.new
593
810
  client.execute_request(:post, "/v1/charges")
594
811
  end
595
812
 
596
- should 'ensure there is always an idempotency_key on DELETE requests' do
813
+ should "ensure there is always an idempotency_key on DELETE requests" do
597
814
  SecureRandom.expects(:uuid).at_least_once.returns("random_key")
598
- stub_request(:delete, "#{Stripe.api_base}/v1/charges/ch_123").
599
- with(headers: {"Idempotency-Key" => "random_key"}).
600
- to_return(body: JSON.generate({ object: "charge" }))
815
+ stub_request(:delete, "#{Stripe.api_base}/v1/charges/ch_123")
816
+ .with(headers: { "Idempotency-Key" => "random_key" })
817
+ .to_return(body: JSON.generate(object: "charge"))
601
818
  client = StripeClient.new
602
819
  client.execute_request(:delete, "/v1/charges/ch_123")
603
820
  end
604
821
 
605
- should 'not override a provided idempotency_key' do
822
+ should "not override a provided idempotency_key" do
606
823
  # Note that this expectation looks like `:idempotency_key` instead of
607
824
  # the header `Idempotency-Key` because it's user provided as seen
608
825
  # below. The ones injected by the library itself look like headers
609
826
  # (`Idempotency-Key`), but rest-client does allow this symbol
610
827
  # formatting and will properly override the system generated one as
611
828
  # expected.
612
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
613
- with(headers: {"Idempotency-Key" => "provided_key"}).
614
- to_return(body: JSON.generate({ object: "charge" }))
829
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
830
+ .with(headers: { "Idempotency-Key" => "provided_key" })
831
+ .to_return(body: JSON.generate(object: "charge"))
615
832
 
616
833
  client = StripeClient.new
617
834
  client.execute_request(:post, "/v1/charges",
618
- headers: {:idempotency_key => 'provided_key'})
835
+ headers: { idempotency_key: "provided_key" })
619
836
  end
620
837
  end
621
838
 
@@ -624,75 +841,120 @@ module Stripe
624
841
  Stripe.stubs(:max_network_retries).returns(2)
625
842
  end
626
843
 
627
- should 'retry failed requests and raise if error persists' do
844
+ should "retry failed requests and raise if error persists" do
628
845
  StripeClient.expects(:sleep_time).at_least_once.returns(0)
629
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
630
- to_raise(Errno::ECONNREFUSED.new)
846
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
847
+ .to_raise(Errno::ECONNREFUSED.new)
631
848
 
632
849
  client = StripeClient.new
633
850
  err = assert_raises Stripe::APIConnectionError do
634
- client.execute_request(:post, '/v1/charges')
851
+ client.execute_request(:post, "/v1/charges")
635
852
  end
636
853
  assert_match(/Request was retried 2 times/, err.message)
637
854
  end
638
855
 
639
- should 'retry failed requests and return successful response' do
856
+ should "retry failed requests and return successful response" do
640
857
  StripeClient.expects(:sleep_time).at_least_once.returns(0)
641
858
 
642
859
  i = 0
643
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
644
- to_return { |_|
860
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
861
+ .to_return do |_|
645
862
  if i < 2
646
863
  i += 1
647
- raise Errno::ECONNREFUSED.new
864
+ raise Errno::ECONNREFUSED
648
865
  else
649
- { body: JSON.generate({"id" => "myid"}) }
866
+ { body: JSON.generate("id" => "myid") }
650
867
  end
651
- }
868
+ end
652
869
 
653
870
  client = StripeClient.new
654
- client.execute_request(:post, '/v1/charges')
871
+ client.execute_request(:post, "/v1/charges")
655
872
  end
656
873
  end
657
874
 
658
875
  context "params serialization" do
659
- should 'allows empty strings in params' do
876
+ should "allows empty strings in params" do
877
+ client = StripeClient.new
878
+ client.execute_request(:get, "/v1/invoices/upcoming", params: {
879
+ customer: "cus_123",
880
+ coupon: "",
881
+ })
882
+ assert_requested(
883
+ :get,
884
+ "#{Stripe.api_base}/v1/invoices/upcoming?",
885
+ query: {
886
+ customer: "cus_123",
887
+ coupon: "",
888
+ }
889
+ )
890
+ end
891
+
892
+ should "filter nils in params" do
893
+ client = StripeClient.new
894
+ client.execute_request(:get, "/v1/invoices/upcoming", params: {
895
+ customer: "cus_123",
896
+ coupon: nil,
897
+ })
898
+ assert_requested(
899
+ :get,
900
+ "#{Stripe.api_base}/v1/invoices/upcoming?",
901
+ query: {
902
+ customer: "cus_123",
903
+ }
904
+ )
905
+ end
906
+
907
+ should "merge query parameters in URL and params" do
660
908
  client = StripeClient.new
661
- client.execute_request(:get, '/v1/invoices/upcoming', params: {
662
- customer: 'cus_123',
663
- coupon: ''
909
+ client.execute_request(:get, "/v1/invoices/upcoming?coupon=25OFF", params: {
910
+ customer: "cus_123",
664
911
  })
665
912
  assert_requested(
666
913
  :get,
667
914
  "#{Stripe.api_base}/v1/invoices/upcoming?",
668
915
  query: {
669
- customer: 'cus_123',
670
- coupon: ''
916
+ coupon: "25OFF",
917
+ customer: "cus_123",
671
918
  }
672
919
  )
673
920
  end
674
921
 
675
- should 'filter nils in params' do
922
+ should "prefer query parameters in params when specified in URL as well" do
676
923
  client = StripeClient.new
677
- client.execute_request(:get, '/v1/invoices/upcoming', params: {
678
- customer: 'cus_123',
679
- coupon: nil
924
+ client.execute_request(:get, "/v1/invoices/upcoming?customer=cus_query", params: {
925
+ customer: "cus_param",
680
926
  })
681
927
  assert_requested(
682
928
  :get,
683
929
  "#{Stripe.api_base}/v1/invoices/upcoming?",
684
930
  query: {
685
- customer: 'cus_123'
931
+ customer: "cus_param",
686
932
  }
687
933
  )
688
934
  end
689
935
  end
690
936
  end
691
937
 
938
+ context "#connection_manager" do
939
+ should "warn that #connection_manager is deprecated" do
940
+ old_stderr = $stderr
941
+ $stderr = StringIO.new
942
+ begin
943
+ client = StripeClient.new
944
+ client.connection_manager
945
+ message = "NOTE: Stripe::StripeClient#connection_manager is " \
946
+ "deprecated"
947
+ assert_match Regexp.new(message), $stderr.string
948
+ ensure
949
+ $stderr = old_stderr
950
+ end
951
+ end
952
+ end
953
+
692
954
  context "#request" do
693
955
  should "return a result and response object" do
694
- stub_request(:post, "#{Stripe.api_base}/v1/charges").
695
- to_return(body: JSON.generate({ object: "charge" }))
956
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
957
+ .to_return(body: JSON.generate(object: "charge"))
696
958
 
697
959
  client = StripeClient.new
698
960
  charge, resp = client.request { Charge.create }
@@ -704,46 +966,325 @@ module Stripe
704
966
 
705
967
  should "return the value of given block" do
706
968
  client = StripeClient.new
707
- ret, _ = client.request { 7 }
969
+ ret, = client.request { 7 }
708
970
  assert_equal 7, ret
709
971
  end
710
972
 
711
973
  should "reset local thread state after a call" do
712
974
  begin
713
- Thread.current[:stripe_client] = :stripe_client
975
+ StripeClient.current_thread_context.active_client = :stripe_client
714
976
 
715
977
  client = StripeClient.new
716
978
  client.request {}
717
979
 
718
- assert_equal :stripe_client, Thread.current[:stripe_client]
980
+ assert_equal :stripe_client,
981
+ StripeClient.current_thread_context.active_client
719
982
  ensure
720
- Thread.current[:stripe_client] = nil
983
+ StripeClient.current_thread_context.active_client = nil
984
+ end
985
+ end
986
+
987
+ should "correctly return last responses despite multiple clients" do
988
+ charge_resp = { object: "charge" }
989
+ coupon_resp = { object: "coupon" }
990
+
991
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
992
+ .to_return(body: JSON.generate(charge_resp))
993
+ stub_request(:post, "#{Stripe.api_base}/v1/coupons")
994
+ .to_return(body: JSON.generate(coupon_resp))
995
+
996
+ client1 = StripeClient.new
997
+ client2 = StripeClient.new
998
+
999
+ client2_resp = nil
1000
+ _charge, client1_resp = client1.request do
1001
+ Charge.create
1002
+
1003
+ # This is contrived, but we run one client nested in the `request`
1004
+ # block of another one just to ensure that the parent is still
1005
+ # unwinding when this goes through. If the parent's last response
1006
+ # were to be overridden by this client (through a bug), then it would
1007
+ # happen here.
1008
+ _coupon, client2_resp = client2.request do
1009
+ Coupon.create
1010
+ end
721
1011
  end
1012
+
1013
+ assert_equal charge_resp, client1_resp.data
1014
+ assert_equal coupon_resp, client2_resp.data
1015
+ end
1016
+
1017
+ should "correctly return last responses despite multiple threads" do
1018
+ charge_resp = { object: "charge" }
1019
+ coupon_resp = { object: "coupon" }
1020
+
1021
+ stub_request(:post, "#{Stripe.api_base}/v1/charges")
1022
+ .to_return(body: JSON.generate(charge_resp))
1023
+ stub_request(:post, "#{Stripe.api_base}/v1/coupons")
1024
+ .to_return(body: JSON.generate(coupon_resp))
1025
+
1026
+ client = StripeClient.new
1027
+
1028
+ # Poorly named class -- note this is actually a concurrent queue.
1029
+ recv_queue = Queue.new
1030
+ send_queue = Queue.new
1031
+
1032
+ # Start a thread, make an API request, but then idle in the `request`
1033
+ # block until the main thread has been able to make its own API request
1034
+ # and signal that it's done. If this thread's last response were to be
1035
+ # overridden by the main thread (through a bug), then this routine
1036
+ # should suss it out.
1037
+ resp1 = nil
1038
+ thread = Thread.start do
1039
+ _charge, resp1 = client.request do
1040
+ Charge.create
1041
+
1042
+ # Idle in `request` block until main thread signals.
1043
+ send_queue.pop
1044
+ end
1045
+
1046
+ # Signal main thread that we're done and it can run its checks.
1047
+ recv_queue << true
1048
+ end
1049
+
1050
+ # Make an API request.
1051
+ _coupon, resp2 = client.request do
1052
+ Coupon.create
1053
+ end
1054
+
1055
+ # Tell background thread to finish `request`, then wait for it to
1056
+ # signal back to us that it's ready.
1057
+ send_queue << true
1058
+ recv_queue.pop
1059
+
1060
+ assert_equal charge_resp, resp1.data
1061
+ assert_equal coupon_resp, resp2.data
1062
+
1063
+ # And for maximum hygiene, make sure that our thread rejoins.
1064
+ thread.join
1065
+ end
1066
+
1067
+ should "error if calls to #request are nested on the same thread" do
1068
+ client = StripeClient.new
1069
+ client.request do
1070
+ e = assert_raises(RuntimeError) do
1071
+ client.request {}
1072
+ end
1073
+ assert_equal "calls to StripeClient#request cannot be nested within a thread",
1074
+ e.message
1075
+ end
1076
+ end
1077
+ end
1078
+
1079
+ context "#proxy" do
1080
+ should "run the request through the proxy" do
1081
+ begin
1082
+ StripeClient.current_thread_context.default_connection_manager = nil
1083
+
1084
+ Stripe.proxy = "http://user:pass@localhost:8080"
1085
+
1086
+ client = StripeClient.new
1087
+ client.request {}
1088
+
1089
+ connection = Stripe::StripeClient.default_connection_manager.connection_for(Stripe.api_base)
1090
+
1091
+ assert_equal "localhost", connection.proxy_address
1092
+ assert_equal 8080, connection.proxy_port
1093
+ assert_equal "user", connection.proxy_user
1094
+ assert_equal "pass", connection.proxy_pass
1095
+ ensure
1096
+ Stripe.proxy = nil
1097
+
1098
+ StripeClient.current_thread_context.default_connection_manager = nil
1099
+ end
1100
+ end
1101
+ end
1102
+
1103
+ context "#telemetry" do
1104
+ teardown do
1105
+ # make sure to always set telemetry back to false
1106
+ # to not mutate global state
1107
+ Stripe.enable_telemetry = false
1108
+ end
1109
+
1110
+ should "not send metrics if enable trace flag is not set" do
1111
+ Stripe.enable_telemetry = false
1112
+
1113
+ trace_metrics_header = nil
1114
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1115
+ .with do |req|
1116
+ trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
1117
+ false
1118
+ end.to_return(body: JSON.generate(object: "charge"))
1119
+
1120
+ Stripe::Charge.list
1121
+ assert(trace_metrics_header.nil?)
1122
+
1123
+ Stripe::Charge.list
1124
+ assert(trace_metrics_header.nil?)
1125
+ end
1126
+
1127
+ should "send metrics if enabled telemetry is true" do
1128
+ Stripe.enable_telemetry = true
1129
+
1130
+ trace_metrics_header = nil
1131
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1132
+ .with do |req|
1133
+ trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
1134
+ false
1135
+ end.to_return(body: JSON.generate(object: "charge"))
1136
+
1137
+ Stripe::Charge.list
1138
+ Stripe::Charge.list
1139
+
1140
+ assert(!trace_metrics_header.nil?)
1141
+
1142
+ trace_payload = JSON.parse(trace_metrics_header)
1143
+ assert(trace_payload["last_request_metrics"]["request_id"] == "req_123")
1144
+ assert(!trace_payload["last_request_metrics"]["request_duration_ms"].nil?)
1145
+ end
1146
+ end
1147
+
1148
+ context "instrumentation" do
1149
+ teardown do
1150
+ Stripe::Instrumentation.unsubscribe(:request, :test)
1151
+ end
1152
+
1153
+ should "notify a subscribe on HTTP request start" do
1154
+ events = []
1155
+ Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
1156
+
1157
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1158
+ .to_return(body: JSON.generate(object: "charge"))
1159
+ Stripe::Charge.list
1160
+
1161
+ assert_equal(1, events.size)
1162
+ event = events.first
1163
+ assert_equal(:get, event.method)
1164
+ assert_equal("/v1/charges", event.path)
1165
+ end
1166
+
1167
+ should "notify a subscriber of a successful HTTP request" do
1168
+ events = []
1169
+ Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
1170
+
1171
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1172
+ .to_return(body: JSON.generate(object: "charge"))
1173
+ Stripe::Charge.list
1174
+
1175
+ assert_equal(1, events.size)
1176
+ event = events.first
1177
+ assert_equal(:get, event.method)
1178
+ assert_equal("/v1/charges", event.path)
1179
+ assert_equal(200, event.http_status)
1180
+ assert(event.duration.positive?)
1181
+ assert_equal(0, event.num_retries)
1182
+ end
1183
+
1184
+ should "notify a subscriber of a StripeError" do
1185
+ events = []
1186
+ Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
1187
+
1188
+ error = {
1189
+ code: "code",
1190
+ message: "message",
1191
+ param: "param",
1192
+ type: "type",
1193
+ }
1194
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1195
+ .to_return(
1196
+ body: JSON.generate(error: error),
1197
+ status: 500
1198
+ )
1199
+ assert_raises(Stripe::APIError) do
1200
+ Stripe::Charge.list
1201
+ end
1202
+
1203
+ assert_equal(1, events.size)
1204
+ event = events.first
1205
+ assert_equal(:get, event.method)
1206
+ assert_equal("/v1/charges", event.path)
1207
+ assert_equal(500, event.http_status)
1208
+ assert(event.duration.positive?)
1209
+ assert_equal(0, event.num_retries)
1210
+ end
1211
+
1212
+ should "notify a subscriber of a network error" do
1213
+ events = []
1214
+ Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
1215
+
1216
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1217
+ .to_raise(Net::OpenTimeout)
1218
+ assert_raises(Stripe::APIConnectionError) do
1219
+ Stripe::Charge.list
1220
+ end
1221
+
1222
+ assert_equal(1, events.size)
1223
+ event = events.first
1224
+ assert_equal(:get, event.method)
1225
+ assert_equal("/v1/charges", event.path)
1226
+ assert_nil(event.http_status)
1227
+ assert(event.duration.positive?)
1228
+ assert_equal(0, event.num_retries)
1229
+ end
1230
+
1231
+ should "pass `user_data` from `request_begin` to `request_end`" do
1232
+ actual_user_data = nil
1233
+
1234
+ Stripe::Instrumentation.subscribe(:request_begin) do |event|
1235
+ event.user_data[:foo] = :bar
1236
+ end
1237
+ Stripe::Instrumentation.subscribe(:request_end) do |event|
1238
+ actual_user_data = event.user_data
1239
+ end
1240
+
1241
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1242
+ .to_return(body: JSON.generate(object: "charge"))
1243
+ Stripe::Charge.list
1244
+
1245
+ assert_equal({ foo: :bar }, actual_user_data)
1246
+ end
1247
+
1248
+ should "provide backward compatibility on `request` topic" do
1249
+ events = []
1250
+ Stripe::Instrumentation.subscribe(:request, :test) { |event| events << event }
1251
+
1252
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
1253
+ .to_return(body: JSON.generate(object: "charge"))
1254
+ Stripe::Charge.list
1255
+
1256
+ assert_equal(1, events.size)
1257
+ event = events.first
1258
+ assert_equal(:get, event.method)
1259
+ assert_equal("/v1/charges", event.path)
1260
+ assert_equal(200, event.http_status)
1261
+ assert(event.duration.positive?)
1262
+ assert_equal(0, event.num_retries)
722
1263
  end
723
1264
  end
724
1265
  end
725
1266
 
726
1267
  class SystemProfilerTest < Test::Unit::TestCase
727
- context "#get_uname" do
1268
+ context "#uname" do
728
1269
  should "run without failure" do
729
1270
  # Don't actually check the result because we try a variety of different
730
1271
  # strategies that will have different results depending on where this
731
1272
  # test and running. We're mostly making sure that no exception is thrown.
732
- _ = StripeClient::SystemProfiler.get_uname
1273
+ _ = StripeClient::SystemProfiler.uname
733
1274
  end
734
1275
  end
735
1276
 
736
- context "#get_uname_from_system" do
1277
+ context "#uname_from_system" do
737
1278
  should "run without failure" do
738
1279
  # as above, just verify that an exception is not thrown
739
- _ = StripeClient::SystemProfiler.get_uname_from_system
1280
+ _ = StripeClient::SystemProfiler.uname_from_system
740
1281
  end
741
1282
  end
742
1283
 
743
- context "#get_uname_from_system_ver" do
1284
+ context "#uname_from_system_ver" do
744
1285
  should "run without failure" do
745
1286
  # as above, just verify that an exception is not thrown
746
- _ = StripeClient::SystemProfiler.get_uname_from_system_ver
1287
+ _ = StripeClient::SystemProfiler.uname_from_system_ver
747
1288
  end
748
1289
  end
749
1290
  end