stripe 5.1.1 → 5.2.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 +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.
|