test(acp-snapshot): cover pre-fallback Windows exit state

Model the requested signal setting a child termination marker before the launcher begins fallback handling. The regression proves close drains inherited stdio and propagates the original process error without sending a redundant SIGKILL.

This complements the post-check fallback-refusal race and restores the launcher's required 100% per-file statement and branch coverage.
This commit is contained in:
Tianyi Cui
2026-07-19 12:53:41 +08:00
parent c660048759
commit e9aac53fde

View File

@@ -179,6 +179,29 @@ describe('runScenario', () => {
}
})
it('preserves the child error when the requested signal sets an exit marker', async () => {
const { dir } = await scenario({})
const launched = launchAcpTestAgent({ agent: AGENT, cwd: dir })
await launched.spawned
const childFailure = Object.assign(new Error('signal failed as the child exited'), { code: 'EPERM' })
const originalKill = launched.child.kill.bind(launched.child)
const kill = vi.spyOn(launched.child, 'kill').mockImplementation((signal) => {
expect(signal).toBe('SIGTERM')
originalKill('SIGKILL')
Object.defineProperty(launched.child, 'signalCode', { configurable: true, enumerable: true, writable: true, value: 'SIGTERM' })
return true
})
try {
launched.child.emit('error', childFailure)
await expect(launched.close('SIGTERM')).rejects.toBe(childFailure)
expect(kill).toHaveBeenCalledOnce()
} finally {
kill.mockRestore()
if (launched.child.exitCode === null && launched.child.signalCode === null) originalKill('SIGKILL')
}
})
it('preserves the child error when fallback refusal races with an exit marker', async () => {
const { dir } = await scenario({})
const launched = launchAcpTestAgent({ agent: AGENT, cwd: dir })