Search / tests /test_reader_chapter_scheduler.js
vomebook
refactor: organize project layout and Reader responsibilities
2c1d035
Raw History Blame Contribute Delete
3.07 kB
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const vm = require("vm");
async function main() {
const sandbox = { DOMException, AbortController };
sandbox.self = sandbox;
vm.runInNewContext(fs.readFileSync(path.join(__dirname, "../static/reader/formats/reader-chapter-repository.js"), "utf8"), sandbox);
const starts = [], held = new Map();
const scheduler = sandbox.VoiceOfMLReaderChapters.createChapterScheduler({
create(index, signal, priority) {
starts.push({ index, signal, priority });
return new Promise(resolve => held.set(index, resolve));
}
});
const tick = () => new Promise(resolve => setImmediate(resolve));
scheduler.prefetch([1, 2, 3, 4, 5, 6]);
await tick();
assert.deepStrictEqual(starts.map(item => item.index), [1, 2]);
const foreground = scheduler.load(20);
await tick();
assert.deepStrictEqual(starts.map(item => item.index), [1, 2, 20]);
assert.strictEqual(starts[2].priority, "high");
assert.ok(starts[0].signal.aborted && starts[1].signal.aborted);
assert.strictEqual(scheduler.activeCount, 3, "cancelled creates retain ownership until settlement");
held.get(20)("target");
assert.strictEqual(await foreground, "target");
held.get(1)("late"); held.get(2)("late");
await tick();
assert.strictEqual(scheduler.activeCount, 0);
assert.strictEqual(scheduler.pendingCount, 0);
scheduler.prefetch([30, 31, 32]);
const promoted = scheduler.load(32);
assert.strictEqual(scheduler.load(32), promoted);
await tick();
assert.strictEqual(starts[3].index, 32, "queued demand overtakes speculation");
assert.deepStrictEqual(starts.slice(3).map(item => item.index), [32, 30, 31]);
assert.ok(starts.slice(3).every(item => !item.signal.aborted), "promotion retains current-window peers");
held.get(32)("promoted");
assert.strictEqual(await promoted, "promoted");
held.get(30)("neighbor"); held.get(31)("neighbor");
await tick();
const obsolete=scheduler.load(60);
const obsoleteRejected=assert.rejects(obsolete,error=>error.name==='AbortError');
await tick();
const latest=scheduler.load(61,true,true);
await obsoleteRejected;
await tick();
assert.ok(starts.find(item=>item.index===60).signal.aborted);
held.get(61)('latest');
assert.strictEqual(await latest,'latest');
held.get(60)('obsolete');
await tick();
scheduler.prefetch([40, 41, 42]);
await tick();
scheduler.prefetch([41, 43]);
assert.ok(starts.find(item => item.index === 40).signal.aborted);
const closing = scheduler.load(50);
const rejected = assert.rejects(closing, error => error.name === "AbortError");
scheduler.dispose();
await rejected;
for (const resolve of held.values()) resolve("closed");
await tick();
assert.strictEqual(scheduler.activeCount, 0);
assert.strictEqual(scheduler.pendingCount, 0);
await assert.rejects(scheduler.load(1), error => error.name === "AbortError");
console.log("reader chapter scheduler contracts passed");
}
main().catch(error => { console.error(error); process.exitCode = 1; });