Skip to content

Commit 3c1f350

Browse files
committed
test: diagnose Windows owner release preflight
1 parent fafab6f commit 3c1f350

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

tests/hooks.test.mjs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ async function runHook(script, input, env = {}, options = {}) {
4848
});
4949
}
5050

51+
async function probePidFromChild(pid) {
52+
return new Promise((resolvePromise, reject) => {
53+
const child = spawn(process.execPath, ['-e', `try { process.kill(${JSON.stringify(pid)}, 0); process.stdout.write(JSON.stringify({ ok: true })); } catch (error) { process.stdout.write(JSON.stringify({ ok: false, code: error?.code ?? null })); }`], { stdio: ['ignore', 'pipe', 'ignore'] }); let stdout = '';
54+
child.stdout.on('data', (chunk) => { stdout += chunk; }); child.once('error', reject); child.once('exit', () => resolvePromise(JSON.parse(stdout)));
55+
});
56+
}
57+
5158
async function workspace() {
5259
const cwd = await mkdtemp(join(tmpdir(), 'zpc-hooks-workspace-'));
5360
const data = await mkdtemp(join(tmpdir(), 'zpc-hooks-data-'));
@@ -283,7 +290,7 @@ test('SessionEnd releases only its broker owner sessions and lets the idle broke
283290
assert.equal(ended.code, 0);
284291
const owners = JSON.parse(await readFile(ownershipPath, 'utf8'));
285292
let releaseDiagnostic = 'owner release succeeded without diagnostic collection';
286-
if (JSON.stringify(owners.sessions) !== JSON.stringify({ 'zcode-b': ownerIdForSession('b') })) { const callsAtFailure = (await readFile(record, 'utf8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line)); const ownershipAfter = await stat(ownershipPath); const healthyAfterFailure = await probeBrokerHealth(identity, 250); releaseDiagnostic = `release-stage ${JSON.stringify({ hookElapsedMs, stopObserved: callsAtFailure.some((call) => call.method === 'session/stop' && call.params?.sessionId === 'zcode-a'), ownerStoreReplaced: ownershipAfter.ino !== ownershipBefore.ino || ownershipAfter.mtimeMs !== ownershipBefore.mtimeMs, healthyAfterFailure, hookCode: ended.code, hookDiagnostic: ended.stderr.trim() || null })}`; }
293+
if (JSON.stringify(owners.sessions) !== JSON.stringify({ 'zcode-b': ownerIdForSession('b') })) { const callsAtFailure = (await readFile(record, 'utf8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line)); const ownershipAfter = await stat(ownershipPath); const healthyAfterFailure = await probeBrokerHealth(identity, 250); const childPidProbe = await probePidFromChild(identity.pid); let ownedJobsProbe; try { ownedJobsProbe = { count: (await createStateStore({ dataRoot: data }).listOwnedJobs(cwd, 'a')).length }; } catch (error) { ownedJobsProbe = { error: { code: error?.code ?? null, category: error?.category ?? null, details: error?.details ?? null } }; } releaseDiagnostic = `release-stage ${JSON.stringify({ hookElapsedMs, stopObserved: callsAtFailure.some((call) => call.method === 'session/stop' && call.params?.sessionId === 'zcode-a'), ownerStoreReplaced: ownershipAfter.ino !== ownershipBefore.ino || ownershipAfter.mtimeMs !== ownershipBefore.mtimeMs, healthyAfterFailure, childPidProbe, ownedJobsProbe, hookCode: ended.code, hookDiagnostic: ended.stderr.trim() || null })}`; }
287294
assert.deepEqual(owners.sessions, { 'zcode-b': ownerIdForSession('b') }, releaseDiagnostic);
288295
const calls = (await readFile(record, 'utf8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
289296
assert.ok(calls.some((call) => call.method === 'session/stop' && call.params?.sessionId === 'zcode-a'));

0 commit comments

Comments
 (0)