1
1
/* eslint-disable @typescript-eslint/no-empty-function */
2
2
import { expect } from 'chai' ;
3
3
import * as sinon from 'sinon' ;
4
- import { MongoClient } from '../../mongodb' ;
4
+ import { Connection , HostAddress , MongoClient } from '../../mongodb' ;
5
5
import { type TestConfiguration } from '../../tools/runner/config' ;
6
6
import { runScriptAndGetProcessInfo } from './resource_tracking_script_builder' ;
7
7
import { sleep } from '../../tools/utils' ;
8
- import { ConnectionPool , Timeout } from '../../mongodb' ;
8
+ import { ConnectionPool } from '../../mongodb' ;
9
+ import { getActiveResourcesInfo } from 'process' ;
9
10
10
11
describe . only ( 'MongoClient.close() Integration' , ( ) => {
11
12
// note: these tests are set-up in accordance of the resource ownership tree
@@ -80,31 +81,34 @@ describe.only('MongoClient.close() Integration', () => {
80
81
describe ( 'Topology' , ( ) => {
81
82
describe ( 'Node.js resource: Server Selection Timer' , ( ) => {
82
83
describe ( 'after a Topology is created through client.connect()' , ( ) => {
83
- it . only ( 'server selection timers are cleaned up by client.close()' , async ( ) => {
84
- // note: this test is not called in a separate process since it requires stubbing internal class: Timeout
85
- const run = async function ( { MongoClient, uri, expect, sinon, sleep, getTimerCount } ) {
86
- const serverSelectionTimeoutMS = 777 ;
84
+ it ( 'server selection timers are cleaned up by client.close()' , async ( ) => {
85
+ const run = async function ( { MongoClient, uri, expect, sinon, sleep, mongodb, getTimerCount } ) {
86
+ const serverSelectionTimeoutMS = 2222 ;
87
87
const client = new MongoClient ( uri , { minPoolSize : 1 , serverSelectionTimeoutMS } ) ;
88
- const timeoutStartedSpy = sinon . spy ( Timeout , 'expires' ) ;
88
+ const timers = require ( 'timers' ) ;
89
+ const timeoutStartedSpy = sinon . spy ( timers , 'setTimeout' ) ;
89
90
let serverSelectionTimeoutStarted = false ;
90
91
91
92
// make server selection hang so check out timer isn't cleared and check that the timeout has started
92
- sinon . stub ( Promise , 'race' ) . callsFake ( ( ) => {
93
- serverSelectionTimeoutStarted = timeoutStartedSpy . getCalls ( ) . filter ( r => r . args . includes ( 777 ) ) . flat ( ) . length > 0 ;
93
+ sinon . stub ( Promise , 'race' ) . callsFake ( async ( [ serverPromise , timeout ] ) => {
94
+ serverSelectionTimeoutStarted = timeoutStartedSpy . getCalls ( ) . filter ( r => r . args . includes ( serverSelectionTimeoutMS ) ) . flat ( ) . length > 0 ;
95
+ await timeout ;
94
96
} ) ;
95
97
96
- client . db ( 'db' ) . collection ( 'collection' ) . insertOne ( { x : 1 } ) . catch ( e => e ) ;
98
+ const insertPromise = client . db ( 'db' ) . collection ( 'collection' ) . insertOne ( { x : 1 } ) ;
97
99
98
- // don't allow entire checkout timer to elapse to ensure close is called mid-timeout
100
+ // don't allow entire server selection timer to elapse to ensure close is called mid-timeout
99
101
await sleep ( serverSelectionTimeoutMS / 2 ) ;
100
102
expect ( serverSelectionTimeoutStarted ) . to . be . true ;
101
103
104
+ expect ( getTimerCount ( ) ) . to . not . equal ( 0 ) ;
102
105
await client . close ( ) ;
103
106
expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
104
- } ;
105
107
106
- const getTimerCount = ( ) => process . getActiveResourcesInfo ( ) . filter ( r => r === 'Timeout' ) . length ;
107
- await run ( { MongoClient, uri : config . uri , sleep, sinon, expect, getTimerCount} ) ;
108
+ const err = await insertPromise . catch ( e => e ) ;
109
+ expect ( err ) . to . be . instanceOf ( mongodb . MongoServerSelectionError ) ;
110
+ } ;
111
+ await runScriptAndGetProcessInfo ( 'timer-server-selection' , config , run ) ;
108
112
} ) ;
109
113
} ) ;
110
114
} ) ;
@@ -143,13 +147,35 @@ describe.only('MongoClient.close() Integration', () => {
143
147
144
148
expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
145
149
} ;
146
-
147
150
await runScriptAndGetProcessInfo ( 'timer-monitor-interval' , config , run ) ;
148
151
} ) ;
149
152
} ) ;
150
153
151
154
describe ( 'after a heartbeat fails' , ( ) => {
152
- it . skip ( 'the new monitor interval timer is cleaned up by client.close()' , metadata , async ( ) => { } ) ;
155
+ it ( 'the new monitor interval timer is cleaned up by client.close()' , metadata , async ( ) => {
156
+ const run = async function ( { MongoClient, uri, expect, sleep, getTimerCount } ) {
157
+ const heartbeatFrequencyMS = 2000 ;
158
+ const client = new MongoClient ( 'mongodb://fakeUri' , { heartbeatFrequencyMS } ) ;
159
+ let heartbeatHappened = false ;
160
+ client . on ( 'serverHeartbeatFailed' , ( ) => heartbeatHappened = true ) ;
161
+ client . connect ( ) ;
162
+ await sleep ( heartbeatFrequencyMS * 2.5 ) ;
163
+ expect ( heartbeatHappened ) . to . be . true ;
164
+
165
+ function getMonitorTimer ( servers ) {
166
+ for ( const server of servers ) {
167
+ return server [ 1 ] ?. monitor . monitorId . timerId ;
168
+ }
169
+ } ;
170
+ const servers = client . topology . s . servers ;
171
+ expect ( getMonitorTimer ( servers ) ) . to . exist ;
172
+ await client . close ( ) ;
173
+ expect ( getMonitorTimer ( servers ) ) . to . not . exist ;
174
+
175
+ expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
176
+ } ;
177
+ await runScriptAndGetProcessInfo ( 'timer-heartbeat-failed-monitor' , config , run ) ;
178
+ } ) ;
153
179
} ) ;
154
180
} ) ;
155
181
} ) ;
@@ -219,7 +245,6 @@ describe.only('MongoClient.close() Integration', () => {
219
245
220
246
expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
221
247
} ;
222
-
223
248
await runScriptAndGetProcessInfo ( 'timer-rtt-monitor' , config , run ) ;
224
249
} ) ;
225
250
} ) ;
@@ -315,31 +340,33 @@ describe.only('MongoClient.close() Integration', () => {
315
340
} ) ;
316
341
317
342
describe ( 'Node.js resource: checkOut Timer' , ( ) => {
318
- // waitQueueTimeoutMS
319
343
describe ( 'after new connection pool is created' , ( ) => {
320
344
it ( 'the wait queue timer is cleaned up by client.close()' , async function ( ) {
321
- // note: this test is not called in a separate process since it requires stubbing internal function
345
+ // note: this test is not called in a separate process since it stubs internal class: ConnectionPool
322
346
const run = async function ( { MongoClient, uri, expect, sinon, sleep, getTimerCount } ) {
323
347
const waitQueueTimeoutMS = 999 ;
324
348
const client = new MongoClient ( uri , { minPoolSize : 1 , waitQueueTimeoutMS } ) ;
325
- const timeoutStartedSpy = sinon . spy ( Timeout , 'expires' ) ;
349
+ const timers = require ( 'timers' ) ;
350
+ const timeoutStartedSpy = sinon . spy ( timers , 'setTimeout' ) ;
326
351
let checkoutTimeoutStarted = false ;
327
352
328
353
// make waitQueue hang so check out timer isn't cleared and check that the timeout has started
329
354
sinon . stub ( ConnectionPool . prototype , 'processWaitQueue' ) . callsFake ( async ( ) => {
330
- checkoutTimeoutStarted = timeoutStartedSpy . getCalls ( ) . map ( r => r . args ) . filter ( r => r . includes ( 999 ) ) ? true : false ;
355
+ checkoutTimeoutStarted = timeoutStartedSpy . getCalls ( ) . filter ( r => r . args . includes ( waitQueueTimeoutMS ) ) . flat ( ) . length > 0 ;
331
356
} ) ;
332
357
333
- client . db ( 'db' ) . collection ( 'collection' ) . insertOne ( { x : 1 } ) . catch ( e => e ) ;
358
+ const insertPromise = client . db ( 'db' ) . collection ( 'collection' ) . insertOne ( { x : 1 } ) . catch ( e => e ) ;
334
359
335
360
// don't allow entire checkout timer to elapse to ensure close is called mid-timeout
336
361
await sleep ( waitQueueTimeoutMS / 2 ) ;
337
362
expect ( checkoutTimeoutStarted ) . to . be . true ;
338
363
339
364
await client . close ( ) ;
340
365
expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
341
- } ;
342
366
367
+ const err = await insertPromise ;
368
+ expect ( err ) . to . not . be . instanceOf ( Error ) ;
369
+ } ;
343
370
const getTimerCount = ( ) => process . getActiveResourcesInfo ( ) . filter ( r => r === 'Timeout' ) . length ;
344
371
await run ( { MongoClient, uri : config . uri , sleep, sinon, expect, getTimerCount} ) ;
345
372
} ) ;
@@ -389,39 +416,40 @@ describe.only('MongoClient.close() Integration', () => {
389
416
}
390
417
} ;
391
418
describe ( 'after SRVPoller is created' , ( ) => {
392
- it . skip ( 'timers are cleaned up by client.close()' , metadata , async ( ) => {
393
- const run = async function ( { MongoClient, uri, expect, log , sinon, mongodb , getTimerCount } ) {
419
+ it . only ( 'timers are cleaned up by client.close()' , metadata , async ( ) => {
420
+ const run = async function ( { MongoClient, uri, expect, mongodb , sinon, getTimerCount } ) {
394
421
const dns = require ( 'dns' ) ;
395
-
396
422
sinon . stub ( dns . promises , 'resolveTxt' ) . callsFake ( async ( ) => {
397
423
throw { code : 'ENODATA' } ;
398
424
} ) ;
399
425
sinon . stub ( dns . promises , 'resolveSrv' ) . callsFake ( async ( ) => {
400
- const formattedUri = mongodb . HostAddress . fromString ( uri . split ( '//' ) [ 1 ] ) ;
401
426
return [
402
427
{
403
- name : formattedUri . host ,
404
- port : formattedUri . port ,
428
+ name : 'domain.localhost' ,
429
+ port : 27017 ,
405
430
weight : 0 ,
406
431
priority : 0 ,
407
- protocol : formattedUri . host . isIPv6 ? 'IPv6' : 'IPv4 '
432
+ protocol : 'IPv6'
408
433
}
409
434
] ;
410
435
} ) ;
411
- /* sinon.stub(mongodb, 'checkParentDomainMatch').callsFake(async () => {
412
- console.log('in here!!!');
413
- }); */
414
436
415
437
const client = new MongoClient ( 'mongodb+srv://localhost' ) ;
416
- await client . connect ( ) ;
438
+ client . connect ( ) ;
439
+
440
+ const topology = client . topology ;
441
+ const prevDesc = topology ;
442
+ log ( { topology } ) ;
443
+ const currDesc = prevDesc ;
444
+ client . topology . emit (
445
+ 'topologyDescriptionChanged' ,
446
+ mongodb . TopologyDescriptionChangedEvent ( client . topology . s . id , prevDesc , currDesc )
447
+ ) ;
448
+
417
449
await client . close ( ) ;
418
450
expect ( getTimerCount ( ) ) . to . equal ( 0 ) ;
419
- sinon . restore ( ) ;
420
451
} ;
421
-
422
- const getTimerCount = ( ) => process . getActiveResourcesInfo ( ) . filter ( r => r === 'Timeout' ) . length ;
423
- // await run({ MongoClient, uri: config.uri, sleep, sinon, expect, mongodb, getTimerCount});
424
- await runScriptAndGetProcessInfo ( 'srv-poller-timer' , config , run ) ;
452
+ await runScriptAndGetProcessInfo ( 'timer-srv-poller' , config , run ) ;
425
453
} ) ;
426
454
} ) ;
427
455
} ) ;
@@ -564,4 +592,4 @@ describe.only('MongoClient.close() Integration', () => {
564
592
it . skip ( 'all active server-side cursors are closed by client.close()' , async function ( ) { } ) ;
565
593
} ) ;
566
594
} ) ;
567
- } ) ;
595
+ } ) ;
0 commit comments