bongloy 4.21.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +76 -0
  3. data/.editorconfig +10 -0
  4. data/.gitattributes +4 -0
  5. data/.github/ISSUE_TEMPLATE.md +5 -0
  6. data/.github/README.md +79 -0
  7. data/.github/pull.yml +5 -0
  8. data/.gitignore +8 -0
  9. data/.rubocop.yml +43 -0
  10. data/.rubocop_todo.yml +38 -0
  11. data/.travis.yml +43 -0
  12. data/.vscode/extensions.json +7 -0
  13. data/.vscode/settings.json +8 -0
  14. data/CHANGELOG.md +770 -0
  15. data/CONTRIBUTORS +3 -0
  16. data/Gemfile +39 -0
  17. data/History.txt +1 -0
  18. data/LICENSE +21 -0
  19. data/README.md +282 -0
  20. data/Rakefile +36 -0
  21. data/VERSION +1 -0
  22. data/bin/stripe-console +16 -0
  23. data/bongloy.gemspec +37 -0
  24. data/lib/bongloy.rb +7 -0
  25. data/lib/data/ca-certificates.crt +4043 -0
  26. data/lib/stripe.rb +208 -0
  27. data/lib/stripe/api_operations/create.rb +12 -0
  28. data/lib/stripe/api_operations/delete.rb +35 -0
  29. data/lib/stripe/api_operations/list.rb +30 -0
  30. data/lib/stripe/api_operations/nested_resource.rb +70 -0
  31. data/lib/stripe/api_operations/request.rb +53 -0
  32. data/lib/stripe/api_operations/save.rb +94 -0
  33. data/lib/stripe/api_resource.rb +107 -0
  34. data/lib/stripe/errors.rb +156 -0
  35. data/lib/stripe/list_object.rb +110 -0
  36. data/lib/stripe/oauth.rb +63 -0
  37. data/lib/stripe/object_types.rb +98 -0
  38. data/lib/stripe/resources.rb +79 -0
  39. data/lib/stripe/resources/account.rb +174 -0
  40. data/lib/stripe/resources/account_link.rb +9 -0
  41. data/lib/stripe/resources/alipay_account.rb +34 -0
  42. data/lib/stripe/resources/apple_pay_domain.rb +16 -0
  43. data/lib/stripe/resources/application_fee.rb +24 -0
  44. data/lib/stripe/resources/application_fee_refund.rb +30 -0
  45. data/lib/stripe/resources/balance.rb +7 -0
  46. data/lib/stripe/resources/balance_transaction.rb +13 -0
  47. data/lib/stripe/resources/bank_account.rb +42 -0
  48. data/lib/stripe/resources/bitcoin_receiver.rb +23 -0
  49. data/lib/stripe/resources/bitcoin_transaction.rb +15 -0
  50. data/lib/stripe/resources/capability.rb +33 -0
  51. data/lib/stripe/resources/card.rb +37 -0
  52. data/lib/stripe/resources/charge.rb +84 -0
  53. data/lib/stripe/resources/checkout/session.rb +11 -0
  54. data/lib/stripe/resources/country_spec.rb +9 -0
  55. data/lib/stripe/resources/coupon.rb +12 -0
  56. data/lib/stripe/resources/credit_note.rb +18 -0
  57. data/lib/stripe/resources/customer.rb +95 -0
  58. data/lib/stripe/resources/customer_balance_transaction.rb +30 -0
  59. data/lib/stripe/resources/discount.rb +7 -0
  60. data/lib/stripe/resources/dispute.rb +23 -0
  61. data/lib/stripe/resources/ephemeral_key.rb +19 -0
  62. data/lib/stripe/resources/event.rb +9 -0
  63. data/lib/stripe/resources/exchange_rate.rb +9 -0
  64. data/lib/stripe/resources/file.rb +44 -0
  65. data/lib/stripe/resources/file_link.rb +11 -0
  66. data/lib/stripe/resources/invoice.rb +48 -0
  67. data/lib/stripe/resources/invoice_item.rb +12 -0
  68. data/lib/stripe/resources/invoice_line_item.rb +7 -0
  69. data/lib/stripe/resources/issuer_fraud_record.rb +9 -0
  70. data/lib/stripe/resources/issuing/authorization.rb +25 -0
  71. data/lib/stripe/resources/issuing/card.rb +20 -0
  72. data/lib/stripe/resources/issuing/card_details.rb +9 -0
  73. data/lib/stripe/resources/issuing/cardholder.rb +13 -0
  74. data/lib/stripe/resources/issuing/dispute.rb +13 -0
  75. data/lib/stripe/resources/issuing/transaction.rb +12 -0
  76. data/lib/stripe/resources/login_link.rb +14 -0
  77. data/lib/stripe/resources/order.rb +32 -0
  78. data/lib/stripe/resources/order_return.rb +9 -0
  79. data/lib/stripe/resources/payment_intent.rb +30 -0
  80. data/lib/stripe/resources/payment_method.rb +24 -0
  81. data/lib/stripe/resources/payout.rb +24 -0
  82. data/lib/stripe/resources/person.rb +31 -0
  83. data/lib/stripe/resources/plan.rb +12 -0
  84. data/lib/stripe/resources/product.rb +12 -0
  85. data/lib/stripe/resources/radar/early_fraud_warning.rb +11 -0
  86. data/lib/stripe/resources/radar/value_list.rb +14 -0
  87. data/lib/stripe/resources/radar/value_list_item.rb +13 -0
  88. data/lib/stripe/resources/recipient.rb +17 -0
  89. data/lib/stripe/resources/recipient_transfer.rb +7 -0
  90. data/lib/stripe/resources/refund.rb +11 -0
  91. data/lib/stripe/resources/reporting/report_run.rb +12 -0
  92. data/lib/stripe/resources/reporting/report_type.rb +12 -0
  93. data/lib/stripe/resources/reversal.rb +29 -0
  94. data/lib/stripe/resources/review.rb +16 -0
  95. data/lib/stripe/resources/setup_intent.rb +24 -0
  96. data/lib/stripe/resources/sigma/scheduled_query_run.rb +15 -0
  97. data/lib/stripe/resources/sku.rb +12 -0
  98. data/lib/stripe/resources/source.rb +42 -0
  99. data/lib/stripe/resources/source_transaction.rb +7 -0
  100. data/lib/stripe/resources/subscription.rb +25 -0
  101. data/lib/stripe/resources/subscription_item.rb +17 -0
  102. data/lib/stripe/resources/subscription_schedule.rb +32 -0
  103. data/lib/stripe/resources/subscription_schedule_revision.rb +34 -0
  104. data/lib/stripe/resources/tax_id.rb +26 -0
  105. data/lib/stripe/resources/tax_rate.rb +11 -0
  106. data/lib/stripe/resources/terminal/connection_token.rb +11 -0
  107. data/lib/stripe/resources/terminal/location.rb +14 -0
  108. data/lib/stripe/resources/terminal/reader.rb +14 -0
  109. data/lib/stripe/resources/three_d_secure.rb +13 -0
  110. data/lib/stripe/resources/token.rb +9 -0
  111. data/lib/stripe/resources/topup.rb +18 -0
  112. data/lib/stripe/resources/transfer.rb +27 -0
  113. data/lib/stripe/resources/usage_record.rb +23 -0
  114. data/lib/stripe/resources/usage_record_summary.rb +7 -0
  115. data/lib/stripe/resources/webhook_endpoint.rb +12 -0
  116. data/lib/stripe/singleton_api_resource.rb +26 -0
  117. data/lib/stripe/stripe_client.rb +686 -0
  118. data/lib/stripe/stripe_object.rb +583 -0
  119. data/lib/stripe/stripe_response.rb +50 -0
  120. data/lib/stripe/util.rb +336 -0
  121. data/lib/stripe/version.rb +5 -0
  122. data/lib/stripe/webhook.rb +90 -0
  123. data/stripe.gemspec +37 -0
  124. data/test/api_stub_helpers.rb +1 -0
  125. data/test/openapi/README.md +9 -0
  126. data/test/stripe/account_link_test.rb +18 -0
  127. data/test/stripe/account_test.rb +428 -0
  128. data/test/stripe/alipay_account_test.rb +37 -0
  129. data/test/stripe/api_operations_test.rb +80 -0
  130. data/test/stripe/api_resource_test.rb +544 -0
  131. data/test/stripe/apple_pay_domain_test.rb +46 -0
  132. data/test/stripe/application_fee_refund_test.rb +37 -0
  133. data/test/stripe/application_fee_test.rb +58 -0
  134. data/test/stripe/balance_test.rb +13 -0
  135. data/test/stripe/bank_account_test.rb +36 -0
  136. data/test/stripe/capability_test.rb +45 -0
  137. data/test/stripe/charge_test.rb +80 -0
  138. data/test/stripe/checkout/session_test.rb +41 -0
  139. data/test/stripe/country_spec_test.rb +20 -0
  140. data/test/stripe/coupon_test.rb +61 -0
  141. data/test/stripe/credit_note_test.rb +61 -0
  142. data/test/stripe/customer_balance_transaction_test.rb +37 -0
  143. data/test/stripe/customer_card_test.rb +42 -0
  144. data/test/stripe/customer_test.rb +269 -0
  145. data/test/stripe/dispute_test.rb +51 -0
  146. data/test/stripe/ephemeral_key_test.rb +93 -0
  147. data/test/stripe/errors_test.rb +20 -0
  148. data/test/stripe/exchange_rate_test.rb +20 -0
  149. data/test/stripe/file_link_test.rb +41 -0
  150. data/test/stripe/file_test.rb +97 -0
  151. data/test/stripe/file_upload_test.rb +79 -0
  152. data/test/stripe/invoice_item_test.rb +66 -0
  153. data/test/stripe/invoice_line_item_test.rb +8 -0
  154. data/test/stripe/invoice_test.rb +213 -0
  155. data/test/stripe/issuer_fraud_record_test.rb +20 -0
  156. data/test/stripe/issuing/authorization_test.rb +72 -0
  157. data/test/stripe/issuing/card_test.rb +62 -0
  158. data/test/stripe/issuing/cardholder_test.rb +53 -0
  159. data/test/stripe/issuing/dispute_test.rb +45 -0
  160. data/test/stripe/issuing/transaction_test.rb +48 -0
  161. data/test/stripe/list_object_test.rb +156 -0
  162. data/test/stripe/login_link_test.rb +37 -0
  163. data/test/stripe/oauth_test.rb +88 -0
  164. data/test/stripe/order_return_test.rb +21 -0
  165. data/test/stripe/order_test.rb +82 -0
  166. data/test/stripe/payment_intent_test.rb +107 -0
  167. data/test/stripe/payment_method_test.rb +84 -0
  168. data/test/stripe/payout_test.rb +57 -0
  169. data/test/stripe/person_test.rb +46 -0
  170. data/test/stripe/plan_test.rb +98 -0
  171. data/test/stripe/product_test.rb +59 -0
  172. data/test/stripe/radar/early_fraud_warning_test.rb +22 -0
  173. data/test/stripe/radar/value_list_item_test.rb +48 -0
  174. data/test/stripe/radar/value_list_test.rb +61 -0
  175. data/test/stripe/recipient_test.rb +62 -0
  176. data/test/stripe/refund_test.rb +39 -0
  177. data/test/stripe/reporting/report_run_test.rb +33 -0
  178. data/test/stripe/reporting/report_type_test.rb +22 -0
  179. data/test/stripe/reversal_test.rb +43 -0
  180. data/test/stripe/review_test.rb +27 -0
  181. data/test/stripe/setup_intent_test.rb +84 -0
  182. data/test/stripe/sigma/scheduled_query_run_test.rb +22 -0
  183. data/test/stripe/sku_test.rb +60 -0
  184. data/test/stripe/source_test.rb +99 -0
  185. data/test/stripe/source_transaction_test.rb +19 -0
  186. data/test/stripe/stripe_client_test.rb +842 -0
  187. data/test/stripe/stripe_object_test.rb +525 -0
  188. data/test/stripe/stripe_response_test.rb +49 -0
  189. data/test/stripe/subscription_item_test.rb +63 -0
  190. data/test/stripe/subscription_schedule_revision_test.rb +37 -0
  191. data/test/stripe/subscription_schedule_test.rb +116 -0
  192. data/test/stripe/subscription_test.rb +80 -0
  193. data/test/stripe/tax_id_test.rb +31 -0
  194. data/test/stripe/tax_rate_test.rb +43 -0
  195. data/test/stripe/terminal/connection_token_test.rb +16 -0
  196. data/test/stripe/terminal/location_test.rb +68 -0
  197. data/test/stripe/terminal/reader_test.rb +62 -0
  198. data/test/stripe/three_d_secure_test.rb +23 -0
  199. data/test/stripe/topup_test.rb +62 -0
  200. data/test/stripe/transfer_test.rb +88 -0
  201. data/test/stripe/usage_record_summary_test.rb +19 -0
  202. data/test/stripe/usage_record_test.rb +28 -0
  203. data/test/stripe/util_test.rb +402 -0
  204. data/test/stripe/webhook_endpoint_test.rb +59 -0
  205. data/test/stripe/webhook_test.rb +96 -0
  206. data/test/stripe_mock.rb +77 -0
  207. data/test/stripe_test.rb +63 -0
  208. data/test/test_data.rb +61 -0
  209. data/test/test_helper.rb +71 -0
  210. metadata +372 -0
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ module Reporting
7
+ class ReportTypeTest < Test::Unit::TestCase
8
+ should "be listable" do
9
+ report_types = Stripe::Reporting::ReportType.list
10
+ assert_requested :get, "#{Stripe.api_base}/v1/reporting/report_types"
11
+ assert report_types.data.is_a?(Array)
12
+ assert report_types.data[0].is_a?(Stripe::Reporting::ReportType)
13
+ end
14
+
15
+ should "be retrievable" do
16
+ report_type = Stripe::Reporting::ReportType.retrieve("activity.summary.1")
17
+ assert_requested :get, "#{Stripe.api_base}/v1/reporting/report_types/activity.summary.1"
18
+ assert report_type.is_a?(Stripe::Reporting::ReportType)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class ReversalTest < Test::Unit::TestCase
7
+ setup do
8
+ @transfer = Stripe::Transfer.retrieve("tr_123")
9
+ end
10
+
11
+ should "be listable" do
12
+ reversals = @transfer.reversals.list
13
+ assert_requested :get,
14
+ "#{Stripe.api_base}/v1/transfers/#{@transfer.id}/reversals"
15
+ assert reversals.data.is_a?(Array)
16
+ assert reversals.data[0].is_a?(Stripe::Reversal)
17
+ end
18
+
19
+ should "be retrievable" do
20
+ reversal = @transfer.reversals.retrieve("trr_123")
21
+ assert_requested :get,
22
+ "#{Stripe.api_base}/v1/transfers/#{@transfer.id}/reversals/trr_123"
23
+ assert reversal.is_a?(Stripe::Reversal)
24
+ end
25
+
26
+ should "be creatable" do
27
+ reversal = @transfer.reversals.create(
28
+ amount: 100
29
+ )
30
+ assert_requested :post,
31
+ "#{Stripe.api_base}/v1/transfers/#{@transfer.id}/reversals"
32
+ assert reversal.is_a?(Stripe::Reversal)
33
+ end
34
+
35
+ should "be saveable" do
36
+ reversal = @transfer.reversals.retrieve("trr_123")
37
+ reversal.metadata["key"] = "value"
38
+ reversal.save
39
+ assert_requested :post,
40
+ "#{Stripe.api_base}/v1/transfers/#{reversal.transfer}/reversals/#{reversal.id}"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class ReviewTest < Test::Unit::TestCase
7
+ should "be listable" do
8
+ reviews = Stripe::Review.list
9
+ assert_requested :get, "#{Stripe.api_base}/v1/reviews"
10
+ assert reviews.data.is_a?(Array)
11
+ assert reviews.first.is_a?(Stripe::Review)
12
+ end
13
+
14
+ should "be retrievable" do
15
+ review = Stripe::Review.retrieve("prv_123")
16
+ assert_requested :get, "#{Stripe.api_base}/v1/reviews/prv_123"
17
+ assert review.is_a?(Stripe::Review)
18
+ end
19
+
20
+ should "be approvable" do
21
+ review = Stripe::Review.retrieve("prv_123")
22
+ review.approve
23
+ assert_requested :post, "#{Stripe.api_base}/v1/reviews/prv_123/approve"
24
+ assert review.is_a?(Stripe::Review)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class SetupIntentTest < Test::Unit::TestCase
7
+ TEST_RESOURCE_ID = "seti_123".freeze
8
+
9
+ should "be listable" do
10
+ setup_intents = Stripe::SetupIntent.list
11
+ assert_requested :get, "#{Stripe.api_base}/v1/setup_intents"
12
+ assert setup_intents.data.is_a?(Array)
13
+ assert setup_intents.data[0].is_a?(Stripe::SetupIntent)
14
+ end
15
+
16
+ should "be retrievable" do
17
+ setup_intent = Stripe::SetupIntent.retrieve("seti_123")
18
+ assert_requested :get, "#{Stripe.api_base}/v1/setup_intents/seti_123"
19
+ assert setup_intent.is_a?(Stripe::SetupIntent)
20
+ end
21
+
22
+ should "be creatable" do
23
+ setup_intent = Stripe::SetupIntent.create(
24
+ payment_method_types: ["card"]
25
+ )
26
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents"
27
+ assert setup_intent.is_a?(Stripe::SetupIntent)
28
+ end
29
+
30
+ should "be saveable" do
31
+ setup_intent = Stripe::SetupIntent.construct_from(id: "seti_123", object: "setup_intent", metadata: {})
32
+ setup_intent.metadata["key"] = "value"
33
+ setup_intent.save
34
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/#{setup_intent.id}"
35
+ end
36
+
37
+ should "be updateable" do
38
+ setup_intent = Stripe::SetupIntent.update("seti_123", metadata: { foo: "bar" })
39
+
40
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123"
41
+ assert setup_intent.is_a?(Stripe::SetupIntent)
42
+ end
43
+
44
+ context "#cancel" do
45
+ should "cancel a setup_intent" do
46
+ setup_intent = Stripe::SetupIntent.construct_from(id: "seti_123", object: "setup_intent")
47
+ setup_intent = setup_intent.cancel
48
+
49
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/cancel"
50
+ assert setup_intent.is_a?(Stripe::SetupIntent)
51
+ end
52
+ end
53
+
54
+ context ".cancel" do
55
+ should "cancel a setup_intent" do
56
+ setup_intent = Stripe::SetupIntent.cancel("seti_123")
57
+
58
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/cancel"
59
+ assert setup_intent.is_a?(Stripe::SetupIntent)
60
+ end
61
+ end
62
+
63
+ context "#confirm" do
64
+ should "confirm a setup_intent" do
65
+ setup_intent = Stripe::SetupIntent.construct_from(id: "seti_123", object: "setup_intent")
66
+ setup_intent = setup_intent.confirm(
67
+ payment_method: "pm_123"
68
+ )
69
+
70
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/confirm"
71
+ assert setup_intent.is_a?(Stripe::SetupIntent)
72
+ end
73
+ end
74
+
75
+ context ".confirm" do
76
+ should "confirm a setup_intent" do
77
+ setup_intent = Stripe::SetupIntent.confirm("seti_123", payment_method: "pm_123")
78
+
79
+ assert_requested :post, "#{Stripe.api_base}/v1/setup_intents/seti_123/confirm"
80
+ assert setup_intent.is_a?(Stripe::SetupIntent)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ module Issuing
7
+ class ScheduledQueryRunTest < Test::Unit::TestCase
8
+ should "be listable" do
9
+ runs = Stripe::Sigma::ScheduledQueryRun.list
10
+ assert_requested :get, "#{Stripe.api_base}/v1/sigma/scheduled_query_runs"
11
+ assert runs.data.is_a?(Array)
12
+ assert runs.data[0].is_a?(Stripe::Sigma::ScheduledQueryRun)
13
+ end
14
+
15
+ should "be retrievable" do
16
+ run = Stripe::Sigma::ScheduledQueryRun.retrieve("sqr_123")
17
+ assert_requested :get, "#{Stripe.api_base}/v1/sigma/scheduled_query_runs/sqr_123"
18
+ assert run.is_a?(Stripe::Sigma::ScheduledQueryRun)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class SKUTest < Test::Unit::TestCase
7
+ should "be listable" do
8
+ skus = Stripe::SKU.list
9
+ assert_requested :get, "#{Stripe.api_base}/v1/skus"
10
+ assert skus.data.is_a?(Array)
11
+ assert skus.data[0].is_a?(Stripe::SKU)
12
+ end
13
+
14
+ should "be retrievable" do
15
+ sku = Stripe::SKU.retrieve("sku_123")
16
+ assert_requested :get, "#{Stripe.api_base}/v1/skus/sku_123"
17
+ assert sku.is_a?(Stripe::SKU)
18
+ end
19
+
20
+ should "be creatable" do
21
+ _ = Stripe::SKU.create(
22
+ currency: "USD",
23
+ inventory: { type: "finite", quantity: 500 },
24
+ price: 100,
25
+ product: "prod_123"
26
+ )
27
+ assert_requested :post, "#{Stripe.api_base}/v1/skus"
28
+ end
29
+
30
+ should "be saveable" do
31
+ sku = Stripe::SKU.retrieve("sku_123")
32
+ sku.metadata["key"] = "value"
33
+ sku.save
34
+ assert_requested :post, "#{Stripe.api_base}/v1/skus/#{sku.id}"
35
+ end
36
+
37
+ should "be updateable" do
38
+ sku = Stripe::SKU.update("sku_123", metadata: { foo: "bar" })
39
+ assert_requested :post, "#{Stripe.api_base}/v1/skus/sku_123"
40
+ assert sku.is_a?(Stripe::SKU)
41
+ end
42
+
43
+ context "#delete" do
44
+ should "be deletable" do
45
+ sku = Stripe::SKU.retrieve("sku_123")
46
+ sku = sku.delete
47
+ assert_requested :delete, "#{Stripe.api_base}/v1/skus/#{sku.id}"
48
+ assert sku.is_a?(Stripe::SKU)
49
+ end
50
+ end
51
+
52
+ context ".delete" do
53
+ should "be deletable" do
54
+ sku = Stripe::SKU.delete("sku_123")
55
+ assert_requested :delete, "#{Stripe.api_base}/v1/skus/sku_123"
56
+ assert sku.is_a?(Stripe::SKU)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class SourceTest < Test::Unit::TestCase
7
+ should "be retrievable" do
8
+ source = Stripe::Source.retrieve("src_123")
9
+ assert_requested :get, "#{Stripe.api_base}/v1/sources/src_123"
10
+ assert source.is_a?(Stripe::Source)
11
+ end
12
+
13
+ should "be creatable" do
14
+ source = Stripe::Source.create(
15
+ type: "card",
16
+ token: "tok_123"
17
+ )
18
+ assert_requested :post, "#{Stripe.api_base}/v1/sources"
19
+ assert source.is_a?(Stripe::Source)
20
+ end
21
+
22
+ should "be saveable" do
23
+ source = Stripe::Source.retrieve("src_123")
24
+ source.metadata["key"] = "value"
25
+ source.save
26
+ assert_requested :post, "#{Stripe.api_base}/v1/sources/#{source.id}"
27
+ end
28
+
29
+ should "be updateable" do
30
+ source = Stripe::Source.update("src_123", metadata: { foo: "bar" })
31
+ assert_requested :post, "#{Stripe.api_base}/v1/sources/src_123"
32
+ assert source.is_a?(Stripe::Source)
33
+ end
34
+
35
+ context "#detach" do
36
+ should "not be deletable when unattached" do
37
+ source = Stripe::Source.retrieve("src_123")
38
+
39
+ assert_raises NotImplementedError do
40
+ source.detach
41
+ end
42
+ end
43
+
44
+ should "be deletable when attached to a customer" do
45
+ source = Stripe::Source.construct_from(customer: "cus_123",
46
+ id: "src_123",
47
+ object: "source")
48
+ source = source.detach
49
+ assert_requested :delete, "#{Stripe.api_base}/v1/customers/cus_123/sources/src_123"
50
+ assert source.is_a?(Stripe::Source)
51
+ end
52
+ end
53
+
54
+ context "#delete" do
55
+ should "warn that #delete is deprecated" do
56
+ old_stderr = $stderr
57
+ $stderr = StringIO.new
58
+ begin
59
+ source = Stripe::Source.construct_from(customer: "cus_123",
60
+ id: "src_123",
61
+ object: "source")
62
+ source.delete
63
+ message = "NOTE: Stripe::Source#delete is " \
64
+ "deprecated; use #detach instead"
65
+ assert_match Regexp.new(message), $stderr.string
66
+ ensure
67
+ $stderr = old_stderr
68
+ end
69
+ end
70
+ end
71
+
72
+ should "not be listable" do
73
+ assert_raises NoMethodError do
74
+ Stripe::Source.list
75
+ end
76
+ end
77
+
78
+ context "#verify" do
79
+ should "verify the source" do
80
+ source = Stripe::Source.retrieve("src_123")
81
+ source = source.verify(values: [1, 2])
82
+ assert_requested :post,
83
+ "#{Stripe.api_base}/v1/sources/#{source.id}/verify",
84
+ body: { values: [1, 2] }
85
+ assert source.is_a?(Stripe::Source)
86
+ end
87
+ end
88
+
89
+ context ".verify" do
90
+ should "verify the source" do
91
+ source = Stripe::Source.verify("src_123", values: [1, 2])
92
+ assert_requested :post,
93
+ "#{Stripe.api_base}/v1/sources/src_123/verify",
94
+ body: { values: [1, 2] }
95
+ assert source.is_a?(Stripe::Source)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
4
+
5
+ module Stripe
6
+ class SourceTransactionTest < Test::Unit::TestCase
7
+ setup do
8
+ @source = Stripe::Source.retrieve("src_123")
9
+ end
10
+
11
+ should "be listable" do
12
+ transactions = @source.source_transactions
13
+
14
+ assert_requested :get, "#{Stripe.api_base}/v1/sources/#{@source.id}/source_transactions"
15
+ assert transactions.data.is_a?(Array)
16
+ assert transactions.first.is_a?(Stripe::SourceTransaction)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,842 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path("../test_helper", __dir__)
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 "#proxy" do
754
+ should "run the request through the proxy" do
755
+ begin
756
+ Thread.current[:stripe_client_default_conn] = nil
757
+
758
+ Stripe.proxy = "http://localhost:8080"
759
+
760
+ client = StripeClient.new
761
+ client.request {}
762
+
763
+ assert_equal "http://localhost:8080", Stripe::StripeClient.default_conn.proxy.uri.to_s
764
+ ensure
765
+ Stripe.proxy = nil
766
+
767
+ Thread.current[:stripe_client_default_conn] = nil
768
+ end
769
+ end
770
+ end
771
+
772
+ context "#telemetry" do
773
+ teardown do
774
+ # make sure to always set telemetry back to false
775
+ # to not mutate global state
776
+ Stripe.enable_telemetry = false
777
+ end
778
+
779
+ should "not send metrics if enable trace flag is not set" do
780
+ Stripe.enable_telemetry = false
781
+
782
+ trace_metrics_header = nil
783
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
784
+ .with do |req|
785
+ trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
786
+ false
787
+ end.to_return(body: JSON.generate(object: "charge"))
788
+
789
+ Stripe::Charge.list
790
+ assert(trace_metrics_header.nil?)
791
+
792
+ Stripe::Charge.list
793
+ assert(trace_metrics_header.nil?)
794
+ end
795
+
796
+ should "send metrics if enabled telemetry is true" do
797
+ Stripe.enable_telemetry = true
798
+
799
+ trace_metrics_header = nil
800
+ stub_request(:get, "#{Stripe.api_base}/v1/charges")
801
+ .with do |req|
802
+ trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
803
+ false
804
+ end.to_return(body: JSON.generate(object: "charge"))
805
+
806
+ Stripe::Charge.list
807
+ Stripe::Charge.list
808
+
809
+ assert(!trace_metrics_header.nil?)
810
+
811
+ trace_payload = JSON.parse(trace_metrics_header)
812
+ assert(trace_payload["last_request_metrics"]["request_id"] == "req_123")
813
+ assert(!trace_payload["last_request_metrics"]["request_duration_ms"].nil?)
814
+ end
815
+ end
816
+ end
817
+
818
+ class SystemProfilerTest < Test::Unit::TestCase
819
+ context "#uname" do
820
+ should "run without failure" do
821
+ # Don't actually check the result because we try a variety of different
822
+ # strategies that will have different results depending on where this
823
+ # test and running. We're mostly making sure that no exception is thrown.
824
+ _ = StripeClient::SystemProfiler.uname
825
+ end
826
+ end
827
+
828
+ context "#uname_from_system" do
829
+ should "run without failure" do
830
+ # as above, just verify that an exception is not thrown
831
+ _ = StripeClient::SystemProfiler.uname_from_system
832
+ end
833
+ end
834
+
835
+ context "#uname_from_system_ver" do
836
+ should "run without failure" do
837
+ # as above, just verify that an exception is not thrown
838
+ _ = StripeClient::SystemProfiler.uname_from_system_ver
839
+ end
840
+ end
841
+ end
842
+ end