Seen on igneum-build-1 at 10:39Z on 7 October 2026: both slot files flock-held and empty while two suites ran and three waiters queued, so the header read 0/2. The holder's missing line is the build-server agent's to fix; the collector no longer reports a full box as free either way, and the page shows "held, no holder line" in the lane. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
175 lines
14 KiB
JavaScript
175 lines
14 KiB
JavaScript
// node --test tools/workers/test : the collector's parsers against the fixtures, and the page's data shaping.
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync, readdirSync } from 'node:fs';
|
|
import { join, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { parseProcStat, cpuBusy, parseMeminfo, parseNetDev, parseLoadavg, parseSlotLine, splitLabel, deriveKind, parseLockDir, parseBuildsJsonl, parseSccacheStats, pickTemps, cargoProcess, summaryOf } from '../lib.mjs';
|
|
import { durationByKind, buildsPerHour, hitRateSeries, compareKinds, timeline, closingLines, ukTime, headline, quantile } from '../shape.js';
|
|
|
|
const FX = join(dirname(fileURLToPath(import.meta.url)), '..', 'fixtures');
|
|
const fx = n => readFileSync(join(FX, n), 'utf8');
|
|
|
|
test('/proc/stat: cores and busy deltas', () => {
|
|
const a = parseProcStat(fx('proc-stat-0.txt')), b = parseProcStat(fx('proc-stat-1.txt'));
|
|
assert.equal(a.cores.length, 4);
|
|
const busy = cpuBusy(a, b);
|
|
assert.equal(busy.per_core.length, 4);
|
|
assert.equal(busy.per_core[0], 100); // 100 user jiffies, 0 idle
|
|
assert.equal(busy.per_core[1], 0); // idle only
|
|
assert.equal(busy.per_core[2], 100); // 50 user + 50 system
|
|
assert.equal(busy.per_core[3], 25); // 25 busy of 100
|
|
assert.equal(busy.cores_busy, 2);
|
|
// whole box: 1000 user + 200 system busy of 2000 -> 60 %
|
|
assert.equal(busy.busy_pct, 60);
|
|
// a zero delta never divides by zero
|
|
assert.equal(cpuBusy(a, a).busy_pct, 0);
|
|
});
|
|
|
|
test('/proc/meminfo, /proc/net/dev, /proc/loadavg', () => {
|
|
const m = parseMeminfo('MemTotal: 131556268 kB\nMemFree: 88262160 kB\nMemAvailable: 97647588 kB\nSwapTotal: 0 kB\nSwapFree: 0 kB\n');
|
|
assert.equal(m.total_kb, 131556268); assert.equal(m.used_kb, 131556268 - 97647588); assert.equal(m.used_pct, 25.8);
|
|
const n = parseNetDev('Inter-| Receive | Transmit\n face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n lo: 17515759 1 0 0 0 0 0 0 17515759 1 0 0 0 0 0 0\nenp193s0f0np0: 994079034 2 0 0 0 0 0 0 80040958 3 0 0 0 0 0 0\n');
|
|
assert.deepEqual(n, [{ iface: 'enp193s0f0np0', rx_bytes: 994079034, tx_bytes: 80040958 }]);
|
|
assert.deepEqual(parseLoadavg('13.86 9.61 4.32 1/1235 36952\n'), { load: [13.86, 9.61, 4.32], running: 1, threads: 1235 });
|
|
});
|
|
|
|
test('slot line: pid, since, waited, label, agent, worktree, crate, command, target', () => {
|
|
const l = parseSlotLine('pid 36992 since 17:34:00Z waited 0 s: igneum-wt-build-server/vendor/igneum-node-bs cross x86_64-pc-windows-gnu; agent=build-server', { day: '2026-10-06', now: '2026-10-06T18:00:00Z' });
|
|
assert.equal(l.pid, 36992); assert.equal(l.since, '2026-10-06T17:34:00Z'); assert.equal(l.waited_s, 0);
|
|
assert.equal(l.worktree, 'igneum-wt-build-server'); assert.equal(l.crate, 'vendor/igneum-node-bs');
|
|
assert.equal(l.target, 'x86_64-pc-windows-gnu'); assert.equal(l.agent, 'build-server');
|
|
assert.equal(deriveKind(l), 'node-windows');
|
|
// a clock time later than now is yesterday
|
|
const y = parseSlotLine('pid 5 since 23:50:00Z waited 2 s: x', { day: '2026-10-06', now: '2026-10-06T00:10:00Z' });
|
|
assert.equal(y.since, '2026-10-05T23:50:00Z');
|
|
assert.equal(parseSlotLine(''), null); assert.equal(parseSlotLine('garbage'), null);
|
|
// a Mac with-lock label is a bare command
|
|
const m = splitLabel('cargo build --release -p igneum-miner');
|
|
assert.equal(m.worktree, null); assert.equal(m.target, 'x86_64-unknown-linux-gnu');
|
|
});
|
|
|
|
test('kind rule matches the JSONL proposal', () => {
|
|
assert.equal(deriveKind({ command: 'cargo test --release -p kaspa-consensus-core', crate: 'vendor/igneum-node-v4' }), 'suite');
|
|
assert.equal(deriveKind({ command: 'cargo clippy --all-targets', crate: 'app/igneum-app' }), 'check');
|
|
assert.equal(deriveKind({ command: 'cargo build --release -p kaspad', crate: 'vendor/igneum-node-bs' }), 'node-linux');
|
|
assert.equal(deriveKind({ command: 'cargo build --release -p kaspad --target x86_64-pc-windows-gnu', crate: 'vendor/igneum-node-bs' }), 'node-windows');
|
|
assert.equal(deriveKind({ command: 'cargo build --release', crate: 'app/igneum-app' }), 'app');
|
|
assert.equal(deriveKind({ command: 'cargo build --release', crate: 'app/igneum-app', tool: 'cross-remote' }), 'app-windows');
|
|
assert.equal(deriveKind({ command: 'cargo build --release', crate: 'proving/igneum-prove' }), 'prove');
|
|
assert.equal(deriveKind({ kind: 'suite', command: 'cargo build' }), 'suite'); // an explicit kind wins
|
|
assert.equal(deriveKind({ command: 'cargo build --release', crate: 'tools/x' }), 'other');
|
|
});
|
|
|
|
test('lock dir fixture: one held slot, one stale line, one empty, count from slots', () => {
|
|
const dir = join(FX, 'locks');
|
|
const files = readdirSync(dir).map(name => ({ name, text: readFileSync(join(dir, name), 'utf8') }));
|
|
const alive = pid => pid === 36992; // only the real holder is alive; pid 1's line is stale
|
|
const r = parseLockDir(files, { day: '2026-10-06', now: '2026-10-06T18:00:00Z', aliveFn: alive });
|
|
assert.equal(r.count, 1);
|
|
assert.equal(r.held.length, 1); assert.equal(r.held[0].slot, 'build-0'); assert.equal(r.held[0].kind, 'node-windows'); assert.equal(r.held[0].agent, 'build-server');
|
|
assert.deepEqual(r.free, ['build-1', 'build-2']);
|
|
// an explicit flock verdict overrides the pid check
|
|
const r2 = parseLockDir(files.map(f => ({ ...f, held: f.name === 'build-1' })), { day: '2026-10-06', now: '2026-10-06T18:00:00Z' });
|
|
assert.deepEqual(r2.held.map(h => h.slot), ['build-1']);
|
|
// a flock-held slot whose file is empty is still held (7 Oct 2026 on build-1: two held, both empty, the box full)
|
|
const r3 = parseLockDir([{ name: 'build-2', text: '', held: true }, { name: 'build-0', text: '', held: false }, { name: 'slots', text: '2' }], { now: '2026-10-07T10:39:00Z' });
|
|
assert.equal(r3.held.length, 1); assert.equal(r3.held[0].slot, 'build-2'); assert.equal(r3.held[0].no_line, true); assert.deepEqual(r3.free, ['build-0']);
|
|
});
|
|
|
|
test('builds JSONL fixture: five rows, one bad line, newest first, derived fields', () => {
|
|
const r = parseBuildsJsonl(fx('builds.jsonl'));
|
|
assert.equal(r.total, 5); assert.equal(r.bad, 1);
|
|
assert.equal(r.rows[0].id, 'igneum-build-1-1759774200-37300');
|
|
const win = r.rows.find(b => b.tool === 'cross-remote');
|
|
assert.equal(win.kind, 'node-windows'); assert.equal(win.ok, true); assert.equal(win.sccache.hit_rate_pct, 0); assert.equal(win.artefacts.length, 2);
|
|
const suite = r.rows.find(b => b.exit === 101);
|
|
assert.equal(suite.kind, 'suite'); assert.equal(suite.ok, false);
|
|
const lin = r.rows.find(b => b.id.endsWith('37001'));
|
|
assert.equal(lin.kind, 'node-linux'); assert.equal(lin.target, 'x86_64-unknown-linux-gnu'); assert.equal(lin.sccache.hit_rate_pct, 71.7);
|
|
// secs derived from start and end when missing
|
|
const d = parseBuildsJsonl('{"start":"2026-10-06T10:00:00Z","end":"2026-10-06T10:05:30Z","exit":0,"command":"cargo build"}');
|
|
assert.equal(d.rows[0].secs, 330);
|
|
});
|
|
|
|
test('sccache --show-stats', () => {
|
|
const s = parseSccacheStats(fx('sccache-stats.txt'));
|
|
assert.equal(s.requests, 2294); assert.equal(s.hits, 790); assert.equal(s.misses, 1886); assert.equal(s.hit_rate_pct, 29.5);
|
|
assert.equal(s.cache_size, '12 GiB'); assert.equal(s.max_size, '100 GiB');
|
|
assert.equal(parseSccacheStats('Cache hits 0\nCache misses 10\n').hit_rate_pct, 0);
|
|
});
|
|
|
|
test('hwmon pick: hottest per class, cpu first, nothing absurd', () => {
|
|
const t = pickTemps([{ name: 'bnxt_en', label: null, millic: 55000 }, { name: 'nvme', label: 'Composite', millic: 36850 }, { name: 'nvme', label: 'Composite', millic: 34850 }, { name: 'k10temp', label: 'Tctl', millic: 75125 }, { name: 'k10temp', label: 'Tccd1', millic: 0 }, { name: 'acpitz', label: null, millic: 999000 }]);
|
|
assert.deepEqual(t.map(x => [x.name, x.c]), [['cpu', 75.1], ['nvme', 36.9], ['nic', 55]]);
|
|
});
|
|
|
|
test('a cargo process becomes a running build with its worktree, target, kind and start', () => {
|
|
const stat = '37210 (cargo) S 37209 37210 36992 0 -1 4194304 1 0 0 0 1 2 0 0 20 0 2 0 62341 1 2 3 4 5 6 7 8 9';
|
|
const p = cargoProcess({ pid: 37210, cwd: '/srv/builds/igneum-wt-build-server/vendor/igneum-node-bs', cmdline: ['/home/build/.rustup/toolchains/1.99.0-x86_64-unknown-linux-gnu/bin/cargo','build','--release','-p','kaspad','--target','x86_64-pc-windows-gnu','-j','90',''].join('\0'), stat, bootSec: 1759772000, clk: 100, now: (1759772000 + 1000) * 1000 });
|
|
assert.equal(p.worktree, 'igneum-wt-build-server'); assert.equal(p.crate, 'vendor/igneum-node-bs');
|
|
assert.equal(p.target, 'x86_64-pc-windows-gnu'); assert.equal(p.kind, 'node-windows');
|
|
assert.equal(p.started_at, new Date((1759772000 + 623.41) * 1000).toISOString().replace(/\.\d{3}Z$/, 'Z'));
|
|
assert.equal(p.elapsed_s, 377);
|
|
assert.equal(cargoProcess({ pid: 1, cmdline: ['rustc','--crate-name','x'].join('\0') }), null);
|
|
});
|
|
|
|
test('relay job report: SUMMARY and closing line, running without finished_at', () => {
|
|
const done = summaryOf('IGNEUM-APP 0.3.14\nSUMMARY {"job":"build-20261006-171423","kind":"build","status":"done","exit":0,"duration_s":622,"started_at":"2026-10-06T17:15:09Z","finished_at":"2026-10-06T17:25:31Z","summary":"ok"}\nSTAGE linux start 2026-10-06T17:16:00Z cap 20 min\njob build-20261006-171423: done (exit 0) after 622 s: every stage ok\n');
|
|
assert.equal(done.status, 'done'); assert.equal(done.duration_s, 622); assert.equal(done.stage, 'linux');
|
|
const run = summaryOf('SUMMARY {"job":"j1","kind":"build","status":"running","started_at":"2026-10-06T17:15:09Z"}\nSTAGE windows start 2026-10-06T17:30:00Z cap 20 min\n');
|
|
assert.equal(run.status, 'running'); assert.equal(run.stage, 'windows');
|
|
assert.equal(summaryOf('nothing here'), null);
|
|
});
|
|
|
|
// ---- page shaping ----------------------------------------------------------------------------------------------------------
|
|
const builds = parseBuildsJsonl(fx('builds.jsonl')).rows;
|
|
|
|
test('shape: median and p90 by kind, builds per hour, hit-rate series', () => {
|
|
const d = durationByKind(builds);
|
|
const nl = d.find(x => x.kind === 'node-linux'); assert.equal(nl.n, 1); assert.equal(nl.median_s, 801); assert.equal(nl.p90_s, 801);
|
|
assert.equal(quantile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0.9), 9.1);
|
|
const h = buildsPerHour(builds, '2026-10-06');
|
|
assert.equal(h.length, 24); assert.equal(h[17].n, 1); assert.equal(h[18].n, 4); assert.equal(h[18].failed, 1); assert.equal(h[3].n, 0);
|
|
const s = hitRateSeries(builds);
|
|
assert.deepEqual(s.map(x => x.pct), [0, 71.7, 77.6, 85.7, 93.8]);
|
|
});
|
|
|
|
test('shape: box against Mac, timeline bars, closing lines, headline', () => {
|
|
const c = compareKinds(builds, { 'node-linux': { secs: 720, source: 'infra/cross/build-linux.sh, 4 Oct' }, 'app-windows': { secs: 900, source: 'runner' } });
|
|
const nl = c.find(x => x.kind === 'node-linux'); assert.equal(nl.mac_s, 720); assert.equal(nl.speedup, 0.9);
|
|
const aw = c.find(x => x.kind === 'app-windows'); assert.equal(aw.box_s, null); assert.equal(aw.mac_s, 900);
|
|
const t = timeline(builds, { limit: 3 });
|
|
assert.equal(t.length, 3); assert.equal(t[0].id, 'igneum-build-1-1759774200-37300');
|
|
assert.equal(Math.max(...t.map(r => r.bar_pct)), 100);
|
|
const lines = closingLines(builds.find(b => b.tool === 'cross-remote'));
|
|
assert.ok(lines[0].startsWith('$ cargo build')); assert.ok(lines.some(l => /igneumd\.exe\s+50\.5 MB\s+sha256 0f3a9c2e1d8b7a6f/.test(l)));
|
|
const hl = headline({ clean_node: { box_s: 600, mac_s: 2400 } });
|
|
assert.equal(hl[0].speedup, 4); assert.equal(hl[1].box_s, null); assert.equal(hl.length, 3);
|
|
});
|
|
|
|
test('shape: UK local time with the UTC in the tooltip', () => {
|
|
const t = ukTime('2026-10-06T17:34:00Z');
|
|
assert.equal(t.text, '18:34'); // BST on 6 October
|
|
assert.equal(t.utc, '2026-10-06 17:34:00 UTC');
|
|
assert.equal(ukTime('2026-12-06T17:34:00Z').text, '17:34'); // GMT in December
|
|
assert.deepEqual(ukTime(null), { text: '', utc: '' });
|
|
});
|
|
|
|
test('scheduling classes (7 Oct 2026): kind, nice, cores on the slot line; wait and gate files; JSONL fields', async () => {
|
|
const { splitLabelParts } = await import('../lib.mjs');
|
|
const l = parseSlotLine('pid 7 since 12:40:00Z waited 3 s: igneum-wt-build-server/vendor/igneum-node-bs cargo test -p kaspa-build-info --lib; kind=suite nice=10 cores=32; agent=build-server', { day: '2026-10-07', now: '2026-10-07T13:00:00Z' });
|
|
assert.equal(l.kind, 'suite'); assert.equal(l.nice, 10); assert.equal(l.cores, 32); assert.equal(l.agent, 'build-server');
|
|
assert.equal(l.label, 'igneum-wt-build-server/vendor/igneum-node-bs cargo test -p kaspa-build-info --lib');
|
|
assert.equal(l.command, 'cargo test -p kaspa-build-info --lib');
|
|
const g = parseSlotLine('pid 8 since 12:41:00Z waited 0 s: igneum-wt-build-server/vendor/igneum-node-bs cargo check -p kaspa-build-info; kind=gate nice=0 cores=96; agent=build-server', { day: '2026-10-07' });
|
|
assert.equal(g.kind, 'gate'); assert.equal(g.nice, 0); assert.equal(g.cores, 96);
|
|
// the old line shape still parses and derives its kind
|
|
const o = parseSlotLine('pid 9 since 12:41:00Z waited 0 s: igneum-wt-x/app/igneum-app cargo build --release; agent=x', { day: '2026-10-07' });
|
|
assert.equal(o.kind, 'app'); assert.equal(o.nice, null); assert.equal(o.cores, null); assert.equal(o.agent, 'x');
|
|
assert.deepEqual(splitLabelParts('plain cargo build'), { label: 'plain cargo build', agent: null, class: null, nice: null, cores: null });
|
|
const b = parseBuildsJsonl('{"start":"2026-10-07T12:00:00Z","end":"2026-10-07T12:01:00Z","exit":0,"command":"cargo test -p x","crate":"vendor/igneum-node-bs","nice":10,"cores":32,"jobs":32,"priority":"normal"}').rows[0];
|
|
assert.equal(b.kind, 'suite'); assert.equal(b.nice, 10); assert.equal(b.cores, 32); assert.equal(b.jobs, 32); assert.equal(b.priority, 'normal');
|
|
assert.ok(closingLines(b).some(x => x === 'class: nice 10 · last 32 cores · -j 32'));
|
|
assert.equal(deriveKind({ command: 'cargo bench -p igneum-pow' }), 'bench');
|
|
});
|