@@ -4,6 +4,7 @@ import * as net from 'net';
44import * as sinon from 'sinon' ;
55
66import {
7+ type Collection ,
78 type CommandFailedEvent ,
89 type CommandStartedEvent ,
910 type CommandSucceededEvent ,
@@ -31,7 +32,6 @@ describe('class MongoClient', function () {
3132 afterEach ( async ( ) => {
3233 sinon . restore ( ) ;
3334 await client ?. close ( ) ;
34- // @ts -expect-error: Put this variable back to undefined to force tests to make their own client
3535 client = undefined ;
3636 } ) ;
3737
@@ -567,7 +567,44 @@ describe('class MongoClient', function () {
567567 } ) ;
568568 } ) ;
569569
570- context ( '#close()' , ( ) => {
570+ describe ( 'active cursors' , function ( ) {
571+ let client : MongoClient ;
572+ let collection : Collection < { _id : number } > ;
573+ const kills = [ ] ;
574+
575+ beforeEach ( async function ( ) {
576+ client = this . configuration . newClient ( ) ;
577+ collection = client . db ( 'activeCursors' ) . collection ( 'activeCursors' ) ;
578+ await collection . drop ( ) . catch ( ( ) => null ) ;
579+ await collection . insertMany ( Array . from ( { length : 50 } , ( _ , _id ) => ( { _id } ) ) ) ;
580+
581+ kills . length = 0 ;
582+ client . on ( 'commandStarted' , ev => ev . commandName === 'killCursors' && kills . push ( ev ) ) ;
583+ } ) ;
584+
585+ afterEach ( async function ( ) {
586+ await client . close ( ) ;
587+ } ) ;
588+
589+ it ( 'are tracked upon creation and removed upon exhaustion' , async ( ) => {
590+ const cursors = Array . from ( { length : 30 } , ( _ , skip ) =>
591+ collection . find ( { } , { skip, batchSize : 1 } )
592+ ) ;
593+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 30 ) ;
594+ await Promise . all ( cursors . map ( c => c . toArray ( ) ) ) ;
595+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 0 ) ;
596+ expect ( kills ) . to . have . lengthOf ( 0 ) ;
597+ } ) ;
598+
599+ it ( 'are removed from tracking if exhausted in first batch' , async ( ) => {
600+ const cursors = Array . from ( { length : 30 } , ( ) => collection . find ( ) ) ;
601+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 30 ) ;
602+ await Promise . all ( cursors . map ( c => c . next ( ) ) ) ; // only one document pulled from each.
603+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 0 ) ;
604+ } ) ;
605+ } ) ;
606+
607+ describe ( '#close()' , ( ) => {
571608 let client : MongoClient ;
572609 let db : Db ;
573610
@@ -702,7 +739,7 @@ describe('class MongoClient', function () {
702739 expect ( endEvents [ 0 ] ) . to . have . property ( 'reply' , undefined ) ; // noReponse: true
703740 } ) ;
704741
705- context ( 'when server selection would return no servers' , ( ) => {
742+ describe ( 'when server selection would return no servers' , ( ) => {
706743 const serverDescription = new ServerDescription ( 'a:1' ) ;
707744
708745 it ( 'short circuits and does not end sessions' , async ( ) => {
@@ -722,6 +759,49 @@ describe('class MongoClient', function () {
722759 expect ( client . s . sessionPool . sessions ) . to . have . lengthOf ( 1 ) ;
723760 } ) ;
724761 } ) ;
762+
763+ describe ( 'active cursors' , function ( ) {
764+ let collection : Collection < { _id : number } > ;
765+ const kills = [ ] ;
766+
767+ beforeEach ( async ( ) => {
768+ collection = client . db ( 'test' ) . collection ( 'activeCursors' ) ;
769+ await collection . drop ( ) . catch ( ( ) => null ) ;
770+ await collection . insertMany ( Array . from ( { length : 50 } , ( _ , _id ) => ( { _id } ) ) ) ;
771+
772+ kills . length = 0 ;
773+ client . on ( 'commandStarted' , ev => ev . commandName === 'killCursors' && kills . push ( ev ) ) ;
774+ } ) ;
775+
776+ it ( 'are all closed' , async ( ) => {
777+ const cursors = Array . from ( { length : 30 } , ( _ , skip ) =>
778+ collection . find ( { } , { skip, batchSize : 1 } )
779+ ) ;
780+ await Promise . all ( cursors . map ( c => c . next ( ) ) ) ;
781+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 30 ) ;
782+ await client . close ( ) ;
783+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 0 ) ;
784+ expect ( kills ) . to . have . lengthOf ( 30 ) ;
785+ } ) ;
786+
787+ it ( 'creating cursors after close adds to activeCursors' , async ( ) => {
788+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 0 ) ;
789+ await client . close ( ) ;
790+ collection . find ( { } ) ;
791+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 1 ) ;
792+ } ) ;
793+
794+ it ( 'rewinding cursors after close adds to activeCursors' , async ( ) => {
795+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 0 ) ;
796+ const cursor = collection . find ( { } , { batchSize : 1 } ) ;
797+ await cursor . next ( ) ;
798+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 1 ) ;
799+ await client . close ( ) ;
800+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 0 ) ;
801+ cursor . rewind ( ) ;
802+ expect ( client . s . activeCursors ) . to . have . lengthOf ( 1 ) ;
803+ } ) ;
804+ } ) ;
725805 } ) ;
726806
727807 context ( 'when connecting' , function ( ) {
0 commit comments