connection_pool 2.1.3 → 2.2.4

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.
@@ -1,3 +1,3 @@
1
1
  class ConnectionPool
2
- VERSION = "2.1.3"
2
+ VERSION = "2.2.4"
3
3
  end
@@ -0,0 +1,51 @@
1
+ class ConnectionPool
2
+ class Wrapper < ::BasicObject
3
+ METHODS = [:with, :pool_shutdown, :wrapped_pool]
4
+
5
+ def initialize(options = {}, &block)
6
+ @pool = options.fetch(:pool) { ::ConnectionPool.new(options, &block) }
7
+ end
8
+
9
+ def wrapped_pool
10
+ @pool
11
+ end
12
+
13
+ def with(&block)
14
+ @pool.with(&block)
15
+ end
16
+
17
+ def pool_shutdown(&block)
18
+ @pool.shutdown(&block)
19
+ end
20
+
21
+ def pool_size
22
+ @pool.size
23
+ end
24
+
25
+ def pool_available
26
+ @pool.available
27
+ end
28
+
29
+ def respond_to?(id, *args)
30
+ METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
31
+ end
32
+
33
+ # rubocop:disable Style/MethodMissingSuper
34
+ # rubocop:disable Style/MissingRespondToMissing
35
+ if ::RUBY_VERSION >= "2.7.0"
36
+ def method_missing(name, *args, **kwargs, &block)
37
+ with do |connection|
38
+ connection.send(name, *args, **kwargs, &block)
39
+ end
40
+ end
41
+ else
42
+ def method_missing(name, *args, &block)
43
+ with do |connection|
44
+ connection.send(name, *args, &block)
45
+ end
46
+ end
47
+ end
48
+ # rubocop:enable Style/MethodMissingSuper
49
+ # rubocop:enable Style/MissingRespondToMissing
50
+ end
51
+ end
data/test/helper.rb CHANGED
@@ -1,8 +1,8 @@
1
- gem 'minitest'
1
+ gem "minitest"
2
2
 
3
- require 'minitest/pride'
4
- require 'minitest/autorun'
3
+ require "minitest/pride"
4
+ require "minitest/autorun"
5
5
 
6
6
  $VERBOSE = 1
7
7
 
8
- require_relative '../lib/connection_pool'
8
+ require_relative "../lib/connection_pool"
@@ -1,15 +1,16 @@
1
- require_relative 'helper'
1
+ require_relative "helper"
2
2
 
3
3
  class TestConnectionPool < Minitest::Test
4
-
5
4
  class NetworkConnection
5
+ SLEEP_TIME = 0.1
6
+
6
7
  def initialize
7
8
  @x = 0
8
9
  end
9
10
 
10
- def do_something
11
- @x += 1
12
- sleep 0.05
11
+ def do_something(*_args, increment: 1)
12
+ @x += increment
13
+ sleep SLEEP_TIME
13
14
  @x
14
15
  end
15
16
 
@@ -19,7 +20,7 @@ class TestConnectionPool < Minitest::Test
19
20
 
20
21
  def do_something_with_block
21
22
  @x += yield
22
- sleep 0.05
23
+ sleep SLEEP_TIME
23
24
  @x
24
25
  end
25
26
 
@@ -41,12 +42,12 @@ class TestConnectionPool < Minitest::Test
41
42
  end
42
43
 
43
44
  def use_pool(pool, size)
44
- Array.new(size) do
45
+ Array.new(size) {
45
46
  Thread.new do
46
- pool.with do sleep end
47
+ pool.with { sleep }
47
48
  end
48
- end.each do |thread|
49
- Thread.pass until thread.status == 'sleep'
49
+ }.each do |thread|
50
+ Thread.pass until thread.status == "sleep"
50
51
  end
51
52
  end
52
53
 
@@ -58,33 +59,38 @@ class TestConnectionPool < Minitest::Test
58
59
  end
59
60
 
60
61
  def test_basic_multithreaded_usage
