@@ -371,82 +371,6 @@ func TestPool(t *testing.T) {
371
371
t .Run ("checkOut" , func (t * testing.T ) {
372
372
t .Parallel ()
373
373
374
- t .Run ("checkOut on a full pool should return a new connection as soon as the pool isn't full" , func (t * testing.T ) {
375
- t .Parallel ()
376
-
377
- cleanup := make (chan struct {})
378
- defer close (cleanup )
379
- addr := bootstrapConnections (t , 3 , func (nc net.Conn ) {
380
- <- cleanup
381
- _ = nc .Close ()
382
- })
383
-
384
- d := newdialer (& net.Dialer {})
385
- p := newPool (
386
- poolConfig {
387
- Address : address .Address (addr .String ()),
388
- MaxPoolSize : 2 ,
389
- },
390
- WithDialer (func (Dialer ) Dialer { return d }),
391
- )
392
- err := p .connect ()
393
- noerr (t , err )
394
-
395
- // Check out two connections (MaxPoolSize) so that subsequent checkOut() calls should
396
- // block until a connection is checked back in or removed from the pool.
397
- c , err := p .checkOut (context .Background ())
398
- noerr (t , err )
399
- _ , err = p .checkOut (context .Background ())
400
- noerr (t , err )
401
- assert .Equalf (t , 2 , d .lenopened (), "should have opened 2 connection" )
402
- assert .Equalf (t , 2 , p .totalConnectionCount (), "pool should have 2 total connection" )
403
- assert .Equalf (t , 0 , p .availableConnectionCount (), "pool should have 0 idle connection" )
404
-
405
- // Run a checkOut() with timeout and expect it to time out because the pool is at
406
- // MaxPoolSize and no connections are checked in or removed from the pool.
407
- ctx , cancel := context .WithTimeout (context .Background (), 1 * time .Millisecond )
408
- defer cancel ()
409
- _ , err = p .checkOut (ctx )
410
- assert .Equalf (t , context .DeadlineExceeded , err .(WaitQueueTimeoutError ).Wrapped , "TODO" )
411
-
412
- // Start a goroutine that calls checkOut() without a timeout after recording the start
413
- // time of the checkOut().
414
- var start time.Time
415
- waiting := make (chan struct {})
416
- var wg sync.WaitGroup
417
- wg .Add (1 )
418
- go func () {
419
- defer wg .Done ()
420
-
421
- close (waiting )
422
- start = time .Now ()
423
- _ , err := p .checkOut (context .Background ())
424
- noerr (t , err )
425
- }()
426
-
427
- // Close a connection, wait for the checkOut() goroutine to signal it is waiting for a
428
- // checkOut(), then check in the closed connection. Expect that the checkOut() goroutine
429
- // exits within 5ms of checking in the closed connection.
430
- c .close ()
431
- <- waiting
432
- err = p .checkIn (c )
433
- noerr (t , err )
434
- wg .Wait ()
435
- assert .WithinDurationf (
436
- t ,
437
- start ,
438
- time .Now (),
439
- 5 * time .Millisecond ,
440
- "expected checkOut to complete within 5ms of checking in a closed connection" )
441
-
442
- assert .Equalf (t , 1 , d .lenclosed (), "should have closed 1 connection" )
443
- assert .Equalf (t , 3 , d .lenopened (), "should have opened 3 connection" )
444
- assert .Equalf (t , 2 , p .totalConnectionCount (), "pool should have 2 total connection" )
445
- assert .Equalf (t , 0 , p .availableConnectionCount (), "pool should have 0 idle connection" )
446
-
447
- err = p .disconnect (context .Background ())
448
- noerr (t , err )
449
- })
450
374
t .Run ("return error when attempting to create new connection" , func (t * testing.T ) {
451
375
t .Parallel ()
452
376
@@ -686,6 +610,78 @@ func TestPool(t *testing.T) {
686
610
noerr (t , err )
687
611
wg .Wait ()
688
612
})
613
+ // Test that checkOut() on a full connection pool creates and returns a new connection
614
+ // immediately as soon as the pool is no longer full.
615
+ t .Run ("should return a new connection as soon as the pool isn't full" , func (t * testing.T ) {
616
+ t .Parallel ()
617
+
618
+ cleanup := make (chan struct {})
619
+ defer close (cleanup )
620
+ addr := bootstrapConnections (t , 3 , func (nc net.Conn ) {
621
+ <- cleanup
622
+ _ = nc .Close ()
623
+ })
624
+
625
+ d := newdialer (& net.Dialer {})
626
+ p := newPool (
627
+ poolConfig {
628
+ Address : address .Address (addr .String ()),
629
+ MaxPoolSize : 2 ,
630
+ },
631
+ WithDialer (func (Dialer ) Dialer { return d }),
632
+ )
633
+ err := p .connect ()
634
+ noerr (t , err )
635
+
636
+ // Check out two connections (MaxPoolSize) so that subsequent checkOut() calls should
637
+ // block until a connection is checked back in or removed from the pool.
638
+ c , err := p .checkOut (context .Background ())
639
+ noerr (t , err )
640
+ _ , err = p .checkOut (context .Background ())
641
+ noerr (t , err )
642
+ assert .Equalf (t , 2 , d .lenopened (), "should have opened 2 connection" )
643
+ assert .Equalf (t , 2 , p .totalConnectionCount (), "pool should have 2 total connection" )
644
+ assert .Equalf (t , 0 , p .availableConnectionCount (), "pool should have 0 idle connection" )
645
+
646
+ // Run a checkOut() with timeout and expect it to time out because the pool is at
647
+ // MaxPoolSize and no connections are checked in or removed from the pool.
648
+ ctx , cancel := context .WithTimeout (context .Background (), 1 * time .Millisecond )
649
+ defer cancel ()
650
+ _ , err = p .checkOut (ctx )
651
+ assert .Equalf (
652
+ t ,
653
+ context .DeadlineExceeded ,
654
+ err .(WaitQueueTimeoutError ).Wrapped ,
655
+ "expected wrapped error to be a context.DeadlineExceeded" )
656
+
657
+ // Start a goroutine that closes one of the checked-out conections and checks it in.
658
+ // Expect that the checked-in connection is closed and allows blocked checkOut() to
659
+ // complete. Assert that the time between checking in the closed connection and when the
660
+ // checkOut() completes is within 50ms.
661
+ var start time.Time
662
+ go func () {
663
+ c .close ()
664
+ start = time .Now ()
665
+ err := p .checkIn (c )
666
+ noerr (t , err )
667
+ }()
668
+ _ , err = p .checkOut (context .Background ())
669
+ noerr (t , err )
670
+ assert .WithinDurationf (
671
+ t ,
672
+ time .Now (),
673
+ start ,
674
+ 50 * time .Millisecond ,
675
+ "expected checkOut to complete within 50ms of checking in a closed connection" )
676
+
677
+ assert .Equalf (t , 1 , d .lenclosed (), "should have closed 1 connection" )
678
+ assert .Equalf (t , 3 , d .lenopened (), "should have opened 3 connection" )
679
+ assert .Equalf (t , 2 , p .totalConnectionCount (), "pool should have 2 total connection" )
680
+ assert .Equalf (t , 0 , p .availableConnectionCount (), "pool should have 0 idle connection" )
681
+
682
+ err = p .disconnect (context .Background ())
683
+ noerr (t , err )
684
+ })
689
685
})
690
686
t .Run ("checkIn" , func (t * testing.T ) {
691
687
t .Parallel ()
0 commit comments