stripe 4.9.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|