test(daemon): pin the connection/hello shutdown barriers with a mutation-killing test

The shuttingDown guards in handleConnection and handleFirstMessage had no
test that fails when either is deleted — the existing coverage drove
routeRequest directly or never sent a hello. Raise only the barrier flag
while the listener still accepts, then assert a pre-admitted socket's late
valid hello and a brand-new connection are both destroyed unregistered.
Verified: deleting either guard fails this test.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Brennan Benson
2026-07-10 17:36:42 -07:00
co-authored by Orca
parent 9052b315d2
commit 1c57de85be
+37
View File
@@ -55,6 +55,7 @@ type DaemonServerPrivate = {
}
>
idleExit: { isArmed(): boolean } | null
shuttingDown: boolean
routeRequest(clientId: string, request: DaemonRequest): Promise<unknown>
}
@@ -687,6 +688,42 @@ describe('DaemonServer', () => {
expect(daemon.clients.size).toBe(0)
})
it('destroys sockets that connect or hello after the shutdown barrier is raised', async () => {
// Why raise only the flag: while the listener is still accepting, the
// handleConnection/handleFirstMessage barriers are the only defense
// against a socket becoming a client on a half-shut server.
await startServer()
const daemon = server as unknown as DaemonServerPrivate
// Admitted before the barrier, hello still unsent.
const preBarrier = connect(socketPath)
await new Promise<void>((resolve) => preBarrier.once('connect', resolve))
const preBarrierClosed = new Promise<void>((resolve) => preBarrier.once('close', resolve))
preBarrier.on('error', () => {})
daemon.shuttingDown = true
// A valid late hello must be destroyed unanswered, never registered.
preBarrier.write(
encodeNdjson({
type: 'hello',
version: PROTOCOL_VERSION,
token: readFileSync(tokenPath, 'utf-8').trim(),
clientId: 'late-hello',
role: 'control'
})
)
await preBarrierClosed
expect(daemon.clients.size).toBe(0)
// A brand-new connection after the barrier is destroyed on arrival.
const postBarrier = connect(socketPath)
const postBarrierClosed = new Promise<void>((resolve) => postBarrier.once('close', resolve))
postBarrier.on('error', () => {})
await postBarrierClosed
expect(daemon.clients.size).toBe(0)
})
it('never fires while a session is alive and exits after the last session ends', async () => {
// Why seed the session before start(): start() is what arms the
// countdown, so with a session already present the timer never arms at