@@ -386,4 +386,136 @@ describe("connectionManager", () => {
386386 } ) ;
387387 } ) ;
388388 } ) ;
389+
390+ it ( "Connection retry timeout - throws error when delay exceeds remaining timeout" , async ( ) => {
391+ // Arrange
392+ const timeoutMs = 5000 ; // 5 second timeout
393+ const connectionManager = new ConnectionManager (
394+ ( ) => mockDocumentService ,
395+ ( ) => false ,
396+ client as IClient ,
397+ true /* reconnectAllowed */ ,
398+ mockLogger . toTelemetryLogger ( ) ,
399+ props ,
400+ timeoutMs , // Set the retry connection timeout
401+ ) ;
402+
403+ // Mock connectToDeltaStream to throw retryable errors that cause delays
404+ const stubbedConnectToDeltaStream = stub ( mockDocumentService , "connectToDeltaStream" ) ;
405+ stubbedConnectToDeltaStream . throws (
406+ new RetryableError ( "Throttling error" , DriverErrorTypes . throttlingError , {
407+ retryAfterSeconds : 3 , // 3 second delay from error
408+ driverVersion : pkgVersion ,
409+ } ) ,
410+ ) ;
411+
412+ // Act
413+ connectionManager . connect ( { text : "test:retry timeout" } , "write" ) ;
414+
415+ // Advance time to trigger multiple retries and eventually hit the timeout
416+ await clock . tickAsync ( 6000 ) ; // This should trigger the timeout logic
417+
418+ // Verify the telemetry event was logged
419+ mockLogger . assertMatchAny ( [
420+ {
421+ eventName : "RetryDelayExceedsConnectionTimeout" ,
422+ attempts : 2 ,
423+ calculatedDelayMs : 6000 , // The calculated delay that exceeded timeout
424+ remainingTimeMs : 2000 , // Should be positive but less than calculatedDelayMs
425+ timeoutMs,
426+ } ,
427+ ] ) ;
428+
429+ // Verify that the container was closed due to the timeout
430+ assert ( closed , "Connection manager should close when retry delay exceeds timeout" ) ;
431+
432+ stubbedConnectToDeltaStream . restore ( ) ;
433+ } ) ;
434+
435+ it ( "Connection retry timeout - continues retrying when delay is within timeout" , async ( ) => {
436+ // Arrange
437+ const timeoutMs = 20000 ; // 20 second timeout (longer than test duration)
438+ const connectionManager = new ConnectionManager (
439+ ( ) => mockDocumentService ,
440+ ( ) => false ,
441+ client as IClient ,
442+ true /* reconnectAllowed */ ,
443+ mockLogger . toTelemetryLogger ( ) ,
444+ props ,
445+ timeoutMs , // Set the retry connection timeout
446+ ) ;
447+
448+ // Mock connectToDeltaStream to throw retryable errors with short delays
449+ const stubbedConnectToDeltaStream = stub ( mockDocumentService , "connectToDeltaStream" ) ;
450+ stubbedConnectToDeltaStream . throws (
451+ new RetryableError ( "Temporary error" , DriverErrorTypes . genericError , {
452+ retryAfterSeconds : 0.1 , // Very small delay to keep within timeout
453+ driverVersion : pkgVersion ,
454+ } ) ,
455+ ) ;
456+
457+ // Act
458+ connectionManager . connect ( { text : "test:retry within timeout" } , "write" ) ;
459+
460+ // Advance time for a few retries but not long enough to exceed timeout
461+ await clock . tickAsync ( 2000 ) ; // 2 seconds - should allow for multiple retries
462+
463+ // Assert - the connection should still be retrying and not have closed
464+ assert ( ! closed , "Connection manager should not close when retries are within timeout" ) ;
465+ assert (
466+ stubbedConnectToDeltaStream . callCount > 1 ,
467+ "Should have made multiple connection attempts" ,
468+ ) ;
469+
470+ // Verify no timeout telemetry was logged
471+ assert (
472+ ! mockLogger . matchEvents ( [ { eventName : "RetryDelayExceedsConnectionTimeout" } ] ) ,
473+ "Should not log timeout event when retries are within limit" ,
474+ ) ;
475+
476+ stubbedConnectToDeltaStream . restore ( ) ;
477+ } ) ;
478+
479+ it ( "Connection retry timeout - no timeout when retryConnectionTimeoutMs is undefined" , async ( ) => {
480+ // Arrange - Create connection manager without timeout
481+ const connectionManager = new ConnectionManager (
482+ ( ) => mockDocumentService ,
483+ ( ) => false ,
484+ client as IClient ,
485+ true /* reconnectAllowed */ ,
486+ mockLogger . toTelemetryLogger ( ) ,
487+ props ,
488+ undefined , // No retry timeout
489+ ) ;
490+
491+ // Mock connectToDeltaStream to throw retryable errors
492+ const stubbedConnectToDeltaStream = stub ( mockDocumentService , "connectToDeltaStream" ) ;
493+ stubbedConnectToDeltaStream . throws (
494+ new RetryableError ( "Delay error" , DriverErrorTypes . genericError , {
495+ retryAfterSeconds : 1 , // 1 second delay
496+ driverVersion : pkgVersion ,
497+ } ) ,
498+ ) ;
499+
500+ // Act
501+ connectionManager . connect ( { text : "test:no timeout limit" } , "write" ) ;
502+
503+ // Advance time for several retries
504+ await clock . tickAsync ( 10000 ) ; // 10 seconds - would exceed most reasonable timeouts
505+
506+ // Assert - the connection should still be retrying and not have closed
507+ assert ( ! closed , "Connection manager should not close when no timeout is set" ) ;
508+ assert (
509+ stubbedConnectToDeltaStream . callCount > 1 ,
510+ "Should have made multiple connection attempts" ,
511+ ) ;
512+
513+ // Verify no timeout telemetry was logged
514+ assert (
515+ ! mockLogger . matchEvents ( [ { eventName : "RetryDelayExceedsConnectionTimeout" } ] ) ,
516+ "Should not log timeout event when no timeout is configured" ,
517+ ) ;
518+
519+ stubbedConnectToDeltaStream . restore ( ) ;
520+ } ) ;
389521} ) ;
0 commit comments