stripe 5.2.0 → 5.6.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/.rubocop.yml +6 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +0 -1
- data/VERSION +1 -1
- data/lib/stripe/api_operations/nested_resource.rb +28 -26
- data/lib/stripe/api_operations/request.rb +17 -1
- data/lib/stripe/connection_manager.rb +6 -5
- data/lib/stripe/stripe_client.rb +34 -23
- data/lib/stripe/util.rb +12 -0
- data/lib/stripe/version.rb +1 -1
- data/test/stripe/api_resource_test.rb +17 -0
- data/test/stripe/connection_manager_test.rb +12 -15
- data/test/stripe/stripe_client_test.rb +83 -30
- data/test/test_helper.rb +0 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b717ef70627c0f7467317a2e2f08e8d553b04411b6324df41f4cc5eac6bd6800
|
4
|
+
data.tar.gz: 26a05a4ceeb4412c95c2ad12776785c72bd291841c5843eba2ec03a6dc21a722
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef1b962195d8a8510a1d360d8fbd18a246c65363877b43a451bccd1340c1ea18008581c04c4a0e62eb6eed9f2f8afebfccf9c4f5d059b08a2ccd921cae5b5cd0
|
7
|
+
data.tar.gz: 98fb62f907a16aadb4cab5564053ce85e96931193a8e1eeccb8ef10ebcfa726ddf086e51aef09db0825c685129867d5a91716addcc2252ae771869ca4d83bc8a
|
data/.rubocop.yml
CHANGED
@@ -4,6 +4,12 @@ AllCops:
|
|
4
4
|
DisplayCopNames: true
|
5
5
|
TargetRubyVersion: 2.3
|
6
6
|
|
7
|
+
Exclude:
|
8
|
+
# brandur: Exclude ephmeral script-like files that I use to try and
|
9
|
+
# reproduce problems with the library. If you know of a better way of doing
|
10
|
+
# this (e.g. exclude files not tracked by Git), feel free to change it.
|
11
|
+
- "example_*"
|
12
|
+
|
7
13
|
Layout/CaseIndentation:
|
8
14
|
EnforcedStyle: end
|
9
15
|
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 5.6.0 - 2019-10-04
|
4
|
+
* [#861](https://github.com/stripe/stripe-ruby/pull/861) Nicer error when specifying non-nil non-string opt value
|
5
|
+
|
6
|
+
## 5.5.0 - 2019-10-03
|
7
|
+
* [#859](https://github.com/stripe/stripe-ruby/pull/859) User-friendly messages and retries for `EOFError`, `Errno::ECONNRESET`, `Errno::ETIMEDOUT`, and `Errno::EHOSTUNREACH` network errors
|
8
|
+
|
9
|
+
## 5.4.1 - 2019-10-01
|
10
|
+
* [#858](https://github.com/stripe/stripe-ruby/pull/858) Drop Timecop dependency
|
11
|
+
|
12
|
+
## 5.4.0 - 2019-10-01
|
13
|
+
* [#857](https://github.com/stripe/stripe-ruby/pull/857) Move to monotonic time for duration calculations
|
14
|
+
|
15
|
+
## 5.3.0 - 2019-10-01
|
16
|
+
* [#853](https://github.com/stripe/stripe-ruby/pull/853) Support `Stripe-Should-Retry` header
|
17
|
+
|
3
18
|
## 5.2.0 - 2019-09-19
|
4
19
|
* [#851](https://github.com/stripe/stripe-ruby/pull/851) Introduce system for garbage collecting connection managers
|
5
20
|
|
data/Gemfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.
|
1
|
+
5.6.0
|
@@ -6,7 +6,7 @@ module Stripe
|
|
6
6
|
# that it's possible to do so from a static context (i.e. without a
|
7
7
|
# pre-existing collection of subresources on the parent).
|
8
8
|
#
|
9
|
-
# For
|
9
|
+
# For example, a transfer gains the static methods for reversals so that the
|
10
10
|
# methods `.create_reversal`, `.retrieve_reversal`, `.update_reversal`,
|
11
11
|
# etc. all become available.
|
12
12
|
module NestedResource
|
@@ -14,9 +14,11 @@ module Stripe
|
|
14
14
|
resource_plural: nil)
|
15
15
|
resource_plural ||= "#{resource}s"
|
16
16
|
path ||= resource_plural
|
17
|
+
|
17
18
|
raise ArgumentError, "operations array required" if operations.nil?
|
18
19
|
|
19
20
|
resource_url_method = :"#{resource}s_url"
|
21
|
+
|
20
22
|
define_singleton_method(resource_url_method) do |id, nested_id = nil|
|
21
23
|
url = "#{resource_url}/#{CGI.escape(id)}/#{CGI.escape(path)}"
|
22
24
|
url += "/#{CGI.escape(nested_id)}" unless nested_id.nil?
|
@@ -27,39 +29,39 @@ module Stripe
|
|
27
29
|
case operation
|
28
30
|
when :create
|
29
31
|
define_singleton_method(:"create_#{resource}") \
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
do |id, params = {}, opts = {}|
|
33
|
+
url = send(resource_url_method, id)
|
34
|
+
resp, opts = request(:post, url, params, opts)
|
35
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
36
|
+
end
|
35
37
|
when :retrieve
|
36
38
|
define_singleton_method(:"retrieve_#{resource}") \
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
do |id, nested_id, opts = {}|
|
40
|
+
url = send(resource_url_method, id, nested_id)
|
41
|
+
resp, opts = request(:get, url, {}, opts)
|
42
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
43
|
+
end
|
42
44
|
when :update
|
43
45
|
define_singleton_method(:"update_#{resource}") \
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
do |id, nested_id, params = {}, opts = {}|
|
47
|
+
url = send(resource_url_method, id, nested_id)
|
48
|
+
resp, opts = request(:post, url, params, opts)
|
49
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
50
|
+
end
|
49
51
|
when :delete
|
50
52
|
define_singleton_method(:"delete_#{resource}") \
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
do |id, nested_id, params = {}, opts = {}|
|
54
|
+
url = send(resource_url_method, id, nested_id)
|
55
|
+
resp, opts = request(:delete, url, params, opts)
|
56
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
57
|
+
end
|
56
58
|
when :list
|
57
59
|
define_singleton_method(:"list_#{resource_plural}") \
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
do |id, params = {}, opts = {}|
|
61
|
+
url = send(resource_url_method, id)
|
62
|
+
resp, opts = request(:get, url, params, opts)
|
63
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
64
|
+
end
|
63
65
|
else
|
64
66
|
raise ArgumentError, "Unknown operation: #{operation.inspect}"
|
65
67
|
end
|
@@ -8,6 +8,8 @@ module Stripe
|
|
8
8
|
warn_on_opts_in_params(params)
|
9
9
|
|
10
10
|
opts = Util.normalize_opts(opts)
|
11
|
+
error_on_non_string_user_opts(opts)
|
12
|
+
|
11
13
|
opts[:client] ||= StripeClient.active_client
|
12
14
|
|
13
15
|
headers = opts.clone
|
@@ -31,10 +33,24 @@ module Stripe
|
|
31
33
|
[resp, opts_to_persist]
|
32
34
|
end
|
33
35
|
|
36
|
+
private def error_on_non_string_user_opts(opts)
|
37
|
+
Util::OPTS_USER_SPECIFIED.each do |opt|
|
38
|
+
next unless opts.key?(opt)
|
39
|
+
|
40
|
+
val = opts[opt]
|
41
|
+
next if val.nil?
|
42
|
+
next if val.is_a?(String)
|
43
|
+
|
44
|
+
raise ArgumentError,
|
45
|
+
"request option '#{opt}' should be a string value " \
|
46
|
+
"(was a #{val.class})"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
34
50
|
private def warn_on_opts_in_params(params)
|
35
51
|
Util::OPTS_USER_SPECIFIED.each do |opt|
|
36
52
|
if params.key?(opt)
|
37
|
-
warn("WARNING: #{opt} should be in opts instead of params.")
|
53
|
+
warn("WARNING: '#{opt}' should be in opts instead of params.")
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
@@ -10,14 +10,15 @@ module Stripe
|
|
10
10
|
# Note that this class in itself is *not* thread safe. We expect it to be
|
11
11
|
# instantiated once per thread.
|
12
12
|
class ConnectionManager
|
13
|
-
# Timestamp
|
14
|
-
#
|
15
|
-
#
|
13
|
+
# Timestamp (in seconds procured from the system's monotonic clock)
|
14
|
+
# indicating when the connection manager last made a request. This is used
|
15
|
+
# by `StripeClient` to determine whether a connection manager should be
|
16
|
+
# garbage collected or not.
|
16
17
|
attr_reader :last_used
|
17
18
|
|
18
19
|
def initialize
|
19
20
|
@active_connections = {}
|
20
|
-
@last_used =
|
21
|
+
@last_used = Util.monotonic_time
|
21
22
|
|
22
23
|
# A connection manager may be accessed across threads as one thread makes
|
23
24
|
# requests on it while another is trying to clear it (either because it's
|
@@ -78,7 +79,7 @@ module Stripe
|
|
78
79
|
raise ArgumentError, "query should be a string" \
|
79
80
|
if query && !query.is_a?(String)
|
80
81
|
|
81
|
-
@last_used =
|
82
|
+
@last_used = Util.monotonic_time
|
82
83
|
|
83
84
|
connection = connection_for(uri)
|
84
85
|
|
data/lib/stripe/stripe_client.rb
CHANGED
@@ -9,7 +9,7 @@ module Stripe
|
|
9
9
|
# synchronize global access to them.
|
10
10
|
@thread_contexts_with_connection_managers = []
|
11
11
|
@thread_contexts_with_connection_managers_mutex = Mutex.new
|
12
|
-
@last_connection_manager_gc =
|
12
|
+
@last_connection_manager_gc = Util.monotonic_time
|
13
13
|
|
14
14
|
# Initializes a new `StripeClient`.
|
15
15
|
#
|
@@ -81,17 +81,23 @@ module Stripe
|
|
81
81
|
def self.should_retry?(error, method:, num_retries:)
|
82
82
|
return false if num_retries >= Stripe.max_network_retries
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
case error
|
85
|
+
when Net::OpenTimeout, Net::ReadTimeout
|
86
|
+
# Retry on timeout-related problems (either on open or read).
|
87
|
+
true
|
88
|
+
when EOFError, Errno::ECONNREFUSED, Errno::ECONNRESET,
|
89
|
+
Errno::EHOSTUNREACH, Errno::ETIMEDOUT, SocketError
|
90
|
+
# Destination refused the connection, the connection was reset, or a
|
91
|
+
# variety of other connection failures. This could occur from a single
|
92
|
+
# saturated server, so retry in case it's intermittent.
|
93
|
+
true
|
94
|
+
when Stripe::StripeError
|
95
|
+
# The API may ask us not to retry (e.g. if doing so would be a no-op),
|
96
|
+
# or advise us to retry (e.g. in cases of lock timeouts). Defer to
|
97
|
+
# those instructions if given.
|
98
|
+
return false if error.http_headers["stripe-should-retry"] == "false"
|
99
|
+
return true if error.http_headers["stripe-should-retry"] == "true"
|
87
100
|
|
88
|
-
# Destination refused the connection, the connection was reset, or a
|
89
|
-
# variety of other connection failures. This could occur from a single
|
90
|
-
# saturated server, so retry in case it's intermittent.
|
91
|
-
return true if error.is_a?(Errno::ECONNREFUSED)
|
92
|
-
return true if error.is_a?(SocketError)
|
93
|
-
|
94
|
-
if error.is_a?(Stripe::StripeError)
|
95
101
|
# 409 Conflict
|
96
102
|
return true if error.http_status == 409
|
97
103
|
|
@@ -113,10 +119,10 @@ module Stripe
|
|
113
119
|
return true if error.http_status == 500 && method != :post
|
114
120
|
|
115
121
|
# 503 Service Unavailable
|
116
|
-
|
122
|
+
error.http_status == 503
|
123
|
+
else
|
124
|
+
false
|
117
125
|
end
|
118
|
-
|
119
|
-
false
|
120
126
|
end
|
121
127
|
|
122
128
|
def self.sleep_time(num_retries)
|
@@ -290,7 +296,11 @@ module Stripe
|
|
290
296
|
# The original error message is also appended onto the final exception for
|
291
297
|
# full transparency.
|
292
298
|
NETWORK_ERROR_MESSAGES_MAP = {
|
299
|
+
EOFError => ERROR_MESSAGE_CONNECTION,
|
293
300
|
Errno::ECONNREFUSED => ERROR_MESSAGE_CONNECTION,
|
301
|
+
Errno::ECONNRESET => ERROR_MESSAGE_CONNECTION,
|
302
|
+
Errno::EHOSTUNREACH => ERROR_MESSAGE_CONNECTION,
|
303
|
+
Errno::ETIMEDOUT => ERROR_MESSAGE_TIMEOUT_CONNECT,
|
294
304
|
SocketError => ERROR_MESSAGE_CONNECTION,
|
295
305
|
|
296
306
|
Net::OpenTimeout => ERROR_MESSAGE_TIMEOUT_CONNECT,
|
@@ -362,11 +372,11 @@ module Stripe
|
|
362
372
|
# For internal use only. Does not provide a stable API and may be broken
|
363
373
|
# with future non-major changes.
|
364
374
|
def self.maybe_gc_connection_managers
|
365
|
-
|
366
|
-
|
367
|
-
end
|
375
|
+
next_gc_time = @last_connection_manager_gc + CONNECTION_MANAGER_GC_PERIOD
|
376
|
+
return nil if next_gc_time > Util.monotonic_time
|
368
377
|
|
369
|
-
last_used_threshold =
|
378
|
+
last_used_threshold =
|
379
|
+
Util.monotonic_time - CONNECTION_MANAGER_GC_LAST_USED_EXPIRY
|
370
380
|
|
371
381
|
pruned_thread_contexts = []
|
372
382
|
@thread_contexts_with_connection_managers.each do |thread_context|
|
@@ -379,7 +389,7 @@ module Stripe
|
|
379
389
|
end
|
380
390
|
|
381
391
|
@thread_contexts_with_connection_managers -= pruned_thread_contexts
|
382
|
-
@last_connection_manager_gc =
|
392
|
+
@last_connection_manager_gc = Util.monotonic_time
|
383
393
|
|
384
394
|
pruned_thread_contexts.count
|
385
395
|
end
|
@@ -439,7 +449,7 @@ module Stripe
|
|
439
449
|
private def execute_request_with_rescues(method, api_base, context)
|
440
450
|
num_retries = 0
|
441
451
|
begin
|
442
|
-
request_start =
|
452
|
+
request_start = Util.monotonic_time
|
443
453
|
log_request(context, num_retries)
|
444
454
|
resp = yield
|
445
455
|
context = context.dup_from_response_headers(resp)
|
@@ -449,7 +459,8 @@ module Stripe
|
|
449
459
|
log_response(context, request_start, resp.code.to_i, resp.body)
|
450
460
|
|
451
461
|
if Stripe.enable_telemetry? && context.request_id
|
452
|
-
request_duration_ms =
|
462
|
+
request_duration_ms =
|
463
|
+
((Util.monotonic_time - request_start) * 1000).to_int
|
453
464
|
@last_request_metrics =
|
454
465
|
StripeRequestMetrics.new(context.request_id, request_duration_ms)
|
455
466
|
end
|
@@ -720,7 +731,7 @@ module Stripe
|
|
720
731
|
Util.log_info("Response from Stripe API",
|
721
732
|
account: context.account,
|
722
733
|
api_version: context.api_version,
|
723
|
-
elapsed:
|
734
|
+
elapsed: Util.monotonic_time - request_start,
|
724
735
|
idempotency_key: context.idempotency_key,
|
725
736
|
method: context.method,
|
726
737
|
path: context.path,
|
@@ -742,7 +753,7 @@ module Stripe
|
|
742
753
|
|
743
754
|
private def log_response_error(context, request_start, error)
|
744
755
|
Util.log_error("Request error",
|
745
|
-
elapsed:
|
756
|
+
elapsed: Util.monotonic_time - request_start,
|
746
757
|
error_message: error.message,
|
747
758
|
idempotency_key: context.idempotency_key,
|
748
759
|
method: context.method,
|
data/lib/stripe/util.rb
CHANGED
@@ -172,6 +172,18 @@ module Stripe
|
|
172
172
|
result
|
173
173
|
end
|
174
174
|
|
175
|
+
# `Time.now` can be unstable in cases like an administrator manually
|
176
|
+
# updating its value or a reconcilation via NTP. For this reason, prefer
|
177
|
+
# the use of the system's monotonic clock especially where comparing times
|
178
|
+
# to calculate an elapsed duration.
|
179
|
+
#
|
180
|
+
# Shortcut for getting monotonic time, mostly for purposes of line length
|
181
|
+
# and test stubbing. Returns time in seconds since the event used for
|
182
|
+
# monotonic reference purposes by the platform (e.g. system boot time).
|
183
|
+
def self.monotonic_time
|
184
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
185
|
+
end
|
186
|
+
|
175
187
|
def self.normalize_id(id)
|
176
188
|
if id.is_a?(Hash) # overloaded id
|
177
189
|
params_hash = id.dup
|
data/lib/stripe/version.rb
CHANGED
@@ -227,6 +227,23 @@ module Stripe
|
|
227
227
|
end
|
228
228
|
end
|
229
229
|
|
230
|
+
should "error if a user-specified opt is given a non-nil non-string value" do
|
231
|
+
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
232
|
+
.to_return(body: JSON.generate(charge_fixture))
|
233
|
+
|
234
|
+
# Works fine if not included or a string.
|
235
|
+
Stripe::Charge.create({ amount: 100, currency: "usd" }, {})
|
236
|
+
Stripe::Charge.create({ amount: 100, currency: "usd" }, idempotency_key: "12345")
|
237
|
+
|
238
|
+
# Errors on a non-string.
|
239
|
+
e = assert_raises(ArgumentError) do
|
240
|
+
Stripe::Charge.create({ amount: 100, currency: "usd" }, idempotency_key: :foo)
|
241
|
+
end
|
242
|
+
assert_equal "request option 'idempotency_key' should be a string value " \
|
243
|
+
"(was a Symbol)",
|
244
|
+
e.message
|
245
|
+
end
|
246
|
+
|
230
247
|
should "requesting with a unicode ID should result in a request" do
|
231
248
|
stub_request(:get, "#{Stripe.api_base}/v1/customers/%E2%98%83")
|
232
249
|
.to_return(body: JSON.generate(make_missing_id_error), status: 404)
|
@@ -10,10 +10,9 @@ module Stripe
|
|
10
10
|
|
11
11
|
context "#initialize" do
|
12
12
|
should "set #last_used to current time" do
|
13
|
-
t =
|
14
|
-
|
15
|
-
|
16
|
-
end
|
13
|
+
t = 123.0
|
14
|
+
Util.stubs(:monotonic_time).returns(t)
|
15
|
+
assert_equal t, Stripe::ConnectionManager.new.last_used
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
@@ -147,19 +146,17 @@ module Stripe
|
|
147
146
|
stub_request(:post, "#{Stripe.api_base}/path")
|
148
147
|
.to_return(body: JSON.generate(object: "account"))
|
149
148
|
|
150
|
-
t =
|
149
|
+
t = 123.0
|
150
|
+
Util.stubs(:monotonic_time).returns(t)
|
151
151
|
|
152
|
-
|
153
|
-
# than the one we're going to measure at because `#last_used` is also
|
154
|
-
# set by the constructor.
|
155
|
-
manager = Timecop.freeze(t) do
|
156
|
-
Stripe::ConnectionManager.new
|
157
|
-
end
|
152
|
+
manager = Stripe::ConnectionManager.new
|
158
153
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
154
|
+
# `#last_used` is also set by the constructor, so make sure we get a
|
155
|
+
# new value for it.
|
156
|
+
Util.stubs(:monotonic_time).returns(t + 1.0)
|
157
|
+
|
158
|
+
manager.execute_request(:post, "#{Stripe.api_base}/path")
|
159
|
+
assert_equal t + 1.0, manager.last_used
|
163
160
|
end
|
164
161
|
end
|
165
162
|
end
|
@@ -27,47 +27,63 @@ module Stripe
|
|
27
27
|
StripeClient.clear_all_connection_managers
|
28
28
|
|
29
29
|
# Establish a base time.
|
30
|
-
t =
|
30
|
+
t = 0.0
|
31
31
|
|
32
32
|
# And pretend that `StripeClient` was just initialized for the first
|
33
33
|
# time. (Don't access instance variables like this, but it's tricky to
|
34
34
|
# test properly otherwise.)
|
35
35
|
StripeClient.instance_variable_set(:@last_connection_manager_gc, t)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
client.execute_request(:post, "/v1/path")
|
37
|
+
#
|
38
|
+
# t
|
39
|
+
#
|
40
|
+
Util.stubs(:monotonic_time).returns(t)
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
# Execute an initial request to ensure that a connection manager was
|
43
|
+
# created.
|
44
|
+
client = StripeClient.new
|
45
|
+
client.execute_request(:post, "/v1/path")
|
46
|
+
|
47
|
+
# The GC shouldn't run yet (a `nil` return indicates that GC didn't run).
|
48
|
+
assert_equal nil, StripeClient.maybe_gc_connection_managers
|
46
49
|
|
50
|
+
#
|
51
|
+
# t + StripeClient::CONNECTION_MANAGER_GC_PERIOD - 1
|
52
|
+
#
|
47
53
|
# Move time to just *before* garbage collection is eligible to run.
|
48
54
|
# Nothing should happen.
|
49
|
-
|
50
|
-
|
51
|
-
|
55
|
+
#
|
56
|
+
Util.stubs(:monotonic_time).returns(t + StripeClient::CONNECTION_MANAGER_GC_PERIOD - 1)
|
57
|
+
|
58
|
+
assert_equal nil, StripeClient.maybe_gc_connection_managers
|
52
59
|
|
60
|
+
#
|
61
|
+
# t + StripeClient::CONNECTION_MANAGER_GC_PERIOD + 1
|
62
|
+
#
|
53
63
|
# Move time to just *after* garbage collection is eligible to run.
|
54
64
|
# Garbage collection will run, but because the connection manager is
|
55
65
|
# not passed its expiry age, it will not be collected. Zero is returned
|
56
66
|
# to indicate so.
|
57
|
-
|
58
|
-
|
59
|
-
|
67
|
+
#
|
68
|
+
Util.stubs(:monotonic_time).returns(t + StripeClient::CONNECTION_MANAGER_GC_PERIOD + 1)
|
69
|
+
|
70
|
+
assert_equal 0, StripeClient.maybe_gc_connection_managers
|
60
71
|
|
72
|
+
#
|
73
|
+
# t + StripeClient::CONNECTION_MANAGER_GC_LAST_USED_EXPIRY + 1
|
74
|
+
#
|
61
75
|
# Move us far enough into the future that we're passed the horizons for
|
62
76
|
# both a GC run as well as well as the expiry age of a connection
|
63
77
|
# manager. That means the GC will run and collect the connection
|
64
78
|
# manager that we created above.
|
65
|
-
|
66
|
-
|
79
|
+
#
|
80
|
+
Util.stubs(:monotonic_time).returns(t + StripeClient::CONNECTION_MANAGER_GC_LAST_USED_EXPIRY + 1)
|
67
81
|
|
68
|
-
|
69
|
-
|
70
|
-
|
82
|
+
assert_equal 1, StripeClient.maybe_gc_connection_managers
|
83
|
+
|
84
|
+
# And as an additional check, the connection manager of the current
|
85
|
+
# thread context should have been set to `nil` as it was GCed.
|
86
|
+
assert_nil StripeClient.current_thread_context.default_connection_manager
|
71
87
|
end
|
72
88
|
end
|
73
89
|
|
@@ -156,6 +172,26 @@ module Stripe
|
|
156
172
|
method: :post, num_retries: 0)
|
157
173
|
end
|
158
174
|
|
175
|
+
should "retry on EOFError" do
|
176
|
+
assert StripeClient.should_retry?(EOFError.new,
|
177
|
+
method: :post, num_retries: 0)
|
178
|
+
end
|
179
|
+
|
180
|
+
should "retry on Errno::ECONNRESET" do
|
181
|
+
assert StripeClient.should_retry?(Errno::ECONNRESET.new,
|
182
|
+
method: :post, num_retries: 0)
|
183
|
+
end
|
184
|
+
|
185
|
+
should "retry on Errno::ETIMEDOUT" do
|
186
|
+
assert StripeClient.should_retry?(Errno::ETIMEDOUT.new,
|
187
|
+
method: :post, num_retries: 0)
|
188
|
+
end
|
189
|
+
|
190
|
+
should "retry on Errno::EHOSTUNREACH" do
|
191
|
+
assert StripeClient.should_retry?(Errno::EHOSTUNREACH.new,
|
192
|
+
method: :post, num_retries: 0)
|
193
|
+
end
|
194
|
+
|
159
195
|
should "retry on Net::OpenTimeout" do
|
160
196
|
assert StripeClient.should_retry?(Net::OpenTimeout.new,
|
161
197
|
method: :post, num_retries: 0)
|
@@ -171,6 +207,28 @@ module Stripe
|
|
171
207
|
method: :post, num_retries: 0)
|
172
208
|
end
|
173
209
|
|
210
|
+
should "retry when the `Stripe-Should-Retry` header is `true`" do
|
211
|
+
headers = StripeResponse::Headers.new(
|
212
|
+
"Stripe-Should-Retry" => ["true"]
|
213
|
+
)
|
214
|
+
|
215
|
+
# Note we send status 400 here, which would normally not be retried.
|
216
|
+
assert StripeClient.should_retry?(Stripe::StripeError.new(http_headers: headers,
|
217
|
+
http_status: 400),
|
218
|
+
method: :post, num_retries: 0)
|
219
|
+
end
|
220
|
+
|
221
|
+
should "not retry when the `Stripe-Should-Retry` header is `false`" do
|
222
|
+
headers = StripeResponse::Headers.new(
|
223
|
+
"Stripe-Should-Retry" => ["false"]
|
224
|
+
)
|
225
|
+
|
226
|
+
# Note we send status 409 here, which would normally be retried.
|
227
|
+
refute StripeClient.should_retry?(Stripe::StripeError.new(http_headers: headers,
|
228
|
+
http_status: 409),
|
229
|
+
method: :post, num_retries: 0)
|
230
|
+
end
|
231
|
+
|
174
232
|
should "retry on a 409 Conflict" do
|
175
233
|
assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 409),
|
176
234
|
method: :post, num_retries: 0)
|
@@ -279,16 +337,11 @@ module Stripe
|
|
279
337
|
context "logging" do
|
280
338
|
setup do
|
281
339
|
# Freeze time for the purposes of the `elapsed` parameter that we
|
282
|
-
# emit for responses.
|
283
|
-
#
|
284
|
-
#
|
285
|
-
#
|
286
|
-
|
287
|
-
Timecop.freeze(Time.local(1990))
|
288
|
-
end
|
289
|
-
|
290
|
-
teardown do
|
291
|
-
Timecop.return
|
340
|
+
# emit for responses. Mocha's `anything` parameter can't match inside
|
341
|
+
# of a hash and is therefore not useful for this purpose. If we
|
342
|
+
# switch over to rspec-mocks at some point, we can probably remove
|
343
|
+
# this.
|
344
|
+
Util.stubs(:monotonic_time).returns(0.0)
|
292
345
|
end
|
293
346
|
|
294
347
|
should "produce appropriate logging" do
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Stripe is the easiest way to accept payments online. See https://stripe.com
|
14
14
|
for details.
|
@@ -246,7 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
246
|
- !ruby/object:Gem::Version
|
247
247
|
version: '0'
|
248
248
|
requirements: []
|
249
|
-
rubygems_version: 3.0.
|
249
|
+
rubygems_version: 3.0.6
|
250
250
|
signing_key:
|
251
251
|
specification_version: 4
|
252
252
|
summary: Ruby bindings for the Stripe API
|