Files
hermes-agent/apps/desktop/electron/backend-exit.test.ts
brooklyn! 768e5c2af3 fix(desktop): serialize idle reclamation and release slots on real exit
Serve foreground queue promotions and concurrent opens without interrupting backend work. Park retired scopes and keep failed-stop generations fenced until exit.

Co-authored-by: Nikolas de Hor <nikolasdehor79@gmail.com>
Co-authored-by: Mark Sheppard <mark@orchardstreetpress.com>
Co-authored-by: chelsealong <chelsealong@126.com>
2026-09-17 00:34:50 -05:00

58 lines
1.6 KiB
TypeScript

import assert from 'node:assert/strict'
import { EventEmitter } from 'node:events'
import { test, vi } from 'vitest'
import { waitForBackendExit } from './backend-child'
test('backend exit escalation remains bounded when no exit or close arrives', async () => {
vi.useFakeTimers()
try {
const child = Object.assign(new EventEmitter(), { exitCode: null, signalCode: null, kill: vi.fn() })
const waiting = waitForBackendExit(child, { forceKillProcessTree: () => {} }, 20)
const outcome = waiting.then(
() => null,
error => error
)
await vi.advanceTimersByTimeAsync(1020)
assert.match(String(await outcome), /did not exit/)
assert.equal(child.exitCode, null)
assert.equal(child.signalCode, null)
assert.equal(child.kill.mock.calls.length, 1)
assert.equal(child.kill.mock.calls[0][0], 'SIGKILL')
assert.equal(child.listenerCount('exit'), 0)
assert.equal(vi.getTimerCount(), 0)
} finally {
vi.useRealTimers()
}
})
test('a failed escalation is not evidence that the child exited', async () => {
vi.useFakeTimers()
try {
const child = Object.assign(new EventEmitter(), {
exitCode: null,
signalCode: null,
kill: () => {
throw new Error('signal denied')
}
})
const outcome = waitForBackendExit(child, { forceKillProcessTree: () => {} }, 20).then(
() => null,
error => error
)
await vi.advanceTimersByTimeAsync(1020)
assert.match(String(await outcome), /did not exit/)
assert.equal(child.listenerCount('exit'), 0)
assert.equal(vi.getTimerCount(), 0)
} finally {
vi.useRealTimers()
}
})