// The drill's pure parts: how it decides the harness has stopped (issue #20), and what it starts clean. // node --test tools/drill/drill.test.js const test = require('node:test') const assert = require('node:assert') const { harnessProgress, unfinishedFinding, FRESH_DATA, KITS_FILE, harnessKits, HARNESS_STALL_MS } = require('./drill.js') const MIN = 60000 const T0 = 1000000 test('a harness that keeps writing is running, and its clock restarts on each new line', () => { let v = harnessProgress(['# run all'], { count: 0, at: T0 }, T0 + 30000, HARNESS_STALL_MS) assert.equal(v.state, 'running') assert.deepEqual(v.seen, { count: 1, at: T0 + 30000 }) // Four silent minutes, then a line: still running, and the clock restarts. v = harnessProgress(['# run all', 'a: PASS '], v.seen, T0 + 30000 + 4 * MIN, HARNESS_STALL_MS) assert.equal(v.state, 'running') assert.equal(v.seen.at, T0 + 30000 + 4 * MIN) }) test('no new line for five minutes is a stall; four minutes and a bit is not', () => { const seen = { count: 2, at: T0 } const lines = ['# run all', 'a: PASS '] assert.equal(harnessProgress(lines, seen, T0 + 5 * MIN - 1, HARNESS_STALL_MS).state, 'running') assert.equal(harnessProgress(lines, seen, T0 + 5 * MIN, HARNESS_STALL_MS).state, 'stalled') }) test('a harness that never wrote a line stalls from when the wait began', () => { assert.equal(harnessProgress([], { count: 0, at: T0 }, T0 + 5 * MIN, HARNESS_STALL_MS).state, 'stalled') }) test('done wins, even when the file has been still for a long time', () => { const lines = ['# run all', '# done all: 10 pass, 1 fail'] assert.equal(harnessProgress(lines, { count: 2, at: T0 }, T0 + 30 * MIN, HARNESS_STALL_MS).state, 'done') }) test('the stall finding names the last line and the counts', () => { const lines = ['# run all', 'place.set.each: FAIL position: off the navmesh', 'place.spawned: FAIL each 0, group 3'] const f = unfinishedFinding({ pass: 40, fail: 2 }, lines, 'stalled') assert.equal(f, 'The harness stopped after `place.spawned: FAIL each 0, group 3` (no output for 5 minutes; 40 pass, 2 fail so far).') }) test('a backtick in the last line cannot break the issue body, and a long line is cut', () => { const f = unfinishedFinding({ pass: 0, fail: 0 }, ['x`y' + 'z'.repeat(500)], 'stalled') assert.equal(f.split('`').length, 3) assert.ok(f.length < 330) assert.match(unfinishedFinding({ pass: 0, fail: 0 }, [], 'stalled'), /stopped after `no line at all`/) }) test('a capped wait keeps the 45-minute message', () => { assert.equal(unfinishedFinding({ pass: 3, fail: 1 }, ['# run all'], 'capped'), 'The harness did not finish in 45 minutes (3 pass, 1 fail so far).') }) test('the clean start deletes files only: every path ends in .json and none is a directory', () => { assert.ok(FRESH_DATA.includes('/oxide/data/RunicNPC/state.json')) for (const f of FRESH_DATA) assert.match(f, /^\/oxide\/data\/RunicNPC\/[a-z_]+\.json$/) }) test("Kits' file is replaced, not deleted, by one holding only the harness's kit (#22)", () => { assert.ok(!FRESH_DATA.includes(KITS_FILE)) assert.equal(KITS_FILE, '/oxide/data/Kits/kits_data.json') const kits = harnessKits()._kits assert.deepEqual(Object.keys(kits), ['rnhrevolver']) assert.equal(kits.rnhrevolver.Name, 'rnhrevolver') assert.equal(kits.rnhrevolver.IsHidden, true) assert.deepEqual(kits.rnhrevolver.BeltItems.map((i) => i.Shortname), ['pistol.revolver']) })