11import  {  logger  }  from  "@coder/logger" 
22import  {  readFile ,  writeFile ,  stat ,  utimes  }  from  "fs/promises" 
3- import  {  Heart ,  heartbeatTimer  }  from  "../../../src/node/heart" 
4- import  {  wrapper  }  from  "../../../src/node/wrapper" 
3+ import  {  Heart  }  from  "../../../src/node/heart" 
54import  {  clean ,  mockLogger ,  tmpdir  }  from  "../../utils/helpers" 
65
76const  mockIsActive  =  ( resolveTo : boolean )  =>  jest . fn ( ) . mockResolvedValue ( resolveTo ) 
87
9- jest . mock ( "../../../src/node/wrapper" ,  ( )  =>  { 
10-   const  original  =  jest . requireActual ( "../../../src/node/wrapper" ) 
11-   return  { 
12-     ...original , 
13-     wrapper : { 
14-       exit : jest . fn ( ) , 
15-     } , 
16-   } 
17- } ) 
18- 
198describe ( "Heart" ,  ( )  =>  { 
209  const  testName  =  "heartTests" 
2110  let  testDir  =  "" 
@@ -27,7 +16,7 @@ describe("Heart", () => {
2716    testDir  =  await  tmpdir ( testName ) 
2817  } ) 
2918  beforeEach ( ( )  =>  { 
30-     heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  undefined ,   mockIsActive ( true ) ) 
19+     heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  mockIsActive ( true ) ) 
3120  } ) 
3221  afterAll ( ( )  =>  { 
3322    jest . restoreAllMocks ( ) 
@@ -53,7 +42,7 @@ describe("Heart", () => {
5342
5443    expect ( fileContents ) . toBe ( text ) 
5544
56-     heart  =  new  Heart ( pathToFile ,  undefined ,   mockIsActive ( true ) ) 
45+     heart  =  new  Heart ( pathToFile ,  mockIsActive ( true ) ) 
5746    await  heart . beat ( ) 
5847    // Check that the heart wrote to the heartbeatFilePath and overwrote our text 
5948    const  fileContentsAfterBeat  =  await  readFile ( pathToFile ,  {  encoding : "utf8"  } ) 
@@ -63,7 +52,7 @@ describe("Heart", () => {
6352    expect ( fileStatusAfterEdit . mtimeMs ) . toBeGreaterThan ( 0 ) 
6453  } ) 
6554  it ( "should log a warning when given an invalid file path" ,  async  ( )  =>  { 
66-     heart  =  new  Heart ( `fakeDir/fake.txt` ,  undefined ,   mockIsActive ( false ) ) 
55+     heart  =  new  Heart ( `fakeDir/fake.txt` ,  mockIsActive ( false ) ) 
6756    await  heart . beat ( ) 
6857    expect ( logger . warn ) . toHaveBeenCalled ( ) 
6958  } ) 
@@ -82,7 +71,7 @@ describe("Heart", () => {
8271  it ( "should beat twice without warnings" ,  async  ( )  =>  { 
8372    // Use fake timers so we can speed up setTimeout 
8473    jest . useFakeTimers ( ) 
85-     heart  =  new  Heart ( `${ testDir }  /hello.txt` ,  undefined ,   mockIsActive ( true ) ) 
74+     heart  =  new  Heart ( `${ testDir }  /hello.txt` ,  mockIsActive ( true ) ) 
8675    await  heart . beat ( ) 
8776    // we need to speed up clocks, timeouts 
8877    // call heartbeat again (and it won't be alive I think) 
@@ -93,37 +82,47 @@ describe("Heart", () => {
9382} ) 
9483
9584describe ( "heartbeatTimer" ,  ( )  =>  { 
96-   beforeAll ( ( )  =>  { 
85+   const  testName  =  "heartbeatTimer" 
86+   let  testDir  =  "" 
87+   beforeAll ( async  ( )  =>  { 
88+     await  clean ( testName ) 
89+     testDir  =  await  tmpdir ( testName ) 
9790    mockLogger ( ) 
9891  } ) 
9992  afterAll ( ( )  =>  { 
10093    jest . restoreAllMocks ( ) 
10194  } ) 
95+   beforeEach ( ( )  =>  { 
96+     jest . useFakeTimers ( ) 
97+   } ) 
10298  afterEach ( ( )  =>  { 
10399    jest . resetAllMocks ( ) 
100+     jest . clearAllTimers ( ) 
101+     jest . useRealTimers ( ) 
104102  } ) 
105-   it ( "should call beat  when isActive resolves to true " ,  async  ( )  =>  { 
103+   it ( "should call isActive  when timeout expires " ,  async  ( )  =>  { 
106104    const  isActive  =  true 
107105    const  mockIsActive  =  jest . fn ( ) . mockResolvedValue ( isActive ) 
108-     const  mockBeatFn  =  jest . fn ( ) 
109-     await  heartbeatTimer ( mockIsActive ,  mockBeatFn ) 
106+     const  heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  mockIsActive ) 
107+     await  heart . beat ( ) 
108+     jest . advanceTimersByTime ( 60  *  1000 ) 
110109    expect ( mockIsActive ) . toHaveBeenCalled ( ) 
111-     expect ( mockBeatFn ) . toHaveBeenCalled ( ) 
112110  } ) 
113111  it ( "should log a warning when isActive rejects" ,  async  ( )  =>  { 
114112    const  errorMsg  =  "oh no" 
115113    const  error  =  new  Error ( errorMsg ) 
116114    const  mockIsActive  =  jest . fn ( ) . mockRejectedValue ( error ) 
117-     const  mockBeatFn  =  jest . fn ( ) 
118-     await  heartbeatTimer ( mockIsActive ,  mockBeatFn ) 
115+     const  heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  mockIsActive ) 
116+     await  heart . beat ( ) 
117+     jest . advanceTimersByTime ( 60  *  1000 ) 
118+ 
119119    expect ( mockIsActive ) . toHaveBeenCalled ( ) 
120-     expect ( mockBeatFn ) . not . toHaveBeenCalled ( ) 
121120    expect ( logger . warn ) . toHaveBeenCalledWith ( errorMsg ) 
122121  } ) 
123122} ) 
124123
125- describe ( "idleTimeout " ,  ( )  =>  { 
126-   const  testName  =  "idleHeartTests " 
124+ describe ( "stateChange " ,  ( )  =>  { 
125+   const  testName  =  "stateChange " 
127126  let  testDir  =  "" 
128127  let  heart : Heart 
129128  beforeAll ( async  ( )  =>  { 
@@ -140,12 +139,23 @@ describe("idleTimeout", () => {
140139      heart . dispose ( ) 
141140    } 
142141  } ) 
143-   it ( "should call beat when isActive resolves to true" ,  async  ( )  =>  { 
142+   it ( "should change to alive after a beat" ,  async  ( )  =>  { 
143+     heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  mockIsActive ( true ) ) 
144+     const  mockOnChange  =  jest . fn ( ) 
145+     heart . onChange ( mockOnChange ) 
146+     await  heart . beat ( ) 
147+ 
148+     expect ( mockOnChange . mock . calls [ 0 ] [ 0 ] ) . toBe ( "alive" ) 
149+   } ) 
150+   it . only ( "should change to idle when not active" ,  async  ( )  =>  { 
144151    jest . useFakeTimers ( ) 
145-     heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  60 ,  mockIsActive ( true ) ) 
152+     heart  =  new  Heart ( `${ testDir }  /shutdown.txt` ,  ( )  =>  new  Promise ( ( resolve )  =>  resolve ( false ) ) ) 
153+     const  mockOnChange  =  jest . fn ( ) 
154+     heart . onChange ( mockOnChange ) 
155+     await  heart . beat ( ) 
146156
147-     jest . advanceTimersByTime ( 60  *  1000 ) 
148-     expect ( wrapper . exit ) . toHaveBeenCalled ( ) 
157+     await   jest . advanceTimersByTime ( 60  *  1000 ) 
158+     expect ( mockOnChange . mock . calls [ 1 ] [ 0 ] ) . toBe ( "idle" ) 
149159    jest . clearAllTimers ( ) 
150160    jest . useRealTimers ( ) 
151161  } ) 
0 commit comments