@@ -10,7 +10,12 @@ import {
1010 type MongoClient
1111} from '../../../src' ;
1212import { getCSFLEKMSProviders } from '../../csfle-kms-providers' ;
13- import { configureMongocryptdSpawnHooks } from '../../tools/utils' ;
13+ import {
14+ clearFailPoint ,
15+ configureFailPoint ,
16+ configureMongocryptdSpawnHooks ,
17+ sleep
18+ } from '../../tools/utils' ;
1419import { filterForCommands } from '../shared' ;
1520import { runScriptAndGetProcessInfo } from './resource_tracking_script_builder' ;
1621
@@ -716,6 +721,78 @@ describe('MongoClient.close() Integration', () => {
716721 } ) ;
717722 } ) ;
718723
724+ describe ( 'closeCheckedOutConnections' , ( ) => {
725+ const metadata : MongoDBMetadataUI = { requires : { mongodb : '>=4.4' } } ;
726+ let client : MongoClient ;
727+
728+ beforeEach ( async function ( ) {
729+ await configureFailPoint ( this . configuration , {
730+ configureFailPoint : 'failCommand' ,
731+ mode : 'alwaysOn' ,
732+ data : {
733+ failCommands : [ 'find' ] ,
734+ blockConnection : true ,
735+ blockTimeMS : 500
736+ }
737+ } ) ;
738+ client = this . configuration . newClient ( { } , { } ) ;
739+ await client . connect ( ) ;
740+ } ) ;
741+
742+ afterEach ( async function ( ) {
743+ await clearFailPoint ( this . configuration ) ;
744+ await client ?. close ( ) ;
745+ } ) ;
746+
747+ it (
748+ 'emits connectionCheckedIn immediately followed by connectionClosed for each in-flight connection' ,
749+ metadata ,
750+ async function ( ) {
751+ const allEvents : Array < { name : string ; address : string ; connectionId : number } > = [ ] ;
752+ const push = e => allEvents . push ( e ) ;
753+
754+ client
755+ . on ( 'connectionCheckedOut' , push )
756+ . on ( 'connectionCheckedIn' , push )
757+ . on ( 'connectionClosed' , push ) ;
758+
759+ const finds = Promise . allSettled ( [
760+ client . db ( 'test' ) . collection ( 'test' ) . findOne ( { a : 1 } ) ,
761+ client . db ( 'test' ) . collection ( 'test' ) . findOne ( { a : 1 } ) ,
762+ client . db ( 'test' ) . collection ( 'test' ) . findOne ( { a : 1 } )
763+ ] ) ;
764+
765+ // wait until all three finds have checked out a connection
766+ while ( allEvents . filter ( e => e . name === 'connectionCheckedOut' ) . length < 3 ) {
767+ await sleep ( 1 ) ;
768+ }
769+
770+ const findConnectionIds = new Set (
771+ allEvents
772+ . filter ( e => e . name === 'connectionCheckedOut' )
773+ . map ( ( { address, connectionId } ) => `${ address } +${ connectionId } ` )
774+ ) ;
775+
776+ await client . close ( ) ;
777+
778+ const findEvents = allEvents
779+ . filter ( e => e . name === 'connectionCheckedIn' || e . name === 'connectionClosed' )
780+ . filter ( ( { address, connectionId } ) =>
781+ findConnectionIds . has ( `${ address } +${ connectionId } ` )
782+ ) ;
783+
784+ expect ( findEvents ) . to . have . lengthOf ( 6 ) ;
785+
786+ // spec requires each connectionCheckedIn to be immediately followed by connectionClosed
787+ expect ( findEvents . map ( e => e . name ) ) . to . deep . equal (
788+ Array . from ( { length : 3 } , ( ) => [ 'connectionCheckedIn' , 'connectionClosed' ] ) . flat ( )
789+ ) ;
790+
791+ await finds ;
792+ }
793+ ) ;
794+ } ) ;
795+
719796 describe ( 'Server resource: Cursor' , ( ) => {
720797 describe ( 'after cursors are created' , ( ) => {
721798 let client : MongoClient ;
0 commit comments