61
- pool = ConnectionPool.new(:size => 5) { NetworkConnection.new }
62
+ pool_size = 5
63
+ pool = ConnectionPool.new(size: pool_size) { NetworkConnection.new }
64
+
65
+ start = Time.new
66
+
67
+ generations = 3
62
68
 
63
- threads = Array.new(15) do
69
+ result = Array.new(pool_size * generations) {
64
70
  Thread.new do
65
71
  pool.with do |net|
66
72
  net.do_something
67
73
  end
68
74
  end
69
- end
75
+ }.map(&:value)
76
+
77
+ finish = Time.new
78
+
79
+ assert_equal((1..generations).cycle(pool_size).sort, result.sort)
70
80
 
71
- a = Time.now
72
- result = threads.map(&:value)
73
- b = Time.now
74
- assert_operator((b - a), :>, 0.125)
75
- assert_equal([1,2,3].cycle(5).sort, result.sort)
81
+ assert_operator(finish - start, :>, generations * NetworkConnection::SLEEP_TIME)
76
82
  end
77
83
 
78
84
  def test_timeout
79
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { NetworkConnection.new }
80
- thread = Thread.new do
85
+ pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
86
+ thread = Thread.new {
81
87
  pool.with do |net|
82
88
  net.do_something
83
89
  sleep 0.01
84
90
  end
85
- end
91
+ }
86
92
 
87
- Thread.pass while thread.status == 'run'
93
+ Thread.pass while thread.status == "run"
88
94
 
89
95
  assert_raises Timeout::Error do
90
96
  pool.with { |net| net.do_something }
@@ -98,79 +104,132 @@ class TestConnectionPool < Minitest::Test
98
104
  end
99
105
 
100
106
  def test_with
101
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
107
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
102
108
 
103
109
  pool.with do
104
- assert_raises Timeout::Error do
105
- Thread.new { pool.checkout }.join
106
- end
110
+ Thread.new {
111
+ assert_raises Timeout::Error do
112
+ pool.checkout
113
+ end
114
+ }.join
107
115
  end
108
116
 
109
117
  assert Thread.new { pool.checkout }.join
110
118
  end
111
119
 
112
- def test_with_with_dangerous_timeouts
113
- case RUBY_ENGINE.to_sym
114
- when :jruby
115
- skip('JRuby GC dislikes this test')
116
- when :ruby
117
- if RUBY_VERSION == '2.0.0' && RUBY_PATCHLEVEL == 598
118
- skip("#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} GC dislikes this test")
120
+ def test_then
121
+ pool = ConnectionPool.new { Object.new }
122
+
123
+ assert_equal pool.method(:then), pool.method(:with)
124
+ end
125
+
126
+ def test_with_timeout
127
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
128
+
129
+ assert_raises Timeout::Error do
130
+ Timeout.timeout(0.01) do
131
+ pool.with do |obj|
132
+ assert_equal 0, pool.available
133
+ sleep 0.015
134
+ end
119
135
  end
120
136
  end
137
+ assert_equal 1, pool.available
138
+ end
121
139
 
122
- marker_class = Class.new
123
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { marker_class.new }
140
+ def test_invalid_size
141
+ assert_raises ArgumentError, TypeError do
142
+ ConnectionPool.new(timeout: 0, size: nil) { Object.new }
143
+ end
144
+ assert_raises ArgumentError, TypeError do
145
+ ConnectionPool.new(timeout: 0, size: "") { Object.new }
146
+ end
147
+ end
124
148
 
125
- # no "connections" allocated yet
126
- assert_equal [], ObjectSpace.each_object(marker_class).to_a
149
+ def test_handle_interrupt_ensures_checkin
150
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
151
+ def pool.checkout(options)
152
+ sleep 0.015
153
+ super
154
+ end
127
155
 
128
- checkin_time = 0.05
156
+ did_something = false
129
157
 
