stripe 4.20.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -4
- data/.rubocop_todo.yml +10 -9
- data/.travis.yml +2 -6
- data/CHANGELOG.md +52 -1
- data/Gemfile +2 -12
- data/README.md +10 -10
- data/Rakefile +8 -7
- data/VERSION +1 -1
- data/lib/stripe/api_operations/list.rb +0 -6
- data/lib/stripe/api_resource.rb +16 -0
- data/lib/stripe/connection_manager.rb +131 -0
- data/lib/stripe/error_object.rb +94 -0
- data/lib/stripe/errors.rb +15 -2
- data/lib/stripe/list_object.rb +2 -1
- data/lib/stripe/multipart_encoder.rb +131 -0
- data/lib/stripe/object_types.rb +1 -4
- data/lib/stripe/resources/account.rb +7 -7
- data/lib/stripe/resources/account_link.rb +1 -1
- data/lib/stripe/resources/alipay_account.rb +1 -1
- data/lib/stripe/resources/apple_pay_domain.rb +1 -1
- data/lib/stripe/resources/application_fee.rb +1 -12
- data/lib/stripe/resources/application_fee_refund.rb +1 -1
- data/lib/stripe/resources/balance.rb +1 -1
- data/lib/stripe/resources/balance_transaction.rb +1 -5
- data/lib/stripe/resources/bank_account.rb +1 -1
- data/lib/stripe/resources/bitcoin_receiver.rb +1 -1
- data/lib/stripe/resources/bitcoin_transaction.rb +1 -1
- data/lib/stripe/resources/capability.rb +1 -1
- data/lib/stripe/resources/card.rb +1 -1
- data/lib/stripe/resources/charge.rb +7 -69
- data/lib/stripe/resources/checkout/session.rb +1 -1
- data/lib/stripe/resources/country_spec.rb +1 -1
- data/lib/stripe/resources/coupon.rb +1 -1
- data/lib/stripe/resources/credit_note.rb +7 -3
- data/lib/stripe/resources/customer.rb +5 -66
- data/lib/stripe/resources/customer_balance_transaction.rb +1 -1
- data/lib/stripe/resources/discount.rb +1 -1
- data/lib/stripe/resources/dispute.rb +7 -9
- data/lib/stripe/resources/ephemeral_key.rb +1 -1
- data/lib/stripe/resources/event.rb +1 -1
- data/lib/stripe/resources/exchange_rate.rb +1 -1
- data/lib/stripe/resources/file.rb +3 -13
- data/lib/stripe/resources/file_link.rb +1 -1
- data/lib/stripe/resources/invoice.rb +36 -11
- data/lib/stripe/resources/invoice_item.rb +1 -1
- data/lib/stripe/resources/invoice_line_item.rb +1 -1
- data/lib/stripe/resources/issuing/authorization.rb +13 -5
- data/lib/stripe/resources/issuing/card.rb +7 -3
- data/lib/stripe/resources/issuing/card_details.rb +1 -1
- data/lib/stripe/resources/issuing/cardholder.rb +1 -1
- data/lib/stripe/resources/issuing/dispute.rb +1 -1
- data/lib/stripe/resources/issuing/transaction.rb +1 -1
- data/lib/stripe/resources/login_link.rb +1 -1
- data/lib/stripe/resources/order.rb +13 -13
- data/lib/stripe/resources/order_return.rb +1 -1
- data/lib/stripe/resources/payment_intent.rb +19 -7
- data/lib/stripe/resources/payment_method.rb +13 -5
- data/lib/stripe/resources/payout.rb +7 -9
- data/lib/stripe/resources/person.rb +1 -1
- data/lib/stripe/resources/plan.rb +1 -1
- data/lib/stripe/resources/product.rb +1 -1
- data/lib/stripe/resources/radar/early_fraud_warning.rb +1 -1
- data/lib/stripe/resources/radar/value_list.rb +1 -1
- data/lib/stripe/resources/radar/value_list_item.rb +1 -1
- data/lib/stripe/resources/recipient.rb +1 -5
- data/lib/stripe/resources/recipient_transfer.rb +1 -1
- data/lib/stripe/resources/refund.rb +1 -1
- data/lib/stripe/resources/reporting/report_run.rb +1 -1
- data/lib/stripe/resources/reporting/report_type.rb +1 -1
- data/lib/stripe/resources/reversal.rb +1 -1
- data/lib/stripe/resources/review.rb +7 -3
- data/lib/stripe/resources/setup_intent.rb +32 -0
- data/lib/stripe/resources/sigma/scheduled_query_run.rb +1 -1
- data/lib/stripe/resources/sku.rb +1 -1
- data/lib/stripe/resources/source.rb +7 -9
- data/lib/stripe/resources/source_transaction.rb +1 -1
- data/lib/stripe/resources/subscription.rb +9 -9
- data/lib/stripe/resources/subscription_item.rb +4 -1
- data/lib/stripe/resources/subscription_schedule.rb +13 -13
- data/lib/stripe/resources/tax_id.rb +1 -1
- data/lib/stripe/resources/tax_rate.rb +1 -1
- data/lib/stripe/resources/terminal/connection_token.rb +1 -1
- data/lib/stripe/resources/terminal/location.rb +1 -1
- data/lib/stripe/resources/terminal/reader.rb +1 -1
- data/lib/stripe/resources/three_d_secure.rb +1 -1
- data/lib/stripe/resources/token.rb +1 -1
- data/lib/stripe/resources/topup.rb +7 -3
- data/lib/stripe/resources/transfer.rb +7 -8
- data/lib/stripe/resources/usage_record.rb +1 -17
- data/lib/stripe/resources/usage_record_summary.rb +1 -1
- data/lib/stripe/resources/webhook_endpoint.rb +1 -1
- data/lib/stripe/resources.rb +1 -2
- data/lib/stripe/stripe_client.rb +281 -183
- data/lib/stripe/stripe_object.rb +4 -23
- data/lib/stripe/stripe_response.rb +53 -21
- data/lib/stripe/util.rb +14 -11
- data/lib/stripe/version.rb +1 -1
- data/lib/stripe/webhook.rb +1 -1
- data/lib/stripe.rb +56 -15
- data/stripe.gemspec +10 -3
- data/test/stripe/account_test.rb +0 -16
- data/test/stripe/api_operations_test.rb +2 -2
- data/test/stripe/api_resource_test.rb +98 -8
- data/test/stripe/balance_transaction_test.rb +20 -0
- data/test/stripe/charge_test.rb +0 -16
- data/test/stripe/connection_manager_test.rb +138 -0
- data/test/stripe/customer_test.rb +1 -44
- data/test/stripe/errors_test.rb +29 -8
- data/test/stripe/file_test.rb +0 -10
- data/test/stripe/invoice_test.rb +17 -1
- data/test/stripe/list_object_test.rb +0 -16
- data/test/stripe/login_link_test.rb +1 -1
- data/test/stripe/multipart_encoder_test.rb +130 -0
- data/test/stripe/payment_intent_test.rb +2 -2
- data/test/stripe/setup_intent_test.rb +84 -0
- data/test/stripe/source_test.rb +0 -18
- data/test/stripe/stripe_client_test.rb +214 -29
- data/test/stripe/stripe_object_test.rb +7 -35
- data/test/stripe/stripe_response_test.rb +70 -24
- data/test/stripe/subscription_item_test.rb +12 -0
- data/test/stripe/subscription_schedule_test.rb +0 -34
- data/test/stripe/subscription_test.rb +2 -2
- data/test/stripe/webhook_test.rb +2 -2
- data/test/stripe_mock.rb +4 -3
- data/test/stripe_test.rb +0 -13
- data/test/test_helper.rb +10 -5
- metadata +23 -43
- data/lib/stripe/resources/issuer_fraud_record.rb +0 -9
- data/lib/stripe/resources/subscription_schedule_revision.rb +0 -34
- data/test/stripe/file_upload_test.rb +0 -79
- data/test/stripe/issuer_fraud_record_test.rb +0 -20
- data/test/stripe/subscription_schedule_revision_test.rb +0 -37
- data/test/stripe/usage_record_test.rb +0 -28
@@ -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,54 @@ 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)
|
57
123
|
end
|
58
124
|
|
59
|
-
should "retry on a
|
60
|
-
assert StripeClient.should_retry?(
|
125
|
+
should "retry on a 500 Internal Server Error when non-POST" do
|
126
|
+
assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500),
|
127
|
+
method: :get, num_retries: 0)
|
61
128
|
end
|
62
129
|
|
63
|
-
should "retry on a
|
64
|
-
|
65
|
-
|
66
|
-
assert StripeClient.should_retry?(e, 0)
|
130
|
+
should "retry on a 503 Service Unavailable" do
|
131
|
+
assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 503),
|
132
|
+
method: :post, num_retries: 0)
|
67
133
|
end
|
68
134
|
|
69
135
|
should "not retry at maximum count" do
|
70
|
-
refute StripeClient.should_retry?(RuntimeError.new,
|
136
|
+
refute StripeClient.should_retry?(RuntimeError.new,
|
137
|
+
method: :post, num_retries: Stripe.max_network_retries)
|
71
138
|
end
|
72
139
|
|
73
140
|
should "not retry on a certificate validation error" do
|
74
|
-
refute StripeClient.should_retry?(
|
141
|
+
refute StripeClient.should_retry?(OpenSSL::SSL::SSLError.new,
|
142
|
+
method: :post, num_retries: 0)
|
143
|
+
end
|
144
|
+
|
145
|
+
should "not retry on a 500 Internal Server Error when POST" do
|
146
|
+
refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500),
|
147
|
+
method: :post, num_retries: 0)
|
75
148
|
end
|
76
149
|
end
|
77
150
|
|
@@ -115,15 +188,16 @@ module Stripe
|
|
115
188
|
end
|
116
189
|
|
117
190
|
context "#initialize" do
|
118
|
-
should "set Stripe.
|
191
|
+
should "set Stripe.default_connection_manager" do
|
119
192
|
client = StripeClient.new
|
120
|
-
assert_equal StripeClient.
|
193
|
+
assert_equal StripeClient.default_connection_manager,
|
194
|
+
client.connection_manager
|
121
195
|
end
|
122
196
|
|
123
197
|
should "set a different connection if one was specified" do
|
124
|
-
|
125
|
-
client = StripeClient.new(
|
126
|
-
assert_equal
|
198
|
+
connection_manager = ConnectionManager.new
|
199
|
+
client = StripeClient.new(connection_manager)
|
200
|
+
assert_equal connection_manager, client.connection_manager
|
127
201
|
end
|
128
202
|
end
|
129
203
|
|
@@ -178,7 +252,7 @@ module Stripe
|
|
178
252
|
Util.expects(:log_debug).with("Request details",
|
179
253
|
body: "",
|
180
254
|
idempotency_key: "abc",
|
181
|
-
|
255
|
+
query: nil)
|
182
256
|
|
183
257
|
Util.expects(:log_info).with("Response from Stripe API",
|
184
258
|
account: "acct_123",
|
@@ -403,6 +477,20 @@ module Stripe
|
|
403
477
|
assert_equal 'Invalid response object from API: "" (HTTP response code was 200)', e.message
|
404
478
|
end
|
405
479
|
|
480
|
+
should "handle low level error" do
|
481
|
+
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
482
|
+
.to_raise(Errno::ECONNREFUSED.new)
|
483
|
+
|
484
|
+
client = StripeClient.new
|
485
|
+
e = assert_raises Stripe::APIConnectionError do
|
486
|
+
client.execute_request(:post, "/v1/charges")
|
487
|
+
end
|
488
|
+
|
489
|
+
assert_equal StripeClient::ERROR_MESSAGE_CONNECTION % Stripe.api_base +
|
490
|
+
"\n\n(Network error: Connection refused)",
|
491
|
+
e.message
|
492
|
+
end
|
493
|
+
|
406
494
|
should "handle error response with unknown value" do
|
407
495
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
408
496
|
.to_return(body: JSON.generate(bar: "foo"), status: 500)
|
@@ -738,14 +826,106 @@ module Stripe
|
|
738
826
|
|
739
827
|
should "reset local thread state after a call" do
|
740
828
|
begin
|
741
|
-
|
829
|
+
StripeClient.current_thread_context.active_client = :stripe_client
|
742
830
|
|
743
831
|
client = StripeClient.new
|
744
832
|
client.request {}
|
745
833
|
|
746
|
-
assert_equal :stripe_client,
|
834
|
+
assert_equal :stripe_client,
|
835
|
+
StripeClient.current_thread_context.active_client
|
747
836
|
ensure
|
748
|
-
|
837
|
+
StripeClient.current_thread_context.active_client = nil
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
should "correctly return last responses despite multiple clients" do
|
842
|
+
charge_resp = { object: "charge" }
|
843
|
+
coupon_resp = { object: "coupon" }
|
844
|
+
|
845
|
+
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
846
|
+
.to_return(body: JSON.generate(charge_resp))
|
847
|
+
stub_request(:post, "#{Stripe.api_base}/v1/coupons")
|
848
|
+
.to_return(body: JSON.generate(coupon_resp))
|
849
|
+
|
850
|
+
client1 = StripeClient.new
|
851
|
+
client2 = StripeClient.new
|
852
|
+
|
853
|
+
client2_resp = nil
|
854
|
+
_charge, client1_resp = client1.request do
|
855
|
+
Charge.create
|
856
|
+
|
857
|
+
# This is contrived, but we run one client nested in the `request`
|
858
|
+
# block of another one just to ensure that the parent is still
|
859
|
+
# unwinding when this goes through. If the parent's last response
|
860
|
+
# were to be overridden by this client (through a bug), then it would
|
861
|
+
# happen here.
|
862
|
+
_coupon, client2_resp = client2.request do
|
863
|
+
Coupon.create
|
864
|
+
end
|
865
|
+
end
|
866
|
+
|
867
|
+
assert_equal charge_resp, client1_resp.data
|
868
|
+
assert_equal coupon_resp, client2_resp.data
|
869
|
+
end
|
870
|
+
|
871
|
+
should "correctly return last responses despite multiple threads" do
|
872
|
+
charge_resp = { object: "charge" }
|
873
|
+
coupon_resp = { object: "coupon" }
|
874
|
+
|
875
|
+
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
876
|
+
.to_return(body: JSON.generate(charge_resp))
|
877
|
+
stub_request(:post, "#{Stripe.api_base}/v1/coupons")
|
878
|
+
.to_return(body: JSON.generate(coupon_resp))
|
879
|
+
|
880
|
+
client = StripeClient.new
|
881
|
+
|
882
|
+
# Poorly named class -- note this is actually a concurrent queue.
|
883
|
+
recv_queue = Queue.new
|
884
|
+
send_queue = Queue.new
|
885
|
+
|
886
|
+
# Start a thread, make an API request, but then idle in the `request`
|
887
|
+
# block until the main thread has been able to make its own API request
|
888
|
+
# and signal that it's done. If this thread's last response were to be
|
889
|
+
# overridden by the main thread (through a bug), then this routine
|
890
|
+
# should suss it out.
|
891
|
+
resp1 = nil
|
892
|
+
thread = Thread.start do
|
893
|
+
_charge, resp1 = client.request do
|
894
|
+
Charge.create
|
895
|
+
|
896
|
+
# Idle in `request` block until main thread signals.
|
897
|
+
send_queue.pop
|
898
|
+
end
|
899
|
+
|
900
|
+
# Signal main thread that we're done and it can run its checks.
|
901
|
+
recv_queue << true
|
902
|
+
end
|
903
|
+
|
904
|
+
# Make an API request.
|
905
|
+
_coupon, resp2 = client.request do
|
906
|
+
Coupon.create
|
907
|
+
end
|
908
|
+
|
909
|
+
# Tell background thread to finish `request`, then wait for it to
|
910
|
+
# signal back to us that it's ready.
|
911
|
+
send_queue << true
|
912
|
+
recv_queue.pop
|
913
|
+
|
914
|
+
assert_equal charge_resp, resp1.data
|
915
|
+
assert_equal coupon_resp, resp2.data
|
916
|
+
|
917
|
+
# And for maximum hygiene, make sure that our thread rejoins.
|
918
|
+
thread.join
|
919
|
+
end
|
920
|
+
|
921
|
+
should "error if calls to #request are nested on the same thread" do
|
922
|
+
client = StripeClient.new
|
923
|
+
client.request do
|
924
|
+
e = assert_raises(RuntimeError) do
|
925
|
+
client.request {}
|
926
|
+
end
|
927
|
+
assert_equal "calls to StripeClient#request cannot be nested within a thread",
|
928
|
+
e.message
|
749
929
|
end
|
750
930
|
end
|
751
931
|
end
|
@@ -753,18 +933,23 @@ module Stripe
|
|
753
933
|
context "#proxy" do
|
754
934
|
should "run the request through the proxy" do
|
755
935
|
begin
|
756
|
-
|
936
|
+
StripeClient.current_thread_context.default_connection_manager = nil
|
757
937
|
|
758
|
-
Stripe.proxy = "http://localhost:8080"
|
938
|
+
Stripe.proxy = "http://user:pass@localhost:8080"
|
759
939
|
|
760
940
|
client = StripeClient.new
|
761
941
|
client.request {}
|
762
942
|
|
763
|
-
|
943
|
+
connection = Stripe::StripeClient.default_connection_manager.connection_for(Stripe.api_base)
|
944
|
+
|
945
|
+
assert_equal "localhost", connection.proxy_address
|
946
|
+
assert_equal 8080, connection.proxy_port
|
947
|
+
assert_equal "user", connection.proxy_user
|
948
|
+
assert_equal "pass", connection.proxy_pass
|
764
949
|
ensure
|
765
950
|
Stripe.proxy = nil
|
766
951
|
|
767
|
-
|
952
|
+
StripeClient.current_thread_context.default_connection_manager = nil
|
768
953
|
end
|
769
954
|
end
|
770
955
|
end
|
@@ -52,9 +52,9 @@ module Stripe
|
|
52
52
|
2,
|
53
53
|
],
|
54
54
|
map: {
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
"0": StripeObject.construct_from({ id: "index0" }, opts),
|
56
|
+
"1": "index1",
|
57
|
+
"2": 2,
|
58
58
|
},
|
59
59
|
}
|
60
60
|
|
@@ -235,20 +235,6 @@ module Stripe
|
|
235
235
|
assert_equal true, obj.send(:metaclass).method_defined?(:foo)
|
236
236
|
end
|
237
237
|
|
238
|
-
should "warn that #refresh_from is deprecated" do
|
239
|
-
old_stderr = $stderr
|
240
|
-
$stderr = StringIO.new
|
241
|
-
begin
|
242
|
-
obj = Stripe::StripeObject.construct_from({})
|
243
|
-
obj.refresh_from({}, {})
|
244
|
-
message = "NOTE: Stripe::StripeObject#refresh_from is " \
|
245
|
-
"deprecated; use #update_attributes instead"
|
246
|
-
assert_match Regexp.new(message), $stderr.string
|
247
|
-
ensure
|
248
|
-
$stderr = old_stderr
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
238
|
should "pass opts down to children when initializing" do
|
253
239
|
opts = { custom: "opts" }
|
254
240
|
|
@@ -302,14 +288,14 @@ module Stripe
|
|
302
288
|
end
|
303
289
|
|
304
290
|
should "#serialize_params on an array that shortens" do
|
305
|
-
obj = Stripe::StripeObject.construct_from(foo: [
|
291
|
+
obj = Stripe::StripeObject.construct_from(foo: %w[0-index 1-index 2-index])
|
306
292
|
obj.foo = ["new-value"]
|
307
293
|
assert_equal({ foo: ["new-value"] },
|
308
294
|
obj.serialize_params)
|
309
295
|
end
|
310
296
|
|
311
297
|
should "#serialize_params on an array that lengthens" do
|
312
|
-
obj = Stripe::StripeObject.construct_from(foo: [
|
298
|
+
obj = Stripe::StripeObject.construct_from(foo: %w[0-index 1-index 2-index])
|
313
299
|
obj.foo = ["new-value"] * 4
|
314
300
|
assert_equal({ foo: ["new-value"] * 4 },
|
315
301
|
obj.serialize_params)
|
@@ -331,8 +317,8 @@ module Stripe
|
|
331
317
|
end
|
332
318
|
|
333
319
|
should "#serialize_params on an array that is unchanged" do
|
334
|
-
obj = Stripe::StripeObject.construct_from(foo: [
|
335
|
-
obj.foo = [
|
320
|
+
obj = Stripe::StripeObject.construct_from(foo: %w[0-index 1-index 2-index])
|
321
|
+
obj.foo = %w[0-index 1-index 2-index]
|
336
322
|
assert_equal({}, obj.serialize_params)
|
337
323
|
end
|
338
324
|
|
@@ -475,20 +461,6 @@ module Stripe
|
|
475
461
|
assert_equal(expected, obj.to_s)
|
476
462
|
end
|
477
463
|
|
478
|
-
should "warn that .serialize_params is deprecated" do
|
479
|
-
old_stderr = $stderr
|
480
|
-
$stderr = StringIO.new
|
481
|
-
begin
|
482
|
-
obj = Stripe::StripeObject.construct_from({})
|
483
|
-
Stripe::StripeObject.serialize_params(obj)
|
484
|
-
message = "NOTE: Stripe::StripeObject.serialize_params is " \
|
485
|
-
"deprecated; use #serialize_params instead"
|
486
|
-
assert_match Regexp.new(message), $stderr.string
|
487
|
-
ensure
|
488
|
-
$stderr = old_stderr
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
464
|
should "error on setting a property to an empty string" do
|
493
465
|
obj = Stripe::StripeObject.construct_from(foo: "bar")
|
494
466
|
e = assert_raises ArgumentError do
|
@@ -4,46 +4,92 @@ require ::File.expand_path("../test_helper", __dir__)
|
|
4
4
|
|
5
5
|
module Stripe
|
6
6
|
class StripeResponseTest < Test::Unit::TestCase
|
7
|
-
context "
|
8
|
-
should "
|
9
|
-
body = '{"foo": "bar"}'
|
7
|
+
context "Headers" do
|
8
|
+
should "allow case-insensitive header access" do
|
10
9
|
headers = { "Request-Id" => "request-id" }
|
10
|
+
http_resp = create_net_http_resp(200, "", headers)
|
11
11
|
|
12
|
-
|
13
|
-
body: body,
|
14
|
-
headers: headers,
|
15
|
-
status: 200,
|
16
|
-
}
|
12
|
+
headers = StripeResponse::Headers.from_net_http(http_resp)
|
17
13
|
|
18
|
-
|
14
|
+
assert_equal "request-id", headers["request-id"]
|
15
|
+
assert_equal "request-id", headers["Request-Id"]
|
16
|
+
assert_equal "request-id", headers["Request-ID"]
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
should "initialize without error" do
|
20
|
+
StripeResponse::Headers.new({})
|
21
|
+
StripeResponse::Headers.new("Request-Id" => [])
|
22
|
+
StripeResponse::Headers.new("Request-Id" => ["request-id"])
|
23
|
+
end
|
24
|
+
|
25
|
+
should "initialize with error on a malformed hash" do
|
26
|
+
assert_raises(ArgumentError) do
|
27
|
+
StripeResponse::Headers.new(nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_raises(ArgumentError) do
|
31
|
+
StripeResponse::Headers.new(1 => [])
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_raises(ArgumentError) do
|
35
|
+
StripeResponse::Headers.new("Request-Id" => 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_raises(ArgumentError) do
|
39
|
+
StripeResponse::Headers.new("Request-Id" => [1])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
should "warn on duplicate header values" do
|
44
|
+
old_stderr = $stderr
|
45
|
+
$stderr = StringIO.new
|
46
|
+
begin
|
47
|
+
headers = StripeResponse::Headers.new("Duplicated" => %w[a b])
|
48
|
+
assert_equal "a", headers["Duplicated"]
|
49
|
+
assert_equal "Duplicate header values for `Duplicated`; returning only first",
|
50
|
+
$stderr.string.rstrip
|
51
|
+
ensure
|
52
|
+
$stderr = old_stderr
|
53
|
+
end
|
25
54
|
end
|
26
55
|
end
|
27
56
|
|
28
|
-
context ".
|
57
|
+
context ".from_net_http" do
|
29
58
|
should "converts to StripeResponse" do
|
59
|
+
code = 200
|
30
60
|
body = '{"foo": "bar"}'
|
31
61
|
headers = { "Request-Id" => "request-id" }
|
62
|
+
http_resp = create_net_http_resp(code, body, headers)
|
32
63
|
|
33
|
-
|
34
|
-
status: 200, body: body,
|
35
|
-
response_headers: headers
|
36
|
-
)
|
37
|
-
http_resp = Faraday::Response.new(env)
|
38
|
-
|
39
|
-
resp = StripeResponse.from_faraday_response(http_resp)
|
64
|
+
resp = StripeResponse.from_net_http(http_resp)
|
40
65
|
|
41
66
|
assert_equal JSON.parse(body, symbolize_names: true), resp.data
|
42
67
|
assert_equal body, resp.http_body
|
43
|
-
assert_equal
|
44
|
-
assert_equal
|
68
|
+
assert_equal "request-id", resp.http_headers["Request-ID"]
|
69
|
+
assert_equal code, resp.http_status
|
45
70
|
assert_equal "request-id", resp.request_id
|
46
71
|
end
|
47
72
|
end
|
73
|
+
|
74
|
+
# Synthesizes a `Net::HTTPResponse` object for testing purposes.
|
75
|
+
private def create_net_http_resp(code, body, headers)
|
76
|
+
# The "1.1" is HTTP version.
|
77
|
+
http_resp = Net::HTTPResponse.new("1.1", code.to_s, nil)
|
78
|
+
http_resp.body = body
|
79
|
+
|
80
|
+
# This is obviously super sketchy, but the Ruby team has done everything
|
81
|
+
# in their power to make these objects as difficult to test with as
|
82
|
+
# possible. Even if you specify a body, accessing `#body` the first time
|
83
|
+
# will attempt to read from a non-existent socket which will subsequently
|
84
|
+
# blow up. Setting this internal variable skips that read and allows the
|
85
|
+
# object to use the body that we specified above.
|
86
|
+
http_resp.instance_variable_set(:@read, true)
|
87
|
+
|
88
|
+
headers.each do |name, value|
|
89
|
+
http_resp[name] = value
|
90
|
+
end
|
91
|
+
|
92
|
+
http_resp
|
93
|
+
end
|
48
94
|
end
|
49
95
|
end
|
@@ -59,5 +59,17 @@ module Stripe
|
|
59
59
|
assert item.is_a?(Stripe::SubscriptionItem)
|
60
60
|
end
|
61
61
|
end
|
62
|
+
|
63
|
+
context "#create_usage_record" do
|
64
|
+
should "create a usage record" do
|
65
|
+
Stripe::SubscriptionItem.create_usage_record(
|
66
|
+
"si_123",
|
67
|
+
quantity: 5000,
|
68
|
+
timestamp: Time.now.to_i,
|
69
|
+
action: "increment"
|
70
|
+
)
|
71
|
+
assert_requested :post, "#{Stripe.api_base}/v1/subscription_items/si_123/usage_records"
|
72
|
+
end
|
73
|
+
end
|
62
74
|
end
|
63
75
|
end
|
@@ -78,39 +78,5 @@ module Stripe
|
|
78
78
|
assert schedule.is_a?(Stripe::SubscriptionSchedule)
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
82
|
-
context "#revisions" do
|
83
|
-
should "retrieve the subscription schedule's revisions" do
|
84
|
-
schedule = Stripe::SubscriptionSchedule.retrieve("sub_sched_123")
|
85
|
-
revisions = schedule.revisions
|
86
|
-
assert_requested :get,
|
87
|
-
"#{Stripe.api_base}/v1/subscription_schedules/sub_sched_123/revisions"
|
88
|
-
assert revisions.data.is_a?(Array)
|
89
|
-
assert revisions.data[0].is_a?(Stripe::SubscriptionScheduleRevision)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context "#retrieve_revision" do
|
94
|
-
should "retrieve a subscription schedule revision" do
|
95
|
-
revision = Stripe::SubscriptionSchedule.retrieve_revision(
|
96
|
-
"sub_sched_123",
|
97
|
-
"sub_sched_rev_123"
|
98
|
-
)
|
99
|
-
assert_requested :get, "#{Stripe.api_base}/v1/subscription_schedules/sub_sched_123/revisions/sub_sched_rev_123"
|
100
|
-
assert revision.is_a?(Stripe::SubscriptionScheduleRevision)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
context "#list_revisions" do
|
105
|
-
should "list a subscription schedule's revisions" do
|
106
|
-
revisions = Stripe::SubscriptionSchedule.list_revisions(
|
107
|
-
"sub_sched_123"
|
108
|
-
)
|
109
|
-
assert_requested :get, "#{Stripe.api_base}/v1/subscription_schedules/sub_sched_123/revisions"
|
110
|
-
assert revisions.is_a?(Stripe::ListObject)
|
111
|
-
assert revisions.data.is_a?(Array)
|
112
|
-
assert revisions.data[0].is_a?(Stripe::SubscriptionScheduleRevision)
|
113
|
-
end
|
114
|
-
end
|
115
81
|
end
|
116
82
|
end
|
@@ -63,9 +63,9 @@ module Stripe
|
|
63
63
|
context "#delete_discount" do
|
64
64
|
should "be able to delete a subscriptions's discount" do
|
65
65
|
subscription = Stripe::Subscription.retrieve("sub_123")
|
66
|
-
|
66
|
+
discount = subscription.delete_discount
|
67
67
|
assert_requested :delete, "#{Stripe.api_base}/v1/subscriptions/sub_123/discount"
|
68
|
-
assert
|
68
|
+
assert discount.is_a?(Stripe::Discount)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
data/test/stripe/webhook_test.rb
CHANGED
@@ -4,13 +4,13 @@ require ::File.expand_path("../test_helper", __dir__)
|
|
4
4
|
|
5
5
|
module Stripe
|
6
6
|
class WebhookTest < Test::Unit::TestCase
|
7
|
-
EVENT_PAYLOAD =
|
7
|
+
EVENT_PAYLOAD = <<~PAYLOAD
|
8
8
|
{
|
9
9
|
"id": "evt_test_webhook",
|
10
10
|
"object": "event"
|
11
11
|
}
|
12
12
|
PAYLOAD
|
13
|
-
SECRET = "whsec_test_secret"
|
13
|
+
SECRET = "whsec_test_secret"
|
14
14
|
|
15
15
|
def generate_header(opts = {})
|
16
16
|
opts[:timestamp] ||= Time.now.to_i
|
data/test/stripe_mock.rb
CHANGED
@@ -4,8 +4,8 @@ module Stripe
|
|
4
4
|
class StripeMock
|
5
5
|
include Singleton
|
6
6
|
|
7
|
-
PATH_SPEC = "#{::File.dirname(__FILE__)}/openapi/spec3.json"
|
8
|
-
PATH_FIXTURES = "#{::File.dirname(__FILE__)}/openapi/fixtures3.json"
|
7
|
+
PATH_SPEC = "#{::File.dirname(__FILE__)}/openapi/spec3.json"
|
8
|
+
PATH_FIXTURES = "#{::File.dirname(__FILE__)}/openapi/fixtures3.json"
|
9
9
|
|
10
10
|
@pid = nil
|
11
11
|
@port = -1
|
@@ -29,7 +29,7 @@ module Stripe
|
|
29
29
|
@stderr, @child_stderr = ::IO.pipe
|
30
30
|
|
31
31
|
@pid = ::Process.spawn(
|
32
|
-
[
|
32
|
+
%w[stripe-mock stripe-mock],
|
33
33
|
"-http-port",
|
34
34
|
"0", # have stripe-mock select a port
|
35
35
|
"-spec",
|
@@ -66,6 +66,7 @@ module Stripe
|
|
66
66
|
# Stops stripe-mock, if necessary.
|
67
67
|
def self.stop
|
68
68
|
return if @pid.nil?
|
69
|
+
|
69
70
|
puts("Stopping stripe-mock...")
|
70
71
|
::Process.kill(:SIGTERM, @pid)
|
71
72
|
::Process.waitpid2(@pid)
|
data/test/stripe_test.rb
CHANGED
@@ -3,19 +3,6 @@
|
|
3
3
|
require ::File.expand_path("test_helper", __dir__)
|
4
4
|
|
5
5
|
class StripeTest < Test::Unit::TestCase
|
6
|
-
should "warn that #refresh_from is deprecated" do
|
7
|
-
old_stderr = $stderr
|
8
|
-
$stderr = StringIO.new
|
9
|
-
begin
|
10
|
-
Stripe.uri_encode({})
|
11
|
-
message = "NOTE: Stripe.uri_encode is deprecated; use " \
|
12
|
-
"Stripe::Util#encode_parameters instead"
|
13
|
-
assert_match Regexp.new(message), $stderr.string
|
14
|
-
ensure
|
15
|
-
$stderr = old_stderr
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
6
|
should "allow app_info to be configured" do
|
20
7
|
begin
|
21
8
|
old = Stripe.app_info
|