Skip to content

Commit f8cde5d

Browse files
committed
fix: restore process sets currentDay
1 parent 1b55254 commit f8cde5d

File tree

7 files changed

+141
-0
lines changed

7 files changed

+141
-0
lines changed

apps/server/src/services/restore-service/__tests__/restore.parser.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('isRestorePoint()', () => {
1313
pausedAt: 3,
1414
firstStart: 1,
1515
startEpoch: 1,
16+
currentDay: 0,
1617
};
1718
expect(isRestorePoint(restorePoint)).toBe(true);
1819

@@ -24,6 +25,21 @@ describe('isRestorePoint()', () => {
2425
pausedAt: null,
2526
firstStart: 1,
2627
startEpoch: 1,
28+
currentDay: 2,
29+
};
30+
expect(isRestorePoint(restorePoint)).toBe(true);
31+
});
32+
33+
it('accepts null start fields', () => {
34+
const restorePoint: RestorePoint = {
35+
playback: Playback.Stop,
36+
selectedEventId: null,
37+
startedAt: null,
38+
addedTime: 0,
39+
pausedAt: null,
40+
firstStart: null,
41+
startEpoch: null,
42+
currentDay: null,
2743
};
2844
expect(isRestorePoint(restorePoint)).toBe(true);
2945
});
@@ -63,5 +79,39 @@ describe('isRestorePoint()', () => {
6379
};
6480
expect(isRestorePoint(restorePoint)).toBe(false);
6581
});
82+
it('with missing firstStart', () => {
83+
const restorePoint = {
84+
playback: Playback.Roll,
85+
selectedEventId: '123',
86+
startedAt: null,
87+
addedTime: 0,
88+
pausedAt: null,
89+
startEpoch: 1,
90+
};
91+
expect(isRestorePoint(restorePoint)).toBe(false);
92+
});
93+
it('with missing startEpoch', () => {
94+
const restorePoint = {
95+
playback: Playback.Roll,
96+
selectedEventId: '123',
97+
startedAt: null,
98+
addedTime: 0,
99+
pausedAt: null,
100+
firstStart: 1,
101+
};
102+
expect(isRestorePoint(restorePoint)).toBe(false);
103+
});
104+
it('with missing currentDay', () => {
105+
const restorePoint = {
106+
playback: Playback.Roll,
107+
selectedEventId: '123',
108+
startedAt: null,
109+
addedTime: 0,
110+
pausedAt: null,
111+
firstStart: 1,
112+
startEpoch: 1,
113+
};
114+
expect(isRestorePoint(restorePoint)).toBe(false);
115+
});
66116
});
67117
});