130
- assert_raises Timeout::Error do
131
- Timeout.timeout(checkin_time) do
132
- pool.with do
133
- # a "connection" has been allocated
134
- refute_equal [], ObjectSpace.each_object(marker_class).to_a
135
- sleep 2 * checkin_time
158
+ action = lambda do
159
+ Timeout.timeout(0.01) do
160
+ pool.with do |obj|
161
+ did_something = true
162
+ # Timeout::Error will be triggered by any non-trivial Ruby code
163
+ # executed here since it couldn't be raised during checkout.
164
+ # It looks like setting the local variable above does not trigger
165
+ # the Timeout check in MRI 2.2.1.
166
+ obj.tap { obj.hash }
136
167
  end
137
168
  end
138
169
  end
139
170
 
140
- GC.start
171
+ if RUBY_ENGINE == "ruby"
172
+ # These asserts rely on the Ruby implementation reaching `did_something =
173
+ # true` before the interrupt is detected by the thread. Interrupt
174
+ # detection timing is implementation-specific in practice, with JRuby,
175
+ # Rubinius, and TruffleRuby all having different interrupt timings to MRI.
176
+ # In fact they generally detect interrupts more quickly than MRI, so they
177
+ # may not reach `did_something = true` before detecting the interrupt.
178
+
179
+ assert_raises Timeout::Error, &action
180
+
181
+ assert did_something
182
+ else
183
+ action.call
184
+ end
185
+
186
+ assert_equal 1, pool.available
187
+ end
188
+
189
+ def test_explicit_return
190
+ pool = ConnectionPool.new(timeout: 0, size: 1) {
191
+ mock = Minitest::Mock.new
192
+ def mock.disconnect!
193
+ raise "should not disconnect upon explicit return"
194
+ end
195
+ mock
196
+ }
141
197
 
142
- # no dangling references to this "connection" remain
143
- assert_equal [], ObjectSpace.each_object(marker_class).to_a
198
+ pool.with do |conn|
199
+ return true
200
+ end
144
201
  end
145
202
 
146
203
  def test_with_timeout_override
147
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { NetworkConnection.new }
204
+ pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
148
205
 
149
- t = Thread.new do
206
+ t = Thread.new {
150
207
  pool.with do |net|
151
208
  net.do_something
152
209
  sleep 0.01
153
210
  end
154
- end
211
+ }
155
212
 
156
- Thread.pass while t.status == 'run'
213
+ Thread.pass while t.status == "run"
157
214
 
158
215
  assert_raises Timeout::Error do
159
216
  pool.with { |net| net.do_something }
160
217
  end
161
218
 
162
- pool.with(:timeout => 0.1) do |conn|
219
+ pool.with(timeout: 2 * NetworkConnection::SLEEP_TIME) do |conn|
163
220
  refute_nil conn
164
221
  end
165
222
  end
166
223
 
167
224
  def test_checkin
168
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { NetworkConnection.new }
225
+ pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
169
226
  conn = pool.checkout
170
227
 
171
- assert_raises Timeout::Error do
172
- Thread.new { pool.checkout }.join
173
- end
228
+ Thread.new {
229
+ assert_raises Timeout::Error do
230
+ pool.checkout
231
+ end
232
+ }.join
174
233
 
175
234
  pool.checkin
176
235
 
@@ -178,22 +237,19 @@ class TestConnectionPool < Minitest::Test
178
237
  end
179
238
 
180
239
  def test_returns_value
181
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
182
- assert_equal 1, pool.with {|o| 1 }
240
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
241
+ assert_equal 1, pool.with { |o| 1 }
183
242
  end
184
243
 
185
244
  def test_checkin_never_checkout
186
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
245
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
187
246
 
188
- e = assert_raises ConnectionPool::Error do
189
- pool.checkin
190
- end
191
-
192
- assert_equal 'no connections are checked out', e.message
247
+ e = assert_raises(ConnectionPool::Error) { pool.checkin }
248
+ assert_equal "no connections are checked out", e.message
193
249
  end
194
250
 
195
251
  def test_checkin_no_current_checkout
196
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
252
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
197
253
 
198
254
  pool.checkout
199
255
  pool.checkin
@@ -204,18 +260,18 @@ class TestConnectionPool < Minitest::Test
204
260
  end
