Repository: hashgraph/hedera-local-node (ts)

Issue:
Improve the onStart function of the AttachState
### Problem

The onStart function of the AttachState has a while loop, which contains a big timeout of 10 seconds. This makes unit testing very slow

### Solution

Move the while loop to a separate function, so it can be stubbed in the tests

### Alternatives

_No response_

Pull request:
fix: Moves while loop to a function and stub it in the unit tests for AttаchState
**Description**:
<!--
One or two line summary of what this PR does and why it is needed, followed by a list
of changes in imperative, present tense for use in the commit message or changelog. Example:

This PR modifies ... in order to support ...
* Add config property
* Change column name
* Remove ...
-->
This PR changes the onStart method in the AttachState class.
So far we had a while loop in the onStart, which was updating the statusBoard. This made testing slow and not efficient.
The while was moved to a separate function, which can be stubbed, therefore supporting better testing
**Related issue(s)**:

Fixes #538 


**Checklist**

- [x] Tested (unit, integration, etc.)


Patch:
diff --git a/src/state/AttachState.ts b/src/state/AttachState.ts
index 0d2890d..62beb92 100644
--- a/src/state/AttachState.ts
+++ b/src/state/AttachState.ts
@@ -48,6 +48,11 @@ export class AttachState implements IState{
      * The name of the state.
      */
     private stateName: string;
+
+    /**
+     * Timeout for updateStatusBoard
+     */
+    private timeOut: number = 10000;
     
     /**
      * Represents the AttachState class.
@@ -87,11 +92,7 @@ export class AttachState implements IState{
         await this.attachContainerLogs(MIRROR_NODE_LABEL);
         await this.attachContainerLogs(RELAY_LABEL);
 
-        let i = 0;
-        while (i++ < this.loopIterations()) {
-          await this.logger.updateStatusBoard();
-          await new Promise((resolve) => setTimeout(resolve, 10000));
-        }
+        await this.continuouslyUpdateStatusBoard();
     }
 
     /**
@@ -134,6 +135,14 @@ export class AttachState implements IState{
         );
     }
 
+    private async continuouslyUpdateStatusBoard(): Promise<void> {
+      let i = 0;
+      while (i++ < this.loopIterations()) {
+        await this.logger.updateStatusBoard();
+        await new Promise((resolve) => setTimeout(resolve, this.timeOut));
+      }
+    }
+
     private loopIterations(): number {
       return Number.MAX_VALUE;
     }


Test patch:
diff --git a/test/unit/states/AttachState.spec.ts b/test/unit/states/AttachState.spec.ts
index 4fccd73..7999722 100644
--- a/test/unit/states/AttachState.spec.ts
+++ b/test/unit/states/AttachState.spec.ts
@@ -1,5 +1,5 @@
 import { expect } from 'chai';
-import sinon, { SinonSandbox, SinonStubbedInstance } from 'sinon';
+import sinon, { SinonSandbox, SinonStub, SinonStubbedInstance } from 'sinon';
 import { AttachState } from '../../../src/state/AttachState';
 import { IOBserver } from '../../../src/controller/IObserver';
 import { CLIService } from '../../../src/services/CLIService';
@@ -10,25 +10,28 @@ import { getTestBed } from '../testBed';
 
 describe('AttachState', () => {
   let attachState: AttachState,
-      loggerService: SinonStubbedInstance<LoggerService>,
       dockerService: SinonStubbedInstance<DockerService>,
       cliService: SinonStubbedInstance<CLIService>,
-      testSandbox: SinonSandbox;
+      testSandbox: SinonSandbox,
+      loggerService: SinonStubbedInstance<LoggerService>,
+      continuouslyUpdateStatusBoardStub: SinonStub;
 
   before(() => {
     const {
         sandbox,
-        loggerServiceStub,
         dockerServiceStub,
-        cliServiceStub
+        cliServiceStub,
+        loggerServiceStub
     } = getTestBed({
         workDir: 'testDir',
     });
 
     dockerService = dockerServiceStub
-    loggerService = loggerServiceStub
     cliService = cliServiceStub
     testSandbox = sandbox
+    loggerService = loggerServiceStub
+
+    continuouslyUpdateStatusBoardStub = testSandbox.stub(AttachState.prototype, <any>'continuouslyUpdateStatusBoard');
 
     // Create an instance of AttachState
     attachState = new AttachState();
@@ -58,22 +61,18 @@ describe('AttachState', () => {
         detached: false
       } as any);
       const attachContainerLogsStub = testSandbox.stub(AttachState.prototype, <any>'attachContainerLogs');
-      const iterations = testSandbox.stub(AttachState.prototype, <any>'loopIterations');
-      iterations.returns(2);
-
       await attachState.onStart();
 
       expect(attachContainerLogsStub.calledThrice).to.be.true;
       expect(attachContainerLogsStub.firstCall.calledWithExactly("network-node")).to.be.true;
       expect(attachContainerLogsStub.secondCall.calledWithExactly("mirror-node-rest")).to.be.true;
       expect(attachContainerLogsStub.thirdCall.calledWithExactly("json-rpc-relay")).to.be.true;
-      testSandbox.assert.calledTwice(loggerService.updateStatusBoard);
+      testSandbox.assert.called(continuouslyUpdateStatusBoardStub);
 
       attachContainerLogsStub.restore();
-      iterations.restore();
-    }).timeout(25000);
+    });
 
-    it('should not call attachContainerLogs when detached', async () => {
+    it('should call observer update attachContainerLogs when detached', async () => {
       (attachState as any).observer = { update: testSandbox.stub()};
       cliService.getCurrentArgv.returns({
         async: false,
@@ -84,15 +83,14 @@ describe('AttachState', () => {
         detached: true
       } as any);
       const attachContainerLogsStub = testSandbox.stub(AttachState.prototype, <any>'attachContainerLogs');
-      const iterations = testSandbox.stub(AttachState.prototype, <any>'loopIterations');
-      iterations.returns(2);
 
       await attachState.onStart();
 
+      testSandbox.assert.called(continuouslyUpdateStatusBoardStub);
       testSandbox.assert.calledOnceWithExactly(attachState.observer?.update, EventType.Finish);
+
       attachContainerLogsStub.restore();
-      iterations.restore();
-    }).timeout(25000);
+    });
   });
 
   describe('attachContainerLogs', () => {
@@ -112,8 +110,6 @@ describe('AttachState', () => {
         modem: { demuxStream: demuxSpy },
       } as any);
       const attachContainerLogsStub = testSandbox.stub(AttachState.prototype, <any>'attachContainerLogs');
-      const iterations = testSandbox.stub(AttachState.prototype, <any>'loopIterations');
-      iterations.returns(2);
       attachContainerLogsStub.withArgs("mirror-node-rest").resolves();
       attachContainerLogsStub.withArgs("json-rpc-relay").resolves();
       attachContainerLogsStub.callThrough();
@@ -122,9 +118,37 @@ describe('AttachState', () => {
 
       testSandbox.assert.calledOnce(dockerService.getContainer);
       const spy1 = dockerService.getContainer.getCall(0);
-
+      testSandbox.assert.called(continuouslyUpdateStatusBoardStub);
       testSandbox.assert.calledWithExactly(spy1, "network-node");
       testSandbox.assert.calledOnce(logsSpy);
-    }).timeout(25000);
+
+      continuouslyUpdateStatusBoardStub.restore();
+      attachContainerLogsStub.restore();
+    });
+  });
+
+  describe('continuouslyUpdateStatusBoard', () => {
+    it('should updateStatusBoard every 2 seconds', async () => {
+      continuouslyUpdateStatusBoardStub.restore();
+      const continuouslyUpdateStatusBoardSpy = testSandbox.spy(AttachState.prototype, <any>'continuouslyUpdateStatusBoard');
+      cliService.getCurrentArgv.returns({
+        async: false,
+        blocklisting: false,
+        balance: 1000,
+        accounts: 10,
+        startup: false,
+        detached: false
+      } as any);
+      const attachContainerLogsStub = testSandbox.stub(AttachState.prototype, <any>'attachContainerLogs');
+      (attachState as any).timeOut = 2;
+      const iterations = testSandbox.stub(AttachState.prototype, <any>'loopIterations');
+      iterations.returns(2);
+
+      await attachState.onStart();
+
+      testSandbox.assert.called(continuouslyUpdateStatusBoardSpy);
+      testSandbox.assert.calledTwice(loggerService.updateStatusBoard);
+      testSandbox.assert.calledThrice(attachContainerLogsStub);
+    });
   });
 });