Files
stack/packages/processing-control/tests/task.test.mjs
T
rocko 4bdc7e0e86 processing: inspectable per-run stop seam for lifecycle fire
Unify halt and fire cancellation by verified run identity with durable first-owner receipts and shared deadlines. Integrate the instance control with the current host, library and tester-socket paths. Focused nine-file evidence is 62 passing tests; broad suites, mutants and review remain pending.
2026-10-21 22:42:12 -05:00

69 lines
5.0 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { fixture, tmp } from '../../cli/tests/helpers.mjs';
import { initializeControl, transition } from '../src/state.mjs';
const TASK = new URL('../../../scripts/mosaic-task.mjs', import.meta.url).pathname;
function setup(t, stop = false) {
const root = tmp(t), f = fixture(root), bin = join(root, 'bin'); mkdirSync(bin);
const source = new URL('../src/state.mjs', import.meta.url).href;
const runtimes = new URL('../src/runtimes.mjs', import.meta.url).href;
writeFileSync(join(bin, 'docker'), `#!${process.execPath}
(async()=>{const args=process.argv.slice(2);require('node:fs').writeFileSync(${JSON.stringify(join(root, 'called'))},JSON.stringify(args));
${stop ? `const {transition}=await import(${JSON.stringify(source)});const {updateRuntime}=await import(${JSON.stringify(runtimes)});const s=transition(process.env.MOSAIC_DATA_ROOT,{business:'acme',human:'jason',halted:true});const tag=args.find(x=>x.startsWith('mosaic.runtime='));if(tag)updateRuntime(process.env.MOSAIC_DATA_ROOT,tag.slice(15),{haltGeneration:s.generation});process.exit(137);` : `console.log('normal response');`}
})().catch(e=>{console.error(e.message);process.exit(1)});\n`, { mode: 0o755 });
f.env.PATH = bin + ':' + f.env.PATH;
const task = join(root, 'task.json'); writeFileSync(task, JSON.stringify({ taskVersion: 1, id: 'one', prompt: 'request' }));
const run = args => spawnSync(process.execPath, [TASK, ...args], { env: f.env, encoding: 'utf8', timeout: 10000 });
return { root, f, task, run };
}
test('task halt keeps the true Docker exit status, writes kill-switch once and leaves snapshots unchanged', t => {
const f = setup(t, true), result = f.run(['run', f.task]);
assert.equal(result.status, 1, result.stderr);
const runs = join(f.f.dataRoot, 'runs'), [id] = readdirSync(runs);
const file = join(runs, id, 'result.json'), bytes = readFileSync(file), record = JSON.parse(bytes);
assert.equal(record.reason, 'kill-switch'); assert.match(record.haltGeneration, /^[a-f0-9-]{36}$/);
assert.equal(record.exitCode, 137); assert.equal(record.signal, null);
assert.deepEqual(readFileSync(join(runs, id, 'task.json')), readFileSync(f.task));
const retry = f.run(['retry', id]); assert.equal(retry.status, 3, retry.stderr);
assert.deepEqual(readFileSync(file), bytes); assert.deepEqual(readdirSync(runs), [id]);
});
test('halt refuses direct task launch before Docker or a run record; clear allows a fresh normal result', t => {
const f = setup(t), actor = { business: 'acme', human: 'jason' };
initializeControl(f.f.dataRoot); const halted = transition(f.f.dataRoot, { ...actor, halted: true });
const result = f.run(['run', f.task]); assert.equal(result.status, 3, result.stderr);
assert.equal(existsSync(join(f.root, 'called')), false);
assert.equal(existsSync(join(f.f.dataRoot, 'runs')), false);
transition(f.f.dataRoot, { ...actor, halted: false, generation: halted.generation });
const normal = f.run(['run', f.task]); assert.equal(normal.status, 0, normal.stderr);
const [id] = readdirSync(join(f.f.dataRoot, 'runs'));
const record = JSON.parse(readFileSync(join(f.f.dataRoot, 'runs', id, 'result.json')));
assert.equal(record.reason, null); assert.equal(record.status, 'succeeded');
assert.equal(record.response, 'normal response'); assert.equal('haltGeneration' in record, false);
});
for (const [script, args] of [['hello.sh', []], ['verify.sh', []], ['agent.sh', ['fixture']]]) {
test(`halt refuses ${script} before Docker, credentials or release alignment`, t => {
const f = setup(t); initializeControl(f.f.dataRoot);
transition(f.f.dataRoot, { business: 'acme', human: 'jason', halted: true });
const r = spawnSync('bash', [new URL('../../../scripts/' + script, import.meta.url).pathname, ...args],
{ env: f.f.env, encoding: 'utf8', timeout: 5000 });
assert.equal(r.status, 3, r.stderr); assert.match(r.stderr, /processing-halted/);
assert.equal(existsSync(join(f.root, 'called')), false);
});
}
for (const starter of ['task', 'container-cli']) test(`a nonzero Docker client exit retains its unresolved runtime receipt (${starter})`, t => {
const f = setup(t);
writeFileSync(join(f.root, 'bin', 'docker'), `#!${process.execPath}\nprocess.exit(137);\n`, { mode: 0o755 });
const result = starter === 'task' ? f.run(['run', f.task]) : spawnSync(process.execPath,
[new URL('../src/container-cli.mjs', import.meta.url).pathname, 'request'], { env: f.f.env, encoding: 'utf8', timeout: 10000 });
assert.equal(result.status, starter === 'task' ? 1 : 137, result.stderr);
const files = readdirSync(join(f.f.dataRoot, 'control', 'runtimes'));
assert.equal(files.length, 1, 'a failed Docker client cannot prove the container stopped');
const runtime = JSON.parse(readFileSync(join(f.f.dataRoot, 'control', 'runtimes', files[0])));
assert.notEqual(runtime.phase, 'ended');
});