205
261
 
206
262
  def test_checkin_twice
207
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
263
+ pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
208
264
 
209
265
  pool.checkout
210
266
  pool.checkout
211
267
 
212
268
  pool.checkin
213
269
 
214
- assert_raises Timeout::Error do
215
- Thread.new do
270
+ Thread.new {
271
+ assert_raises Timeout::Error do
216
272
  pool.checkout
217
- end.join
218
- end
273
+ end
274
+ }.join
219
275
 
220
276
  pool.checkin
221
277
 
@@ -223,7 +279,7 @@ class TestConnectionPool < Minitest::Test
223
279
  end
224
280
 
225
281
  def test_checkout
226
- pool = ConnectionPool.new(:size => 1) { NetworkConnection.new }
282
+ pool = ConnectionPool.new(size: 1) { NetworkConnection.new }
227
283
 
228
284
  conn = pool.checkout
229
285
 
@@ -233,18 +289,18 @@ class TestConnectionPool < Minitest::Test
233
289
  end
234
290
 
235
291
  def test_checkout_multithread
236
- pool = ConnectionPool.new(:size => 2) { NetworkConnection.new }
292
+ pool = ConnectionPool.new(size: 2) { NetworkConnection.new }
237
293
  conn = pool.checkout
238
294
 
239
- t = Thread.new do
295
+ t = Thread.new {
240
296
  pool.checkout
241
- end
297
+ }
242
298
 
243
299
  refute_same conn, t.value
244
300
  end
245
301
 
246
302
  def test_checkout_timeout
247
- pool = ConnectionPool.new(:timeout => 0, :size => 0) { Object.new }
303
+ pool = ConnectionPool.new(timeout: 0, size: 0) { Object.new }
248
304
 
249
305
  assert_raises Timeout::Error do
250
306
  pool.checkout
@@ -252,34 +308,35 @@ class TestConnectionPool < Minitest::Test
252
308
  end
253
309
 
254
310
  def test_checkout_timeout_override
255
- pool = ConnectionPool.new(:timeout => 0, :size => 1) { NetworkConnection.new }
311
+ pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
256
312
 
257
- thread = Thread.new do
313
+ thread = Thread.new {
258
314
  pool.with do |net|
259
315
  net.do_something
260
316
  sleep 0.01
261
317
  end
262
- end
318
+ }
263
319
 
264
- Thread.pass while thread.status == 'run'
320
+ Thread.pass while thread.status == "run"
265
321
 
266
322
  assert_raises Timeout::Error do
267
323
  pool.checkout
268
324
  end
269
325
 
270
- assert pool.checkout :timeout => 0.1
326
+ assert pool.checkout timeout: 2 * NetworkConnection::SLEEP_TIME
271
327
  end
272
328
 
273
329
  def test_passthru
274
- pool = ConnectionPool.wrap(:timeout => 0.1, :size => 1) { NetworkConnection.new }
330
+ pool = ConnectionPool.wrap(timeout: 2 * NetworkConnection::SLEEP_TIME, size: 1) { NetworkConnection.new }
275
331
  assert_equal 1, pool.do_something
276
332
  assert_equal 2, pool.do_something
277
333
  assert_equal 5, pool.do_something_with_block { 3 }
278
334
  assert_equal 6, pool.with { |net| net.fast }
335
+ assert_equal 8, pool.do_something(increment: 2)
279
336
  end
280
337
 
281
338
  def test_passthru_respond_to
282
- pool = ConnectionPool.wrap(:timeout => 0.1, :size => 1) { NetworkConnection.new }
339
+ pool = ConnectionPool.wrap(timeout: 2 * NetworkConnection::SLEEP_TIME, size: 1) { NetworkConnection.new }
283
340
  assert pool.respond_to?(:with)
284
341
  assert pool.respond_to?(:do_something)
285
342
  assert pool.respond_to?(:do_magic)
@@ -287,67 +344,67 @@ class TestConnectionPool < Minitest::Test
287
344
  end
288
345
 
289
346
  def test_return_value
