em-pg-client 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,655 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'eventmachine'
5
+ require 'em-synchrony'
6
+ require 'pg/em/connection_pool'
7
+ require 'connection_pool_helpers'
8
+
9
+ RSpec.configure do |c|
10
+ c.include ConnectionPoolHelpers
11
+ end
12
+
13
+ describe PG::EM::ConnectionPool do
14
+ subject { PG::EM::ConnectionPool }
15
+
16
+ let(:client) { Class.new }
17
+ let(:deferrable) { PG::EM::FeaturedDeferrable }
18
+ let(:checkpoint) { proc {} }
19
+ let(:pgerror) { PG::Error.new }
20
+ let(:fooerror) { RuntimeError.new 'foo' }
21
+ let(:timeout) { 10 }
22
+
23
+ it "should allocate one connection" do
24
+ client.should_receive(:new).with({}).once.and_return(client.allocate)
25
+ pool = subject.new connection_class: client
26
+ pool.should be_an_instance_of subject
27
+ pool.max_size.should eq subject::DEFAULT_SIZE
28
+ pool.available.length.should eq 1
29
+ pool.allocated.length.should eq 0
30
+ pool.size.should eq 1
31
+ pool.available.first.should be_an_instance_of client
32
+ pool.available.first.should_receive(:finish).once
33
+ pool.finish.should be pool
34
+ pool.max_size.should eq subject::DEFAULT_SIZE
35
+ pool.available.length.should eq 0
36
+ pool.allocated.length.should eq 0
37
+ pool.size.should eq 0
38
+ end
39
+
40
+ it "should asynchronously allocate one connection" do
41
+ checkpoint.should_receive(:call) do |pool|
42
+ pool.should be_an_instance_of subject
43
+ pool.max_size.should eq 42
44
+ pool.available.length.should eq 1
45
+ pool.allocated.length.should eq 0
46
+ pool.size.should eq 1
47
+ pool.available.first.should be_an_instance_of client
48
+ end
49
+ client.should_receive(:connect_defer).with({}).once.and_return(
50
+ deferrable.new.tap {|df| df.succeed client.allocate }
51
+ )
52
+ df = subject.connect_defer connection_class: client, size: 42
53
+ df.should be_an_instance_of deferrable
54
+ df.callback(&checkpoint)
55
+ end
56
+
57
+ it "should write to client attributes and finish" do
58
+ client.should_receive(:new) do |options|
59
+ options.should be_empty
60
+ client.allocate.tap do |conn|
61
+ conn.should_receive(:connect_timeout=).with(timeout).once
62
+ conn.should_receive(:query_timeout=).with(timeout).once
63
+ conn.should_receive(:finish).once
64
+ end
65
+ end.exactly(3)
66
+ pool = subject.new connection_class: client, size: 3
67
+ pool.should be_an_instance_of subject
68
+ pool.connect_timeout.should be_nil
69
+ pool.query_timeout.should be_nil
70
+ pool.max_size.should eq 3
71
+ pool.available.length.should eq 1
72
+ pool.allocated.length.should eq 0
73
+ pool.size.should eq 1
74
+ pool.hold do
75
+ pool.size.should eq 1
76
+ Fiber.new do
77
+ pool.hold do
78
+ pool.size.should eq 2
79
+ Fiber.new do
80
+ pool.hold do
81
+ pool.available.length.should eq 0
82
+ pool.allocated.length.should eq 3
83
+ pool.size.should eq 3
84
+ end
85
+ end.resume
86
+ pool.available.length.should eq 1
87
+ pool.allocated.length.should eq 2
88
+ pool.connect_timeout = timeout
89
+ pool.query_timeout = timeout
90
+ end
91
+ end.resume
92
+ end
93
+ pool.available.length.should eq 3
94
+ pool.allocated.length.should eq 0
95
+ pool.size.should eq 3
96
+ pool.connect_timeout.should eq timeout
97
+ pool.query_timeout.should eq timeout
98
+ pool.finish.should be pool
99
+ pool.max_size.should eq 3
100
+ pool.available.length.should eq 0
101
+ pool.allocated.length.should eq 0
102
+ pool.size.should eq 0
103
+ end
104
+
105
+ it "should allocate new connection with altered attributes" do
106
+ client.should_receive(:new).with(
107
+ {connect_timeout: timeout, query_timeout: timeout}
108
+ ).once.and_return(client.allocate)
109
+ pool = subject.new connection_class: client, size: 1, lazy: true
110
+ pool.should be_an_instance_of subject
111
+ pool.connect_timeout.should be_nil
112
+ pool.query_timeout.should be_nil
113
+ pool.connect_timeout = timeout
114
+ pool.query_timeout = timeout
115
+ pool.connect_timeout.should eq timeout
116
+ pool.query_timeout.should eq timeout
117
+ pool.max_size.should eq 1
118
+ pool.available.length.should eq 0
119
+ pool.allocated.length.should eq 0
120
+ pool.size.should eq 0
121
+ pool.hold
122
+ pool.available.length.should eq 1
123
+ pool.allocated.length.should eq 0
124
+ pool.size.should eq 1
125
+ end
126
+
127
+ it "should lazy write attributes to connecting client" do
128
+ pool = nil
129
+ client.should_receive(:new) do |options|
130
+ options.should be_empty
131
+ pool.connect_timeout = timeout
132
+ pool.query_timeout = timeout
133
+ client.allocate.tap do |conn|
134
+ conn.should_receive(:connect_timeout=).with(timeout).once
135
+ conn.should_receive(:query_timeout=).with(timeout).once
136
+ end
137
+ end.once
138
+ client.should_receive(:connect_defer) do |options|
139
+ options.should be_empty
140
+ pool.connect_timeout = timeout
141
+ pool.query_timeout = timeout
142
+ deferrable.new.tap do |df|
143
+ df.succeed(client.allocate.tap do |conn|
144
+ conn.should_receive(:connect_timeout=).with(timeout).once
145
+ conn.should_receive(:query_timeout=).with(timeout).once
146
+ end)
147
+ end
148
+ end.once
149
+ checkpoint.should_receive(:call).with(:hurray).once
150
+
151
+ pool = subject.new connection_class: client, size: 1, lazy: true
152
+ pool.should be_an_instance_of subject
153
+ pool.connect_timeout.should be_nil
154
+ pool.query_timeout.should be_nil
155
+ pool.max_size.should eq 1
156
+ pool.size.should eq 0
157
+ pool.hold
158
+ pool.connect_timeout.should eq timeout
159
+ pool.query_timeout.should eq timeout
160
+ pool.size.should eq 1
161
+
162
+ pool = subject.new connection_class: client, size: 1, lazy: true
163
+ pool.should be_an_instance_of subject
164
+ pool.connect_timeout.should be_nil
165
+ pool.query_timeout.should be_nil
166
+ pool.__send__(:hold_deferred, checkpoint) do
167
+ deferrable.new.tap { |df| df.succeed :hurray }
168
+ end
169
+ pool.connect_timeout.should eq timeout
170
+ pool.query_timeout.should eq timeout
171
+ pool.size.should eq 1
172
+ end
173
+
174
+ it "should pass missing methods to connection" do
175
+ client.should_receive(:new) do
176
+ client.allocate.tap do |conn|
177
+ conn.should_receive(:foobar).once.and_return(:ok)
178
+ end
179
+ end.once
180
+ pool = subject.new connection_class: client
181
+ pool.should be_an_instance_of subject
182
+ pool.foobar.should be :ok
183
+ pool.respond_to?(:foobar).should be_true
184
+ pool.respond_to?(:crowbar).should be_false
185
+ end
186
+
187
+ it "should hold nested commands" do
188
+ ::EM.should_not_receive(:next_tick)
189
+ client.should_receive(:new).with({}).once.and_return(client.allocate)
190
+ pool = subject.new connection_class: client
191
+ pool.should be_an_instance_of subject
192
+ checkpoint.should_receive(:check) do |conn|
193
+ pool.max_size.should eq subject::DEFAULT_SIZE
194
+ pool.available.length.should eq 0
195
+ pool.allocated.length.should eq 1
196
+ pool.size.should eq 1
197
+ end.exactly(3)
198
+ pool.hold do |conn|
199
+ conn.should be_an_instance_of client
200
+ checkpoint.check
201
+ pool.hold do |conn2|
202
+ conn2.should be conn
203
+ checkpoint.check
204
+ end
205
+ checkpoint.check
206
+ end
207
+ pool.max_size.should eq subject::DEFAULT_SIZE
208
+ pool.available.length.should eq 1
209
+ pool.allocated.length.should eq 0
210
+ pool.size.should eq 1
211
+ pool.available.first.should be_an_instance_of client
212
+ end
213
+
214
+ it "should hold commands concurrently" do
215
+ ::EM.should_not_receive(:next_tick)
216
+ client.should_receive(:new) { client.allocate }.twice
217
+ pool = subject.new connection_class: client, size: 2
218
+ pool.should be_an_instance_of subject
219
+ pool.max_size.should eq 2
220
+ pool.available.length.should eq 1
221
+ pool.allocated.length.should eq 0
222
+ pool.size.should eq 1
223
+ pool.available.first.should be_an_instance_of client
224
+ checkpoint.should_receive(:check).exactly(8)
225
+ result = []
226
+ pool.hold do |conn1|
227
+ conn1.should be_an_instance_of client
228
+ result << conn1
229
+ pool.max_size.should eq 2
230
+ pool.available.length.should eq 0
231
+ pool.allocated.length.should eq 1
232
+ pool.size.should eq 1
233
+ checkpoint.check
234
+ Fiber.new do
235
+ pool.hold do |conn2|
236
+ conn2.should be_an_instance_of client
237
+ pool.instance_variable_get(:@pending).length.should eq 0
238
+ Fiber.new do
239
+ pool.hold do |conn3|
240
+ result << conn3
241
+ conn3.should be conn2
242
+ pool.available.length.should eq 0
243
+ pool.allocated.length.should eq 2
244
+ pool.size.should eq 2
245
+ checkpoint.check
246
+ end
247
+ end.resume
248
+ pool.instance_variable_get(:@pending).length.should eq 1
249
+ Fiber.new do
250
+ pool.hold do |conn4|
251
+ result << conn4
252
+ result.should eq [conn1, conn2, conn2, conn4]
253
+ conn4.should be conn2
254
+ pool.available.length.should eq 0
255
+ pool.allocated.length.should eq 2
256
+ pool.size.should eq 2
257
+ checkpoint.check
258
+ pool.hold do |conn5|
259
+ conn5.should be conn4
260
+ pool.max_size.should eq 2
261
+ pool.available.length.should eq 0
262
+ pool.allocated.length.should eq 2
263
+ pool.size.should eq 2
264
+ checkpoint.check
265
+ end
266
+ pool.available.length.should eq 0
267
+ pool.allocated.length.should eq 2
268
+ pool.size.should eq 2
269
+ checkpoint.check
270
+ end
271
+ end.resume
272
+ pool.instance_variable_get(:@pending).length.should eq 2
273
+ result << conn2
274
+ conn2.should_not be conn1
275
+ pool.available.length.should eq 0
276
+ pool.allocated.length.should eq 2
277
+ pool.size.should eq 2
278
+ checkpoint.check
279
+ end
280
+ pool.max_size.should eq 2
281
+ pool.available.length.should eq 1
282
+ pool.allocated.length.should eq 1
283
+ pool.size.should eq 2
284
+ checkpoint.check
285
+ end.resume
286
+ pool.instance_variable_get(:@pending).length.should eq 0
287
+ end
288
+ pool.max_size.should eq 2
289
+ pool.available.length.should eq 2
290
+ pool.allocated.length.should eq 0
291
+ pool.size.should eq 2
292
+ checkpoint.check
293
+ end
294
+
295
+ it "should hold deferred commands concurrently" do
296
+ ::EM.should_not_receive(:next_tick)
297
+ client.should_not_receive(:new)
298
+ client.should_receive(:connect_defer) do
299
+ deferrable.new.tap {|d| d.succeed client.allocate }
300
+ end.twice
301
+ checkpoint.should_receive(:call).exactly(4)
302
+ checkpoint.should_receive(:check).exactly(9)
303
+ pool = subject.new connection_class: client, size: 2, lazy: true
304
+ pool.should be_an_instance_of subject
305
+ pool.max_size.should eq 2
306
+ pool.available.length.should eq 0
307
+ pool.allocated.length.should eq 0
308
+ pool.size.should eq 0
309
+ result = []
310
+ df = pool.__send__(:hold_deferred, checkpoint) do |conn1|
311
+ conn1.should be_an_instance_of client
312
+ pool.available.length.should eq 0
313
+ pool.allocated.length.should eq 1
314
+ checkpoint.check
315
+ df2 = pool.__send__(:hold_deferred, checkpoint) do |conn2|
316
+ conn2.should be_an_instance_of client
317
+ conn2.should_not be conn1
318
+ pool.available.length.should eq 0
319
+ pool.allocated.length.should eq 2
320
+ checkpoint.check
321
+ df3 = pool.__send__(:hold_deferred, checkpoint) do |conn3|
322
+ conn3.should be_an_instance_of client
323
+ conn3.should be conn2
324
+ pool.available.length.should eq 0
325
+ pool.allocated.length.should eq 2
326
+ checkpoint.check
327
+ deferrable.new.tap {|d| d.succeed :result3 }
328
+ end
329
+ df3.should be_an_instance_of deferrable
330
+ df3.should_not be df
331
+ df3.should_not be df2
332
+ df3.callback do |result3|
333
+ result << result3
334
+ result3.should eq :result3
335
+ pool.available.length.should eq 1
336
+ pool.allocated.length.should eq 1
337
+ checkpoint.check
338
+ end
339
+ pool.instance_variable_get(:@pending).length.should eq 1
340
+ deferrable.new.tap {|d| d.succeed :result2 }
341
+ end
342
+ df2.should be_an_instance_of deferrable
343
+ df2.should_not be df
344
+ df2.callback do |result2|
345
+ result << result2
346
+ result2.should eq :result2
347
+ pool.available.length.should eq 1
348
+ pool.allocated.length.should eq 1
349
+ checkpoint.check
350
+ end
351
+ pool.instance_variable_get(:@pending).length.should eq 0
352
+ deferrable.new.tap {|d| d.succeed :result1 }
353
+ end
354
+ df.should be_an_instance_of deferrable
355
+ df.callback do |result1|
356
+ result << result1
357
+ result1.should eq :result1
358
+ pool.available.length.should eq 2
359
+ pool.allocated.length.should eq 0
360
+ checkpoint.check
361
+ df4 = pool.__send__(:hold_deferred, checkpoint) do |conn4|
362
+ conn4.should be_an_instance_of client
363
+ pool.available.length.should eq 1
364
+ pool.allocated.length.should eq 1
365
+ checkpoint.check
366
+ deferrable.new.tap {|d| d.succeed :result4 }
367
+ end
368
+ df4.should be_an_instance_of deferrable
369
+ df4.should_not be df
370
+ df4.callback do |result4|
371
+ result << result4
372
+ result4.should eq :result4
373
+ pool.available.length.should eq 2
374
+ pool.allocated.length.should eq 0
375
+ checkpoint.check
376
+ end
377
+ end
378
+ pool.available.length.should eq 2
379
+ pool.allocated.length.should eq 0
380
+ pool.size.should eq 2
381
+ result.should eq [:result3, :result2, :result1, :result4]
382
+ checkpoint.check
383
+ end
384
+
385
+ it "should drop failed connection while connecting" do
386
+ pool = nil
387
+ ::EM.should_not_receive(:next_tick)
388
+ client.should_receive(:new) do
389
+ if pool
390
+ pool.available.length.should eq 0
391
+ pool.allocated.length.should eq 1
392
+ pool.size.should eq 1
393
+ end
394
+ raise PG::Error
395
+ end.twice
396
+ expect do
397
+ subject.new connection_class: client, size: 1
398
+ end.to raise_error PG::Error
399
+
400
+ pool = subject.new connection_class: client, size: 1, lazy: true
401
+ pool.should be_an_instance_of subject
402
+ pool.max_size.should eq 1
403
+ pool.available.length.should eq 0
404
+ pool.allocated.length.should eq 0
405
+ pool.size.should eq 0
406
+ expect do
407
+ pool.hold
408
+ end.to raise_error PG::Error
409
+ pool.max_size.should eq 1
410
+ pool.available.length.should eq 0
411
+ pool.allocated.length.should eq 0
412
+ pool.size.should eq 0
413
+ end
414
+
415
+ it "should drop failed connection while connecting asynchronously" do
416
+ pool = nil
417
+ ::EM.should_not_receive(:next_tick)
418
+ client.should_not_receive(:new)
419
+ client.should_receive(:connect_defer) do
420
+ if pool
421
+ pool.available.length.should eq 0
422
+ pool.allocated.length.should eq 1
423
+ pool.size.should eq 1
424
+ end
425
+ deferrable.new.tap {|d| d.fail pgerror }
426
+ end.twice
427
+ checkpoint.should_receive(:call).with(pgerror).exactly(3)
428
+ df = subject.connect_defer connection_class: client, size: 1
429
+ df.should be_an_instance_of deferrable
430
+ df.errback(&checkpoint)
431
+
432
+ pool = subject.new connection_class: client, size: 1, lazy: true
433
+ pool.should be_an_instance_of subject
434
+ pool.max_size.should eq 1
435
+ pool.available.length.should eq 0
436
+ pool.allocated.length.should eq 0
437
+ pool.size.should eq 0
438
+ df = pool.__send__(:hold_deferred, checkpoint)
439
+ df.should be_an_instance_of deferrable
440
+ df.errback(&checkpoint)
441
+ pool.max_size.should eq 1
442
+ pool.available.length.should eq 0
443
+ pool.allocated.length.should eq 0
444
+ pool.size.should eq 0
445
+ end
446
+
447
+ it "should drop only failed connection on error" do
448
+ pool = nil
449
+ ::EM.should_not_receive(:next_tick)
450
+ client.should_receive(:new) do
451
+ if pool
452
+ pool.available.length.should eq 0
453
+ pool.allocated.length.should eq 1
454
+ pool.size.should eq 1
455
+ end
456
+ client.allocate
457
+ end.twice
458
+ checkpoint.should_receive(:check).exactly(2)
459
+ pool = subject.new connection_class: client, size: 1
460
+ pool.should be_an_instance_of subject
461
+ pool.max_size.should eq 1
462
+ pool.available.length.should eq 1
463
+ pool.allocated.length.should eq 0
464
+ pool.size.should eq 1
465
+ expect do
466
+ pool.hold do |conn|
467
+ conn.should be_an_instance_of client
468
+ pool.available.length.should eq 0
469
+ pool.allocated.length.should eq 1
470
+ pool.size.should eq 1
471
+ conn.should_receive(:status).once.and_return(PG::CONNECTION_BAD)
472
+ conn.should_receive(:finished?).once.and_return(false)
473
+ conn.should_receive(:finish).once
474
+ checkpoint.check
475
+ raise PG::Error
476
+ end
477
+ end.to raise_error PG::Error
478
+ pool.max_size.should eq 1
479
+ pool.available.length.should eq 0
480
+ pool.allocated.length.should eq 0
481
+ pool.size.should eq 0
482
+ expect do
483
+ pool.hold do |conn|
484
+ pool.available.length.should eq 0
485
+ pool.allocated.length.should eq 1
486
+ pool.size.should eq 1
487
+ conn.should be_an_instance_of client
488
+ conn.should_not_receive(:status)
489
+ conn.should_not_receive(:finished?)
490
+ conn.should_not_receive(:finish)
491
+ checkpoint.check
492
+ raise 'foo'
493
+ end
494
+ end.to raise_error RuntimeError, 'foo'
495
+ pool.available.length.should eq 1
496
+ pool.allocated.length.should eq 0
497
+ pool.size.should eq 1
498
+ end
499
+
500
+ it "should drop only failed connection on deferred error" do
501
+ pool = nil
502
+ ::EM.should_not_receive(:next_tick)
503
+ client.should_not_receive(:new)
504
+ client.should_receive(:connect_defer) do
505
+ if pool
506
+ pool.available.length.should eq 0
507
+ pool.allocated.length.should eq 1
508
+ pool.size.should eq 1
509
+ end
510
+ deferrable.new.tap {|d| d.succeed client.allocate }
511
+ end.twice
512
+ checkpoint.should_receive(:check).exactly(2)
513
+ checkpoint.should_receive(:call).with(pgerror).exactly(2)
514
+ checkpoint.should_receive(:call).with(fooerror).exactly(2)
515
+ pool = subject.new connection_class: client, size: 1, lazy: true
516
+ pool.should be_an_instance_of subject
517
+ pool.max_size.should eq 1
518
+ pool.available.length.should eq 0
519
+ pool.allocated.length.should eq 0
520
+ pool.size.should eq 0
521
+ df = pool.__send__(:hold_deferred, checkpoint) do |conn|
522
+ pool.available.length.should eq 0
523
+ pool.allocated.length.should eq 1
524
+ pool.size.should eq 1
525
+ conn.should be_an_instance_of client
526
+ conn.should_receive(:status).once.and_return(PG::CONNECTION_BAD)
527
+ conn.should_receive(:finished?).once.and_return(false)
528
+ conn.should_receive(:finish).once
529
+ checkpoint.check
530
+ deferrable.new.tap {|d| d.fail pgerror }
531
+ end
532
+ df.should be_an_instance_of deferrable
533
+ df.errback(&checkpoint)
534
+ pool.max_size.should eq 1
535
+ pool.available.length.should eq 0
536
+ pool.allocated.length.should eq 0
537
+ pool.size.should eq 0
538
+ df = pool.__send__(:hold_deferred, checkpoint) do |conn|
539
+ pool.available.length.should eq 0
540
+ pool.allocated.length.should eq 1
541
+ pool.size.should eq 1
542
+ conn.should be_an_instance_of client
543
+ conn.should_not_receive(:status)
544
+ conn.should_not_receive(:finished?)
545
+ conn.should_not_receive(:finish)
546
+ checkpoint.check
547
+ deferrable.new.tap {|d| d.fail fooerror }
548
+ end
549
+ df.should be_an_instance_of deferrable
550
+ df.errback(&checkpoint)
551
+ pool.max_size.should eq 1
552
+ pool.available.length.should eq 1
553
+ pool.allocated.length.should eq 0
554
+ pool.size.should eq 1
555
+ end
556
+
557
+ let(:pool_size) { 7 }
558
+
559
+ it "pending requests should not starve on failed connections" do
560
+ pool = nil
561
+ client.should_receive(:new) do
562
+ pool.available.length.should eq 0
563
+ pool.size.should be > 0
564
+ pool.size.should be <= pool_size
565
+ pool.size.should eq pool.allocated.length
566
+ sleep_one_tick
567
+ raise PG::ConnectionBad
568
+ end.exactly(100)
569
+ client.should_receive(:connect_defer) do
570
+ pool.available.length.should eq 0
571
+ pool.size.should be > 0
572
+ pool.size.should be <= pool_size
573
+ pool.size.should eq pool.allocated.length
574
+ deferrable.new.tap do |df|
575
+ EM.next_tick { df.fail pgerror }
576
+ end
577
+ end.exactly(100)
578
+ pool = subject.new connection_class: client, lazy: true, size: pool_size
579
+ pool.should be_an_instance_of subject
580
+ pool.max_size.should eq pool_size
581
+ pool.size.should eq 0
582
+
583
+ queries = %w[fee bzz bzz fee bzz fee fee bzz fee bzz]*2
584
+ 10.times do
585
+ test_queries pool, queries.rotate! do |progress|
586
+ pending = pool.instance_variable_get(:@pending).length
587
+ expected_pending = progress.length - pool.max_size
588
+ pending.should eq [0, expected_pending].max
589
+ pool.available.length.should eq 0
590
+ pool.size.should be >= [pool_size, expected_pending].min
591
+ end
592
+ end
593
+
594
+ pool.max_size.should eq pool_size
595
+ pool.size.should eq 0
596
+ end
597
+
598
+ it "pending requests should not starve on commands with failing connections" do
599
+ pool = nil
600
+ expected_connections = if pool_size < 20
601
+ 200 + pool_size
602
+ elsif pool_size < 40
603
+ 220
604
+ elsif pool_size < 60
605
+ 180 + pool_size
606
+ else
607
+ 240
608
+ end
609
+ checkpoint.should_receive(:check_fiber).exactly(300)
610
+ checkpoint.should_receive(:check_defer).exactly(300)
611
+ checkpoint.should_receive(:connect).exactly(expected_connections)
612
+ client.stub(:new) do
613
+ pool.available.length.should eq 0
614
+ pool.size.should be > 0
615
+ pool.size.should be <= pool_size
616
+ pool.size.should eq pool.allocated.length
617
+ sleep_one_tick
618
+ checkpoint.connect
619
+ create_connection
620
+ end
621
+ pool = subject.new connection_class: client, lazy: true, size: pool_size
622
+ client.stub(:connect_defer) do
623
+ pool.available.length.should eq 0
624
+ pool.size.should be > 0
625
+ pool.size.should be <= pool_size
626
+ pool.size.should eq pool.allocated.length
627
+ checkpoint.connect
628
+ deferrable.new.tap do |df|
629
+ EM.next_tick { df.succeed create_connection }
630
+ end
631
+ end
632
+ pool.should be_an_instance_of subject
633
+ pool.max_size.should eq pool_size
634
+ pool.size.should eq 0
635
+
636
+ good_queries = %w[foo bar bar foo bar foo foo bar foo bar]*2
637
+ disconnecting_queries = %w[fee bzz bzz fee bzz fee fee bzz fee bzz]*2
638
+
639
+ 10.times do
640
+ test_queries pool, good_queries + disconnecting_queries + good_queries do |progress|
641
+ pending = pool.instance_variable_get(:@pending).length
642
+ expected_pending = progress.length - pool.max_size
643
+ pending.should eq [0, expected_pending].max
644
+ pool.size.should be > 0
645
+ end
646
+ good_queries.rotate!
647
+ disconnecting_queries.rotate!
648
+ end
649
+
650
+ pool.max_size.should eq pool_size
651
+ pool.available.length.should eq pool.size
652
+ pool.size.should eq expected_connections - 200
653
+ end
654
+
655
+ end