// fleet-dash.test.mjs — dependency-light unit tests for the fleet-mode dashboard // adapter. Uses node:assert only (no test framework), matching the repo style. // Run: `node fleet-dash.test.mjs` (also wired into selftest.sh). // // These tests prove the dashboard's CONTRACT ASSUMPTIONS against the /fleet API // (request shaping, response mapping, graceful degradation, action semantics) // via an injected fetch stub. They do NOT prove live server compatibility. import assert from 'node:assert/strict'; import { fleetConfig, mapStage, toBoard, fleetFetch, fetchBoard, fetchEvents, formatEvent, jobAction, } from './fleet-dash.mjs'; let passed = 0; const t = (name, fn) => { try { const r = fn(); if (r && typeof r.then === 'function') { return r.then( () => { passed += 1; }, (e) => { console.error(` ✗ ${name}\n ${e && e.message}`); process.exitCode = 1; }, ); } passed += 1; } catch (e) { console.error(` ✗ ${name}\n ${e && e.message}`); process.exitCode = 1; } return undefined; }; // A recording fetch stub. `routes` maps a matcher → {status, body} (or a fn). function makeFetch(routes) { const calls = []; const fetchImpl = async (url, opts = {}) => { calls.push({ url, opts, headers: opts.headers || {}, method: opts.method || 'GET' }); let entry = routes[url]; if (!entry) { // try suffix match (path only) const key = Object.keys(routes).find((k) => url.endsWith(k)); entry = key ? routes[key] : undefined; } if (typeof entry === 'function') entry = entry({ url, opts }); if (entry === undefined) return mkRes(404, '{}'); if (entry.throw) throw Object.assign(new Error(entry.throw), { name: entry.name || 'Error' }); return mkRes(entry.status ?? 200, entry.body ?? ''); }; fetchImpl.calls = calls; return fetchImpl; } const mkRes = (status, body) => ({ ok: status >= 200 && status < 300, status, text: async () => (typeof body === 'string' ? body : JSON.stringify(body)), }); const CFG = { enabled: true, ok: true, api: 'http://svc/api', token: 'tok', productId: 'prodX', missing: [] }; await (async () => { // ── fleetConfig ── t('fleetConfig: AQ_FLEET_DASH unset ⇒ disabled', () => { const c = fleetConfig({}); assert.equal(c.enabled, false); assert.equal(c.ok, false); }); t('fleetConfig: enabled but missing config ⇒ not ok, lists missing', () => { const c = fleetConfig({ AQ_FLEET_DASH: '1' }); assert.equal(c.enabled, true); assert.equal(c.ok, false); assert.deepEqual(c.missing.sort(), ['AQ_FLEET_API', 'AQ_FLEET_TOKEN', 'AQ_PRODUCT_ID'].sort()); }); t('fleetConfig: enabled + complete ⇒ ok, trims trailing slash', () => { const c = fleetConfig({ AQ_FLEET_DASH: '1', AQ_FLEET_API: 'http://svc/api/', AQ_FLEET_TOKEN: 'k', AQ_PRODUCT_ID: 'p' }); assert.equal(c.ok, true); assert.equal(c.api, 'http://svc/api'); }); // ── mapStage ── t('mapStage: fleet stages collapse to board buckets', () => { assert.equal(mapStage('queued'), 'inbox'); assert.equal(mapStage('assigned'), 'building'); assert.equal(mapStage('building'), 'building'); assert.equal(mapStage('review'), 'review'); assert.equal(mapStage('testing'), 'testing'); assert.equal(mapStage('shipped'), 'shipped'); assert.equal(mapStage('failed'), 'failed'); assert.equal(mapStage('dead_letter'), 'failed'); assert.equal(mapStage('weird'), 'inbox'); }); // ── toBoard ── t('toBoard: counts, actionable items, running, recent', () => { const jobs = [ { id: 'a', stage: 'queued', priority: 'high', capabilities: ['os:any'] }, { id: 'b', stage: 'building', priority: 'critical', factoryId: 'mac-1', leaseEpoch: 3 }, { id: 'c', stage: 'review', updatedAt: '2026-01-01T00:00:02Z' }, { id: 'd', stage: 'testing' }, { id: 'e', stage: 'shipped', updatedAt: '2026-01-01T00:00:09Z' }, { id: 'f', stage: 'failed', updatedAt: '2026-01-01T00:00:05Z' }, { id: 'g', stage: 'dead_letter', updatedAt: '2026-01-01T00:00:01Z' }, ]; const b = toBoard({ jobs }); assert.equal(b.counts.inbox, 1); assert.equal(b.counts.building, 1); assert.equal(b.counts.review, 1); assert.equal(b.counts.testing, 1); assert.equal(b.counts.shipped, 1); assert.equal(b.counts.failed, 2); // failed + dead_letter // running = assigned/building only assert.deepEqual(b.running.map((x) => x.id), ['b']); assert.equal(b.running[0].fleetStage, 'building'); assert.equal(b.running[0].factoryId, 'mac-1'); // actionable items exclude building/shipped, ordered review x.id), ['c', 'd', 'f', 'g', 'a']); // item.stage is the bucket (so dashboard gate()/STAGE_TAG reuse works) assert.equal(b.items[0].stage, 'review'); assert.equal(b.items[4].stage, 'inbox'); // recent = shipped+failed, newest first, capped at 5 assert.deepEqual(b.recent.map((x) => x.id), ['e', 'f', 'g']); }); // ── fleetFetch: headers + product scoping on every request ── await t('fleetFetch: sends bearer + X-Product-Id; parses JSON', async () => { const f = makeFetch({ '/fleet/jobs': { status: 200, body: { jobs: [] } } }); const r = await fleetFetch(CFG, '/fleet/jobs', {}, f); assert.equal(r.ok, true); assert.deepEqual(r.json, { jobs: [] }); const h = f.calls[0].headers; assert.equal(h.Authorization, 'Bearer tok'); assert.equal(h['X-Product-Id'], 'prodX'); assert.equal(f.calls[0].url, 'http://svc/api/fleet/jobs'); }); await t('fleetFetch: network error ⇒ ok:false with message (no throw)', async () => { const f = makeFetch({ '/fleet/jobs': { throw: 'boom' } }); const r = await fleetFetch(CFG, '/fleet/jobs', {}, f); assert.equal(r.ok, false); assert.equal(r.status, 0); assert.match(r.error, /boom/); }); await t('fleetFetch: abort ⇒ timeout error', async () => { const f = makeFetch({ '/fleet/jobs': { throw: 'aborted', name: 'AbortError' } }); const r = await fleetFetch(CFG, '/fleet/jobs', {}, f); assert.equal(r.ok, false); assert.equal(r.error, 'timeout'); }); await t('fleetFetch: non-JSON 500 body ⇒ ok:false, json null', async () => { const f = makeFetch({ '/fleet/jobs': { status: 500, body: 'err' } }); const r = await fleetFetch(CFG, '/fleet/jobs', {}, f); assert.equal(r.ok, false); assert.equal(r.status, 500); assert.equal(r.json, null); }); // ── fetchBoard: assembly + degradation ── await t('fetchBoard: jobs + metrics + factories assembled', async () => { const f = makeFetch({ '/fleet/jobs': { body: { jobs: [{ id: 'a', stage: 'review' }] } }, '/fleet/metrics': { body: { utilizationPct: 50, alerts: [] } }, '/fleet/factories': { body: { factories: [{ factoryId: 'mac-1', health: 'ok' }] } }, }); const r = await fetchBoard(CFG, f); assert.equal(r.ok, true); assert.equal(r.board.items.length, 1); assert.equal(r.board.metrics.utilizationPct, 50); assert.equal(r.board.factories.length, 1); }); await t('fetchBoard: factories 404 ⇒ degrades to []', async () => { const f = makeFetch({ '/fleet/jobs': { body: { jobs: [] } }, '/fleet/metrics': { body: {} }, '/fleet/factories': { status: 404, body: {} }, }); const r = await fetchBoard(CFG, f); assert.equal(r.ok, true); assert.deepEqual(r.board.factories, []); }); await t('fetchBoard: factories 501 ⇒ degrades to []', async () => { const f = makeFetch({ '/fleet/jobs': { body: { jobs: [] } }, '/fleet/metrics': { body: {} }, '/fleet/factories': { status: 501, body: {} }, }); const r = await fetchBoard(CFG, f); assert.equal(r.ok, true); assert.deepEqual(r.board.factories, []); }); await t('fetchBoard: metrics failure ⇒ board still ok, metrics null', async () => { const f = makeFetch({ '/fleet/jobs': { body: { jobs: [] } }, '/fleet/metrics': { status: 500, body: 'oops' }, '/fleet/factories': { body: { factories: [] } }, }); const r = await fetchBoard(CFG, f); assert.equal(r.ok, true); assert.equal(r.board.metrics, null); }); await t('fetchBoard: jobs failure ⇒ board fails with error', async () => { const f = makeFetch({ '/fleet/jobs': { status: 503, body: '{}' } }); const r = await fetchBoard(CFG, f); assert.equal(r.ok, false); assert.match(r.error, /503/); }); // ── events ── t('formatEvent: renders type + actor + data', () => { const line = formatEvent({ type: 'claimed', actor: 'mac-1', at: '2026-01-01T00:00:00Z', data: { leaseEpoch: 2 } }); assert.match(line, /claimed/); assert.match(line, /mac-1/); assert.match(line, /leaseEpoch/); }); await t('fetchEvents: maps events to lines', async () => { const f = makeFetch({ '/events': { body: { events: [{ type: 'queued', at: '2026-01-01T00:00:00Z', data: {} }, { type: 'claimed', data: {} }] } }, }); const r = await fetchEvents(CFG, 'job-1', f); assert.equal(r.ok, true); assert.equal(r.lines.length, 2); assert.match(r.lines[1], /claimed/); assert.match(f.calls[0].url, /\/fleet\/jobs\/job-1\/events$/); }); await t('fetchEvents: failure ⇒ ok:false, empty lines', async () => { const f = makeFetch({ '/events': { status: 500, body: 'x' } }); const r = await fetchEvents(CFG, 'job-1', f); assert.equal(r.ok, false); assert.deepEqual(r.lines, []); }); // ── jobAction ── await t('jobAction: ship re-GETs fresh leaseEpoch then PATCHes shipped', async () => { let patchBody = null; const f = makeFetch({ 'http://svc/api/fleet/jobs/j1': ({ opts }) => { if ((opts.method || 'GET') === 'PATCH') { patchBody = JSON.parse(opts.body); return { status: 200, body: { id: 'j1', stage: 'shipped' } }; } return { status: 200, body: { id: 'j1', stage: 'testing', leaseEpoch: 7 } }; // fresh epoch }, }); const r = await jobAction(CFG, { id: 'j1', leaseEpoch: 2 /* stale */ }, 'ship', f); assert.equal(r.ok, true); assert.equal(patchBody.stage, 'shipped'); assert.equal(patchBody.leaseEpoch, 7); // used the freshly-fetched epoch, not the stale 2 }); await t('jobAction: ship 409 ⇒ actionable fenced message', async () => { const f = makeFetch({ 'http://svc/api/fleet/jobs/j1': ({ opts }) => (opts.method === 'PATCH' ? { status: 409, body: '{}' } : { status: 200, body: { id: 'j1', leaseEpoch: 7 } }), }); const r = await jobAction(CFG, { id: 'j1' }, 'ship', f); assert.equal(r.ok, false); assert.match(r.message, /fenced|refresh/i); }); await t('jobAction: requeue ⇒ POST /actions/requeue', async () => { const f = makeFetch({ '/fleet/jobs/j1/actions/requeue': { status: 200, body: { id: 'j1', stage: 'queued' } } }); const r = await jobAction(CFG, { id: 'j1' }, 'requeue', f); assert.equal(r.ok, true); assert.equal(f.calls[0].method, 'POST'); assert.match(f.calls[0].url, /\/actions\/requeue$/); }); await t('jobAction: reject 409 ⇒ conflict message', async () => { const f = makeFetch({ '/fleet/jobs/j1/actions/reject': { status: 409, body: '{}' } }); const r = await jobAction(CFG, { id: 'j1' }, 'reject', f); assert.equal(r.ok, false); assert.match(r.message, /conflict|terminal|refresh/i); }); t('jobAction: promote ⇒ explicitly unavailable in fleet mode', async () => { return jobAction(CFG, { id: 'j1' }, 'promote', makeFetch({})).then((r) => { assert.equal(r.ok, false); assert.match(r.message, /promote/i); }); }); })(); // Summary line (selftest greps for PASS). process.on('exit', () => { if (process.exitCode && process.exitCode !== 0) { console.error('fleet-dash.test FAIL'); } else { console.log(`fleet-dash.test PASS (${passed} assertions)`); } });