11/* eslint-disable @typescript-eslint/no-empty-function */
2+ import { expect } from 'chai' ;
3+
24import { getCSFLEKMSProviders } from '../../csfle-kms-providers' ;
5+ import { type Collection , type FindCursor , type MongoClient } from '../../mongodb' ;
36import { type TestConfiguration } from '../../tools/runner/config' ;
47import { runScriptAndGetProcessInfo } from './resource_tracking_script_builder' ;
58
6- describe . skip ( 'MongoClient.close() Integration' , ( ) => {
9+ describe ( 'MongoClient.close() Integration' , ( ) => {
710 // note: these tests are set-up in accordance of the resource ownership tree
811
912 let config : TestConfiguration ;
@@ -14,7 +17,7 @@ describe.skip('MongoClient.close() Integration', () => {
1417
1518 describe ( 'Node.js resource: TLS File read' , ( ) => {
1619 describe ( 'when client is connecting and reads an infinite TLS file' , ( ) => {
17- it ( 'the file read is interrupted by client.close()' , async function ( ) {
20+ it . skip ( 'the file read is interrupted by client.close()' , async function ( ) {
1821 await runScriptAndGetProcessInfo (
1922 'tls-file-read' ,
2023 config ,
@@ -50,7 +53,7 @@ describe.skip('MongoClient.close() Integration', () => {
5053 } ) ;
5154
5255 describe ( 'when MongoClientAuthProviders is instantiated and token file read hangs' , ( ) => {
53- it ( 'the file read is interrupted by client.close()' , async ( ) => {
56+ it . skip ( 'the file read is interrupted by client.close()' , async ( ) => {
5457 await runScriptAndGetProcessInfo (
5558 'token-file-read' ,
5659 config ,
@@ -77,8 +80,7 @@ describe.skip('MongoClient.close() Integration', () => {
7780 describe ( 'Node.js resource: Server Selection Timer' , ( ) => {
7881 describe ( 'after a Topology is created through client.connect()' , ( ) => {
7982 const metadata : MongoDBMetadataUI = { requires : { topology : 'replicaset' } } ;
80-
81- it ( 'server selection timers are cleaned up by client.close()' , metadata , async ( ) => {
83+ it . skip ( 'server selection timers are cleaned up by client.close()' , metadata , async ( ) => {
8284 const run = async function ( { MongoClient, uri, expect, sleep, mongodb, getTimerCount } ) {
8385 const serverSelectionTimeoutMS = 2222 ;
8486 const client = new MongoClient ( uri , {
@@ -117,7 +119,7 @@ describe.skip('MongoClient.close() Integration', () => {
117119 describe ( 'MonitorInterval' , ( ) => {
118120 describe ( 'Node.js resource: Timer' , ( ) => {
119121 describe ( 'after a new monitor is made' , ( ) => {
120- it (
122+ it . skip (
121123 'monitor interval timer is cleaned up by client.close()' ,
122124 metadata ,
123125 async function ( ) {
@@ -150,7 +152,7 @@ describe.skip('MongoClient.close() Integration', () => {
150152 } ) ;
151153
152154 describe ( 'after a heartbeat fails' , ( ) => {
153- it (
155+ it . skip (
154156 'the new monitor interval timer is cleaned up by client.close()' ,
155157 metadata ,
156158 async ( ) => {
@@ -160,7 +162,6 @@ describe.skip('MongoClient.close() Integration', () => {
160162 const willBeHeartbeatFailed = once ( client , 'serverHeartbeatFailed' ) ;
161163 client . connect ( ) ;
162164 await willBeHeartbeatFailed ;
163-
164165 function getMonitorTimer ( servers ) {
165166 for ( const [ , server ] of servers ) {
166167 return server ?. monitor . monitorId . timerId ;
@@ -183,7 +184,7 @@ describe.skip('MongoClient.close() Integration', () => {
183184
184185 describe ( 'Monitoring Connection' , ( ) => {
185186 describe ( 'Node.js resource: Socket' , ( ) => {
186- it ( 'no sockets remain after client.close()' , metadata , async function ( ) {
187+ it . skip ( 'no sockets remain after client.close()' , metadata , async function ( ) {
187188 const run = async function ( { MongoClient, uri, expect, getSocketEndpoints } ) {
188189 const client = new MongoClient ( uri ) ;
189190 await client . connect ( ) ;
@@ -211,7 +212,7 @@ describe.skip('MongoClient.close() Integration', () => {
211212 describe ( 'RTT Pinger' , ( ) => {
212213 describe ( 'Node.js resource: Timer' , ( ) => {
213214 describe ( 'after entering monitor streaming mode ' , ( ) => {
214- it (
215+ it . skip (
215216 'the rtt pinger timer is cleaned up by client.close()' ,
216217 metadata ,
217218 async function ( ) {
@@ -247,8 +248,8 @@ describe.skip('MongoClient.close() Integration', () => {
247248 describe ( 'Connection' , ( ) => {
248249 describe ( 'Node.js resource: Socket' , ( ) => {
249250 describe ( 'when rtt monitoring is turned on' , ( ) => {
250- it ( 'no sockets remain after client.close()' , metadata , async ( ) => {
251- const run = async ( { MongoClient, uri, expect, getSockets, once, log } ) => {
251+ it . skip ( 'no sockets remain after client.close()' , metadata , async ( ) => {
252+ const run = async ( { MongoClient, uri, expect, getSockets, once } ) => {
252253 const heartbeatFrequencyMS = 500 ;
253254 const client = new MongoClient ( uri , {
254255 serverMonitoringMode : 'stream' ,
@@ -265,7 +266,6 @@ describe.skip('MongoClient.close() Integration', () => {
265266
266267 while ( heartbeatOccurredSet . size < servers . size ) {
267268 const ev = await once ( client , 'serverHeartbeatSucceeded' ) ;
268- log ( { ev : ev [ 0 ] } ) ;
269269 heartbeatOccurredSet . add ( ev [ 0 ] . connectionId ) ;
270270 }
271271
@@ -281,8 +281,6 @@ describe.skip('MongoClient.close() Integration', () => {
281281
282282 // close the client
283283 await client . close ( ) ;
284-
285- log ( { socketsAfterClose : getSockets ( ) } ) ;
286284 // upon close, assert rttPinger sockets are cleaned up
287285 const activeSocketsAfterClose = activeSocketsAfterHeartbeat ( ) ;
288286 expect ( activeSocketsAfterClose ) . to . have . lengthOf ( 0 ) ;
@@ -299,7 +297,7 @@ describe.skip('MongoClient.close() Integration', () => {
299297 describe ( 'ConnectionPool' , ( ) => {
300298 describe ( 'Node.js resource: minPoolSize timer' , ( ) => {
301299 describe ( 'after new connection pool is created' , ( ) => {
302- it ( 'the minPoolSize timer is cleaned up by client.close()' , async function ( ) {
300+ it . skip ( 'the minPoolSize timer is cleaned up by client.close()' , async function ( ) {
303301 const run = async function ( { MongoClient, uri, expect, getTimerCount } ) {
304302 const client = new MongoClient ( uri , { minPoolSize : 1 } ) ;
305303 let minPoolSizeTimerCreated = false ;
@@ -357,7 +355,7 @@ describe.skip('MongoClient.close() Integration', () => {
357355 await utilClient . close ( ) ;
358356 } ) ;
359357
360- it ( 'the wait queue timer is cleaned up by client.close()' , async function ( ) {
358+ it . skip ( 'the wait queue timer is cleaned up by client.close()' , async function ( ) {
361359 const run = async function ( { MongoClient, uri, expect, getTimerCount, once } ) {
362360 const waitQueueTimeoutMS = 1515 ;
363361
@@ -399,7 +397,7 @@ describe.skip('MongoClient.close() Integration', () => {
399397 describe ( 'Connection' , ( ) => {
400398 describe ( 'Node.js resource: Socket' , ( ) => {
401399 describe ( 'after a minPoolSize has been set on the ConnectionPool' , ( ) => {
402- it ( 'no sockets remain after client.close()' , async function ( ) {
400+ it . skip ( 'no sockets remain after client.close()' , async function ( ) {
403401 const run = async function ( { MongoClient, uri, expect, getSockets } ) {
404402 // assert no sockets to start with
405403 expect ( getSockets ( ) ) . to . have . lengthOf ( 0 ) ;
@@ -431,13 +429,17 @@ describe.skip('MongoClient.close() Integration', () => {
431429 const metadata : MongoDBMetadataUI = { requires : { topology : 'sharded' } } ;
432430
433431 describe ( 'after SRVPoller is created' , ( ) => {
434- it ( 'timers are cleaned up by client.close()' , metadata , async ( ) => {
432+ it . skip ( 'timers are cleaned up by client.close()' , metadata , async ( ) => {
435433 const run = async function ( { MongoClient, expect, getTimerCount } ) {
436434 const SRV_CONNECTION_STRING = `mongodb+srv://test1.test.build.10gen.cc` ;
435+
437436 // 27018 localhost.test.build.10gen.cc.
438437 // 27017 localhost.test.build.10gen.cc.
439438
440- const client = new MongoClient ( SRV_CONNECTION_STRING ) ;
439+ const client = new MongoClient ( SRV_CONNECTION_STRING , {
440+ serverSelectionTimeoutMS : 2000 ,
441+ tls : false
442+ } ) ;
441443 await client . connect ( ) ;
442444 // the current expected behavior is that _timeout is set to undefined until SRV polling starts
443445 // then _timeout is set to undefined again when SRV polling stops
@@ -453,29 +455,143 @@ describe.skip('MongoClient.close() Integration', () => {
453455 } ) ;
454456
455457 describe ( 'ClientSession (Implicit)' , ( ) => {
458+ let idleSessionsBeforeClose ;
459+ let idleSessionsAfterClose ;
460+ let client ;
461+ let utilClient ;
462+ let session ;
463+
464+ const metadata : MongoDBMetadataUI = {
465+ requires : {
466+ topology : [ 'replicaset' , 'sharded' ] ,
467+ mongodb : '>=4.2'
468+ }
469+ } ;
470+
471+ beforeEach ( async function ( ) {
472+ client = this . configuration . newClient ( ) ;
473+ utilClient = this . configuration . newClient ( ) ;
474+ await client . connect ( ) ;
475+ await client
476+ . db ( 'db' )
477+ . collection ( 'collection' )
478+ ?. drop ( )
479+ . catch ( ( ) => null ) ;
480+ const collection = await client . db ( 'db' ) . createCollection ( 'collection' ) ;
481+ session = client . startSession ( { explicit : false } ) ;
482+ session . startTransaction ( ) ;
483+ await collection . insertOne ( { x : 1 } , { session } ) ;
484+
485+ const opBefore = await utilClient . db ( ) . admin ( ) . command ( { currentOp : 1 } ) ;
486+ idleSessionsBeforeClose = opBefore . inprog . filter ( s => s . type === 'idleSession' ) ;
487+
488+ await client . close ( ) ;
489+
490+ const opAfter = await utilClient . db ( ) . admin ( ) . command ( { currentOp : 1 } ) ;
491+ idleSessionsAfterClose = opAfter . inprog . filter ( s => s . type === 'idleSession' ) ;
492+
493+ await utilClient . close ( ) ;
494+ } ) ;
495+
496+ afterEach ( async function ( ) {
497+ await utilClient ?. close ( ) ;
498+ await session ?. endSession ( ) ;
499+ await client ?. close ( ) ;
500+ } ) ;
501+
456502 describe ( 'Server resource: LSID/ServerSession' , ( ) => {
457503 describe ( 'after a clientSession is implicitly created and used' , ( ) => {
458- it . skip ( 'the server-side ServerSession is cleaned up by client.close()' , async function ( ) { } ) ;
504+ it (
505+ 'the server-side ServerSession is cleaned up by client.close()' ,
506+ metadata ,
507+ async function ( ) {
508+ expect ( idleSessionsBeforeClose ) . to . not . be . empty ;
509+ expect ( idleSessionsAfterClose ) . to . be . empty ;
510+ }
511+ ) ;
459512 } ) ;
460513 } ) ;
461514
462515 describe ( 'Server resource: Transactions' , ( ) => {
463516 describe ( 'after a clientSession is implicitly created and used' , ( ) => {
464- it . skip ( 'the server-side transaction is cleaned up by client.close()' , async function ( ) { } ) ;
517+ it (
518+ 'the server-side transaction is cleaned up by client.close()' ,
519+ metadata ,
520+ async function ( ) {
521+ expect ( idleSessionsBeforeClose [ 0 ] . transaction . txnNumber ) . to . not . null ;
522+ expect ( idleSessionsAfterClose ) . to . be . empty ;
523+ }
524+ ) ;
465525 } ) ;
466526 } ) ;
467527 } ) ;
468528
469529 describe ( 'ClientSession (Explicit)' , ( ) => {
530+ let idleSessionsBeforeClose ;
531+ let idleSessionsAfterClose ;
532+ let client ;
533+ let utilClient ;
534+ let session ;
535+
536+ const metadata : MongoDBMetadataUI = {
537+ requires : {
538+ topology : [ 'replicaset' , 'sharded' ] ,
539+ mongodb : '>=4.2'
540+ }
541+ } ;
542+
543+ beforeEach ( async function ( ) {
544+ client = this . configuration . newClient ( ) ;
545+ utilClient = this . configuration . newClient ( ) ;
546+ await client . connect ( ) ;
547+ await client
548+ . db ( 'db' )
549+ . collection ( 'collection' )
550+ ?. drop ( )
551+ . catch ( ( ) => null ) ;
552+ const collection = await client . db ( 'db' ) . createCollection ( 'collection' ) ;
553+ session = client . startSession ( ) ;
554+ session . startTransaction ( ) ;
555+ await collection . insertOne ( { x : 1 } , { session } ) ;
556+
557+ const opBefore = await utilClient . db ( ) . admin ( ) . command ( { currentOp : 1 } ) ;
558+ idleSessionsBeforeClose = opBefore . inprog . filter ( s => s . type === 'idleSession' ) ;
559+
560+ await client . close ( ) ;
561+
562+ const opAfter = await utilClient . db ( ) . admin ( ) . command ( { currentOp : 1 } ) ;
563+ idleSessionsAfterClose = opAfter . inprog . filter ( s => s . type === 'idleSession' ) ;
564+ } ) ;
565+
566+ afterEach ( async function ( ) {
567+ await utilClient ?. close ( ) ;
568+ await session ?. endSession ( ) ;
569+ await client ?. close ( ) ;
570+ } ) ;
571+
470572 describe ( 'Server resource: LSID/ServerSession' , ( ) => {
471573 describe ( 'after a clientSession is created and used' , ( ) => {
472- it . skip ( 'the server-side ServerSession is cleaned up by client.close()' , async function ( ) { } ) ;
574+ it (
575+ 'the server-side ServerSession is cleaned up by client.close()' ,
576+ metadata ,
577+ async function ( ) {
578+ expect ( idleSessionsBeforeClose ) . to . not . be . empty ;
579+ expect ( idleSessionsAfterClose ) . to . be . empty ;
580+ }
581+ ) ;
473582 } ) ;
474583 } ) ;
475584
476585 describe ( 'Server resource: Transactions' , ( ) => {
477586 describe ( 'after a clientSession is created and used' , ( ) => {
478- it . skip ( 'the server-side transaction is cleaned up by client.close()' , async function ( ) { } ) ;
587+ it (
588+ 'the server-side transaction is cleaned up by client.close()' ,
589+ metadata ,
590+ async function ( ) {
591+ expect ( idleSessionsBeforeClose [ 0 ] . transaction . txnNumber ) . to . not . null ;
592+ expect ( idleSessionsAfterClose ) . to . be . empty ;
593+ }
594+ ) ;
479595 } ) ;
480596 } ) ;
481597 } ) ;
@@ -491,7 +607,7 @@ describe.skip('MongoClient.close() Integration', () => {
491607 describe ( 'KMS Request' , ( ) => {
492608 describe ( 'Node.js resource: TLS file read' , ( ) => {
493609 describe ( 'when KMSRequest reads an infinite TLS file' , ( ) => {
494- it ( 'the file read is interrupted by client.close()' , metadata , async ( ) => {
610+ it . skip ( 'the file read is interrupted by client.close()' , metadata , async ( ) => {
495611 await runScriptAndGetProcessInfo (
496612 'tls-file-read-auto-encryption' ,
497613 config ,
@@ -584,8 +700,75 @@ describe.skip('MongoClient.close() Integration', () => {
584700 } ) ;
585701
586702 describe ( 'Server resource: Cursor' , ( ) => {
703+ const metadata : MongoDBMetadataUI = {
704+ requires : {
705+ mongodb : '>=4.2.0'
706+ }
707+ } ;
708+
587709 describe ( 'after cursors are created' , ( ) => {
588- it . skip ( 'all active server-side cursors are closed by client.close()' , async function ( ) { } ) ;
710+ let client : MongoClient ;
711+ let coll : Collection ;
712+ let cursor : FindCursor ;
713+ let utilClient : MongoClient ;
714+
715+ beforeEach ( async function ( ) {
716+ client = this . configuration . newClient ( ) ;
717+ utilClient = this . configuration . newClient ( ) ;
718+ await client . connect ( ) ;
719+ await client
720+ . db ( 'db' )
721+ . collection ( 'coll' )
722+ ?. drop ( )
723+ . catch ( ( ) => null ) ;
724+ coll = await client
725+ . db ( 'db' )
726+ . createCollection ( 'coll' , { capped : true , size : 1_000 , max : 4 } ) ;
727+ await coll . insertMany ( [ { a : 1 } , { b : 2 } , { c : 3 } ] ) ;
728+ } ) ;
729+
730+ afterEach ( async function ( ) {
731+ await utilClient ?. close ( ) ;
732+ await client ?. close ( ) ;
733+ await cursor ?. close ( ) ;
734+ } ) ;
735+
736+ it (
737+ 'all active server-side cursors are closed by client.close()' ,
738+ metadata ,
739+ async function ( ) {
740+ const getCursors = async ( ) => {
741+ const res = await utilClient
742+ . db ( )
743+ . admin ( )
744+ . command ( {
745+ aggregate : 1 ,
746+ cursor : { } ,
747+ pipeline : [ { $currentOp : { idleCursors : true } } ]
748+ } ) ;
749+ return res . cursor . firstBatch . filter (
750+ r => r . type === 'idleCursor' || ( r . type === 'op' && r . desc === 'getMore' )
751+ ) ;
752+ } ;
753+
754+ cursor = coll . find (
755+ { } ,
756+ {
757+ tailable : true ,
758+ awaitData : true
759+ }
760+ ) ;
761+ await cursor . next ( ) ;
762+
763+ // assert creation
764+ expect ( await getCursors ( ) ) . to . not . be . empty ;
765+
766+ await client . close ( ) ;
767+
768+ // assert clean-up
769+ expect ( await getCursors ( ) ) . to . be . empty ;
770+ }
771+ ) ;
589772 } ) ;
590773 } ) ;
591774} ) ;
0 commit comments