Files
Bram 91f22b54b4
Build and Push Docker Images / build-and-push (push) Successful in 36s
xtream bundler
2026-11-06 19:24:39 +01:00

121 lines
4.5 KiB
JavaScript

'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']);
});