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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3317e27f361af5e5506ab608ccdc9c18b3746c76e6244a5db15b149135b7deee
4
- data.tar.gz: 65f8bd1faf0c64125bfd0badeb835e555cf3a23437bf8d62c3101058b153de76
3
+ metadata.gz: 0ec1d1414aafc87b63dca172263ecd4666467cda2ab39eaac1abdbd13e7cd90b
4
+ data.tar.gz: 3adde22d80c8f867e34d2735dd0aea142f0b69e6cd2a84e13fe7c6a53655ee85
5
5
  SHA512:
6
- metadata.gz: b5123ec85b0009c8ae4b3ae7c3532fc59f6501abaaf350f106cd0e64f9d2fec221bd54ca9384636edec370922391d48ceafdb044394a1367a45fdef4e372888e
7
- data.tar.gz: 5fa03e4c45c1b1e82b617fb50f79339740e3c431a0fefbda0c6af78ce4bb0e1e2539ae67b9494fc5fa694ccec1c8444772f179c6f283f6cc6ea20abe71eb850f
6
+ metadata.gz: e4086cfa6bc5281bf1e31e88a2435156d6928716d7022e319afe5845157571731ad260c3728c6bf021d593f11727fa6fdba06c26667d7d5774b6a29cfadf9829
7
+ data.tar.gz: 4b6477d988e90607c8ad8c1d8a4a11e3f0afb3494948403d2b6b9e23cde4a6be0dcb9779100306c28449e6d7d24876043edcc2239ab00cdb1dc7fd88942b57de
@@ -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:
@@ -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:
@@ -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.1
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
- @active_connections.each do |_, connection|
27
- connection.finish
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
- u = URI.parse(uri)
39
- connection = @active_connections[[u.host, u.port]]
49
+ @mutex.synchronize do
50
+ u = URI.parse(uri)
51
+ connection = @active_connections[[u.host, u.port]]
40
52
 
41
- if connection.nil?
42
- connection = create_connection(u)
43
- connection.start
53
+ if connection.nil?
54
+ connection = create_connection(u)
55
+ connection.start
44
56
 
45
- @active_connections[[u.host, u.port]] = connection
46
- end
57
+ @active_connections[[u.host, u.port]] = connection
58
+ end
47
59
 
48
- connection
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
- connection.send_request(method.to_s.upcase, path, body, headers)
92
+ @mutex.synchronize do
93
+ connection.send_request(method.to_s.upcase, path, body, headers)
94
+ end
78
95
  end
79
96
 
80
97
  #
@@ -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 connection managers across all threads and a mutex to
8
+ # A set of all known thread contexts across all threads and a mutex to
9
9
  # synchronize global access to them.
10
- @all_connection_managers = []
11
- @all_connection_managers_mutex = Mutex.new
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
- attr_accessor :connection_manager
14
-
15
- # Initializes a new `StripeClient`. Expects a `ConnectionManager` object,
16
- # and uses a default connection manager unless one is passed.
17
- def initialize(connection_manager = nil)
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 @all_connection_managers.empty?
46
-
47
- @all_connection_managers_mutex.synchronize do
48
- @all_connection_managers.each(&:clear)
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
- @all_connection_managers_mutex.synchronize do
64
- @all_connection_managers << connection_manager
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
- connection_manager.execute_request(method, url,
211
- body: body,
212
- headers: headers,
213
- query: query)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stripe
4
- VERSION = "5.1.1"
4
+ VERSION = "5.2.0"
5
5
  end
@@ -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
- begin
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
- begin
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
- begin
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
- begin
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
- begin
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
- begin
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.1.1
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-04 00:00:00.000000000 Z
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.