@@ -491,6 +491,122 @@ final class ConnectionPoolTests: XCTestCase {
491491 }
492492 }
493493 }
494+
495+ func testLeasingConnectionAfterShutdownIsInvokedFails( ) async throws {
496+ let clock = MockClock ( )
497+ let factory = MockConnectionFactory < MockClock > ( )
498+ let keepAliveDuration = Duration . seconds ( 30 )
499+ let keepAlive = MockPingPongBehavior ( keepAliveFrequency: keepAliveDuration, connectionType: MockConnection . self)
500+
501+ var mutableConfig = ConnectionPoolConfiguration ( )
502+ mutableConfig. minimumConnectionCount = 4
503+ mutableConfig. maximumConnectionSoftLimit = 4
504+ mutableConfig. maximumConnectionHardLimit = 4
505+ mutableConfig. idleTimeout = . seconds( 10 )
506+ let config = mutableConfig
507+
508+ let pool = ConnectionPool (
509+ configuration: config,
510+ idGenerator: ConnectionIDGenerator ( ) ,
511+ requestType: ConnectionRequest< MockConnection> . self ,
512+ keepAliveBehavior: keepAlive,
513+ observabilityDelegate: NoOpConnectionPoolMetrics ( connectionIDType: MockConnection . ID. self) ,
514+ clock: clock
515+ ) {
516+ try await factory. makeConnection ( id: $0, for: $1)
517+ }
518+
519+ try await withThrowingTaskGroup ( of: Void . self) { taskGroup in
520+ taskGroup. addTask {
521+ await pool. run ( )
522+ }
523+
524+ // create 4 persisted connections
525+ for _ in 0 ..< 4 {
526+ await factory. nextConnectAttempt { connectionID in
527+ return 1
528+ }
529+ }
530+
531+ // shutdown
532+ taskGroup. cancelAll ( )
533+
534+ do {
535+ _ = try await pool. leaseConnection ( )
536+ XCTFail ( " Expected a failure " )
537+ } catch {
538+ print ( " failed " )
539+ XCTAssertEqual ( error as? ConnectionPoolError , . poolShutdown)
540+ }
541+
542+ print ( " will close connections: \( factory. runningConnections) " )
543+ for connection in factory. runningConnections {
544+ try await connection. signalToClose
545+ connection. closeIfClosing ( )
546+ }
547+ }
548+ }
549+
550+ func testLeasingConnectionsAfterShutdownIsInvokedFails( ) async throws {
551+ let clock = MockClock ( )
552+ let factory = MockConnectionFactory < MockClock > ( )
553+ let keepAliveDuration = Duration . seconds ( 30 )
554+ let keepAlive = MockPingPongBehavior ( keepAliveFrequency: keepAliveDuration, connectionType: MockConnection . self)
555+
556+ var mutableConfig = ConnectionPoolConfiguration ( )
557+ mutableConfig. minimumConnectionCount = 4
558+ mutableConfig. maximumConnectionSoftLimit = 4
559+ mutableConfig. maximumConnectionHardLimit = 4
560+ mutableConfig. idleTimeout = . seconds( 10 )
561+ let config = mutableConfig
562+
563+ let pool = ConnectionPool (
564+ configuration: config,
565+ idGenerator: ConnectionIDGenerator ( ) ,
566+ requestType: ConnectionFuture . self,
567+ keepAliveBehavior: keepAlive,
568+ observabilityDelegate: NoOpConnectionPoolMetrics ( connectionIDType: MockConnection . ID. self) ,
569+ clock: clock
570+ ) {
571+ try await factory. makeConnection ( id: $0, for: $1)
572+ }
573+
574+ try await withThrowingTaskGroup ( of: Void . self) { taskGroup in
575+ taskGroup. addTask {
576+ await pool. run ( )
577+ }
578+
579+ // create 4 persisted connections
580+ for _ in 0 ..< 4 {
581+ await factory. nextConnectAttempt { connectionID in
582+ return 1
583+ }
584+ }
585+
586+ // shutdown
587+ taskGroup. cancelAll ( )
588+
589+ // create 4 connection requests
590+ let requests = ( 0 ..< 4 ) . map { ConnectionFuture ( id: $0) }
591+
592+ // lease 4 connections at once
593+ pool. leaseConnections ( requests)
594+
595+ for request in requests {
596+ do {
597+ _ = try await request. future. success
598+ XCTFail ( " Expected a failure " )
599+ } catch {
600+ XCTAssertEqual ( error as? ConnectionPoolError , . poolShutdown)
601+ }
602+ }
603+
604+ for connection in factory. runningConnections {
605+ try await connection. signalToClose
606+ connection. closeIfClosing ( )
607+ }
608+ }
609+ }
494610}
495611
496612struct ConnectionFuture : ConnectionRequestProtocol {
0 commit comments