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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +21 -0
- data/Changes.md +35 -0
- data/README.md +53 -14
- data/Rakefile +3 -3
- data/connection_pool.gemspec +14 -14
- data/lib/connection_pool.rb +58 -69
- data/lib/connection_pool/timed_stack.rb +17 -39
- data/lib/connection_pool/version.rb +1 -1
- data/lib/connection_pool/wrapper.rb +51 -0
- data/test/helper.rb +4 -4
- data/test/test_connection_pool.rb +210 -114
- data/test/test_connection_pool_timed_stack.rb +22 -21
- metadata +9 -9
- data/.travis.yml +0 -14
@@ -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,15 +1,16 @@
|
|
1
|
-
require_relative
|
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 +=
|
12
|
-
sleep
|
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
|
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)
|
45
|
+
Array.new(size) {
|
45
46
|
Thread.new do
|
46
|
-
pool.with
|
47
|
+
pool.with { sleep }
|
47
48
|
end
|
48
|
-
|
49
|
-
Thread.pass until thread.status ==
|
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
|
-
|
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
|
-
|
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
|
-
|
75
|
+
}.map(&:value)
|
76
|
+
|
77
|
+
finish = Time.new
|
78
|
+
|
79
|
+
assert_equal((1..generations).cycle(pool_size).sort, result.sort)
|
70
80
|
|
71
|
-
|
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(:
|
80
|
-
thread = Thread.new
|
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
|
-
|
91
|
+
}
|
86
92
|
|
87
|
-
Thread.pass while thread.status ==
|
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(:
|
107
|
+
pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
|
102
108
|
|
103
109
|
pool.with do
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
-
|
123
|
-
|
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
|
-
|
126
|
-
|
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
|
-
|
156
|
+
did_something = false
|
129
157
|
|
130
|
-
|
131
|
-
Timeout.timeout(
|
132
|
-
pool.with do
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
-
|
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
|
-
|
143
|
-
|
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(:
|
204
|
+
pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
|
148
205
|
|
149
|
-
t = Thread.new
|
206
|
+
t = Thread.new {
|
150
207
|
pool.with do |net|
|
151
208
|
net.do_something
|
152
209
|
sleep 0.01
|
153
210
|
end
|
154
|
-
|
211
|
+
}
|
155
212
|
|
156
|
-
Thread.pass while t.status ==
|
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(:
|
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(:
|
225
|
+
pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
|
169
226
|
conn = pool.checkout
|
170
227
|
|
171
|
-
|
172
|
-
|
173
|
-
|
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(:
|
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(:
|
245
|
+
pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
|
187
246
|
|
188
|
-
e = assert_raises
|
189
|
-
|
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(:
|
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(:
|
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
|
-
|
215
|
-
|
270
|
+
Thread.new {
|
271
|
+
assert_raises Timeout::Error do
|
216
272
|
pool.checkout
|
217
|
-
end
|
218
|
-
|
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(:
|
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(:
|
292
|
+
pool = ConnectionPool.new(size: 2) { NetworkConnection.new }
|
237
293
|
conn = pool.checkout
|
238
294
|
|
239
|
-
t = Thread.new
|
295
|
+
t = Thread.new {
|
240
296
|
pool.checkout
|
241
|
-
|
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(:
|
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(:
|
311
|
+
pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
|
256
312
|
|
257
|
-
thread = Thread.new
|
313
|
+
thread = Thread.new {
|
258
314
|
pool.with do |net|
|
259
315
|
net.do_something
|
260
316
|
sleep 0.01
|
261
317
|
end
|
262
|
-
|
318
|
+
}
|
263
319
|
|
264
|
-
Thread.pass while thread.status ==
|
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 :
|
326
|
+
assert pool.checkout timeout: 2 * NetworkConnection::SLEEP_TIME
|
271
327
|
end
|
272
328
|
|
273
329
|
def test_passthru
|
274
|
-
pool = ConnectionPool.wrap(:
|
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(:
|
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(:
|
291
|
-
result = pool.with
|
347
|
+
pool = ConnectionPool.new(timeout: 2 * NetworkConnection::SLEEP_TIME, size: 1) { NetworkConnection.new }
|
348
|
+
result = pool.with { |net|
|
292
349
|
net.fast
|
293
|
-
|
350
|
+
}
|
294
351
|
assert_equal 1, result
|
295
352
|
end
|
296
353
|
|
297
354
|
def test_heavy_threading
|
298
|
-
pool = ConnectionPool.new(:
|
355
|
+
pool = ConnectionPool.new(timeout: 0.5, size: 3) { NetworkConnection.new }
|
299
356
|
|
300
|
-
threads = Array.new(20)
|
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
|
-
|
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(:
|
369
|
+
pool = ConnectionPool.new(size: 5) { NetworkConnection.new }
|
313
370
|
|
314
|
-
ids = 10.times.map
|
371
|
+
ids = 10.times.map {
|
315
372
|
pool.with { |c| c.object_id }
|
316
|
-
|
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(:
|
380
|
+
pool = ConnectionPool.new(size: 1) { recorder }
|
324
381
|
pool.with do |r_outer|
|
325
|
-
@other = Thread.new
|
382
|
+
@other = Thread.new { |t|
|
326
383
|
pool.with do |r_other|
|
327
|
-
r_other.do_work(
|
384
|
+
r_other.do_work("other")
|
328
385
|
end
|
329
|
-
|
386
|
+
}
|
330
387
|
|
331
388
|
pool.with do |r_inner|
|
332
|
-
r_inner.do_work(
|
389
|
+
r_inner.do_work("inner")
|
333
390
|
end
|
334
391
|
|
335
392
|
Thread.pass
|
336
393
|
|
337
|
-
r_outer.do_work(
|
394
|
+
r_outer.do_work("outer")
|
338
395
|
end
|
339
396
|
|
340
397
|
@other.join
|
341
398
|
|
342
|
-
assert_equal [
|
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(:
|
405
|
+
pool = ConnectionPool.new(size: 3) {
|
349
406
|
Recorder.new.tap { |r| recorders << r }
|
350
|
-
|
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(:
|
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(:
|
433
|
+
pool = ConnectionPool.new(size: 3) {
|
377
434
|
Recorder.new.tap { |r| recorders << r }
|
378
|
-
|
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(:
|
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(:
|
465
|
+
wrapper = ConnectionPool::Wrapper.new(size: 3) {
|
409
466
|
Recorder.new.tap { |r| recorders << r }
|
410
|
-
|
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(:
|
501
|
+
wrapper = ConnectionPool::Wrapper.new(timeout: 0, size: 1) { Object.new }
|
440
502
|
|
441
503
|
wrapper.with do
|
442
|
-
|
443
|
-
|
444
|
-
wrapper.with { flunk
|
445
|
-
end
|
446
|
-
|
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 {
|
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
|