stripe 5.1.1 → 5.2.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 +9 -0
- data/.rubocop_todo.yml +0 -6
- data/CHANGELOG.md +3 -0
- data/VERSION +1 -1
- data/lib/stripe/connection_manager.rb +35 -18
- data/lib/stripe/stripe_client.rb +86 -22
- data/lib/stripe/version.rb +1 -1
- data/test/stripe/connection_manager_test.rb +28 -0
- data/test/stripe/stripe_client_test.rb +125 -44
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ec1d1414aafc87b63dca172263ecd4666467cda2ab39eaac1abdbd13e7cd90b
|
4
|
+
data.tar.gz: 3adde22d80c8f867e34d2735dd0aea142f0b69e6cd2a84e13fe7c6a53655ee85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4086cfa6bc5281bf1e31e88a2435156d6928716d7022e319afe5845157571731ad260c3728c6bf021d593f11727fa6fdba06c26667d7d5774b6a29cfadf9829
|
7
|
+
data.tar.gz: 4b6477d988e90607c8ad8c1d8a4a11e3f0afb3494948403d2b6b9e23cde4a6be0dcb9779100306c28449e6d7d24876043edcc2239ab00cdb1dc7fd88942b57de
|
data/.rubocop.yml
CHANGED
@@ -19,8 +19,17 @@ Layout/IndentFirstHashElement:
|
|
19
19
|
Layout/IndentHeredoc:
|
20
20
|
Enabled: false
|
21
21
|
|
22
|
+
Metrics/BlockLength:
|
23
|
+
Max: 40
|
24
|
+
Exclude:
|
25
|
+
# `context` in tests are blocks and get quite large, so exclude the test
|
26
|
+
# directory from having to adhere to this rule.
|
27
|
+
- "test/**/*.rb"
|
28
|
+
|
22
29
|
Metrics/ClassLength:
|
23
30
|
Exclude:
|
31
|
+
# Test classes get quite large, so exclude the test directory from having
|
32
|
+
# to adhere to this rule.
|
24
33
|
- "test/**/*.rb"
|
25
34
|
|
26
35
|
Metrics/LineLength:
|
data/.rubocop_todo.yml
CHANGED
@@ -10,12 +10,6 @@
|
|
10
10
|
Metrics/AbcSize:
|
11
11
|
Max: 51
|
12
12
|
|
13
|
-
# Offense count: 33
|
14
|
-
# Configuration parameters: CountComments, ExcludedMethods.
|
15
|
-
# ExcludedMethods: refine
|
16
|
-
Metrics/BlockLength:
|
17
|
-
Max: 509
|
18
|
-
|
19
13
|
# Offense count: 12
|
20
14
|
# Configuration parameters: CountComments.
|
21
15
|
Metrics/ClassLength:
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 5.2.0 - 2019-09-19
|
4
|
+
* [#851](https://github.com/stripe/stripe-ruby/pull/851) Introduce system for garbage collecting connection managers
|
5
|
+
|
3
6
|
## 5.1.1 - 2019-09-04
|
4
7
|
* [#845](https://github.com/stripe/stripe-ruby/pull/845) Transfer the request_id from the http_headers to error.
|
5
8
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.
|
1
|
+
5.2.0
|
@@ -9,24 +9,35 @@ module Stripe
|
|
9
9
|
#
|
10
10
|
# Note that this class in itself is *not* thread safe. We expect it to be
|
11
11
|
# instantiated once per thread.
|
12
|
-
#
|
13
|
-
# Note also that this class doesn't currently clean up after itself because
|
14
|
-
# it expects to only ever have a few connections (unless `.clear` is called
|
15
|
-
# manually). It'd be possible to tank memory by constantly changing the value
|
16
|
-
# of `Stripe.api_base` or the like. A possible improvement might be to detect
|
17
|
-
# and prune old connections whenever a request is executed.
|
18
12
|
class ConnectionManager
|
13
|
+
# Timestamp indicating when the connection manager last made a request.
|
14
|
+
# This is used by `StripeClient` to determine whether a connection manager
|
15
|
+
# should be garbage collected or not.
|
16
|
+
attr_reader :last_used
|
17
|
+
|
19
18
|
def initialize
|
20
19
|
@active_connections = {}
|
20
|
+
@last_used = Time.now
|
21
|
+
|
22
|
+
# A connection manager may be accessed across threads as one thread makes
|
23
|
+
# requests on it while another is trying to clear it (either because it's
|
24
|
+
# trying to garbage collect the manager or trying to clear it because a
|
25
|
+
# configuration setting has changed). That's probably thread-safe already
|
26
|
+
# because of Ruby's GIL, but just in case the library's running on JRuby
|
27
|
+
# or the like, use a mutex to synchronize access in this connection
|
28
|
+
# manager.
|
29
|
+
@mutex = Mutex.new
|
21
30
|
end
|
22
31
|
|
23
32
|
# Finishes any active connections by closing their TCP connection and
|
24
33
|
# clears them from internal tracking.
|
25
34
|
def clear
|
26
|
-
@
|
27
|
-
connection
|
35
|
+
@mutex.synchronize do
|
36
|
+
@active_connections.each do |_, connection|
|
37
|
+
connection.finish
|
38
|
+
end
|
39
|
+
@active_connections = {}
|
28
40
|
end
|
29
|
-
@active_connections = {}
|
30
41
|
end
|
31
42
|
|
32
43
|
# Gets a connection for a given URI. This is for internal use only as it's
|
@@ -35,17 +46,19 @@ module Stripe
|
|
35
46
|
#
|
36
47
|
# `uri` is expected to be a string.
|
37
48
|
def connection_for(uri)
|
38
|
-
|
39
|
-
|
49
|
+
@mutex.synchronize do
|
50
|
+
u = URI.parse(uri)
|
51
|
+
connection = @active_connections[[u.host, u.port]]
|
40
52
|
|
41
|
-
|
42
|
-
|
43
|
-
|
53
|
+
if connection.nil?
|
54
|
+
connection = create_connection(u)
|
55
|
+
connection.start
|
44
56
|
|
45
|
-
|
46
|
-
|
57
|
+
@active_connections[[u.host, u.port]] = connection
|
58
|
+
end
|
47
59
|
|
48
|
-
|
60
|
+
connection
|
61
|
+
end
|
49
62
|
end
|
50
63
|
|
51
64
|
# Executes an HTTP request to the given URI with the given method. Also
|
@@ -65,6 +78,8 @@ module Stripe
|
|
65
78
|
raise ArgumentError, "query should be a string" \
|
66
79
|
if query && !query.is_a?(String)
|
67
80
|
|
81
|
+
@last_used = Time.now
|
82
|
+
|
68
83
|
connection = connection_for(uri)
|
69
84
|
|
70
85
|
u = URI.parse(uri)
|
@@ -74,7 +89,9 @@ module Stripe
|
|
74
89
|
u.path
|
75
90
|
end
|
76
91
|
|
77
|
-
|
92
|
+
@mutex.synchronize do
|
93
|
+
connection.send_request(method.to_s.upcase, path, body, headers)
|
94
|
+
end
|
78
95
|
end
|
79
96
|
|
80
97
|
#
|
data/lib/stripe/stripe_client.rb
CHANGED
@@ -5,18 +5,17 @@ module Stripe
|
|
5
5
|
# recover both a resource a call returns as well as a response object that
|
6
6
|
# contains information on the HTTP call.
|
7
7
|
class StripeClient
|
8
|
-
# A set of all known
|
8
|
+
# A set of all known thread contexts across all threads and a mutex to
|
9
9
|
# synchronize global access to them.
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@thread_contexts_with_connection_managers = []
|
11
|
+
@thread_contexts_with_connection_managers_mutex = Mutex.new
|
12
|
+
@last_connection_manager_gc = Time.now
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
#
|
17
|
-
def initialize(
|
18
|
-
self.connection_manager = connection_manager ||
|
19
|
-
self.class.default_connection_manager
|
14
|
+
# Initializes a new `StripeClient`.
|
15
|
+
#
|
16
|
+
# Takes a connection manager object for backwards compatibility only, and
|
17
|
+
# that use is DEPRECATED.
|
18
|
+
def initialize(_connection_manager = nil)
|
20
19
|
@system_profiler = SystemProfiler.new
|
21
20
|
@last_request_metrics = nil
|
22
21
|
end
|
@@ -42,17 +41,24 @@ module Stripe
|
|
42
41
|
# Just a quick path for when configuration is being set for the first
|
43
42
|
# time before any connections have been opened. There is technically some
|
44
43
|
# potential for thread raciness here, but not in a practical sense.
|
45
|
-
return if @
|
46
|
-
|
47
|
-
@
|
48
|
-
@
|
44
|
+
return if @thread_contexts_with_connection_managers.empty?
|
45
|
+
|
46
|
+
@thread_contexts_with_connection_managers_mutex.synchronize do
|
47
|
+
@thread_contexts_with_connection_managers.each do |thread_context|
|
48
|
+
# Note that the thread context itself is not destroyed, but we clear
|
49
|
+
# its connection manager and remove our reference to it. If it ever
|
50
|
+
# makes a new request we'll give it a new connection manager and
|
51
|
+
# it'll go back into `@thread_contexts_with_connection_managers`.
|
52
|
+
thread_context.default_connection_manager.clear
|
53
|
+
thread_context.default_connection_manager = nil
|
54
|
+
end
|
55
|
+
@thread_contexts_with_connection_managers.clear
|
49
56
|
end
|
50
57
|
end
|
51
58
|
|
52
59
|
# A default client for the current thread.
|
53
60
|
def self.default_client
|
54
|
-
current_thread_context.default_client ||=
|
55
|
-
StripeClient.new(default_connection_manager)
|
61
|
+
current_thread_context.default_client ||= StripeClient.new
|
56
62
|
end
|
57
63
|
|
58
64
|
# A default connection manager for the current thread.
|
@@ -60,8 +66,9 @@ module Stripe
|
|
60
66
|
current_thread_context.default_connection_manager ||= begin
|
61
67
|
connection_manager = ConnectionManager.new
|
62
68
|
|
63
|
-
@
|
64
|
-
|
69
|
+
@thread_contexts_with_connection_managers_mutex.synchronize do
|
70
|
+
maybe_gc_connection_managers
|
71
|
+
@thread_contexts_with_connection_managers << current_thread_context
|
65
72
|
end
|
66
73
|
|
67
74
|
connection_manager
|
@@ -131,6 +138,15 @@ module Stripe
|
|
131
138
|
sleep_seconds
|
132
139
|
end
|
133
140
|
|
141
|
+
# Gets the connection manager in use for the current `StripeClient`.
|
142
|
+
#
|
143
|
+
# This method is DEPRECATED and for backwards compatibility only.
|
144
|
+
def connection_manager
|
145
|
+
self.class.default_connection_manager
|
146
|
+
end
|
147
|
+
extend Gem::Deprecate
|
148
|
+
deprecate :connection_manager, :none, 2020, 9
|
149
|
+
|
134
150
|
# Executes the API call within the given block. Usage looks like:
|
135
151
|
#
|
136
152
|
# client = StripeClient.new
|
@@ -207,10 +223,10 @@ module Stripe
|
|
207
223
|
context.query = query
|
208
224
|
|
209
225
|
http_resp = execute_request_with_rescues(method, api_base, context) do
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
226
|
+
self.class.default_connection_manager.execute_request(method, url,
|
227
|
+
body: body,
|
228
|
+
headers: headers,
|
229
|
+
query: query)
|
214
230
|
end
|
215
231
|
|
216
232
|
begin
|
@@ -233,6 +249,14 @@ module Stripe
|
|
233
249
|
# private
|
234
250
|
#
|
235
251
|
|
252
|
+
# Time (in seconds) that a connection manager has not been used before it's
|
253
|
+
# eligible for garbage collection.
|
254
|
+
CONNECTION_MANAGER_GC_LAST_USED_EXPIRY = 120
|
255
|
+
|
256
|
+
# How often to check (in seconds) for connection managers that haven't been
|
257
|
+
# used in a long time and which should be garbage collected.
|
258
|
+
CONNECTION_MANAGER_GC_PERIOD = 60
|
259
|
+
|
236
260
|
ERROR_MESSAGE_CONNECTION =
|
237
261
|
"Unexpected error communicating when trying to connect to " \
|
238
262
|
"Stripe (%s). You may be seeing this message because your DNS is not " \
|
@@ -320,6 +344,46 @@ module Stripe
|
|
320
344
|
Thread.current[:stripe_client__internal_use_only] ||= ThreadContext.new
|
321
345
|
end
|
322
346
|
|
347
|
+
# Garbage collects connection managers that haven't been used in some time,
|
348
|
+
# with the idea being that we want to remove old connection managers that
|
349
|
+
# belong to dead threads and the like.
|
350
|
+
#
|
351
|
+
# Prefixed with `maybe_` because garbage collection will only run
|
352
|
+
# periodically so that we're not constantly engaged in busy work. If
|
353
|
+
# connection managers live a little passed their useful age it's not
|
354
|
+
# harmful, so it's not necessary to get them right away.
|
355
|
+
#
|
356
|
+
# For testability, returns `nil` if it didn't run and the number of
|
357
|
+
# connection managers that were garbage collected otherwise.
|
358
|
+
#
|
359
|
+
# IMPORTANT: This method is not thread-safe and expects to be called inside
|
360
|
+
# a lock on `@thread_contexts_with_connection_managers_mutex`.
|
361
|
+
#
|
362
|
+
# For internal use only. Does not provide a stable API and may be broken
|
363
|
+
# with future non-major changes.
|
364
|
+
def self.maybe_gc_connection_managers
|
365
|
+
if @last_connection_manager_gc + CONNECTION_MANAGER_GC_PERIOD > Time.now
|
366
|
+
return nil
|
367
|
+
end
|
368
|
+
|
369
|
+
last_used_threshold = Time.now - CONNECTION_MANAGER_GC_LAST_USED_EXPIRY
|
370
|
+
|
371
|
+
pruned_thread_contexts = []
|
372
|
+
@thread_contexts_with_connection_managers.each do |thread_context|
|
373
|
+
connection_manager = thread_context.default_connection_manager
|
374
|
+
next if connection_manager.last_used > last_used_threshold
|
375
|
+
|
376
|
+
connection_manager.clear
|
377
|
+
thread_context.default_connection_manager = nil
|
378
|
+
pruned_thread_contexts << thread_context
|
379
|
+
end
|
380
|
+
|
381
|
+
@thread_contexts_with_connection_managers -= pruned_thread_contexts
|
382
|
+
@last_connection_manager_gc = Time.now
|
383
|
+
|
384
|
+
pruned_thread_contexts.count
|
385
|
+
end
|
386
|
+
|
323
387
|
private def api_url(url = "", api_base = nil)
|
324
388
|
(api_base || Stripe.api_base) + url
|
325
389
|
end
|
data/lib/stripe/version.rb
CHANGED
@@ -8,6 +8,15 @@ module Stripe
|
|
8
8
|
@manager = Stripe::ConnectionManager.new
|
9
9
|
end
|
10
10
|
|
11
|
+
context "#initialize" do
|
12
|
+
should "set #last_used to current time" do
|
13
|
+
t = Time.new(2019)
|
14
|
+
Timecop.freeze(t) do
|
15
|
+
assert_equal t, Stripe::ConnectionManager.new.last_used
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
11
20
|
context "#clear" do
|
12
21
|
should "clear any active connections" do
|
13
22
|
stub_request(:post, "#{Stripe.api_base}/path")
|
@@ -133,6 +142,25 @@ module Stripe
|
|
133
142
|
end
|
134
143
|
assert_equal e.message, "query should be a string"
|
135
144
|
end
|
145
|
+
|
146
|
+
should "set #last_used to current time" do
|
147
|
+
stub_request(:post, "#{Stripe.api_base}/path")
|
148
|
+
.to_return(body: JSON.generate(object: "account"))
|
149
|
+
|
150
|
+
t = Time.new(2019)
|
151
|
+
|
152
|
+
# Make sure the connection manager is initialized at a different time
|
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
|
158
|
+
|
159
|
+
Timecop.freeze(t + 1) do
|
160
|
+
manager.execute_request(:post, "#{Stripe.api_base}/path")
|
161
|
+
assert_equal t + 1, manager.last_used
|
162
|
+
end
|
163
|
+
end
|
136
164
|
end
|
137
165
|
end
|
138
166
|
end
|
@@ -17,6 +17,60 @@ module Stripe
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
context ".maybe_gc_connection_managers" do
|
21
|
+
should "garbage collect old connection managers when appropriate" do
|
22
|
+
stub_request(:post, "#{Stripe.api_base}/v1/path")
|
23
|
+
.to_return(body: JSON.generate(object: "account"))
|
24
|
+
|
25
|
+
# Make sure we start with a blank slate (state may have been left in
|
26
|
+
# place by other tests).
|
27
|
+
StripeClient.clear_all_connection_managers
|
28
|
+
|
29
|
+
# Establish a base time.
|
30
|
+
t = Time.new(2019)
|
31
|
+
|
32
|
+
# And pretend that `StripeClient` was just initialized for the first
|
33
|
+
# time. (Don't access instance variables like this, but it's tricky to
|
34
|
+
# test properly otherwise.)
|
35
|
+
StripeClient.instance_variable_set(:@last_connection_manager_gc, t)
|
36
|
+
|
37
|
+
Timecop.freeze(t) do
|
38
|
+
# Execute an initial request to ensure that a connection manager was
|
39
|
+
# created.
|
40
|
+
client = StripeClient.new
|
41
|
+
client.execute_request(:post, "/v1/path")
|
42
|
+
|
43
|
+
# The GC shouldn't run yet (a `nil` return indicates that GC didn't run).
|
44
|
+
assert_equal nil, StripeClient.maybe_gc_connection_managers
|
45
|
+
end
|
46
|
+
|
47
|
+
# Move time to just *before* garbage collection is eligible to run.
|
48
|
+
# Nothing should happen.
|
49
|
+
Timecop.freeze(t + StripeClient::CONNECTION_MANAGER_GC_PERIOD - 1) do
|
50
|
+
assert_equal nil, StripeClient.maybe_gc_connection_managers
|
51
|
+
end
|
52
|
+
|
53
|
+
# Move time to just *after* garbage collection is eligible to run.
|
54
|
+
# Garbage collection will run, but because the connection manager is
|
55
|
+
# not passed its expiry age, it will not be collected. Zero is returned
|
56
|
+
# to indicate so.
|
57
|
+
Timecop.freeze(t + StripeClient::CONNECTION_MANAGER_GC_PERIOD + 1) do
|
58
|
+
assert_equal 0, StripeClient.maybe_gc_connection_managers
|
59
|
+
end
|
60
|
+
|
61
|
+
# Move us far enough into the future that we're passed the horizons for
|
62
|
+
# both a GC run as well as well as the expiry age of a connection
|
63
|
+
# manager. That means the GC will run and collect the connection
|
64
|
+
# manager that we created above.
|
65
|
+
Timecop.freeze(t + StripeClient::CONNECTION_MANAGER_GC_LAST_USED_EXPIRY + 1) do
|
66
|
+
assert_equal 1, StripeClient.maybe_gc_connection_managers
|
67
|
+
|
68
|
+
# And as an additional check, the connection manager of the current thread context should have been set to `nil` as it was GCed.
|
69
|
+
assert_nil StripeClient.current_thread_context.default_connection_manager
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
20
74
|
context ".clear_all_connection_managers" do
|
21
75
|
should "clear connection managers across all threads" do
|
22
76
|
stub_request(:post, "#{Stripe.api_base}/path")
|
@@ -199,20 +253,6 @@ module Stripe
|
|
199
253
|
end
|
200
254
|
end
|
201
255
|
|
202
|
-
context "#initialize" do
|
203
|
-
should "set Stripe.default_connection_manager" do
|
204
|
-
client = StripeClient.new
|
205
|
-
assert_equal StripeClient.default_connection_manager,
|
206
|
-
client.connection_manager
|
207
|
-
end
|
208
|
-
|
209
|
-
should "set a different connection if one was specified" do
|
210
|
-
connection_manager = ConnectionManager.new
|
211
|
-
client = StripeClient.new(connection_manager)
|
212
|
-
assert_equal connection_manager, client.connection_manager
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
256
|
context "#execute_request" do
|
217
257
|
context "headers" do
|
218
258
|
should "support literal headers" do
|
@@ -470,10 +510,10 @@ module Stripe
|
|
470
510
|
.to_return(body: "", status: 500)
|
471
511
|
|
472
512
|
client = StripeClient.new
|
513
|
+
|
473
514
|
e = assert_raises Stripe::APIError do
|
474
515
|
client.execute_request(:post, "/v1/charges")
|
475
516
|
end
|
476
|
-
|
477
517
|
assert_equal 'Invalid response object from API: "" (HTTP response code was 500)', e.message
|
478
518
|
end
|
479
519
|
|
@@ -482,22 +522,36 @@ module Stripe
|
|
482
522
|
.to_return(body: "", status: 200)
|
483
523
|
|
484
524
|
client = StripeClient.new
|
525
|
+
|
485
526
|
e = assert_raises Stripe::APIError do
|
486
527
|
client.execute_request(:post, "/v1/charges")
|
487
528
|
end
|
488
|
-
|
489
529
|
assert_equal 'Invalid response object from API: "" (HTTP response code was 200)', e.message
|
490
530
|
end
|
491
531
|
|
532
|
+
should "feed a request ID through to the error object" do
|
533
|
+
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
534
|
+
.to_return(body: JSON.generate(make_missing_id_error),
|
535
|
+
headers: { "Request-ID": "req_123" },
|
536
|
+
status: 400)
|
537
|
+
|
538
|
+
client = StripeClient.new
|
539
|
+
|
540
|
+
e = assert_raises Stripe::InvalidRequestError do
|
541
|
+
client.execute_request(:post, "/v1/charges")
|
542
|
+
end
|
543
|
+
assert_equal("req_123", e.request_id)
|
544
|
+
end
|
545
|
+
|
492
546
|
should "handle low level error" do
|
493
547
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
494
548
|
.to_raise(Errno::ECONNREFUSED.new)
|
495
549
|
|
496
550
|
client = StripeClient.new
|
551
|
+
|
497
552
|
e = assert_raises Stripe::APIConnectionError do
|
498
553
|
client.execute_request(:post, "/v1/charges")
|
499
554
|
end
|
500
|
-
|
501
555
|
assert_equal StripeClient::ERROR_MESSAGE_CONNECTION % Stripe.api_base +
|
502
556
|
"\n\n(Network error: Connection refused)",
|
503
557
|
e.message
|
@@ -508,10 +562,10 @@ module Stripe
|
|
508
562
|
.to_return(body: JSON.generate(bar: "foo"), status: 500)
|
509
563
|
|
510
564
|
client = StripeClient.new
|
565
|
+
|
511
566
|
e = assert_raises Stripe::APIError do
|
512
567
|
client.execute_request(:post, "/v1/charges")
|
513
568
|
end
|
514
|
-
|
515
569
|
assert_equal 'Invalid response object from API: "{\"bar\":\"foo\"}" (HTTP response code was 500)', e.message
|
516
570
|
end
|
517
571
|
|
@@ -521,6 +575,7 @@ module Stripe
|
|
521
575
|
|
522
576
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
523
577
|
.to_return(body: JSON.generate(data), status: 400)
|
578
|
+
|
524
579
|
client = StripeClient.new
|
525
580
|
|
526
581
|
e = assert_raises Stripe::IdempotencyError do
|
@@ -533,75 +588,81 @@ module Stripe
|
|
533
588
|
should "raise InvalidRequestError on other 400s" do
|
534
589
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
535
590
|
.to_return(body: JSON.generate(make_missing_id_error), status: 400)
|
591
|
+
|
536
592
|
client = StripeClient.new
|
537
|
-
|
593
|
+
|
594
|
+
e = assert_raises Stripe::InvalidRequestError do
|
538
595
|
client.execute_request(:post, "/v1/charges")
|
539
|
-
rescue Stripe::InvalidRequestError => e
|
540
|
-
assert_equal(400, e.http_status)
|
541
|
-
assert_equal(true, e.json_body.is_a?(Hash))
|
542
596
|
end
|
597
|
+
assert_equal(400, e.http_status)
|
598
|
+
assert_equal(true, e.json_body.is_a?(Hash))
|
543
599
|
end
|
544
600
|
|
545
601
|
should "raise AuthenticationError on 401" do
|
546
602
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
547
603
|
.to_return(body: JSON.generate(make_missing_id_error), status: 401)
|
604
|
+
|
548
605
|
client = StripeClient.new
|
549
|
-
|
606
|
+
|
607
|
+
e = assert_raises Stripe::AuthenticationError do
|
550
608
|
client.execute_request(:post, "/v1/charges")
|
551
|
-
rescue Stripe::AuthenticationError => e
|
552
|
-
assert_equal(401, e.http_status)
|
553
|
-
assert_equal(true, e.json_body.is_a?(Hash))
|
554
609
|
end
|
610
|
+
assert_equal(401, e.http_status)
|
611
|
+
assert_equal(true, e.json_body.is_a?(Hash))
|
555
612
|
end
|
556
613
|
|
557
614
|
should "raise CardError on 402" do
|
558
615
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
559
616
|
.to_return(body: JSON.generate(make_invalid_exp_year_error), status: 402)
|
617
|
+
|
560
618
|
client = StripeClient.new
|
561
|
-
|
619
|
+
|
620
|
+
e = assert_raises Stripe::CardError do
|
562
621
|
client.execute_request(:post, "/v1/charges")
|
563
|
-
rescue Stripe::CardError => e
|
564
|
-
assert_equal(402, e.http_status)
|
565
|
-
assert_equal(true, e.json_body.is_a?(Hash))
|
566
|
-
assert_equal("invalid_expiry_year", e.code)
|
567
|
-
assert_equal("exp_year", e.param)
|
568
622
|
end
|
623
|
+
assert_equal(402, e.http_status)
|
624
|
+
assert_equal(true, e.json_body.is_a?(Hash))
|
625
|
+
assert_equal("invalid_expiry_year", e.code)
|
626
|
+
assert_equal("exp_year", e.param)
|
569
627
|
end
|
570
628
|
|
571
629
|
should "raise PermissionError on 403" do
|
572
630
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
573
631
|
.to_return(body: JSON.generate(make_missing_id_error), status: 403)
|
632
|
+
|
574
633
|
client = StripeClient.new
|
575
|
-
|
634
|
+
|
635
|
+
e = assert_raises Stripe::PermissionError do
|
576
636
|
client.execute_request(:post, "/v1/charges")
|
577
|
-
rescue Stripe::PermissionError => e
|
578
|
-
assert_equal(403, e.http_status)
|
579
|
-
assert_equal(true, e.json_body.is_a?(Hash))
|
580
637
|
end
|
638
|
+
assert_equal(403, e.http_status)
|
639
|
+
assert_equal(true, e.json_body.is_a?(Hash))
|
581
640
|
end
|
582
641
|
|
583
642
|
should "raise InvalidRequestError on 404" do
|
584
643
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
585
644
|
.to_return(body: JSON.generate(make_missing_id_error), status: 404)
|
645
|
+
|
586
646
|
client = StripeClient.new
|
587
|
-
|
647
|
+
|
648
|
+
e = assert_raises Stripe::InvalidRequestError do
|
588
649
|
client.execute_request(:post, "/v1/charges")
|
589
|
-
rescue Stripe::InvalidRequestError => e
|
590
|
-
assert_equal(404, e.http_status)
|
591
|
-
assert_equal(true, e.json_body.is_a?(Hash))
|
592
650
|
end
|
651
|
+
assert_equal(404, e.http_status)
|
652
|
+
assert_equal(true, e.json_body.is_a?(Hash))
|
593
653
|
end
|
594
654
|
|
595
655
|
should "raise RateLimitError on 429" do
|
596
656
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
597
657
|
.to_return(body: JSON.generate(make_rate_limit_error), status: 429)
|
658
|
+
|
598
659
|
client = StripeClient.new
|
599
|
-
|
660
|
+
|
661
|
+
e = assert_raises Stripe::RateLimitError do
|
600
662
|
client.execute_request(:post, "/v1/charges")
|
601
|
-
rescue Stripe::RateLimitError => e
|
602
|
-
assert_equal(429, e.http_status)
|
603
|
-
assert_equal(true, e.json_body.is_a?(Hash))
|
604
663
|
end
|
664
|
+
assert_equal(429, e.http_status)
|
665
|
+
assert_equal(true, e.json_body.is_a?(Hash))
|
605
666
|
end
|
606
667
|
|
607
668
|
should "raise OAuth::InvalidRequestError when error is a string with value 'invalid_request'" do
|
@@ -610,6 +671,7 @@ module Stripe
|
|
610
671
|
error_description: "No grant type specified"), status: 400)
|
611
672
|
|
612
673
|
client = StripeClient.new
|
674
|
+
|
613
675
|
opts = { api_base: Stripe.connect_base }
|
614
676
|
e = assert_raises Stripe::OAuth::InvalidRequestError do
|
615
677
|
client.execute_request(:post, "/oauth/token", opts)
|
@@ -625,6 +687,7 @@ module Stripe
|
|
625
687
|
error_description: "This authorization code has already been used. All tokens issued with this code have been revoked."), status: 400)
|
626
688
|
|
627
689
|
client = StripeClient.new
|
690
|
+
|
628
691
|
opts = { api_base: Stripe.connect_base }
|
629
692
|
e = assert_raises Stripe::OAuth::InvalidGrantError do
|
630
693
|
client.execute_request(:post, "/oauth/token", opts)
|
@@ -641,6 +704,7 @@ module Stripe
|
|
641
704
|
error_description: "This application is not connected to stripe account acct_19tLK7DSlTMT26Mk, or that account does not exist."), status: 401)
|
642
705
|
|
643
706
|
client = StripeClient.new
|
707
|
+
|
644
708
|
opts = { api_base: Stripe.connect_base }
|
645
709
|
e = assert_raises Stripe::OAuth::InvalidClientError do
|
646
710
|
client.execute_request(:post, "/oauth/deauthorize", opts)
|
@@ -657,6 +721,7 @@ module Stripe
|
|
657
721
|
error_description: "Something."), status: 401)
|
658
722
|
|
659
723
|
client = StripeClient.new
|
724
|
+
|
660
725
|
opts = { api_base: Stripe.connect_base }
|
661
726
|
e = assert_raises Stripe::OAuth::OAuthError do
|
662
727
|
client.execute_request(:post, "/oauth/deauthorize", opts)
|
@@ -817,6 +882,22 @@ module Stripe
|
|
817
882
|
end
|
818
883
|
end
|
819
884
|
|
885
|
+
context "#connection_manager" do
|
886
|
+
should "warn that #connection_manager is deprecated" do
|
887
|
+
old_stderr = $stderr
|
888
|
+
$stderr = StringIO.new
|
889
|
+
begin
|
890
|
+
client = StripeClient.new
|
891
|
+
client.connection_manager
|
892
|
+
message = "NOTE: Stripe::StripeClient#connection_manager is " \
|
893
|
+
"deprecated"
|
894
|
+
assert_match Regexp.new(message), $stderr.string
|
895
|
+
ensure
|
896
|
+
$stderr = old_stderr
|
897
|
+
end
|
898
|
+
end
|
899
|
+
end
|
900
|
+
|
820
901
|
context "#request" do
|
821
902
|
should "return a result and response object" do
|
822
903
|
stub_request(:post, "#{Stripe.api_base}/v1/charges")
|
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.2.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-09-
|
11
|
+
date: 2019-09-20 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.
|