| 1 | import test from 'node:test' |
| 2 | import assert from 'node:assert/strict' |
| 3 | import { createHarnessModule, normalizeOutput } from '../dist/builtin/harness.mjs' |
| 4 | const owner = { plugin_id: 'host:harness', generation: 3, owner_token: 'fixture-token' } |
| 5 | const params = (execution_id = 'one', extra = {}) => ({ owner, execution_id, ticket: 'opaque-exact-fixture-ticket', deadline_ms: 1000, ...extra }) |
| 6 | const signal = () => new AbortController().signal |
| 7 | const tick = () => new Promise(resolve => setImmediate(resolve)) |
| 8 | |
| 9 | test('script result JSON preserves soft failure and metadata', () => { |
| 10 | assert.deepEqual(normalizeOutput({ success: true, stdout: JSON.stringify({ content: 'soft', success: false, metadata: { structured: [1, 2] } }), stderr: '' }), { ok: true, result: { content: 'soft', success: false, metadata: { structured: [1, 2] } } }) |
| 11 | }) |
| 12 | test('plain and non-ToolResult JSON retain original stdout', () => { |
| 13 | for (const stdout of ['hello\n', '{"other":true}', 'null']) assert.deepEqual(normalizeOutput({ success: true, stdout, stderr: '' }), { ok: true, result: { content: stdout, success: true } }) |
| 14 | }) |
| 15 | test('nonzero process exit keeps both streams in failure', () => { assert.deepEqual(normalizeOutput({ success: false, stdout: 'out', stderr: 'err' }), { ok: false, error: 'out\nerr' }) }) |
| 16 | test('real Node Builtin redeems only opaque exact operation fields', async () => { |
| 17 | const calls = []; const runner = createHarnessModule({ async request(method, args) { calls.push([method, args]); return { success: true, stdout: 'ok', stderr: '' } } }, owner) |
| 18 | assert.equal((await runner.run(params(), signal())).result.content, 'ok') |
| 19 | assert.deepEqual(calls, [['exec/redeem', { owner, execution_id: 'one', ticket: 'opaque-exact-fixture-ticket' }]]) |
| 20 | await runner.dispose() |
| 21 | }) |
| 22 | test('wrong owner, generation and token never reach Rust', async () => { |
| 23 | let calls = 0; const runner = createHarnessModule({ async request() { calls++; return {} } }, owner) |
| 24 | for (const wrong of [{ ...owner, plugin_id: 'native' }, { ...owner, generation: 4 }, { ...owner, owner_token: 'old' }]) await assert.rejects(runner.run(params('one', { owner: wrong }), signal()), /owner is stale/) |
| 25 | assert.equal(calls, 0); await runner.dispose() |
| 26 | }) |
| 27 | test('duplicate pending operation refuses without redeeming twice', async () => { |
| 28 | let finish; let calls = 0; const runner = createHarnessModule({ request() { calls++; return new Promise(resolve => { finish = resolve }) } }, owner) |
| 29 | const first = runner.run(params(), signal()); await tick() |
| 30 | await assert.rejects(runner.run(params(), signal()), /not admitted/) |
| 31 | finish({ success: true, stdout: '', stderr: '' }); await first; assert.equal(calls, 1); await runner.dispose() |
| 32 | }) |
| 33 | test('caller cancel settles even if a fake Rust peer ignores abort', async () => { |
| 34 | const controller = new AbortController(); let remoteSignal |
| 35 | const runner = createHarnessModule({ request(_method, _params, supplied) { remoteSignal = supplied; return new Promise(() => {}) } }, owner) |
| 36 | const pending = runner.run(params(), controller.signal); controller.abort() |
| 37 | await assert.rejects(pending, /cancelled/); assert.equal(remoteSignal.aborted, true); await runner.dispose() |
| 38 | }) |
| 39 | test('owner disposal cancels admitted work and refuses reuse', async () => { |
| 40 | const runner = createHarnessModule({ request() { return new Promise(() => {}) } }, owner) |
| 41 | const pending = runner.run(params(), signal()); const rejected = assert.rejects(pending, /cancelled/) |
| 42 | await runner.dispose(); await rejected; await assert.rejects(runner.run(params('two'), signal()), /stale/) |
| 43 | }) |
| 44 | test('deadline reaches broker cancellation without a second execution', async () => { |
| 45 | let remote; const runner = createHarnessModule({ request(_method, _params, supplied) { remote = supplied; return new Promise(() => {}) } }, owner) |
| 46 | await assert.rejects(runner.run(params('deadline', { deadline_ms: 5 }), signal()), /cancelled/); assert.equal(remote.aborted, true); await runner.dispose() |
| 47 | }) |
| 48 | test('runner refuses malformed and oversized output without truncating', () => { |
| 49 | for (const output of [{ success: true, stdout: 1, stderr: '' }, { success: true, stdout: 'x'.repeat(1024 * 1024 + 1), stderr: '' }, { success: true, stdout: '', stderr: 'x'.repeat(64 * 1024 + 1) }]) assert.throws(() => normalizeOutput(output), /invalid or oversized/) |
| 50 | }) |
| 51 | test('bounded pending operations cancel completely on disposal', async () => { |
| 52 | let count = 0; const runner = createHarnessModule({ request() { count++; return new Promise(() => {}) } }, owner) |
| 53 | const pending = Array.from({ length: 32 }, (_, i) => runner.run(params(String(i)), signal()).catch(error => error.message)) |
| 54 | await assert.rejects(runner.run(params('overflow'), signal()), /not admitted/); assert.equal(count, 32) |
| 55 | await runner.dispose(); assert.equal((await Promise.all(pending)).every(value => value === 'execution cancelled'), true) |
| 56 | }) |
| 57 |