@@ -22,7 +22,7 @@ import {
2222} from '../../mongodb' ;
2323import * as mock from '../../tools/mongodb-mock/index' ;
2424import { skipBrokenAuthTestBeforeEachHook } from '../../tools/runner/hooks/configuration' ;
25- import { sleep } from '../../tools/utils' ;
25+ import { processTick , sleep } from '../../tools/utils' ;
2626import { assert as test , setupDatabase } from '../shared' ;
2727
2828const commonConnectOptions = {
@@ -249,6 +249,55 @@ describe('Connection', function () {
249249 client . connect ( ) ;
250250 } ) ;
251251
252+ describe (
253+ 'when a monitoring Connection receives many hellos in one chunk' ,
254+ { requires : { topology : 'replicaset' } } ,
255+ function ( ) {
256+ let client : MongoClient ;
257+ let hbSuccess = 0 ;
258+
259+ beforeEach ( async function ( ) {
260+ client = this . configuration . newClient ( { } , { heartbeatFrequencyMS : 100 } ) ; // just so we don't have to wait so long for a hello
261+ hbSuccess = 0 ;
262+ client . on ( 'serverHeartbeatSucceeded' , ( ) => ( hbSuccess += 1 ) ) ;
263+ } ) ;
264+
265+ afterEach ( async function ( ) {
266+ hbSuccess = 0 ;
267+ await client . close ( ) ;
268+ } ) ;
269+
270+ // In the future we may want to skip processing concatenated heartbeats.
271+ // This test exists to prevent regression of processing many messages inside one chunk.
272+ it (
273+ 'processes all of them and emits heartbeats' ,
274+ { requires : { topology : 'replicaset' } } ,
275+ async function ( ) {
276+ expect ( hbSuccess ) . to . equal ( 0 ) ;
277+
278+ await client . db ( ) . command ( { ping : 1 } ) ; // start monitoring.
279+ const monitor = [ ...client . topology . s . servers . values ( ) ] [ 0 ] . monitor ;
280+
281+ // @ts -expect-error: accessing private property
282+ const messageStream = monitor . connection . messageStream ;
283+ // @ts -expect-error: accessing private property
284+ const socket = monitor . connection . socket ;
285+
286+ const [ hello ] = ( await once ( messageStream , 'data' ) ) as [ Buffer ] ;
287+
288+ const thousandHellos = Array . from ( { length : 1000 } , ( ) => [ ...hello ] ) . flat ( 1 ) ;
289+
290+ // pretend this came from the server
291+ socket . emit ( 'data' , Buffer . from ( thousandHellos ) ) ;
292+
293+ // All of the hb will be emitted synchronously in the next tick as the entire chunk is processed.
294+ await processTick ( ) ;
295+ expect ( hbSuccess ) . to . be . greaterThan ( 100 ) ;
296+ }
297+ ) ;
298+ }
299+ ) ;
300+
252301 context (
253302 'when a large message is written to the socket' ,
254303 { requires : { topology : 'single' , auth : 'disabled' } } ,
0 commit comments