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.
55 lines
3.6 KiB
JavaScript
55 lines
3.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync, writeFileSync, symlinkSync, unlinkSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { randomUUID } from 'node:crypto';
|
|
import { makeRoot } from './helpers.mjs';
|
|
import { ensureJournal, requestStop, stopRequested, stopPath } from '../src/journal.mjs';
|
|
const api = await import('../src/journal.mjs');
|
|
function fixture() { const dir = join(makeRoot(), 'journal'); ensureJournal(dir); return dir; }
|
|
test('resume clears only its own generation-tagged Discord STOP and keeps manual or newer brakes', () => {
|
|
assert.equal(typeof api.requestProcessingStop, 'function');
|
|
const dir = fixture(), generation = randomUUID();
|
|
api.requestProcessingStop(dir, generation); const first = readFileSync(stopPath(dir));
|
|
api.requestProcessingStop(dir, generation); assert.deepEqual(readFileSync(stopPath(dir)), first);
|
|
assert.equal(api.clearProcessingStop(dir, randomUUID()), false);
|
|
assert.equal(api.clearProcessingStop(dir, generation), true); assert.equal(stopRequested(dir), false);
|
|
api.requestProcessingStop(dir, generation); requestStop(dir, 'cli stop');
|
|
const mixed = readFileSync(stopPath(dir));
|
|
assert.equal(api.clearProcessingStop(dir, generation), false); assert.deepEqual(readFileSync(stopPath(dir)), mixed);
|
|
});
|
|
test('unreadable, malformed and symlink STOP never get removed or followed by processing recovery', () => {
|
|
assert.equal(typeof api.requestProcessingStop, 'function');
|
|
const dir = fixture(), generation = randomUUID();
|
|
writeFileSync(stopPath(dir), 'unreadable operator brake\n', { mode: 0o600 });
|
|
assert.equal(api.clearProcessingStop(dir, generation), false);
|
|
unlinkSync(stopPath(dir)); const outside = join(dir, 'outside');
|
|
writeFileSync(outside, 'untouched', { mode: 0o600 }); symlinkSync(outside, stopPath(dir));
|
|
assert.equal(api.clearProcessingStop(dir, generation), false);
|
|
assert.throws(() => api.requestProcessingStop(dir, generation));
|
|
assert.equal(readFileSync(outside, 'utf8'), 'untouched');
|
|
});
|
|
|
|
test('coordinator halt writes the Discord brake and resume clears only its own stopped runtime', async () => {
|
|
const { initializeControl } = await import('../../processing-control/src/state.mjs');
|
|
const { registerRuntime, updateRuntime } = await import('../../processing-control/src/runtimes.mjs');
|
|
const { createProcessing } = await import('../../processing-control/src/coordinator.mjs');
|
|
const { discordProcessingHooks } = await import('../src/processing.mjs');
|
|
const root = makeRoot(); initializeControl(root);
|
|
const dir = join(root, 'discord', 'test-seat'); ensureJournal(dir);
|
|
const processing = createProcessing({ dataRoot: root, ...discordProcessingHooks(root) });
|
|
const first = registerRuntime(root, { kind: 'discord', business: 'instance', run: 'test-seat' });
|
|
updateRuntime(root, first.id, { phase: 'ended' });
|
|
const halted = await processing.halt({ business: 'demo', human: 'jason' });
|
|
assert.equal(halted.quiescent, true); assert.equal(stopRequested(dir), true);
|
|
await processing.resume({ business: 'demo', human: 'jason', generation: halted.generation });
|
|
assert.equal(stopRequested(dir), false);
|
|
const second = registerRuntime(root, { kind: 'discord', business: 'instance', run: 'test-seat' });
|
|
updateRuntime(root, second.id, { phase: 'ended' });
|
|
const again = await processing.halt({ business: 'demo', human: 'jason' });
|
|
requestStop(dir, 'cli stop'); const bytes = readFileSync(stopPath(dir));
|
|
await processing.resume({ business: 'demo', human: 'jason', generation: again.generation });
|
|
assert.deepEqual(readFileSync(stopPath(dir)), bytes);
|
|
await processing.close();
|
|
});
|