stripe 4.10.0 → 5.55.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (258) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +316 -1
  3. data/CODE_OF_CONDUCT.md +77 -0
  4. data/Gemfile +10 -14
  5. data/Makefile +7 -0
  6. data/README.md +186 -62
  7. data/Rakefile +8 -7
  8. data/VERSION +1 -1
  9. data/lib/stripe/api_operations/create.rb +1 -1
  10. data/lib/stripe/api_operations/delete.rb +28 -2
  11. data/lib/stripe/api_operations/list.rb +1 -12
  12. data/lib/stripe/api_operations/nested_resource.rb +38 -28
  13. data/lib/stripe/api_operations/request.rb +81 -9
  14. data/lib/stripe/api_operations/save.rb +8 -7
  15. data/lib/stripe/api_operations/search.rb +19 -0
  16. data/lib/stripe/api_resource.rb +45 -3
  17. data/lib/stripe/api_resource_test_helpers.rb +47 -0
  18. data/lib/stripe/connection_manager.rb +200 -0
  19. data/lib/stripe/error_object.rb +93 -0
  20. data/lib/stripe/errors.rb +31 -10
  21. data/lib/stripe/instrumentation.rb +84 -0
  22. data/lib/stripe/list_object.rb +41 -7
  23. data/lib/stripe/multipart_encoder.rb +131 -0
  24. data/lib/stripe/oauth.rb +8 -6
  25. data/lib/stripe/object_types.rb +119 -0
  26. data/lib/stripe/{account.rb → resources/account.rb} +48 -30
  27. data/lib/stripe/{account_link.rb → resources/account_link.rb} +2 -1
  28. data/lib/stripe/resources/alipay_account.rb +34 -0
  29. data/lib/stripe/{apple_pay_domain.rb → resources/apple_pay_domain.rb} +2 -1
  30. data/lib/stripe/resources/application_fee.rb +14 -0
  31. data/lib/stripe/resources/application_fee_refund.rb +31 -0
  32. data/lib/stripe/{balance.rb → resources/balance.rb} +2 -1
  33. data/lib/stripe/{balance_transaction.rb → resources/balance_transaction.rb} +2 -5
  34. data/lib/stripe/resources/bank_account.rb +43 -0
  35. data/lib/stripe/{issuing/dispute.rb → resources/billing_portal/configuration.rb} +4 -3
  36. data/lib/stripe/resources/billing_portal/session.rb +12 -0
  37. data/lib/stripe/{bitcoin_receiver.rb → resources/bitcoin_receiver.rb} +4 -3
  38. data/lib/stripe/resources/bitcoin_transaction.rb +16 -0
  39. data/lib/stripe/resources/capability.rb +34 -0
  40. data/lib/stripe/{card.rb → resources/card.rb} +13 -4
  41. data/lib/stripe/resources/cash_balance.rb +22 -0
  42. data/lib/stripe/resources/charge.rb +32 -0
  43. data/lib/stripe/resources/checkout/session.rb +27 -0
  44. data/lib/stripe/{country_spec.rb → resources/country_spec.rb} +2 -1
  45. data/lib/stripe/{coupon.rb → resources/coupon.rb} +3 -2
  46. data/lib/stripe/resources/credit_note.rb +33 -0
  47. data/lib/stripe/resources/credit_note_line_item.rb +8 -0
  48. data/lib/stripe/resources/customer.rb +74 -0
  49. data/lib/stripe/resources/customer_balance_transaction.rb +31 -0
  50. data/lib/stripe/resources/discount.rb +8 -0
  51. data/lib/stripe/resources/dispute.rb +22 -0
  52. data/lib/stripe/{ephemeral_key.rb → resources/ephemeral_key.rb} +6 -2
  53. data/lib/stripe/{event.rb → resources/event.rb} +2 -1
  54. data/lib/stripe/{exchange_rate.rb → resources/exchange_rate.rb} +2 -1
  55. data/lib/stripe/resources/file.rb +36 -0
  56. data/lib/stripe/{file_link.rb → resources/file_link.rb} +3 -2
  57. data/lib/stripe/resources/financial_connections/account.rb +31 -0
  58. data/lib/stripe/resources/financial_connections/account_owner.rb +10 -0
  59. data/lib/stripe/resources/financial_connections/account_ownership.rb +10 -0
  60. data/lib/stripe/resources/financial_connections/session.rb +12 -0
  61. data/lib/stripe/resources/funding_instructions.rb +16 -0
  62. data/lib/stripe/resources/identity/verification_report.rb +12 -0
  63. data/lib/stripe/resources/identity/verification_session.rb +35 -0
  64. data/lib/stripe/resources/invoice.rb +83 -0
  65. data/lib/stripe/{invoice_item.rb → resources/invoice_item.rb} +3 -2
  66. data/lib/stripe/{invoice_line_item.rb → resources/invoice_line_item.rb} +2 -1
  67. data/lib/stripe/resources/issuing/authorization.rb +34 -0
  68. data/lib/stripe/resources/issuing/card.rb +25 -0
  69. data/lib/stripe/resources/issuing/card_details.rb +10 -0
  70. data/lib/stripe/{issuing → resources/issuing}/cardholder.rb +3 -2
  71. data/lib/stripe/resources/issuing/dispute.rb +25 -0
  72. data/lib/stripe/{issuing → resources/issuing}/transaction.rb +3 -2
  73. data/lib/stripe/resources/line_item.rb +8 -0
  74. data/lib/stripe/resources/login_link.rb +15 -0
  75. data/lib/stripe/resources/mandate.rb +8 -0
  76. data/lib/stripe/resources/order.rb +33 -0
  77. data/lib/stripe/{order_return.rb → resources/order_return.rb} +2 -1
  78. data/lib/stripe/resources/payment_intent.rb +82 -0
  79. data/lib/stripe/resources/payment_link.rb +23 -0
  80. data/lib/stripe/resources/payment_method.rb +33 -0
  81. data/lib/stripe/resources/payout.rb +33 -0
  82. data/lib/stripe/{person.rb → resources/person.rb} +9 -3
  83. data/lib/stripe/{plan.rb → resources/plan.rb} +2 -1
  84. data/lib/stripe/resources/price.rb +21 -0
  85. data/lib/stripe/resources/product.rb +22 -0
  86. data/lib/stripe/resources/promotion_code.rb +12 -0
  87. data/lib/stripe/resources/quote.rb +105 -0
  88. data/lib/stripe/resources/radar/early_fraud_warning.rb +12 -0
  89. data/lib/stripe/{radar → resources/radar}/value_list.rb +3 -2
  90. data/lib/stripe/{radar → resources/radar}/value_list_item.rb +3 -2
  91. data/lib/stripe/{recipient.rb → resources/recipient.rb} +3 -6
  92. data/lib/stripe/{recipient_transfer.rb → resources/recipient_transfer.rb} +1 -1
  93. data/lib/stripe/resources/refund.rb +42 -0
  94. data/lib/stripe/{reporting → resources/reporting}/report_run.rb +3 -2
  95. data/lib/stripe/{reporting → resources/reporting}/report_type.rb +3 -2
  96. data/lib/stripe/resources/reversal.rb +30 -0
  97. data/lib/stripe/resources/review.rb +21 -0
  98. data/lib/stripe/resources/setup_attempt.rb +10 -0
  99. data/lib/stripe/resources/setup_intent.rb +43 -0
  100. data/lib/stripe/{product.rb → resources/shipping_rate.rb} +4 -4
  101. data/lib/stripe/{sigma → resources/sigma}/scheduled_query_run.rb +3 -2
  102. data/lib/stripe/{sku.rb → resources/sku.rb} +4 -3
  103. data/lib/stripe/resources/source.rb +47 -0
  104. data/lib/stripe/{source_transaction.rb → resources/source_transaction.rb} +2 -1
  105. data/lib/stripe/resources/subscription.rb +35 -0
  106. data/lib/stripe/resources/subscription_item.rb +26 -0
  107. data/lib/stripe/resources/subscription_schedule.rb +33 -0
  108. data/lib/stripe/resources/tax_code.rb +10 -0
  109. data/lib/stripe/resources/tax_id.rb +27 -0
  110. data/lib/stripe/{refund.rb → resources/tax_rate.rb} +3 -2
  111. data/lib/stripe/{terminal/reader.rb → resources/terminal/configuration.rb} +3 -2
  112. data/lib/stripe/resources/terminal/connection_token.rb +12 -0
  113. data/lib/stripe/{terminal → resources/terminal}/location.rb +3 -2
  114. data/lib/stripe/resources/terminal/reader.rb +75 -0
  115. data/lib/stripe/resources/test_helpers/test_clock.rb +25 -0
  116. data/lib/stripe/{three_d_secure.rb → resources/three_d_secure.rb} +2 -1
  117. data/lib/stripe/{token.rb → resources/token.rb} +2 -1
  118. data/lib/stripe/resources/topup.rb +23 -0
  119. data/lib/stripe/resources/transfer.rb +27 -0
  120. data/lib/stripe/resources/usage_record.rb +8 -0
  121. data/lib/stripe/{usage_record_summary.rb → resources/usage_record_summary.rb} +2 -1
  122. data/lib/stripe/{webhook_endpoint.rb → resources/webhook_endpoint.rb} +3 -2
  123. data/lib/stripe/resources.rb +100 -0
  124. data/lib/stripe/search_result_object.rb +86 -0
  125. data/lib/stripe/singleton_api_resource.rb +3 -1
  126. data/lib/stripe/stripe_client.rb +661 -266
  127. data/lib/stripe/stripe_configuration.rb +194 -0
  128. data/lib/stripe/stripe_object.rb +80 -61
  129. data/lib/stripe/stripe_response.rb +87 -27
  130. data/lib/stripe/util.rb +128 -117
  131. data/lib/stripe/version.rb +1 -1
  132. data/lib/stripe/webhook.rb +43 -10
  133. data/lib/stripe.rb +46 -197
  134. data/stripe.gemspec +24 -8
  135. metadata +123 -283
  136. data/.gitattributes +0 -4
  137. data/.github/ISSUE_TEMPLATE.md +0 -5
  138. data/.gitignore +0 -8
  139. data/.rubocop.yml +0 -32
  140. data/.rubocop_todo.yml +0 -50
  141. data/.travis.yml +0 -42
  142. data/lib/stripe/alipay_account.rb +0 -27
  143. data/lib/stripe/application_fee.rb +0 -23
  144. data/lib/stripe/application_fee_refund.rb +0 -22
  145. data/lib/stripe/bank_account.rb +0 -32
  146. data/lib/stripe/bitcoin_transaction.rb +0 -15
  147. data/lib/stripe/charge.rb +0 -84
  148. data/lib/stripe/checkout/session.rb +0 -11
  149. data/lib/stripe/customer.rb +0 -90
  150. data/lib/stripe/dispute.rb +0 -19
  151. data/lib/stripe/file.rb +0 -37
  152. data/lib/stripe/invoice.rb +0 -48
  153. data/lib/stripe/issuer_fraud_record.rb +0 -9
  154. data/lib/stripe/issuing/authorization.rb +0 -22
  155. data/lib/stripe/issuing/card.rb +0 -18
  156. data/lib/stripe/issuing/card_details.rb +0 -9
  157. data/lib/stripe/login_link.rb +0 -11
  158. data/lib/stripe/order.rb +0 -31
  159. data/lib/stripe/payment_intent.rb +0 -26
  160. data/lib/stripe/payment_method.rb +0 -23
  161. data/lib/stripe/payout.rb +0 -20
  162. data/lib/stripe/reversal.rb +0 -22
  163. data/lib/stripe/review.rb +0 -14
  164. data/lib/stripe/source.rb +0 -38
  165. data/lib/stripe/subscription.rb +0 -25
  166. data/lib/stripe/subscription_item.rb +0 -17
  167. data/lib/stripe/subscription_schedule.rb +0 -32
  168. data/lib/stripe/subscription_schedule_revision.rb +0 -25
  169. data/lib/stripe/terminal/connection_token.rb +0 -11
  170. data/lib/stripe/topup.rb +0 -16
  171. data/lib/stripe/transfer.rb +0 -23
  172. data/lib/stripe/usage_record.rb +0 -14
  173. data/test/api_stub_helpers.rb +0 -1
  174. data/test/openapi/README.md +0 -9
  175. data/test/stripe/account_external_accounts_operations_test.rb +0 -69
  176. data/test/stripe/account_link_test.rb +0 -18
  177. data/test/stripe/account_login_links_operations_test.rb +0 -21
  178. data/test/stripe/account_persons_operations_test.rb +0 -70
  179. data/test/stripe/account_test.rb +0 -256
  180. data/test/stripe/alipay_account_test.rb +0 -37
  181. data/test/stripe/api_operations_test.rb +0 -81
  182. data/test/stripe/api_resource_test.rb +0 -526
  183. data/test/stripe/apple_pay_domain_test.rb +0 -33
  184. data/test/stripe/application_fee_refund_test.rb +0 -37
  185. data/test/stripe/application_fee_refunds_operations_test.rb +0 -56
  186. data/test/stripe/application_fee_test.rb +0 -14
  187. data/test/stripe/balance_test.rb +0 -13
  188. data/test/stripe/bank_account_test.rb +0 -36
  189. data/test/stripe/charge_test.rb +0 -59
  190. data/test/stripe/checkout/session_test.rb +0 -41
  191. data/test/stripe/country_spec_test.rb +0 -20
  192. data/test/stripe/coupon_test.rb +0 -51
  193. data/test/stripe/customer_card_test.rb +0 -42
  194. data/test/stripe/customer_sources_operations_test.rb +0 -64
  195. data/test/stripe/customer_test.rb +0 -115
  196. data/test/stripe/dispute_test.rb +0 -42
  197. data/test/stripe/ephemeral_key_test.rb +0 -86
  198. data/test/stripe/errors_test.rb +0 -20
  199. data/test/stripe/exchange_rate_test.rb +0 -20
  200. data/test/stripe/file_link_test.rb +0 -41
  201. data/test/stripe/file_test.rb +0 -73
  202. data/test/stripe/file_upload_test.rb +0 -76
  203. data/test/stripe/invoice_item_test.rb +0 -55
  204. data/test/stripe/invoice_line_item_test.rb +0 -8
  205. data/test/stripe/invoice_test.rb +0 -161
  206. data/test/stripe/issuer_fraud_record_test.rb +0 -20
  207. data/test/stripe/issuing/authorization_test.rb +0 -50
  208. data/test/stripe/issuing/card_test.rb +0 -53
  209. data/test/stripe/issuing/cardholder_test.rb +0 -53
  210. data/test/stripe/issuing/dispute_test.rb +0 -45
  211. data/test/stripe/issuing/transaction_test.rb +0 -48
  212. data/test/stripe/list_object_test.rb +0 -156
  213. data/test/stripe/login_link_test.rb +0 -37
  214. data/test/stripe/oauth_test.rb +0 -88
  215. data/test/stripe/order_return_test.rb +0 -21
  216. data/test/stripe/order_test.rb +0 -57
  217. data/test/stripe/payment_intent_test.rb +0 -80
  218. data/test/stripe/payment_method_test.rb +0 -66
  219. data/test/stripe/payout_test.rb +0 -50
  220. data/test/stripe/person_test.rb +0 -46
  221. data/test/stripe/plan_test.rb +0 -92
  222. data/test/stripe/product_test.rb +0 -49
  223. data/test/stripe/radar/value_list_item_test.rb +0 -38
  224. data/test/stripe/radar/value_list_test.rb +0 -51
  225. data/test/stripe/recipient_test.rb +0 -49
  226. data/test/stripe/refund_test.rb +0 -39
  227. data/test/stripe/reporting/report_run_test.rb +0 -33
  228. data/test/stripe/reporting/report_type_test.rb +0 -22
  229. data/test/stripe/reversal_test.rb +0 -43
  230. data/test/stripe/review_test.rb +0 -27
  231. data/test/stripe/sigma/scheduled_query_run_test.rb +0 -22
  232. data/test/stripe/sku_test.rb +0 -50
  233. data/test/stripe/source_test.rb +0 -86
  234. data/test/stripe/source_transaction_test.rb +0 -19
  235. data/test/stripe/stripe_client_test.rb +0 -823
  236. data/test/stripe/stripe_object_test.rb +0 -525
  237. data/test/stripe/stripe_response_test.rb +0 -49
  238. data/test/stripe/subscription_item_test.rb +0 -53
  239. data/test/stripe/subscription_schedule_revision_test.rb +0 -37
  240. data/test/stripe/subscription_schedule_revisions_operations_test.rb +0 -35
  241. data/test/stripe/subscription_schedule_test.rb +0 -64
  242. data/test/stripe/subscription_test.rb +0 -60
  243. data/test/stripe/terminal/connection_token_test.rb +0 -16
  244. data/test/stripe/terminal/location_test.rb +0 -58
  245. data/test/stripe/terminal/reader_test.rb +0 -52
  246. data/test/stripe/three_d_secure_test.rb +0 -23
  247. data/test/stripe/topup_test.rb +0 -54
  248. data/test/stripe/transfer_reversals_operations_test.rb +0 -57
  249. data/test/stripe/transfer_test.rb +0 -43
  250. data/test/stripe/usage_record_summary_test.rb +0 -19
  251. data/test/stripe/usage_record_test.rb +0 -28
  252. data/test/stripe/util_test.rb +0 -402
  253. data/test/stripe/webhook_endpoint_test.rb +0 -42
  254. data/test/stripe/webhook_test.rb +0 -96
  255. data/test/stripe_mock.rb +0 -77
  256. data/test/stripe_test.rb +0 -63
  257. data/test/test_data.rb +0 -61
  258. data/test/test_helper.rb +0 -73