apps/server/src/services/restore-service/__tests__/restore.service.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ describe('restoreService', () => {
1717
pausedAt: 9087,
1818
firstStart: 1234,
1919
startEpoch: 1234,
20+
currentDay: 0,
2021
};
2122

2223
const mockRead = vi.fn().mockResolvedValue(expected);
@@ -35,6 +36,7 @@ describe('restoreService', () => {
3536
pausedAt: null,
3637
firstStart: 1234,
3738
startEpoch: 1234,
39+
currentDay: null,
3840
};
3941

4042
const mockRead = vi.fn().mockResolvedValue(expected);
@@ -82,6 +84,7 @@ describe('restoreService', () => {
8284
pausedAt: 1234,
8385
firstStart: 1234,
8486
startEpoch: 1234,
87+
currentDay: 0,
8588
};
8689

8790
const mockWrite = vi.fn().mockResolvedValue(undefined);
@@ -90,6 +93,39 @@ describe('restoreService', () => {
9093
expect(mockWrite).toHaveBeenCalledWith(testData);
9194
});
9295

96+
it('writes updated data when values change', async () => {
97+
const firstData: RestorePoint = {
98+
playback: Playback.Play,
99+
selectedEventId: '2345',
100+
startedAt: 2345,
101+
addedTime: 2345,
102+
pausedAt: 2345,
103+
firstStart: 2345,
104+
startEpoch: 2345,
105+
currentDay: 0,
106+
};
107+
108+
const updatedData: RestorePoint = {
109+
playback: Playback.Pause,
110+
selectedEventId: '3456',
111+
startedAt: 3456,
112+
addedTime: 3456,
113+
pausedAt: 3456,
114+
firstStart: 3456,
115+
startEpoch: 3456,
116+
currentDay: 1,
117+
};
118+
119+
const mockWrite = vi.fn().mockResolvedValue(undefined);
120+
121+
await restoreService.save(firstData, mockWrite);
122+
await restoreService.save(updatedData, mockWrite);
123+
124+
expect(mockWrite).toHaveBeenCalledTimes(2);
125+
expect(mockWrite).toHaveBeenNthCalledWith(1, firstData);
126+
expect(mockWrite).toHaveBeenNthCalledWith(2, updatedData);
127+
});
128+
93129
it('handles write failures gracefully', async () => {
94130
const testData: RestorePoint = {
95131
playback: Playback.Pause,
@@ -99,6 +135,7 @@ describe('restoreService', () => {
99135
pausedAt: 5678,
100136
firstStart: 5678,
101137
startEpoch: 5678,
138+
currentDay: 0,
102139
};
103140

104141
const mockWrite = vi.fn().mockRejectedValue(new Error('Write failed'));

apps/server/src/services/restore-service/restore.parser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export function isRestorePoint(restorePoint: unknown): restorePoint is RestorePo
2121
'pausedAt',
2222
'firstStart',
2323
'startEpoch',
24+
'currentDay',
2425
])
2526
) {
2627
return false;
@@ -54,5 +55,9 @@ export function isRestorePoint(restorePoint: unknown): restorePoint is RestorePo
5455
return false;
5556
}
5657

58+
if (!is.number(restorePoint.currentDay) && restorePoint.currentDay !== null) {
59+
return false;
60+
}
61+
5762
return true;
5863
}

apps/server/src/services/restore-service/restore.type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export type RestorePoint = {
88
pausedAt: MaybeNumber;
99
firstStart: MaybeNumber;
1010
startEpoch: MaybeNumber;
11+
currentDay: MaybeNumber;
1112
};

apps/server/src/services/runtime-service/runtime.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,7 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
759759
pausedAt: state._timer.pausedAt,
760760
firstStart: state.rundown.actualStart,
761761
startEpoch: state._startEpoch,
762+
currentDay: state.rundown.currentDay,
762763
})
763764
.catch((_e) => {
764765
//we don't do anything with the error here

apps/server/src/stores/__tests__/runtimeState.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import {
1111
load,
1212
loadGroupFlagAndEnd,
1313
pause,
14+
resume,
1415
roll,
1516
start,
1617
stop,
18+
update,
1719
} from '../runtimeState.js';
1820
import { rundownCache } from '../../api-data/rundown/rundown.dao.js';
1921
import { RundownMetadata } from '../../api-data/rundown/rundown.types.js';
@@ -244,6 +246,44 @@ describe('mutation on runtimeState', () => {
244246
expect(newState.offset.absolute).toBe(0);
245247
expect(newState.offset.expectedRundownEnd).toBeNull();
246248
});
249+
250+
test('resume restores currentDay from restore point', async () => {
251+
clearState();
252+
const mockRundown = makeRundown({
253+
entries: {
254+
event1: { ...mockEvent, id: 'event1', timeStart: 0, timeEnd: 1000, duration: 1000, dayOffset: 0 },
255+
},
256+
order: ['event1'],
257+
});
258+
259+
const startEpoch = new Date('2024-01-01T00:00:00Z').getTime();
260+
vi.setSystemTime(new Date('2024-01-03T00:00:00Z'));
261+
262+
await initRundown(mockRundown, {});
263+
vi.runAllTimers();
264+
265+
const { rundown, metadata } = rundownCache.get();
266+
const restorePoint = {
267+
playback: Playback.Play,
268+
selectedEventId: 'event1',
269+
startedAt: 0,
270+
addedTime: 0,
271+
pausedAt: null,
272+
firstStart: 60 * 1000,
273+
startEpoch,
274+
currentDay: 2,
275+
};
276+
277+
resume(restorePoint, mockRundown.entries.event1 as PlayableEvent, rundown, metadata);
278+
279+
const newState = getState();
280+
expect(newState.rundown.actualStart).toBe(60 * 1000);
281+
expect(newState.rundown.currentDay).toBe(2);
282+
283+
vi.setSystemTime(new Date('2024-01-04T00:00:00Z'));
284+
update();
285+
expect(getState().rundown.currentDay).toBe(3);
286+
});
247287
});
248288

249289
describe('roll mode', () => {

apps/server/src/stores/runtimeState.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,19 @@ export function load(
246246
patchTimer(initialData);
247247
const startEpoch = initialData?.startEpoch;
248248
const firstStart = initialData?.firstStart;
249+
const currentDay = initialData?.currentDay;
249250
if (
250251
(firstStart === null || typeof firstStart === 'number') &&
251252
(startEpoch === null || typeof startEpoch === 'number')
252253
) {
253254
runtimeState.rundown.actualStart = firstStart;
254255
runtimeState._startEpoch = startEpoch;
256+
if (firstStart !== null && runtimeState.rundown.plannedStart !== null) {
257+
runtimeState._startDayOffset = findDayOffset(runtimeState.rundown.plannedStart, firstStart);
258+
}
259+
if (currentDay !== undefined) {
260+
runtimeState.rundown.currentDay = currentDay;
261+
}
255262
const { absolute, relative } = getRuntimeOffset(runtimeState);
256263
runtimeState.offset.absolute = absolute;
257264
runtimeState.offset.relative = relative;

0 commit comments

Comments
 (0)