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