Files
2026-10-29 11:57:29 +01:00

173 lines
6.3 KiB
JavaScript

// Generated, do not edit. sha256:a27e8c58c9aae75ab07e5381309139cb5309819db52788dbf42ff055ad51599e
import { describe, it, beforeEach, mock } from 'node:test';
import assert from 'node:assert/strict';
import { createDbHarness } from '../helpers/db-node.mjs';
const harness = createDbHarness();
mock.module('../../server/db.js', { namedExports: harness.exports });
const { flushChanges, changesSince, pruneChanges } = await import('../../server/data/bus.js');
const { emitChange } = await import('../../server/data/_events.js');
const { CONFIG } = await import('../../shared/config.js');
const rijen = () => harness.exports.all(`SELECT id, name, occurredAt FROM BusSignal ORDER BY id`);
const oudeRij = (naam, urenGeleden) => harness.exports.run(
`INSERT INTO BusSignal (name, occurredAt) VALUES (?,?)`,
[naam, new Date(Date.now() - urenGeleden * 3600_000).toISOString()]);
beforeEach(() => {
harness.recreate();
flushChanges();
});
describe('bus: het mandje wegschrijven', () => {
it('schrijft elke naam uit het mandje naar de tabel', async () => {
emitChange('providers-changed');
emitChange('connections-changed');
const namen = flushChanges();
assert.deepEqual(namen.sort(), ['connections-changed', 'providers-changed']);
assert.deepEqual(rijen().map(r => r.name).sort(), ['connections-changed', 'providers-changed']);
assert.ok(rijen()[0].occurredAt, 'en er staat een moment bij');
});
it('voegt hetzelfde signaal binnen één eenheid werk samen', async () => {
emitChange('providers-changed');
emitChange('providers-changed');
emitChange('providers-changed');
flushChanges();
assert.equal(rijen().length, 1);
});
it('maakt het mandje leeg, zodat een tweede flush niets dubbel schrijft', async () => {
emitChange('providers-changed');
flushChanges();
assert.deepEqual(flushChanges(), [], 'niets meer over');
assert.equal(rijen().length, 1);
});
it('doet niets bij een leeg mandje, en schrijft dus ook geen lege rij', async () => {
assert.deepEqual(flushChanges(), []);
assert.equal(rijen().length, 0);
});
it('GOOIT NOOIT WEG: twee opeenvolgende flushes bewaren allebei hun signaal', async () => {
emitChange('eerst-dit');
flushChanges();
emitChange('daarna-dit');
flushChanges();
assert.deepEqual(rijen().map(r => r.name), ['eerst-dit', 'daarna-dit'], 'allebei, op volgorde');
});
});
describe('bus: teruglezen sinds een cursor', () => {
it('geeft bij een nieuwe client alleen de stand en geen historie', async () => {
emitChange('oud-nieuws');
flushChanges();
const r = changesSince(null);
assert.deepEqual(r.names, []);
assert.equal(r.cursor, 1, 'wél de stand, zodat de volgende poll wél iets kan opleveren');
assert.equal(r.reset, false);
});
it('geeft alleen wat er ná de cursor bij kwam', async () => {
emitChange('eerste');
flushChanges();
const na1 = changesSince(null).cursor;
emitChange('tweede');
flushChanges();
const r = changesSince(na1);
assert.deepEqual(r.names, ['tweede']);
assert.equal(r.cursor, 2);
});
it('ontdubbelt de namen, want een prikkel is inhoudsloos', async () => {
emitChange('providers-changed');
flushChanges();
emitChange('providers-changed');
flushChanges();
assert.deepEqual(changesSince(0).names, ['providers-changed'], 'twee rijen, één naam');
});
it('geeft niets terug als er niets nieuws is, en houdt de cursor gelijk', async () => {
emitChange('iets');
flushChanges();
const r = changesSince(1);
assert.deepEqual(r.names, []);
assert.equal(r.cursor, 1);
});
it('zegt "ververs alles" als de cursor achterloopt op de oudste bewaarde rij', async () => {
for (const naam of ['een', 'twee', 'drie']) { emitChange(naam); flushChanges(); }
harness.exports.run(`DELETE FROM BusSignal WHERE id <= 2`);
const r = changesSince(0);
assert.equal(r.reset, true);
assert.deepEqual(r.names, [], 'en géén halve lijst erbij, die zou suggereren dat het daarbij blijft');
assert.equal(r.cursor, 3);
});
it('meldt geen reset als de cursor precies aansluit op de oudste rij', async () => {
for (const naam of ['een', 'twee', 'drie']) { emitChange(naam); flushChanges(); }
harness.exports.run(`DELETE FROM BusSignal WHERE id <= 2`);
const r = changesSince(2);
assert.equal(r.reset, false);
assert.deepEqual(r.names, ['drie']);
});
it('behandelt onzin als een nieuwe client in plaats van om te vallen', async () => {
emitChange('iets');
flushChanges();
for (const raar of ['onzin', -1, 1.5, undefined, {}]) {
const r = changesSince(raar);
assert.deepEqual(r.names, [], `${JSON.stringify(raar)} hoort als "ik begin nu" te lezen`);
assert.equal(r.reset, false);
}
});
it('geeft op een lege bus een cursor van nul en geen null', async () => {
const r = changesSince(null);
assert.deepEqual(r, { cursor: 0, names: [], reset: false });
});
});
describe('bus: opruimen', () => {
it('gooit weg wat ouder is dan de bewaartermijn en laat de rest staan', async () => {
oudeRij('van-gisteren', CONFIG.BUS.RETENTION_HOURS + 1);
oudeRij('van-net', 1);
assert.equal(pruneChanges(), 1, 'geeft terug hoeveel er weg zijn');
assert.deepEqual(rijen().map(r => r.name), ['van-net']);
});
it('laat een rij die binnen de termijn valt staan', async () => {
oudeRij('net-binnen', CONFIG.BUS.RETENTION_HOURS - 1);
assert.equal(pruneChanges(), 0);
assert.equal(rijen().length, 1);
});
it('doet niets op een lege bus', async () => {
assert.equal(pruneChanges(), 0);
});
it('valt terug op de SSOT-waarde bij onzin', async () => {
oudeRij('oud', CONFIG.BUS.RETENTION_HOURS + 2);
assert.equal(pruneChanges('onzin'), 1);
});
it('ruimt op tijdens het wegschrijven, zonder dat de aanroeper er iets voor doet', async () => {
oudeRij('van-gisteren', CONFIG.BUS.RETENTION_HOURS + 1);
emitChange('nieuw');
flushChanges();
assert.deepEqual(rijen().map(r => r.name), ['nieuw'], 'de oude rij is meegenomen');
});
it('ruimt bij élke schrijfactie op, ook de tweede', async () => {
emitChange('eerste');
flushChanges();
oudeRij('van-gisteren', CONFIG.BUS.RETENTION_HOURS + 1);
emitChange('tweede');
flushChanges();
assert.equal(rijen().some(r => r.name === 'van-gisteren'), false, 'ook nu meegenomen');
});
});