From b18c0393ae434dd31ffb11e439b0eda3e0894b14 Mon Sep 17 00:00:00 2001 From: Eve Date: Fri, 24 Apr 2026 10:43:16 +0800 Subject: [PATCH] test: add subagent watchdog test skeleton --- scripts/test_subagent_delivery_watchdog.mjs | 127 ++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 scripts/test_subagent_delivery_watchdog.mjs diff --git a/scripts/test_subagent_delivery_watchdog.mjs b/scripts/test_subagent_delivery_watchdog.mjs new file mode 100644 index 0000000..889d63d --- /dev/null +++ b/scripts/test_subagent_delivery_watchdog.mjs @@ -0,0 +1,127 @@ +#!/usr/bin/env node + +import assert from 'node:assert/strict'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; + +const ROOT_DIR = path.resolve(import.meta.dirname, '..'); +const WATCHDOG_SCRIPT = path.join(ROOT_DIR, 'scripts', 'subagent_delivery_watchdog.mjs'); + +function createFixtureRunner() { + const fixtureRoot = mkdtempSync(path.join(tmpdir(), 'subagent-watchdog-test-')); + + function writeFixture(name, content) { + const fixturePath = path.join(fixtureRoot, name); + const body = typeof content === 'string' ? content : JSON.stringify(content, null, 2); + writeFileSync(fixturePath, body); + return fixturePath; + } + + function runWatchdog(args = [], options = {}) { + const result = spawnSync(process.execPath, [WATCHDOG_SCRIPT, ...args], { + cwd: ROOT_DIR, + encoding: 'utf8', + ...options, + }); + + return { + status: result.status, + signal: result.signal, + stdout: result.stdout ?? '', + stderr: result.stderr ?? '', + error: result.error ?? null, + }; + } + + function cleanup() { + rmSync(fixtureRoot, { recursive: true, force: true }); + } + + return { + fixtureRoot, + writeFixture, + runWatchdog, + cleanup, + }; +} + +const tests = []; + +function test(name, fn) { + tests.push({ name, fn }); +} + +function printResult(prefix, name, detail = '') { + const suffix = detail ? ` ${detail}` : ''; + process.stdout.write(`${prefix} ${name}${suffix}\n`); +} + +test('fixture runner can invoke watchdog skeleton with a generated input file', () => { + const runner = createFixtureRunner(); + + try { + const inputPath = runner.writeFixture('dispatch.json', { + runId: 'fixture-run-001', + childSessionKey: 'session:test', + }); + + const result = runner.runWatchdog(['--compact', '--input', inputPath]); + + assert.equal(result.status, 0, `expected zero exit status, got ${result.status}\n${result.stderr}`); + assert.equal(result.stderr, ''); + + const payload = JSON.parse(result.stdout); + assert.equal(payload.ok, true); + assert.equal(payload.tool, 'subagent_delivery_watchdog'); + assert.equal(payload.result.status, 'not_implemented'); + assert.equal(payload.input.path, inputPath); + assert.equal(payload.input.exists, true); + } finally { + runner.cleanup(); + } +}); + +test('fixture runner exposes missing-input behavior for future fail-first cases', () => { + const runner = createFixtureRunner(); + + try { + const missingPath = path.join(runner.fixtureRoot, 'missing.json'); + const result = runner.runWatchdog(['--compact', '--input', missingPath]); + + assert.equal(result.status, 0, `expected zero exit status, got ${result.status}\n${result.stderr}`); + + const payload = JSON.parse(result.stdout); + assert.equal(payload.ok, true); + assert.equal(payload.input.path, missingPath); + assert.equal(payload.input.exists, false); + assert.equal(payload.result.status, 'not_implemented'); + } finally { + runner.cleanup(); + } +}); + +function main() { + let passed = 0; + + for (const { name, fn } of tests) { + try { + fn(); + passed += 1; + printResult('PASS', name); + } catch (error) { + printResult('FAIL', name, error instanceof Error ? `- ${error.message}` : `- ${String(error)}`); + if (error instanceof Error && error.stack) { + process.stderr.write(`${error.stack}\n`); + } + process.exitCode = 1; + } + } + + const failed = tests.length - passed; + process.stdout.write(`\nSummary: ${passed} passed, ${failed} failed, ${tests.length} total\n`); +} + +main();