290
- pool = ConnectionPool.new(:timeout => 0.1, :size => 1) { NetworkConnection.new }
291
- result = pool.with do |net|
347
+ pool = ConnectionPool.new(timeout: 2 * NetworkConnection::SLEEP_TIME, size: 1) { NetworkConnection.new }
348
+ result = pool.with { |net|
292
349
  net.fast
293
- end
350
+ }
294
351
  assert_equal 1, result
295
352
  end
296
353
 
297
354
  def test_heavy_threading
298
- pool = ConnectionPool.new(:timeout => 0.5, :size => 3) { NetworkConnection.new }
355
+ pool = ConnectionPool.new(timeout: 0.5, size: 3) { NetworkConnection.new }
299
356
 
300
- threads = Array.new(20) do
357
+ threads = Array.new(20) {
301
358
  Thread.new do
302
359
  pool.with do |net|
303
360
  sleep 0.01
304
361
  end
305
362
  end
306
- end
363
+ }
307
364
 
308
365
  threads.map { |thread| thread.join }
309
366
  end
310
367
 
311
368
  def test_reuses_objects_when_pool_not_saturated
312
- pool = ConnectionPool.new(:size => 5) { NetworkConnection.new }
369
+ pool = ConnectionPool.new(size: 5) { NetworkConnection.new }
313
370
 
314
- ids = 10.times.map do
371
+ ids = 10.times.map {
315
372
  pool.with { |c| c.object_id }
316
- end
373
+ }
317
374
 
318
375
  assert_equal 1, ids.uniq.size
319
376
  end
320
377
 
321
378
  def test_nested_checkout
322
379
  recorder = Recorder.new
323
- pool = ConnectionPool.new(:size => 1) { recorder }
380
+ pool = ConnectionPool.new(size: 1) { recorder }
324
381
  pool.with do |r_outer|
325
- @other = Thread.new do |t|
382
+ @other = Thread.new { |t|
326
383
  pool.with do |r_other|
327
- r_other.do_work('other')
384
+ r_other.do_work("other")
328
385
  end
329
- end
386
+ }
330
387
 
331
388
  pool.with do |r_inner|
332
- r_inner.do_work('inner')
389
+ r_inner.do_work("inner")
333
390
  end
334
391
 
335
392
  Thread.pass
336
393
 
337
- r_outer.do_work('outer')
394
+ r_outer.do_work("outer")
338
395
  end
339
396
 
340
397
  @other.join
341
398
 
342
- assert_equal ['inner', 'outer', 'other'], recorder.calls
399
+ assert_equal ["inner", "outer", "other"], recorder.calls
343
400
  end
344
401
 
345
402
  def test_shutdown_is_executed_for_all_connections
346
403
  recorders = []
347
404
 
348
- pool = ConnectionPool.new(:size => 3) do
405
+ pool = ConnectionPool.new(size: 3) {
349
406
  Recorder.new.tap { |r| recorders << r }
350
- end
407
+ }
351
408
 
352
409
  threads = use_pool pool, 3
353
410
 
@@ -361,9 +418,9 @@ class TestConnectionPool < Minitest::Test
361
418
  end
362
419
 
363
420
  def test_raises_error_after_shutting_down
364
- pool = ConnectionPool.new(:size => 1) { true }
421
+ pool = ConnectionPool.new(size: 1) { true }
365
422
 
366
- pool.shutdown { }
423
+ pool.shutdown {}
367
424
 
368
425
  assert_raises ConnectionPool::PoolShuttingDownError do
369
426
  pool.checkout
@@ -373,9 +430,9 @@ class TestConnectionPool < Minitest::Test
373
430
  def test_runs_shutdown_block_asynchronously_if_connection_was_in_use
374
431
  recorders = []
375
432
 
376
- pool = ConnectionPool.new(:size => 3) do
433
+ pool = ConnectionPool.new(size: 3) {
377
434
  Recorder.new.tap { |r| recorders << r }
378
- end
435
+ }
379
436
 
380
437
  threads = use_pool pool, 2