@@ -1,823 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require ::File.expand_path("../../test_helper", __FILE__)
4
-
5
- module Stripe
6
- class StripeClientTest < Test::Unit::TestCase
7
- context ".active_client" do
8
- should "be .default_client outside of #request" do
9
- assert_equal StripeClient.default_client, StripeClient.active_client
10
- end
11
-
12
- should "be active client inside of #request" do
13
- client = StripeClient.new
14
- client.request do
15
- assert_equal client, StripeClient.active_client
16
- end
17
- end
18
- end
19
-
20
- context ".default_client" do
21
- should "be a StripeClient" do
22
- assert_kind_of StripeClient, StripeClient.default_client
23
- end
24
-
25
- should "be a different client on each thread" do
26
- other_thread_client = nil
27
- thread = Thread.new do
28
- other_thread_client = StripeClient.default_client
29
- end
30
- thread.join
31
- refute_equal StripeClient.default_client, other_thread_client
32
- end
33
- end
34
-
35
- context ".default_conn" do
36
- should "be a Faraday::Connection" do
37
- assert_kind_of Faraday::Connection, StripeClient.default_conn
38
- end
39
-
40
- should "be a different connection on each thread" do
41
- other_thread_conn = nil
42
- thread = Thread.new do
43
- other_thread_conn = StripeClient.default_conn
44
- end
45
- thread.join
46
- refute_equal StripeClient.default_conn, other_thread_conn
47
- end
48
- end
49
-
50
- context ".should_retry?" do
51
- setup do
52
- Stripe.stubs(:max_network_retries).returns(2)
53
- end
54
-
55
- should "retry on timeout" do
56
- assert StripeClient.should_retry?(Faraday::TimeoutError.new(""), 0)
57
- end
58
-
59
- should "retry on a failed connection" do
60
- assert StripeClient.should_retry?(Faraday::ConnectionFailed.new(""), 0)
61
- end
62
-
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)
67
- end
68
-
69
- should "not retry at maximum count" do
70
- refute StripeClient.should_retry?(RuntimeError.new, Stripe.max_network_retries)
71
- end
72
-
73
- should "not retry on a certificate validation error" do
74
- refute StripeClient.should_retry?(Faraday::SSLError.new(""), 0)
75
- end
76
- end
77
-
78
- context ".sleep_time" do
79
- should "should grow exponentially" do
80
- StripeClient.stubs(:rand).returns(1)
81
- Stripe.stubs(:max_network_retry_delay).returns(999)
82
- assert_equal(Stripe.initial_network_retry_delay, StripeClient.sleep_time(1))
83
- assert_equal(Stripe.initial_network_retry_delay * 2, StripeClient.sleep_time(2))
84
- assert_equal(Stripe.initial_network_retry_delay * 4, StripeClient.sleep_time(3))
85
- assert_equal(Stripe.initial_network_retry_delay * 8, StripeClient.sleep_time(4))
86
- end
87
-
88
- should "enforce the max_network_retry_delay" do
89
- StripeClient.stubs(:rand).returns(1)
90
- Stripe.stubs(:initial_network_retry_delay).returns(1)
91
- Stripe.stubs(:max_network_retry_delay).returns(2)
92
- assert_equal(1, StripeClient.sleep_time(1))
93
- assert_equal(2, StripeClient.sleep_time(2))
94
- assert_equal(2, StripeClient.sleep_time(3))
95
- assert_equal(2, StripeClient.sleep_time(4))
96
- end
97
-
98
- should "add some randomness" do
99
- random_value = 0.8
100
- StripeClient.stubs(:rand).returns(random_value)
101
- Stripe.stubs(:initial_network_retry_delay).returns(1)
102
- Stripe.stubs(:max_network_retry_delay).returns(8)
103
-
104
- base_value = Stripe.initial_network_retry_delay * (0.5 * (1 + random_value))
105
-
106
- # the initial value cannot be smaller than the base,
107
- # so the randomness is ignored
108
- assert_equal(Stripe.initial_network_retry_delay, StripeClient.sleep_time(1))
109
-
110
- # after the first one, the randomness is applied
111
- assert_equal(base_value * 2, StripeClient.sleep_time(2))
112
- assert_equal(base_value * 4, StripeClient.sleep_time(3))
113
- assert_equal(base_value * 8, StripeClient.sleep_time(4))
114
- end
115
- end
116
-
117
- context "#initialize" do
118
- should "set Stripe.default_conn" do
119
- client = StripeClient.new
120
- assert_equal StripeClient.default_conn, client.conn
121
- end
122
-
123
- 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
127
- end
128
- end
129
-
130
- context "#execute_request" do
131
- context "headers" do
132
- should "support literal headers" do
133
- stub_request(:post, "#{Stripe.api_base}/v1/account")
134
- .with(headers: { "Stripe-Account" => "bar" })
135
- .to_return(body: JSON.generate(object: "account"))
136
-
137
- client = StripeClient.new
138
- client.execute_request(:post, "/v1/account",
139
- headers: { "Stripe-Account" => "bar" })
140
- end
141
-
142
- should "support RestClient-style header keys" do
143
- stub_request(:post, "#{Stripe.api_base}/v1/account")
144
- .with(headers: { "Stripe-Account" => "bar" })
145
- .to_return(body: JSON.generate(object: "account"))
146
-
147
- client = StripeClient.new
148
- client.execute_request(:post, "/v1/account",
149
- headers: { stripe_account: "bar" })
150
- end
151
- end
152
-
153
- context "logging" do
154
- setup do
155
- # Freeze time for the purposes of the `elapsed` parameter that we
156
- # emit for responses. I didn't want to bring in a new dependency for
157
- # this, but Mocha's `anything` parameter can't match inside of a hash
158
- # and is therefore not useful for this purpose. If we switch over to
159
- # rspec-mocks at some point, we can probably remove Timecop from the
160
- # project.
161
- Timecop.freeze(Time.local(1990))
162
- end
163
-
164
- teardown do
165
- Timecop.return
166
- end
167
-
168
- should "produce appropriate logging" do
169
- body = JSON.generate(object: "account")
170
-
171
- Util.expects(:log_info).with("Request to Stripe API",
172
- account: "acct_123",
173
- api_version: "2010-11-12",
174
- idempotency_key: "abc",
175
- method: :post,
176
- num_retries: 0,
177
- path: "/v1/account")
178
- Util.expects(:log_debug).with("Request details",
179
- body: "",
180
- idempotency_key: "abc",
181
- query_params: nil)
182
-
183
- Util.expects(:log_info).with("Response from Stripe API",
184
- account: "acct_123",
185
- api_version: "2010-11-12",
186
- elapsed: 0.0,
187
- idempotency_key: "abc",
188
- method: :post,
189
- path: "/v1/account",
190
- request_id: "req_123",
191
- status: 200)
192
- Util.expects(:log_debug).with("Response details",
193
- body: body,
194
- idempotency_key: "abc",
195
- request_id: "req_123")
196
- Util.expects(:log_debug).with("Dashboard link for request",
197
- idempotency_key: "abc",
198
- request_id: "req_123",
199
- url: Util.request_id_dashboard_url("req_123", Stripe.api_key))
200
-
201
- stub_request(:post, "#{Stripe.api_base}/v1/account")
202
- .to_return(
203
- body: body,
204
- headers: {
205
- "Idempotency-Key" => "abc",
206
- "Request-Id" => "req_123",
207
- "Stripe-Account" => "acct_123",
208
- "Stripe-Version" => "2010-11-12",
209
- }
210
- )
211
-
212
- client = StripeClient.new
213
- client.execute_request(:post, "/v1/account",
214
- headers: {
215
- "Idempotency-Key" => "abc",
216
- "Stripe-Account" => "acct_123",
217
- "Stripe-Version" => "2010-11-12",
218
- })
219
- end
220
-
221
- should "produce logging on API error" do
222
- Util.expects(:log_info).with("Request to Stripe API",
223
- account: nil,
224
- api_version: nil,
225
- idempotency_key: nil,
226
- method: :post,
227
- num_retries: 0,
228
- path: "/v1/account")
229
- Util.expects(:log_info).with("Response from Stripe API",
230
- account: nil,
231
- api_version: nil,
232
- elapsed: 0.0,
233
- idempotency_key: nil,
234
- method: :post,
235
- path: "/v1/account",
236
- request_id: nil,
237
- status: 500)
238
-
239
- error = {
240
- code: "code",
241
- message: "message",
242
- param: "param",
243
- type: "type",
244
- }
245
- Util.expects(:log_error).with("Stripe API error",
246
- status: 500,
247
- error_code: error[:code],
248
- error_message: error[:message],
249
- error_param: error[:param],
250
- error_type: error[:type],
251
- idempotency_key: nil,
252
- request_id: nil)
253
-
254
- stub_request(:post, "#{Stripe.api_base}/v1/account")
255
- .to_return(
256
- body: JSON.generate(error: error),
257
- status: 500
258
- )
259
-
260
- client = StripeClient.new
261
- assert_raises Stripe::APIError do
262
- client.execute_request(:post, "/v1/account")
263
- end
264
- end
265
-
266
- should "produce logging on OAuth error" do
267
- Util.expects(:log_info).with("Request to Stripe API",
268
- account: nil,
269
- api_version: nil,
270
- idempotency_key: nil,
271
- method: :post,
272
- num_retries: 0,
273
- path: "/oauth/token")
274
- 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
- Util.expects(:log_error).with("Stripe OAuth error",
285
- status: 400,
286
- error_code: "invalid_request",
287
- error_description: "No grant type specified",
288
- idempotency_key: nil,
289
- request_id: nil)
290
-
291
- stub_request(:post, "#{Stripe.connect_base}/oauth/token")
292
- .to_return(body: JSON.generate(error: "invalid_request",
293
- error_description: "No grant type specified"), status: 400)
294
-
295
- client = StripeClient.new
296
- opts = { api_base: Stripe.connect_base }
297
- assert_raises Stripe::OAuth::InvalidRequestError do
298
- client.execute_request(:post, "/oauth/token", opts)
299
- end
300
- end
301
- end
302
-
303
- context "Stripe-Account header" do
304
- should "use a globally set header" do
305
- begin
306
- old = Stripe.stripe_account
307
- Stripe.stripe_account = "acct_1234"
308
-
309
- stub_request(:post, "#{Stripe.api_base}/v1/account")
310
- .with(headers: { "Stripe-Account" => Stripe.stripe_account })
311
- .to_return(body: JSON.generate(object: "account"))
312
-
313
- client = StripeClient.new
314
- client.execute_request(:post, "/v1/account")
315
- ensure
316
- Stripe.stripe_account = old
317
- end
318
- end
319
-
320
- should "use a locally set header" do
321
- stripe_account = "acct_0000"
322
- stub_request(:post, "#{Stripe.api_base}/v1/account")
323
- .with(headers: { "Stripe-Account" => stripe_account })
324
- .to_return(body: JSON.generate(object: "account"))
325
-
326
- client = StripeClient.new
327
- client.execute_request(:post, "/v1/account",
328
- headers: { stripe_account: stripe_account })
329
- end
330
-
331
- should "not send it otherwise" do
332
- stub_request(:post, "#{Stripe.api_base}/v1/account")
333
- .with do |req|
334
- req.headers["Stripe-Account"].nil?
335
- end.to_return(body: JSON.generate(object: "account"))
336
-
337
- client = StripeClient.new
338
- client.execute_request(:post, "/v1/account")
339
- end
340
- end
341
-
342
- context "app_info" do
343
- should "send app_info if set" do
344
- begin
345
- old = Stripe.app_info
346
- Stripe.set_app_info(
347
- "MyAwesomePlugin",
348
- partner_id: "partner_1234",
349
- url: "https://myawesomeplugin.info",
350
- version: "1.2.34"
351
- )
352
-
353
- stub_request(:post, "#{Stripe.api_base}/v1/account")
354
- .with do |req|
355
- assert_equal \
356
- "Stripe/v1 RubyBindings/#{Stripe::VERSION} " \
357
- "MyAwesomePlugin/1.2.34 (https://myawesomeplugin.info)",
358
- req.headers["User-Agent"]
359
-
360
- data = JSON.parse(req.headers["X-Stripe-Client-User-Agent"],
361
- symbolize_names: true)
362
-
363
- assert_equal({
364
- name: "MyAwesomePlugin",
365
- partner_id: "partner_1234",
366
- url: "https://myawesomeplugin.info",
367
- version: "1.2.34",
368
- }, data[:application])
369
-
370
- true
371
- end.to_return(body: JSON.generate(object: "account"))
372
-
373
- client = StripeClient.new
374
- client.execute_request(:post, "/v1/account")
375
- ensure
376
- Stripe.app_info = old
377
- end
378
- end
379
- end
380
-
381
- context "error handling" do
382
- should "handle error response with empty body" do
383
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
384
- .to_return(body: "", status: 500)
385
-
386
- client = StripeClient.new
387
- e = assert_raises Stripe::APIError do
388
- client.execute_request(:post, "/v1/charges")
389
- end
390
-
391
- assert_equal 'Invalid response object from API: "" (HTTP response code was 500)', e.message
392
- end
393
-
394
- should "handle success response with empty body" do
395
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
396
- .to_return(body: "", status: 200)
397
-
398
- client = StripeClient.new
399
- e = assert_raises Stripe::APIError do
400
- client.execute_request(:post, "/v1/charges")
401
- end
402
-
403
- assert_equal 'Invalid response object from API: "" (HTTP response code was 200)', e.message
404
- end
405
-
406
- should "handle error response with unknown value" do
407
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
408
- .to_return(body: JSON.generate(bar: "foo"), status: 500)
409
-
410
- client = StripeClient.new
411
- e = assert_raises Stripe::APIError do
412
- client.execute_request(:post, "/v1/charges")
413
- end
414
-
415
- assert_equal 'Invalid response object from API: "{\"bar\":\"foo\"}" (HTTP response code was 500)', e.message
416
- end
417
-
418
- should "raise IdempotencyError on 400 of type idempotency_error" do
419
- data = make_missing_id_error
420
- data[:error][:type] = "idempotency_error"
421
-
422
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
423
- .to_return(body: JSON.generate(data), status: 400)
424
- client = StripeClient.new
425
-
426
- e = assert_raises Stripe::IdempotencyError do
427
- client.execute_request(:post, "/v1/charges")
428
- end
429
- assert_equal(400, e.http_status)
430
- assert_equal(true, e.json_body.is_a?(Hash))
431
- end
432
-
433
- should "raise InvalidRequestError on other 400s" do
434
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
435
- .to_return(body: JSON.generate(make_missing_id_error), status: 400)
436
- client = StripeClient.new
437
- begin
438
- client.execute_request(:post, "/v1/charges")
439
- rescue Stripe::InvalidRequestError => e
440
- assert_equal(400, e.http_status)
441
- assert_equal(true, e.json_body.is_a?(Hash))
442
- end
443
- end
444
-
445
- should "raise AuthenticationError on 401" do
446
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
447
- .to_return(body: JSON.generate(make_missing_id_error), status: 401)
448
- client = StripeClient.new
449
- begin
450
- client.execute_request(:post, "/v1/charges")
451
- rescue Stripe::AuthenticationError => e
452
- assert_equal(401, e.http_status)
453
- assert_equal(true, e.json_body.is_a?(Hash))
454
- end
455
- end
456
-
457
- should "raise CardError on 402" do
458
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
459
- .to_return(body: JSON.generate(make_invalid_exp_year_error), status: 402)
460
- client = StripeClient.new
461
- begin
462
- client.execute_request(:post, "/v1/charges")
463
- rescue Stripe::CardError => e
464
- assert_equal(402, e.http_status)
465
- assert_equal(true, e.json_body.is_a?(Hash))
466
- assert_equal("invalid_expiry_year", e.code)
467
- assert_equal("exp_year", e.param)
468
- end
469
- end
470
-
471
- should "raise PermissionError on 403" do
472
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
473
- .to_return(body: JSON.generate(make_missing_id_error), status: 403)
474
- client = StripeClient.new
475
- begin
476
- client.execute_request(:post, "/v1/charges")
477
- rescue Stripe::PermissionError => e
478
- assert_equal(403, e.http_status)
479
- assert_equal(true, e.json_body.is_a?(Hash))
480
- end
481
- end
482
-
483
- should "raise InvalidRequestError on 404" do
484
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
485
- .to_return(body: JSON.generate(make_missing_id_error), status: 404)
486
- client = StripeClient.new
487
- begin
488
- client.execute_request(:post, "/v1/charges")
489
- rescue Stripe::InvalidRequestError => e
490
- assert_equal(404, e.http_status)
491
- assert_equal(true, e.json_body.is_a?(Hash))
492
- end
493
- end
494
-
495
- should "raise RateLimitError on 429" do
496
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
497
- .to_return(body: JSON.generate(make_rate_limit_error), status: 429)
498
- client = StripeClient.new
499
- begin
500
- client.execute_request(:post, "/v1/charges")
501
- rescue Stripe::RateLimitError => e
502
- assert_equal(429, e.http_status)
503
- assert_equal(true, e.json_body.is_a?(Hash))
504
- end
505
- end
506
-
507
- should "raise OAuth::InvalidRequestError when error is a string with value 'invalid_request'" do
508
- stub_request(:post, "#{Stripe.connect_base}/oauth/token")
509
- .to_return(body: JSON.generate(error: "invalid_request",
510
- error_description: "No grant type specified"), status: 400)
511
-
512
- client = StripeClient.new
513
- opts = { api_base: Stripe.connect_base }
514
- e = assert_raises Stripe::OAuth::InvalidRequestError do
515
- client.execute_request(:post, "/oauth/token", opts)
516
- end
517
-
518
- assert_equal(400, e.http_status)
519
- assert_equal("No grant type specified", e.message)
520
- end
521
-
522
- should "raise OAuth::InvalidGrantError when error is a string with value 'invalid_grant'" do
523
- stub_request(:post, "#{Stripe.connect_base}/oauth/token")
524
- .to_return(body: JSON.generate(error: "invalid_grant",
525
- error_description: "This authorization code has already been used. All tokens issued with this code have been revoked."), status: 400)
526
-
527
- client = StripeClient.new
528
- opts = { api_base: Stripe.connect_base }
529
- e = assert_raises Stripe::OAuth::InvalidGrantError do
530
- client.execute_request(:post, "/oauth/token", opts)
531
- end
532
-
533
- assert_equal(400, e.http_status)
534
- assert_equal("invalid_grant", e.code)
535
- assert_equal("This authorization code has already been used. All tokens issued with this code have been revoked.", e.message)
536
- end
537
-
538
- should "raise OAuth::InvalidClientError when error is a string with value 'invalid_client'" do
539
- stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize")
540
- .to_return(body: JSON.generate(error: "invalid_client",
541
- error_description: "This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist."), status: 401)
542
-
543
- client = StripeClient.new
544
- opts = { api_base: Stripe.connect_base }
545
- e = assert_raises Stripe::OAuth::InvalidClientError do
546
- client.execute_request(:post, "/oauth/deauthorize", opts)
547
- end
548
-
549
- assert_equal(401, e.http_status)
550
- assert_equal("invalid_client", e.code)
551
- assert_equal("This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist.", e.message)
552
- end
553
-
554
- should "raise Stripe::OAuthError on indeterminate OAuth error" do
555
- stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize")
556
- .to_return(body: JSON.generate(error: "new_code_not_recognized",
557
- error_description: "Something."), status: 401)
558
-
559
- client = StripeClient.new
560
- opts = { api_base: Stripe.connect_base }
561
- e = assert_raises Stripe::OAuth::OAuthError do
562
- client.execute_request(:post, "/oauth/deauthorize", opts)
563
- end
564
-
565
- assert_equal(401, e.http_status)
566
- assert_equal("new_code_not_recognized", e.code)
567
- assert_equal("Something.", e.message)
568
- end
569
- end
570
-
571
- context "idempotency keys" do
572
- setup do
573
- Stripe.stubs(:max_network_retries).returns(2)
574
- end
575
-
576
- should "not add an idempotency key to GET requests" do
577
- SecureRandom.expects(:uuid).times(0)
578
- stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123")
579
- .with do |req|
580
- req.headers["Idempotency-Key"].nil?
581
- end.to_return(body: JSON.generate(object: "charge"))
582
- client = StripeClient.new
583
- client.execute_request(:get, "/v1/charges/ch_123")
584
- end
585
-
586
- should "ensure there is always an idempotency_key on POST requests" do
587
- SecureRandom.expects(:uuid).at_least_once.returns("random_key")
588
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
589
- .with(headers: { "Idempotency-Key" => "random_key" })
590
- .to_return(body: JSON.generate(object: "charge"))
591
- client = StripeClient.new
592
- client.execute_request(:post, "/v1/charges")
593
- end
594
-
595
- should "ensure there is always an idempotency_key on DELETE requests" do
596
- SecureRandom.expects(:uuid).at_least_once.returns("random_key")
597
- stub_request(:delete, "#{Stripe.api_base}/v1/charges/ch_123")
598
- .with(headers: { "Idempotency-Key" => "random_key" })
599
- .to_return(body: JSON.generate(object: "charge"))
600
- client = StripeClient.new
601
- client.execute_request(:delete, "/v1/charges/ch_123")
602
- end
603
-
604
- should "not override a provided idempotency_key" do
605
- # Note that this expectation looks like `:idempotency_key` instead of
606
- # the header `Idempotency-Key` because it's user provided as seen
607
- # below. The ones injected by the library itself look like headers
608
- # (`Idempotency-Key`), but rest-client does allow this symbol
609
- # formatting and will properly override the system generated one as
610
- # expected.
611
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
612
- .with(headers: { "Idempotency-Key" => "provided_key" })
613
- .to_return(body: JSON.generate(object: "charge"))
614
-
615
- client = StripeClient.new
616
- client.execute_request(:post, "/v1/charges",
617
- headers: { idempotency_key: "provided_key" })
618
- end
619
- end
620
-
621
- context "retry logic" do
622
- setup do
623
- Stripe.stubs(:max_network_retries).returns(2)
624
- end
625
-
626
- should "retry failed requests and raise if error persists" do
627
- StripeClient.expects(:sleep_time).at_least_once.returns(0)
628
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
629
- .to_raise(Errno::ECONNREFUSED.new)
630
-
631
- client = StripeClient.new
632
- err = assert_raises Stripe::APIConnectionError do
633
- client.execute_request(:post, "/v1/charges")
634
- end
635
- assert_match(/Request was retried 2 times/, err.message)
636
- end
637
-
638
- should "retry failed requests and return successful response" do
639
- StripeClient.expects(:sleep_time).at_least_once.returns(0)
640
-
641
- i = 0
642
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
643
- .to_return do |_|
644
- if i < 2
645
- i += 1
646
- raise Errno::ECONNREFUSED
647
- else
648
- { body: JSON.generate("id" => "myid") }
649
- end
650
- end
651
-
652
- client = StripeClient.new
653
- client.execute_request(:post, "/v1/charges")
654
- end
655
- end
656
-
657
- context "params serialization" do
658
- should "allows empty strings in params" do
659
- client = StripeClient.new
660
- client.execute_request(:get, "/v1/invoices/upcoming", params: {
661
- customer: "cus_123",
662
- coupon: "",
663
- })
664
- assert_requested(
665
- :get,
666
- "#{Stripe.api_base}/v1/invoices/upcoming?",
667
- query: {
668
- customer: "cus_123",
669
- coupon: "",
670
- }
671
- )
672
- end
673
-
674
- should "filter nils in params" do
675
- client = StripeClient.new
676
- client.execute_request(:get, "/v1/invoices/upcoming", params: {
677
- customer: "cus_123",
678
- coupon: nil,
679
- })
680
- assert_requested(
681
- :get,
682
- "#{Stripe.api_base}/v1/invoices/upcoming?",
683
- query: {
684
- customer: "cus_123",
685
- }
686
- )
687
- end
688
-
689
- should "merge query parameters in URL and params" do
690
- client = StripeClient.new
691
- client.execute_request(:get, "/v1/invoices/upcoming?coupon=25OFF", params: {
692
- customer: "cus_123",
693
- })
694
- assert_requested(
695
- :get,
696
- "#{Stripe.api_base}/v1/invoices/upcoming?",
697
- query: {
698
- coupon: "25OFF",
699
- customer: "cus_123",
700
- }
701
- )
702
- end
703
-
704
- should "prefer query parameters in params when specified in URL as well" do
705
- client = StripeClient.new
706
- client.execute_request(:get, "/v1/invoices/upcoming?customer=cus_query", params: {
707
- customer: "cus_param",
708
- })
709
- assert_requested(
710
- :get,
711
- "#{Stripe.api_base}/v1/invoices/upcoming?",
712
- query: {
713
- customer: "cus_param",
714
- }
715
- )
716
- end
717
- end
718
- end
719
-
720
- context "#request" do
721
- should "return a result and response object" do
722
- stub_request(:post, "#{Stripe.api_base}/v1/charges")
723
- .to_return(body: JSON.generate(object: "charge"))
724
-
725
- client = StripeClient.new
726
- charge, resp = client.request { Charge.create }
727
-
728
- assert charge.is_a?(Charge)
729
- assert resp.is_a?(StripeResponse)
730
- assert_equal 200, resp.http_status
731
- end
732
-
733
- should "return the value of given block" do
734
- client = StripeClient.new
735
- ret, = client.request { 7 }
736
- assert_equal 7, ret
737
- end
738
-
739
- should "reset local thread state after a call" do
740
- begin
741
- Thread.current[:stripe_client] = :stripe_client
742
-
743
- client = StripeClient.new
744
- client.request {}
745
-
746
- assert_equal :stripe_client, Thread.current[:stripe_client]
747
- ensure
748
- Thread.current[:stripe_client] = nil
749
- end
750
- end
751
- end
752
-
753
- context "#telemetry" do
754
- teardown do
755
- # make sure to always set telemetry back to false
756
- # to not mutate global state
757
- Stripe.enable_telemetry = false
758
- end
759
-
760
- should "not send metrics if enable trace flag is not set" do
761
- Stripe.enable_telemetry = false
762
-
763
- trace_metrics_header = nil
764
- stub_request(:get, "#{Stripe.api_base}/v1/charges")
765
- .with do |req|
766
- trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
767
- false
768
- end.to_return(body: JSON.generate(object: "charge"))
769
-
770
- Stripe::Charge.list
771
- assert(trace_metrics_header.nil?)
772
-
773
- Stripe::Charge.list
774
- assert(trace_metrics_header.nil?)
775
- end
776
-
777
- should "send metrics if enabled telemetry is true" do
778
- Stripe.enable_telemetry = true
779
-
780
- trace_metrics_header = nil
781
- stub_request(:get, "#{Stripe.api_base}/v1/charges")
782
- .with do |req|
783
- trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
784
- false
785
- end.to_return(body: JSON.generate(object: "charge"))
786
-
787
- Stripe::Charge.list
788
- Stripe::Charge.list
789
-
790
- assert(!trace_metrics_header.nil?)
791
-
792
- trace_payload = JSON.parse(trace_metrics_header)
793
- assert(trace_payload["last_request_metrics"]["request_id"] == "req_123")
794
- assert(!trace_payload["last_request_metrics"]["request_duration_ms"].nil?)
795
- end
796
- end
797
- end
798
-
799
- class SystemProfilerTest < Test::Unit::TestCase
800
- context "#uname" do
801
- should "run without failure" do
802
- # Don't actually check the result because we try a variety of different
803
- # strategies that will have different results depending on where this
804
- # test and running. We're mostly making sure that no exception is thrown.
805
- _ = StripeClient::SystemProfiler.uname
806
- end
807
- end
808
-
809
- context "#uname_from_system" do
810
- should "run without failure" do
811
- # as above, just verify that an exception is not thrown
812
- _ = StripeClient::SystemProfiler.uname_from_system
813
- end
814
- end
815
-
816
- context "#uname_from_system_ver" do
817
- should "run without failure" do
818
- # as above, just verify that an exception is not thrown
819
- _ = StripeClient::SystemProfiler.uname_from_system_ver
820
- end
821
- end
822
- end
823
- end