From e5a34ff03f1f56f63f7b5a0b8799b01fc10acab4 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Tue, 3 Sep 2024 21:28:10 +0200 Subject: [PATCH] fix: issue with roll evaluating multiple days --- .../src/services/__tests__/rollUtils.mock.ts | 553 ++++++++++++++++++ .../src/services/__tests__/rollUtils.test.ts | 22 +- apps/server/src/services/rollUtils.ts | 14 - 3 files changed, 573 insertions(+), 16 deletions(-) create mode 100644 apps/server/src/services/__tests__/rollUtils.mock.ts diff --git a/apps/server/src/services/__tests__/rollUtils.mock.ts b/apps/server/src/services/__tests__/rollUtils.mock.ts new file mode 100644 index 000000000..1d6b4b5c1 --- /dev/null +++ b/apps/server/src/services/__tests__/rollUtils.mock.ts @@ -0,0 +1,553 @@ +import { EndAction, OntimeRundown, SupportedEvent, TimerType, TimeStrategy } from 'ontime-types'; + +export const testKendal: OntimeRundown = [ + { + title: 'PREP', + type: SupportedEvent.Block, + id: 'a699d5', + }, + { + id: '81a7ba', + type: SupportedEvent.Event, + title: 'PREP', + timeStart: 33000000, + timeEnd: 36000000, + duration: 3000000, + timeStrategy: TimeStrategy.LockEnd, + linkStart: null, + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#9d9d9d', + cue: 'SF1.01', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: { + notes: 'Ari to lead', + key: 'A', + }, + delay: 0, + }, + { + id: 'fe131f', + type: SupportedEvent.Event, + title: 'RIG', + timeStart: 36000000, + timeEnd: 39600000, + duration: 3600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '81a7ba', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: 'this one has a note\nwhich is multiline\nalright', + colour: '#FFCC78', + cue: 'SF1.02', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: { + notes: 'Ari to lead', + key: 'A', + }, + delay: 0, + }, + { + id: 'eee750', + type: SupportedEvent.Event, + title: 'SYSTEMS CHECK', + timeStart: 39600000, + timeEnd: 43200000, + duration: 3600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'fe131f', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FFAB33', + cue: 'SF1.03', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + title: 'ON AIR', + type: SupportedEvent.Block, + id: 'b58839', + }, + { + id: '838a83', + type: SupportedEvent.Event, + title: 'ON AIR - TITLES', + timeStart: 43200000, + timeEnd: 45000000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'eee750', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.04', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'c6fe38', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 45000000, + timeEnd: 46800000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '838a83', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.05', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '239149', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 46800000, + timeEnd: 48300000, + duration: 1500000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'c6fe38', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.06', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '973e31', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 48300000, + timeEnd: 50100000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '239149', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.07', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '04de07', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 50100000, + timeEnd: 51300000, + duration: 1200000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '973e31', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.08', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'b13d25', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 51300000, + timeEnd: 53100000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '04de07', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.09', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'f9998b', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 53100000, + timeEnd: 54300000, + duration: 1200000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'b13d25', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.10', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '60557e', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 54300000, + timeEnd: 56100000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'f9998b', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.11', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'af5fb7', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 56100000, + timeEnd: 57900000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '60557e', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.12', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'e03705', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 57900000, + timeEnd: 59100000, + duration: 1200000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'af5fb7', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.13', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '2e99c4', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 59100000, + timeEnd: 60900000, + duration: 1800000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'e03705', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.14', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '5e4312', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 60900000, + timeEnd: 62100000, + duration: 1200000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '2e99c4', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.15', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'a28751', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 62100000, + timeEnd: 64200000, + duration: 2100000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '5e4312', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.16', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '204a86', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 64200000, + timeEnd: 65700000, + duration: 1500000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'a28751', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.17', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'a85f50', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 65700000, + timeEnd: 67800000, + duration: 2100000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '204a86', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.18', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '3b5ccf', + type: SupportedEvent.Event, + title: 'ARTIST NAME', + timeStart: 67800000, + timeEnd: 71400000, + duration: 3600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'a85f50', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.18', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'f9af23', + type: SupportedEvent.Event, + title: 'CHANGE OVER', + timeStart: 71400000, + timeEnd: 73500000, + duration: 2100000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: '3b5ccf', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#77C785', + cue: 'SF1.19', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'a6ef47', + type: SupportedEvent.Event, + title: 'ARTIST NAME LAST', + timeStart: 75600000, + timeEnd: 81000000, + duration: 5400000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: null, + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#FF7878', + cue: 'SF1.20', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + title: 'OFF AIR', + type: SupportedEvent.Block, + id: '72e18d', + }, + { + id: 'c0ffe0', + type: SupportedEvent.Event, + title: 'SUPER DERIG - NO ONE GOES HOME', + timeStart: 81000000, + timeEnd: 1800000, + duration: 7200000, + timeStrategy: TimeStrategy.LockEnd, + linkStart: 'a6ef47', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '', + cue: 'SF1.21', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: '14b94b', + type: SupportedEvent.Event, + title: 'DRINKS!', + timeStart: 1800000, + timeEnd: 2400000, + duration: 600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: 'c0ffe0', + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '#779BE7', + cue: 'SF1.22', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, + { + id: 'ca327f', + type: SupportedEvent.Event, + title: '', + timeStart: 36000000, + timeEnd: 36600000, + duration: 600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: null, + endAction: EndAction.None, + timerType: TimerType.CountDown, + isPublic: true, + skip: false, + note: '', + colour: '', + cue: 'SF1.23', + revision: 3, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + delay: 0, + }, +]; diff --git a/apps/server/src/services/__tests__/rollUtils.test.ts b/apps/server/src/services/__tests__/rollUtils.test.ts index 9612fe481..656f3cdae 100644 --- a/apps/server/src/services/__tests__/rollUtils.test.ts +++ b/apps/server/src/services/__tests__/rollUtils.test.ts @@ -1,7 +1,8 @@ -import { OntimeEvent, SupportedEvent } from 'ontime-types'; +import { isOntimeEvent, OntimeEvent, SupportedEvent } from 'ontime-types'; import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from 'ontime-utils'; import { loadRoll } from '../rollUtils.js'; +import { testKendal } from './rollUtils.mock.js'; const baseEvent = { type: SupportedEvent.Event, @@ -246,6 +247,22 @@ describe('loadRoll() handle edge cases with midnight', () => { }); }); +describe('loadRoll() handle rundowns with several days', () => { + it('should find the correct event, when we have many days', () => { + const now = 21 * MILLIS_PER_HOUR + 51 * MILLIS_PER_MINUTE; + const timedEvents: OntimeEvent[] = testKendal.filter((event) => isOntimeEvent(event)); + + const state = loadRoll(timedEvents, now); + const expected = { + event: timedEvents[20], + index: 20, + }; + expect(state.event?.title).toBe('ARTIST NAME LAST'); + expect(state.event?.cue).toBe('SF1.20'); + expect(state).toStrictEqual(expected); + }); +}); + describe('loadRoll() handle edge cases with before and after start', () => { it('should prepare first event, if we are not yet in the rundown start', () => { const now = 7 * MILLIS_PER_HOUR; @@ -302,7 +319,7 @@ describe('loadRoll() handle edge cases with before and after start', () => { index: 0, }; const state = loadRoll(singleEventList, now); - expect(state.isPending).toBeUndefined(); + expect(state.isPending).toBeUndefined(); // we are playing the event expect(state).toStrictEqual(expected); }); @@ -443,6 +460,7 @@ describe('loadRoll() test that roll behaviour multi day event edge cases', () => }; const state = loadRoll(eventlist, now); + expect(state.isPending).toBeUndefined(); // we are playing the event expect(state).toStrictEqual(expected); }); }); diff --git a/apps/server/src/services/rollUtils.ts b/apps/server/src/services/rollUtils.ts index 862753c13..0999b866c 100644 --- a/apps/server/src/services/rollUtils.ts +++ b/apps/server/src/services/rollUtils.ts @@ -21,20 +21,6 @@ export function loadRoll( return { event: null, index: null }; } - // check that the rundown wraps around midnight - const wrapsAroundMidnight = firstEvent.timeStart > lastEvent.timeEnd; - - if (!wrapsAroundMidnight) { - // check whether we are before or after the rundown - const lastNormalEnd = normaliseEndTime(lastEvent.timeStart, lastEvent.timeEnd); - const isAfterRundown = timeNow > lastNormalEnd; - const isBeforeRundown = timeNow < firstEvent.timeStart && !isAfterRundown; - - if (isAfterRundown || isBeforeRundown) { - return { event: firstEvent, index: 0, isPending: true }; - } - } - // we know we are in the middle of the rundown and we need to find the current event // account for number of times we went over midnight let daySpan = 0;