Skip to content

Commit b020cae

Browse files
committed
refactor(daemon): address monitoring layer nitpicks
- restore processExitSpy after each test to prevent spy leakage - add Severity.MAJOR assertions to alert tests - replace repeated choose+sendTo blocks with makeMonitoringSender factory
1 parent 7044b7a commit b020cae

File tree

2 files changed

+17
-49
lines changed

2 files changed

+17
-49
lines changed

packages/daemon/__tests__/actors/MonitoringActor.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import MonitoringActor from '../../src/actors/MonitoringActor';
99
import logger from '../../src/logger';
1010
import { EventTypes } from '../../src/types/event';
1111
import getConfig from '../../src/config';
12-
import { addAlert } from '@wallet-service/common';
12+
import { addAlert, Severity } from '@wallet-service/common';
1313

1414
const MONITORING_IDLE_TIMEOUT_EVENT = { type: EventTypes.MONITORING_IDLE_TIMEOUT };
1515

@@ -56,6 +56,10 @@ describe('MonitoringActor', () => {
5656
});
5757
});
5858

59+
afterEach(() => {
60+
processExitSpy.mockRestore();
61+
});
62+
5963
afterAll(() => {
6064
jest.clearAllMocks();
6165
jest.useRealTimers();
@@ -98,6 +102,7 @@ describe('MonitoringActor', () => {
98102

99103
expect(mockAddAlert).toHaveBeenCalledTimes(1);
100104
expect(mockAddAlert.mock.calls[0][0]).toBe('Daemon Idle — No Events Received');
105+
expect(mockAddAlert.mock.calls[0][2]).toBe(Severity.MAJOR);
101106
expect(mockCallback).toHaveBeenCalledWith(MONITORING_IDLE_TIMEOUT_EVENT);
102107
expect(processExitSpy).not.toHaveBeenCalled();
103108
});
@@ -188,6 +193,7 @@ describe('MonitoringActor', () => {
188193

189194
expect(mockAddAlert).toHaveBeenCalledTimes(1);
190195
expect(mockAddAlert.mock.calls[0][0]).toBe('Daemon Stuck In Processing State');
196+
expect(mockAddAlert.mock.calls[0][2]).toBe(Severity.MAJOR);
191197
// Stuck detection intentionally does not notify the machine — machine keeps running
192198
expect(mockCallback).not.toHaveBeenCalled();
193199
});
@@ -243,6 +249,7 @@ describe('MonitoringActor', () => {
243249
await Promise.resolve();
244250
expect(mockAddAlert).toHaveBeenCalledTimes(1);
245251
expect(mockAddAlert.mock.calls[0][0]).toBe('Daemon Reconnection Storm');
252+
expect(mockAddAlert.mock.calls[0][2]).toBe(Severity.MAJOR);
246253
});
247254

248255
it('should NOT fire a reconnection storm alert below the threshold', async () => {

packages/daemon/src/actions/index.ts

Lines changed: 9 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { assign, AssignAction, sendTo, choose } from 'xstate';
9-
import { Context, Event, EventTypes, StandardFullNodeEvent } from '../types';
9+
import { Context, Event, EventTypes, MonitoringEvent, StandardFullNodeEvent } from '../types';
1010
import { get } from 'lodash';
1111
import logger from '../logger';
1212
import { hashTxData } from '../utils';
@@ -211,53 +211,14 @@ export const getMonitoringRefFromContext = (context: Context) => {
211211

212212
const monitoringIsPresent = (context: Context) => context.monitoring !== null;
213213

214-
/*
215-
* Notifies the monitoring actor that the WebSocket became connected.
216-
*/
217-
export const sendMonitoringConnected = choose([{
218-
cond: monitoringIsPresent,
219-
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: 'CONNECTED' } }),
220-
}]);
221-
222-
/*
223-
* Notifies the monitoring actor that the WebSocket disconnected.
224-
*/
225-
export const sendMonitoringDisconnected = choose([{
226-
cond: monitoringIsPresent,
227-
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: 'DISCONNECTED' } }),
228-
}]);
229-
230-
/*
231-
* Notifies the monitoring actor that a fullnode event was received (resets the idle timer).
232-
*/
233-
export const sendMonitoringEventReceived = choose([{
234-
cond: monitoringIsPresent,
235-
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: 'EVENT_RECEIVED' } }),
236-
}]);
237-
238-
/*
239-
* Notifies the monitoring actor that the machine is entering the RECONNECTING state.
240-
*/
241-
export const sendMonitoringReconnecting = choose([{
214+
const makeMonitoringSender = (eventType: MonitoringEvent['type']) => choose([{
242215
cond: monitoringIsPresent,
243-
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: 'RECONNECTING' } }),
216+
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: eventType } }),
244217
}]);
245218

246-
/*
247-
* Notifies the monitoring actor that a processing state was entered.
248-
* The actor starts a stuck-detection timer; if PROCESSING_COMPLETED doesn't
249-
* arrive within STUCK_PROCESSING_TIMEOUT_MS it fires a MAJOR alert.
250-
*/
251-
export const sendMonitoringProcessingStarted = choose([{
252-
cond: monitoringIsPresent,
253-
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: 'PROCESSING_STARTED' } }),
254-
}]);
255-
256-
/*
257-
* Notifies the monitoring actor that a processing state was exited normally,
258-
* cancelling the stuck-detection timer.
259-
*/
260-
export const sendMonitoringProcessingCompleted = choose([{
261-
cond: monitoringIsPresent,
262-
actions: sendTo(getMonitoringRefFromContext, { type: EventTypes.MONITORING_EVENT, event: { type: 'PROCESSING_COMPLETED' } }),
263-
}]);
219+
export const sendMonitoringConnected = makeMonitoringSender('CONNECTED');
220+
export const sendMonitoringDisconnected = makeMonitoringSender('DISCONNECTED');
221+
export const sendMonitoringEventReceived = makeMonitoringSender('EVENT_RECEIVED');
222+
export const sendMonitoringReconnecting = makeMonitoringSender('RECONNECTING');
223+
export const sendMonitoringProcessingStarted = makeMonitoringSender('PROCESSING_STARTED');
224+
export const sendMonitoringProcessingCompleted = makeMonitoringSender('PROCESSING_COMPLETED');

0 commit comments

Comments
 (0)