381
438
 
@@ -395,7 +452,7 @@ class TestConnectionPool < Minitest::Test
395
452
  end
396
453
 
397
454
  def test_raises_an_error_if_shutdown_is_called_without_a_block
398
- pool = ConnectionPool.new(:size => 1) { }
455
+ pool = ConnectionPool.new(size: 1) {}
399
456
 
400
457
  assert_raises ArgumentError do
401
458
  pool.shutdown
@@ -405,9 +462,9 @@ class TestConnectionPool < Minitest::Test
405
462
  def test_shutdown_is_executed_for_all_connections_in_wrapped_pool
406
463
  recorders = []
407
464
 
408
- wrapper = ConnectionPool::Wrapper.new(:size => 3) do
465
+ wrapper = ConnectionPool::Wrapper.new(size: 3) {
409
466
  Recorder.new.tap { |r| recorders << r }
410
- end
467
+ }
411
468
 
412
469
  threads = use_pool wrapper, 3
413
470
 
@@ -420,6 +477,11 @@ class TestConnectionPool < Minitest::Test
420
477
  assert_equal [["shutdown"]] * 3, recorders.map { |r| r.calls }
421
478
  end
422
479
 
480
+ def test_wrapper_wrapped_pool
481
+ wrapper = ConnectionPool::Wrapper.new { NetworkConnection.new }
482
+ assert_equal ConnectionPool, wrapper.wrapped_pool.class
483
+ end
484
+
423
485
  def test_wrapper_method_missing
424
486
  wrapper = ConnectionPool::Wrapper.new { NetworkConnection.new }
425
487
 
@@ -436,17 +498,17 @@ class TestConnectionPool < Minitest::Test
436
498
  end
437
499
 
438
500
  def test_wrapper_with
439
- wrapper = ConnectionPool::Wrapper.new(:timeout => 0, :size => 1) { Object.new }
501
+ wrapper = ConnectionPool::Wrapper.new(timeout: 0, size: 1) { Object.new }
440
502
 
441
503
  wrapper.with do
442
- assert_raises Timeout::Error do
443
- Thread.new do
444
- wrapper.with { flunk 'connection checked out :(' }
445
- end.join
446
- end
504
+ Thread.new {
505
+ assert_raises Timeout::Error do
506
+ wrapper.with { flunk "connection checked out :(" }
507
+ end
508
+ }.join
447
509
  end
448
510
 
449
- assert Thread.new { wrapper.with { } }.join
511
+ assert Thread.new { wrapper.with {} }.join
450
512
  end
451
513
 
452
514
  class ConnWithEval
@@ -461,4 +523,38 @@ class TestConnectionPool < Minitest::Test
461
523
  assert_equal "eval'ed 1", wrapper.eval(1)
462
524
  end
463
525
 
526
+ def test_wrapper_with_connection_pool
527
+ recorder = Recorder.new
528
+ pool = ConnectionPool.new(size: 1) { recorder }
529
+ wrapper = ConnectionPool::Wrapper.new(pool: pool)
530
+
531
+ pool.with { |r| r.do_work("with") }
532
+ wrapper.do_work("wrapped")
533
+
534
+ assert_equal ["with", "wrapped"], recorder.calls
535
+ end
536
+
537
+ def test_stats_without_active_connection
538
+ pool = ConnectionPool.new(size: 2) { NetworkConnection.new }
539
+
540
+ assert_equal(2, pool.size)
541
+ assert_equal(2, pool.available)
542
+ end
543
+
544
+ def test_stats_with_active_connection
545
+ pool = ConnectionPool.new(size: 2) { NetworkConnection.new }
546
+
547
+ pool.with do
548
+ assert_equal(1, pool.available)
549
+ end
550
+ end
551
+
552
+ def test_stats_with_string_size
553
+ pool = ConnectionPool.new(size: "2") { NetworkConnection.new }
554
+
555
+ pool.with do
556
+ assert_equal(2, pool.size)
557
+ assert_equal(1, pool.available)
558
+ end
559
+ end
464
560
  end