1+ import * as events from 'node:events' ;
2+
13import { expect } from 'chai' ;
24
35import { getCSFLEKMSProviders } from '../../csfle-kms-providers' ;
46import { type Collection , type FindCursor , type MongoClient } from '../../mongodb' ;
5- import { type TestConfiguration } from '../../tools/runner/config' ;
67import { runScriptAndGetProcessInfo } from './resource_tracking_script_builder' ;
78
89describe ( 'MongoClient.close() Integration' , ( ) => {
910 // note: these tests are set-up in accordance of the resource ownership tree
1011
11- let config : TestConfiguration ;
12-
13- beforeEach ( function ( ) {
14- config = this . configuration ;
15- } ) ;
16-
1712 describe ( 'Node.js resource: TLS File read' , ( ) => {
1813 describe ( 'when client is connecting and reads an infinite TLS file' , ( ) => {
1914 it . skip ( 'the file read is interrupted by client.close()' , async function ( ) {
2015 await runScriptAndGetProcessInfo (
2116 'tls-file-read' ,
22- config ,
17+ this . configuration ,
2318 async function run ( { MongoClient, uri, expect } ) {
2419 const infiniteFile = '/dev/zero' ;
2520 const client = new MongoClient ( uri , { tls : true , tlsCertificateKeyFile : infiniteFile } ) ;
@@ -52,10 +47,10 @@ describe('MongoClient.close() Integration', () => {
5247 } ) ;
5348
5449 describe ( 'when MongoClientAuthProviders is instantiated and token file read hangs' , ( ) => {
55- it . skip ( 'the file read is interrupted by client.close()' , async ( ) => {
50+ it . skip ( 'the file read is interrupted by client.close()' , async function ( ) {
5651 await runScriptAndGetProcessInfo (
5752 'token-file-read' ,
58- config ,
53+ this . configuration ,
5954 async function run ( { MongoClient, uri, expect } ) {
6055 const infiniteFile = '/dev/zero' ;
6156 process . env . OIDC_TOKEN_FILE = infiniteFile ;
@@ -81,30 +76,41 @@ describe('MongoClient.close() Integration', () => {
8176 describe ( 'after a Topology is created through client.connect()' , ( ) => {
8277 const metadata : MongoDBMetadataUI = { requires : { topology : 'replicaset' } } ;
8378
84- it . skip ( 'server selection timers are cleaned up by client.close()' , metadata , async ( ) => {
85- const run = async function ( { MongoClient, uri, expect, sleep, mongodb, getTimerCount } ) {
86- const serverSelectionTimeoutMS = 2222 ;
87- const client = new MongoClient ( uri , {
88- minPoolSize : 1 ,
89- serverSelectionTimeoutMS,
90- readPreference : new mongodb . ReadPreference ( 'secondary' , [
91- { something : 'that does not exist' }
92- ] )
93- } ) ;
94- const insertPromise = client . db ( 'db' ) . collection ( 'collection' ) . insertOne ( { x : 1 } ) ;
79+ it . skip (
80+ 'server selection timers are cleaned up by client.close()' ,
81+ metadata ,
82+ async function ( ) {
83+ const run = async function ( {
84+ MongoClient,
85+ uri,
86+ expect,
87+ sleep,
88+ mongodb,
89+ getTimerCount
90+ } ) {
91+ const serverSelectionTimeoutMS = 2222 ;
92+ const client = new MongoClient ( uri , {
93+ minPoolSize : 1 ,
94+ serverSelectionTimeoutMS,
95+ readPreference : new mongodb . ReadPreference ( 'secondary' , [
96+ { something : 'that does not exist' }
97+ ] )
98+ } ) ;
99+ const insertPromise = client . db ( 'db' ) . collection ( 'collection' ) . insertOne ( { x : 1 } ) ;
95100
96- // don't allow entire server selection timer to elapse to ensure close is called mid-timeout
97- await sleep ( serverSelectionTimeoutMS / 2 ) ;
101+ // don't allow entire server selection timer to elapse to ensure close is called mid-timeout
102+ await sleep ( serverSelectionTimeoutMS / 2 ) ;
98103
99- expect ( getTimerCount ( ) ) . to . not . equal ( 0 ) ;
100- await client . close ( ) ;
101- expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
104+ expect ( getTimerCount ( ) ) . to . not . equal ( 0 ) ;
105+ await client . close ( ) ;
106+ expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
102107
103- const err = await insertPromise . catch ( e => e ) ;
104- expect ( err ) . to . be . instanceOf ( mongodb . MongoTopologyClosedError ) ;
105- } ;
106- await runScriptAndGetProcessInfo ( 'timer-server-selection' , config , run ) ;
107- } ) ;
108+ const err = await insertPromise . catch ( e => e ) ;
109+ expect ( err ) . to . be . instanceOf ( mongodb . MongoTopologyClosedError ) ;
110+ } ;
111+ await runScriptAndGetProcessInfo ( 'timer-server-selection' , this . configuration , run ) ;
112+ }
113+ ) ;
108114 } ) ;
109115 } ) ;
110116
@@ -147,7 +153,11 @@ describe('MongoClient.close() Integration', () => {
147153
148154 expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
149155 } ;
150- await runScriptAndGetProcessInfo ( 'timer-monitor-interval' , config , run ) ;
156+ await runScriptAndGetProcessInfo (
157+ 'timer-monitor-interval' ,
158+ this . configuration ,
159+ run
160+ ) ;
151161 }
152162 ) ;
153163 } ) ;
@@ -156,7 +166,7 @@ describe('MongoClient.close() Integration', () => {
156166 it . skip (
157167 'the new monitor interval timer is cleaned up by client.close()' ,
158168 metadata ,
159- async ( ) => {
169+ async function ( ) {
160170 const run = async function ( { MongoClient, expect, getTimerCount, once } ) {
161171 const heartbeatFrequencyMS = 2000 ;
162172 const client = new MongoClient ( 'mongodb://fakeUri' , { heartbeatFrequencyMS } ) ;
@@ -178,7 +188,11 @@ describe('MongoClient.close() Integration', () => {
178188
179189 await connectPromise ;
180190 } ;
181- await runScriptAndGetProcessInfo ( 'timer-heartbeat-failed-monitor' , config , run ) ;
191+ await runScriptAndGetProcessInfo (
192+ 'timer-heartbeat-failed-monitor' ,
193+ this . configuration ,
194+ run
195+ ) ;
182196 }
183197 ) ;
184198 } ) ;
@@ -207,7 +221,11 @@ describe('MongoClient.close() Integration', () => {
207221 expect ( getSocketEndpoints ( ) ) . to . not . deep . include ( { host, port } ) ;
208222 }
209223 } ;
210- await runScriptAndGetProcessInfo ( 'socket-connection-monitoring' , config , run ) ;
224+ await runScriptAndGetProcessInfo (
225+ 'socket-connection-monitoring' ,
226+ this . configuration ,
227+ run
228+ ) ;
211229 } ) ;
212230 } ) ;
213231 } ) ;
@@ -242,7 +260,7 @@ describe('MongoClient.close() Integration', () => {
242260
243261 expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
244262 } ;
245- await runScriptAndGetProcessInfo ( 'timer-rtt-monitor' , config , run ) ;
263+ await runScriptAndGetProcessInfo ( 'timer-rtt-monitor' , this . configuration , run ) ;
246264 }
247265 ) ;
248266 } ) ;
@@ -251,7 +269,7 @@ describe('MongoClient.close() Integration', () => {
251269 describe ( 'Connection' , ( ) => {
252270 describe ( 'Node.js resource: Socket' , ( ) => {
253271 describe ( 'when rtt monitoring is turned on' , ( ) => {
254- it . skip ( 'no sockets remain after client.close()' , metadata , async ( ) => {
272+ it . skip ( 'no sockets remain after client.close()' , metadata , async function ( ) {
255273 const run = async ( { MongoClient, uri, expect, getSockets, once } ) => {
256274 const heartbeatFrequencyMS = 500 ;
257275 const client = new MongoClient ( uri , {
@@ -289,7 +307,11 @@ describe('MongoClient.close() Integration', () => {
289307 expect ( activeSocketsAfterClose ) . to . have . lengthOf ( 0 ) ;
290308 } ;
291309
292- await runScriptAndGetProcessInfo ( 'socket-connection-rtt-monitoring' , config , run ) ;
310+ await runScriptAndGetProcessInfo (
311+ 'socket-connection-rtt-monitoring' ,
312+ this . configuration ,
313+ run
314+ ) ;
293315 } ) ;
294316 } ) ;
295317 } ) ;
@@ -323,7 +345,7 @@ describe('MongoClient.close() Integration', () => {
323345 expect ( getMinPoolSizeTimer ( servers ) ) . to . not . exist ;
324346 expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
325347 } ;
326- await runScriptAndGetProcessInfo ( 'timer-min-pool-size' , config , run ) ;
348+ await runScriptAndGetProcessInfo ( 'timer-min-pool-size' , this . configuration , run ) ;
327349 } ) ;
328350 } ) ;
329351 } ) ;
@@ -334,8 +356,8 @@ describe('MongoClient.close() Integration', () => {
334356 const waitQueueTimeoutMS = 1515 ;
335357
336358 beforeEach ( async function ( ) {
337- // configure failPoint
338- utilClient = this . configuration . newClient ( ) ;
359+ // this.configurationure failPoint
360+ utilClient = this . this . configurationuration . newClient ( ) ;
339361 await utilClient . connect ( ) ;
340362 const failPoint = {
341363 configureFailPoint : 'failCommand' ,
@@ -392,7 +414,7 @@ describe('MongoClient.close() Integration', () => {
392414 'Timed out while checking out a connection from connection pool'
393415 ) ;
394416 } ;
395- await runScriptAndGetProcessInfo ( 'timer-check-out' , config , run ) ;
417+ await runScriptAndGetProcessInfo ( 'timer-check-out' , this . configuration , run ) ;
396418 } ) ;
397419 } ) ;
398420 } ) ;
@@ -418,7 +440,7 @@ describe('MongoClient.close() Integration', () => {
418440 expect ( getSockets ( ) ) . to . have . lengthOf ( 0 ) ;
419441 } ;
420442
421- await runScriptAndGetProcessInfo ( 'socket-minPoolSize' , config , run ) ;
443+ await runScriptAndGetProcessInfo ( 'socket-minPoolSize' , this . configuration , run ) ;
422444 } ) ;
423445 } ) ;
424446 } ) ;
@@ -432,7 +454,7 @@ describe('MongoClient.close() Integration', () => {
432454 const metadata : MongoDBMetadataUI = { requires : { topology : 'sharded' } } ;
433455
434456 describe ( 'after SRVPoller is created' , ( ) => {
435- it . skip ( 'timers are cleaned up by client.close()' , metadata , async ( ) => {
457+ it . skip ( 'timers are cleaned up by client.close()' , metadata , async function ( ) {
436458 const run = async function ( { MongoClient, expect, getTimerCount } ) {
437459 const SRV_CONNECTION_STRING = `mongodb+srv://test1.test.build.10gen.cc` ;
438460
@@ -450,13 +472,43 @@ describe('MongoClient.close() Integration', () => {
450472 await client . close ( ) ;
451473 expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
452474 } ;
453- await runScriptAndGetProcessInfo ( 'timer-srv-poller' , config , run ) ;
475+ await runScriptAndGetProcessInfo ( 'timer-srv-poller' , this . configuration , run ) ;
454476 } ) ;
455477 } ) ;
456478 } ) ;
457479 } ) ;
458480 } ) ;
459481
482+ describe ( 'ClientSession (Implicit)' , ( ) => {
483+ let client : MongoClient ;
484+
485+ beforeEach ( async function ( ) {
486+ client = this . configuration . newClient ( { } , { monitorCommands : true } ) ;
487+ } ) ;
488+
489+ afterEach ( async function ( ) {
490+ await client . close ( ) ;
491+ } ) ;
492+
493+ describe ( 'when MongoClient.close is called' , function ( ) {
494+ it ( 'sends an endSessions command' , async function ( ) {
495+ await client . db ( 'a' ) . collection ( 'a' ) . insertOne ( { a : 1 } ) ;
496+ await client . db ( 'a' ) . collection ( 'a' ) . insertOne ( { a : 1 } ) ;
497+ await client . db ( 'a' ) . collection ( 'a' ) . insertOne ( { a : 1 } ) ;
498+ const endSessionsStarted = events . once ( client , 'commandStarted' ) ;
499+ const willEndSessions = events . once ( client , 'commandSucceeded' ) ;
500+
501+ await client . close ( ) ;
502+
503+ const [ startedEv ] = await endSessionsStarted ;
504+ expect ( startedEv ) . to . have . nested . property ( 'command.endSessions' ) . that . has . lengthOf ( 1 ) ;
505+
506+ const [ commandEv ] = await willEndSessions ;
507+ expect ( commandEv ) . to . have . property ( 'commandName' , 'endSessions' ) ;
508+ } ) ;
509+ } ) ;
510+ } ) ;
511+
460512 describe ( 'ClientSession (Explicit)' , ( ) => {
461513 let idleSessionsBeforeClose ;
462514 let idleSessionsAfterClose ;
@@ -538,10 +590,10 @@ describe('MongoClient.close() Integration', () => {
538590 describe ( 'KMS Request' , ( ) => {
539591 describe ( 'Node.js resource: TLS file read' , ( ) => {
540592 describe ( 'when KMSRequest reads an infinite TLS file' , ( ) => {
541- it . skip ( 'the file read is interrupted by client.close()' , metadata , async ( ) => {
593+ it . skip ( 'the file read is interrupted by client.close()' , metadata , async function ( ) {
542594 await runScriptAndGetProcessInfo (
543595 'tls-file-read-auto-encryption' ,
544- config ,
596+ this . configuration ,
545597 async function run ( { MongoClient, uri, expect, mongodb } ) {
546598 const infiniteFile = '/dev/zero' ;
547599
@@ -666,7 +718,7 @@ describe('MongoClient.close() Integration', () => {
666718 'all active server-side cursors are closed by client.close()' ,
667719 metadata ,
668720 async function ( ) {
669- const getCursors = async ( ) => {
721+ const getCursors = async function ( ) {
670722 const cursors = await utilClient
671723 . db ( 'admin' )
672724 . aggregate ( [ { $currentOp : { idleCursors : true } } ] )
0 commit comments