This commit is contained in:
1 parent
d7aea0be65
commit
91f22b54b4
30 files changed
+2475
No files matched your search
@@ -0,0 +1,120 @@
|
||||
'use strict';
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { createState, reconcile, summarize } = require('../src/scheduler');
|
||||
|
||||
const options = { maxChannels: 3, startGraceMs: 24 * 60 * 60 * 1000 };
|
||||
|
||||
function makeEvent(id, startIso, endIso) {
|
||||
return {
|
||||
key: id,
|
||||
title: id,
|
||||
league: 'Jupiler Pro League',
|
||||
language: 'nl',
|
||||
startAt: new Date(startIso),
|
||||
endAt: new Date(endIso),
|
||||
sources: [{ streamId: id, name: id, candidates: [`http://upstream/${id}.ts`] }],
|
||||
missingCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function current(...events) {
|
||||
return new Map(events.map((event) => [event.key, event]));
|
||||
}
|
||||
|
||||
function slotKeys(state) {
|
||||
return state.slots.map((slot) => slot.eventKey);
|
||||
}
|
||||
|
||||
test('fills the first three slots by start time and queues the rest', () => {
|
||||
const state = createState(3);
|
||||
const events = current(
|
||||
makeEvent('A', '2026-11-06T16:00:00Z', '2026-11-06T20:00:00Z'),
|
||||
makeEvent('B', '2026-11-06T16:30:00Z', '2026-11-06T20:30:00Z'),
|
||||
makeEvent('C', '2026-11-06T17:00:00Z', '2026-11-06T21:00:00Z'),
|
||||
makeEvent('D', '2026-11-06T17:30:00Z', '2026-11-06T21:30:00Z'),
|
||||
makeEvent('E', '2026-11-06T18:00:00Z', '2026-11-06T22:00:00Z')
|
||||
);
|
||||
|
||||
reconcile(state, events, Date.parse('2026-11-06T18:00:00Z'), options);
|
||||
|
||||
assert.deepEqual(slotKeys(state), ['A', 'B', 'C']);
|
||||
const summary = summarize(state);
|
||||
assert.deepEqual(summary.queue.map((event) => event.key), ['D', 'E']);
|
||||
});
|
||||
|
||||
test('a freed slot is filled by the oldest waiting event', () => {
|
||||
const state = createState(3);
|
||||
const events = current(
|
||||
makeEvent('A', '2026-11-06T16:00:00Z', '2026-11-06T20:00:00Z'),
|
||||
makeEvent('B', '2026-11-06T16:30:00Z', '2026-11-06T20:30:00Z'),
|
||||
makeEvent('C', '2026-11-06T17:00:00Z', '2026-11-06T21:00:00Z'),
|
||||
makeEvent('D', '2026-11-06T17:30:00Z', '2026-11-06T21:30:00Z'),
|
||||
makeEvent('E', '2026-11-06T18:00:00Z', '2026-11-06T22:00:00Z')
|
||||
);
|
||||
|
||||
reconcile(state, events, Date.parse('2026-11-06T18:00:00Z'), options);
|
||||
assert.deepEqual(slotKeys(state), ['A', 'B', 'C']);
|
||||
|
||||
reconcile(state, events, Date.parse('2026-11-06T20:01:00Z'), options);
|
||||
assert.deepEqual(slotKeys(state), ['D', 'B', 'C']);
|
||||
});
|
||||
|
||||
test('an existing assignment is not preempted by an earlier event', () => {
|
||||
const state = createState(3);
|
||||
const events = current(
|
||||
makeEvent('A', '2026-11-06T16:00:00Z', '2026-11-06T20:00:00Z'),
|
||||
makeEvent('B', '2026-11-06T16:30:00Z', '2026-11-06T20:30:00Z'),
|
||||
makeEvent('C', '2026-11-06T17:00:00Z', '2026-11-06T21:00:00Z')
|
||||
);
|
||||
reconcile(state, events, Date.parse('2026-11-06T18:00:00Z'), options);
|
||||
|
||||
const withEarlier = current(
|
||||
...events.values(),
|
||||
makeEvent('X', '2026-11-06T17:45:00Z', '2026-11-06T21:45:00Z')
|
||||
);
|
||||
reconcile(state, withEarlier, Date.parse('2026-11-06T18:10:00Z'), options);
|
||||
|
||||
assert.deepEqual(slotKeys(state), ['A', 'B', 'C']);
|
||||
});
|
||||
|
||||
test('an assigned event keeps its slot until its end even when it disappears', () => {
|
||||
const state = createState(3);
|
||||
const a = makeEvent('A', '2026-11-06T16:00:00Z', '2026-11-06T20:00:00Z');
|
||||
const b = makeEvent('B', '2026-11-06T16:30:00Z', '2026-11-06T20:30:00Z');
|
||||
reconcile(state, current(a, b), Date.parse('2026-11-06T18:00:00Z'), options);
|
||||
assert.deepEqual(slotKeys(state), ['A', 'B', null]);
|
||||
|
||||
reconcile(state, current(), Date.parse('2026-11-06T19:00:00Z'), options);
|
||||
reconcile(state, current(), Date.parse('2026-11-06T19:30:00Z'), options);
|
||||
assert.deepEqual(slotKeys(state), ['A', 'B', null]);
|
||||
|
||||
reconcile(state, current(), Date.parse('2026-11-06T20:31:00Z'), options);
|
||||
assert.deepEqual(slotKeys(state), [null, null, null]);
|
||||
});
|
||||
|
||||
test('an unassigned event that disappears twice is dropped from the queue', () => {
|
||||
const state = createState(3);
|
||||
const events = current(
|
||||
makeEvent('A', '2026-11-06T16:00:00Z', '2026-11-06T20:00:00Z'),
|
||||
makeEvent('B', '2026-11-06T16:30:00Z', '2026-11-06T20:30:00Z'),
|
||||
makeEvent('C', '2026-11-06T17:00:00Z', '2026-11-06T21:00:00Z'),
|
||||
makeEvent('D', '2026-11-06T17:30:00Z', '2026-11-06T21:30:00Z'),
|
||||
makeEvent('E', '2026-11-06T18:00:00Z', '2026-11-06T22:00:00Z')
|
||||
);
|
||||
|
||||
reconcile(state, events, Date.parse('2026-11-06T18:00:00Z'), options);
|
||||
const withoutD = current(
|
||||
events.get('A'),
|
||||
events.get('B'),
|
||||
events.get('C'),
|
||||
events.get('E')
|
||||
);
|
||||
|
||||
reconcile(state, withoutD, Date.parse('2026-11-06T18:20:00Z'), options);
|
||||
reconcile(state, withoutD, Date.parse('2026-11-06T18:40:00Z'), options);
|
||||
reconcile(state, withoutD, Date.parse('2026-11-06T20:01:00Z'), options);
|
||||
|
||||
assert.deepEqual(slotKeys(state), ['E', 'B', 'C']);
|
||||
});
|
||||
Reference in new issue
Block a user