fix false missing Hermes CLI detection after deployment
Build / build (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s

This commit is contained in:
2026-10-24 20:59:08 +08:00
parent 05a6fbfbae
commit a54913efd2
14 changed files with 317 additions and 41 deletions
+47
View File
@@ -16,6 +16,7 @@ type LoadHealthControllerOptions = {
bridgeReadinessError?: Error
managerError?: Error
runtimeStateError?: Error
cliProbe?: ReturnType<typeof vi.fn>
}
const defaultBridgeReadiness = {
@@ -65,6 +66,12 @@ async function loadHealthController(options: LoadHealthControllerOptions = {}) {
isDockerContainer: () => options.isDocker === true,
}))
const cliProbe = options.cliProbe || vi.fn().mockResolvedValue({ available: true, reason: 'ready' })
vi.doMock('../../packages/server/src/services/hermes/hermes-process', () => ({
probeHermesCli: cliProbe,
resolveHermesBin: () => '/opt/hermes/bin/hermes',
}))
const health = await import('../../packages/server/src/controllers/health')
return {
@@ -303,3 +310,43 @@ describe('health controller version metadata', () => {
})
})
describe('CLI status cache', () => {
afterEach(() => { vi.useRealTimers(); vi.resetModules() })
it('coalesces concurrent requests and allows an explicit recheck after failure', async () => {
let finish!: (value: any) => void
const probe = vi.fn().mockReturnValueOnce(new Promise(resolve => { finish = resolve }))
.mockResolvedValue({ available: true, reason: 'ready' })
const { hermesCliStatus } = await loadHealthController({ cliProbe: probe })
const first = createMockCtx()
const second = createMockCtx()
const pending = [hermesCliStatus(first), hermesCliStatus(second)]
expect(probe).toHaveBeenCalledOnce()
finish({ available: false, reason: 'timeout' })
await Promise.all(pending)
expect(first.body).toMatchObject({ available: false, reason: 'timeout' })
expect(second.body).toEqual(first.body)
await hermesCliStatus(createMockCtx())
expect(probe).toHaveBeenCalledOnce()
const retry = { ...createMockCtx(), query: { refresh: '1' } }
await hermesCliStatus(retry)
expect(retry.body).toMatchObject({ available: true, reason: 'ready' })
expect(probe).toHaveBeenCalledTimes(2)
})
it('expires failures quickly and starts successful cache lifetime after the probe completes', async () => {
vi.useFakeTimers()
const probe = vi.fn().mockResolvedValueOnce({ available: false, reason: 'permission_denied' })
.mockImplementationOnce(() => new Promise(resolve => setTimeout(() => resolve({ available: true, reason: 'ready' }), 8000)))
const { hermesCliStatus } = await loadHealthController({ cliProbe: probe })
await hermesCliStatus(createMockCtx())
await vi.advanceTimersByTimeAsync(5001)
const pending = hermesCliStatus(createMockCtx())
await vi.advanceTimersByTimeAsync(8000)
await pending
await vi.advanceTimersByTimeAsync(29000)
await hermesCliStatus(createMockCtx())
expect(probe).toHaveBeenCalledTimes(2)
})
})