@@ -290,7 +290,7 @@ describe('PassiveDaemonWatcher', () => {
290290
291291 describe ( 'Exponential Backoff' , ( ) => {
292292 it (
293- 'should use exponential backoff for retries (2s, 5s, 10s, 20s, 40s )' ,
293+ 'should use exponential backoff for retries (2s, 5s, 10s, 20s)' ,
294294 async ( ) => {
295295 ( getNxDaemonClient as jest . Mock ) . mockRejectedValue (
296296 new Error ( 'Always fails' ) ,
@@ -314,16 +314,13 @@ describe('PassiveDaemonWatcher', () => {
314314 await new Promise ( ( resolve ) => setTimeout ( resolve , 20500 ) ) ;
315315 expect ( getNxDaemonClient ) . toHaveBeenCalledTimes ( 5 ) ;
316316
317- await new Promise ( ( resolve ) => setTimeout ( resolve , 40500 ) ) ;
318- expect ( getNxDaemonClient ) . toHaveBeenCalledTimes ( 6 ) ;
319-
320317 watcher . dispose ( ) ;
321318 } ,
322- 90000 ,
319+ 50000 ,
323320 ) ;
324321
325322 it (
326- 'should stop retrying after 5 failed attempts' ,
323+ 'should stop retrying after 4 failed attempts' ,
327324 async ( ) => {
328325 ( getNxDaemonClient as jest . Mock ) . mockRejectedValue (
329326 new Error ( 'Always fails' ) ,
@@ -334,17 +331,17 @@ describe('PassiveDaemonWatcher', () => {
334331
335332 await flushPromises ( ) ;
336333
337- await new Promise ( ( resolve ) => setTimeout ( resolve , 80000 ) ) ;
334+ await new Promise ( ( resolve ) => setTimeout ( resolve , 40000 ) ) ;
338335
339- expect ( getNxDaemonClient ) . toHaveBeenCalledTimes ( 6 ) ;
336+ expect ( getNxDaemonClient ) . toHaveBeenCalledTimes ( 5 ) ;
340337
341338 await new Promise ( ( resolve ) => setTimeout ( resolve , 5000 ) ) ;
342339
343- expect ( getNxDaemonClient ) . toHaveBeenCalledTimes ( 6 ) ;
340+ expect ( getNxDaemonClient ) . toHaveBeenCalledTimes ( 5 ) ;
344341
345342 watcher . dispose ( ) ;
346343 } ,
347- 90000 ,
344+ 50000 ,
348345 ) ;
349346 } ) ;
350347
@@ -400,6 +397,114 @@ describe('PassiveDaemonWatcher', () => {
400397 expect ( listener ) . not . toHaveBeenCalled ( ) ;
401398 } ) ;
402399 } ) ;
400+
401+ describe ( 'Operational State Callback' , ( ) => {
402+ it ( 'should call callback with true when starting' , async ( ) => {
403+ const onOperationalStateChange = jest . fn ( ) ;
404+ const watcher = new PassiveDaemonWatcher (
405+ '/workspace' ,
406+ mockLogger ,
407+ onOperationalStateChange ,
408+ ) ;
409+
410+ watcher . start ( ) ;
411+ await flushPromises ( ) ;
412+
413+ expect ( onOperationalStateChange ) . toHaveBeenCalledWith ( true ) ;
414+
415+ watcher . dispose ( ) ;
416+ } ) ;
417+
418+ it ( 'should call callback with true when listening' , async ( ) => {
419+ const onOperationalStateChange = jest . fn ( ) ;
420+ const watcher = new PassiveDaemonWatcher (
421+ '/workspace' ,
422+ mockLogger ,
423+ onOperationalStateChange ,
424+ ) ;
425+
426+ watcher . start ( ) ;
427+ await flushPromises ( ) ;
428+
429+ expect ( onOperationalStateChange ) . toHaveBeenCalledWith ( true ) ;
430+
431+ watcher . dispose ( ) ;
432+ } ) ;
433+
434+ it ( 'should call callback with true when failed but can retry' , async ( ) => {
435+ const onOperationalStateChange = jest . fn ( ) ;
436+ ( getNxDaemonClient as jest . Mock ) . mockRejectedValueOnce (
437+ new Error ( 'Failed once' ) ,
438+ ) ;
439+
440+ const watcher = new PassiveDaemonWatcher (
441+ '/workspace' ,
442+ mockLogger ,
443+ onOperationalStateChange ,
444+ ) ;
445+
446+ watcher . start ( ) ;
447+ await flushPromises ( ) ;
448+
449+ const trueCalls = onOperationalStateChange . mock . calls . filter (
450+ ( call ) => call [ 0 ] === true ,
451+ ) ;
452+ expect ( trueCalls . length ) . toBeGreaterThan ( 0 ) ;
453+
454+ watcher . dispose ( ) ;
455+ } ) ;
456+
457+ it (
458+ 'should call callback with false when permanently failed' ,
459+ async ( ) => {
460+ const onOperationalStateChange = jest . fn ( ) ;
461+ ( getNxDaemonClient as jest . Mock ) . mockRejectedValue (
462+ new Error ( 'Always fails' ) ,
463+ ) ;
464+
465+ const watcher = new PassiveDaemonWatcher (
466+ '/workspace' ,
467+ mockLogger ,
468+ onOperationalStateChange ,
469+ ) ;
470+
471+ watcher . start ( ) ;
472+ await flushPromises ( ) ;
473+
474+ await new Promise ( ( resolve ) => setTimeout ( resolve , 45000 ) ) ;
475+ await flushPromises ( ) ;
476+
477+ const falseCalls = onOperationalStateChange . mock . calls . filter (
478+ ( call ) => call [ 0 ] === false ,
479+ ) ;
480+ expect ( falseCalls . length ) . toBeGreaterThan ( 0 ) ;
481+
482+ watcher . dispose ( ) ;
483+ } ,
484+ 50000 ,
485+ ) ;
486+
487+ it ( 'should call callback with true after stop' , async ( ) => {
488+ const onOperationalStateChange = jest . fn ( ) ;
489+ const watcher = new PassiveDaemonWatcher (
490+ '/workspace' ,
491+ mockLogger ,
492+ onOperationalStateChange ,
493+ ) ;
494+
495+ watcher . start ( ) ;
496+ await flushPromises ( ) ;
497+
498+ onOperationalStateChange . mockClear ( ) ;
499+
500+ watcher . stop ( ) ;
501+ await flushPromises ( ) ;
502+
503+ expect ( onOperationalStateChange ) . toHaveBeenCalledWith ( true ) ;
504+
505+ watcher . dispose ( ) ;
506+ } ) ;
507+ } ) ;
403508} ) ;
404509
405510async function flushPromises ( ) {
0 commit comments