test(bash-local): wait for process readiness
This commit is contained in:
@@ -90,8 +90,8 @@ describe('LocalBashExecutor.run', () => {
|
|||||||
|
|
||||||
it('kill escalation uses the configured graceMs (a TERM-trapping task dies by SIGKILL)', async () => {
|
it('kill escalation uses the configured graceMs (a TERM-trapping task dies by SIGKILL)', async () => {
|
||||||
const { bash } = await setup() // setup pins graceMs: 200 via config
|
const { bash } = await setup() // setup pins graceMs: 200 via config
|
||||||
const task = bash.start(bash.resolve({ command: 'trap \'\' TERM; sleep 60' }))
|
const task = bash.start(bash.resolve({ command: 'trap \'\' TERM; echo ready; while :; do sleep 60 & wait $!; done' }))
|
||||||
await new Promise(resolve => setTimeout(resolve, 100))
|
await readUntil(bash, task.id, 'ready\n')
|
||||||
bash.kill(task.id)
|
bash.kill(task.id)
|
||||||
await task.done
|
await task.done
|
||||||
expect(task.signal).toBe('SIGKILL')
|
expect(task.signal).toBe('SIGKILL')
|
||||||
|
|||||||
@@ -56,6 +56,20 @@ async function waitForStdout(running: RunningBash, expected: string, timeoutMs =
|
|||||||
throw new Error(`stdout did not include ${JSON.stringify(expected)} after ${timeoutMs}ms`)
|
throw new Error(`stdout did not include ${JSON.stringify(expected)} after ${timeoutMs}ms`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function waitForPidFile(path: string, timeoutMs = 5_000): Promise<number> {
|
||||||
|
const deadline = Date.now() + timeoutMs
|
||||||
|
while (Date.now() < deadline) {
|
||||||
|
try {
|
||||||
|
const pid = Number(readFileSync(path, 'utf8').trim())
|
||||||
|
if (Number.isSafeInteger(pid) && pid > 0) return pid
|
||||||
|
} catch {
|
||||||
|
// The child shell has not written the pid file yet.
|
||||||
|
}
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 20))
|
||||||
|
}
|
||||||
|
throw new Error(`pid file ${path} was not written after ${timeoutMs}ms`)
|
||||||
|
}
|
||||||
|
|
||||||
describe('runBash', () => {
|
describe('runBash', () => {
|
||||||
it('captures stdout on success', async () => {
|
it('captures stdout on success', async () => {
|
||||||
const result = await runBash(spec('echo hello')).done
|
const result = await runBash(spec('echo hello')).done
|
||||||
@@ -107,7 +121,7 @@ describe('runBash', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('escalates to SIGKILL when SIGTERM is trapped', async () => {
|
it('escalates to SIGKILL when SIGTERM is trapped', async () => {
|
||||||
const running = runBash(spec('trap \'\' TERM; echo ready; sleep 60', { graceMs: 200 }))
|
const running = runBash(spec('trap \'\' TERM; echo ready; while :; do sleep 60 & wait $!; done', { graceMs: 200 }))
|
||||||
await waitForStdout(running, 'ready\n')
|
await waitForStdout(running, 'ready\n')
|
||||||
running.kill()
|
running.kill()
|
||||||
const result = await running.done
|
const result = await running.done
|
||||||
@@ -119,8 +133,7 @@ describe('runBash', () => {
|
|||||||
// group must take the sleep down with bash.
|
// group must take the sleep down with bash.
|
||||||
const pidFile = join(spillDir, `grandchild-${Date.now()}.pid`)
|
const pidFile = join(spillDir, `grandchild-${Date.now()}.pid`)
|
||||||
const running = runBash(spec(`sleep 60 & echo $! > ${pidFile}; wait`))
|
const running = runBash(spec(`sleep 60 & echo $! > ${pidFile}; wait`))
|
||||||
await new Promise(resolve => setTimeout(resolve, 300))
|
const grandchild = await waitForPidFile(pidFile)
|
||||||
const grandchild = Number(readFileSync(pidFile, 'utf8').trim())
|
|
||||||
expect(grandchild).toBeGreaterThan(0)
|
expect(grandchild).toBeGreaterThan(0)
|
||||||
|
|
||||||
running.kill()
|
running.kill()
|
||||||
|
|||||||
Reference in New Issue
Block a user