mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 00:35:51 +00:00
test: enforce structured UDS timeout failures
CodeRabbit's follow-up surfaced a real consistency gap: UDS send socket errors used UdsPeerConnectionError while response timeouts still rejected a generic Error. Timeouts now use the same structured peer failure contract, and the test exercises that path through a short explicit timeout instead of waiting for the production default. The AgentSummary unchanged-fingerprint test now also asserts that the second unchanged tick does not log errors, preserving the existing behavior checks without changing production scheduling semantics. Constraint: Keep the production timeout default at 5000ms while allowing tests to exercise the timeout path quickly. Rejected: Leave timeout failures as generic Error | callers would need separate handling for the same peer connection failure class. Confidence: high Scope-risk: narrow Directive: Keep UDS send timeout and socket-error branches on the same structured error contract. Tested: bun test src/services/AgentSummary/__tests__/agentSummary.test.ts src/utils/__tests__/udsMessaging.test.ts Tested: bunx tsc --noEmit --pretty false Tested: bun run lint Tested: bun run test:all Tested: bun test --coverage --coverage-reporter lcov --coverage-dir coverage Tested: bun run build Tested: bun run build:vite Not-tested: GitHub-hosted CodeRabbit refresh until pushed.
This commit is contained in:
@@ -134,6 +134,7 @@ describe('startAgentSummarization', () => {
|
|||||||
|
|
||||||
expect(forkCalls).toHaveLength(1)
|
expect(forkCalls).toHaveLength(1)
|
||||||
expect(updateCalls).toHaveLength(1)
|
expect(updateCalls).toHaveLength(1)
|
||||||
|
expect(loggedErrors).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('skips summarization when filtering leaves too little bounded context', async () => {
|
test('skips summarization when filtering leaves too little bounded context', async () => {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
writeFile,
|
writeFile,
|
||||||
} from 'node:fs/promises'
|
} from 'node:fs/promises'
|
||||||
import { createHash } from 'node:crypto'
|
import { createHash } from 'node:crypto'
|
||||||
import { createConnection, createServer } from 'node:net'
|
import { createConnection, createServer, type Socket } from 'node:net'
|
||||||
import { dirname, join } from 'node:path'
|
import { dirname, join } from 'node:path'
|
||||||
import { tmpdir } from 'node:os'
|
import { tmpdir } from 'node:os'
|
||||||
import {
|
import {
|
||||||
@@ -243,6 +243,64 @@ describe('UDS inbox retention', () => {
|
|||||||
expect(error.message).not.toContain('test-token')
|
expect(error.message).not.toContain('test-token')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('udsClient send reports response timeouts as peer connection errors', async () => {
|
||||||
|
const path = socketPath('uds-client-timeout')
|
||||||
|
const capabilityDir = join(tempConfigDir, 'messaging-capabilities')
|
||||||
|
const capabilityName = `${createHash('sha256').update(path).digest('hex')}.json`
|
||||||
|
await mkdir(capabilityDir, { recursive: true, mode: 0o700 })
|
||||||
|
await writeFile(
|
||||||
|
join(capabilityDir, capabilityName),
|
||||||
|
JSON.stringify({ socketPath: path, authToken: 'test-token' }),
|
||||||
|
'utf-8',
|
||||||
|
)
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
await mkdir(dirname(path), { recursive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
const sockets = new Set<Socket>()
|
||||||
|
const receiver = createServer(socket => {
|
||||||
|
sockets.add(socket)
|
||||||
|
socket.on('close', () => {
|
||||||
|
sockets.delete(socket)
|
||||||
|
})
|
||||||
|
socket.on('data', () => undefined)
|
||||||
|
})
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
receiver.on('error', reject)
|
||||||
|
receiver.listen(path, () => resolve())
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { sendToUdsSocket, UdsPeerConnectionError } = await import(
|
||||||
|
'../udsClient.js'
|
||||||
|
)
|
||||||
|
|
||||||
|
const error = await sendToUdsSocket(path, 'hello', 50).then(
|
||||||
|
() => undefined,
|
||||||
|
err => err,
|
||||||
|
)
|
||||||
|
expect(error).toBeInstanceOf(UdsPeerConnectionError)
|
||||||
|
if (!(error instanceof UdsPeerConnectionError)) {
|
||||||
|
throw new Error('Expected UDS peer connection timeout error')
|
||||||
|
}
|
||||||
|
expect(error.socketPath).toBe(path)
|
||||||
|
expect(error.cause).toBeInstanceOf(Error)
|
||||||
|
if (!(error.cause instanceof Error)) {
|
||||||
|
throw new Error('Expected timeout cause')
|
||||||
|
}
|
||||||
|
expect(error.cause.message).toBe('Connection timed out')
|
||||||
|
expect(error.message).not.toContain('test-token')
|
||||||
|
} finally {
|
||||||
|
for (const socket of sockets) {
|
||||||
|
socket.destroy()
|
||||||
|
}
|
||||||
|
await closeServer(receiver)
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
await unlink(path).catch(() => undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('sendUdsMessage fails closed before connecting without an auth token', async () => {
|
test('sendUdsMessage fails closed before connecting without an auth token', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
sendUdsMessage(socketPath('no-auth-token'), { type: 'text', data: 'x' }),
|
sendUdsMessage(socketPath('no-auth-token'), { type: 'text', data: 'x' }),
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ export async function isPeerAlive(
|
|||||||
export async function sendToUdsSocket(
|
export async function sendToUdsSocket(
|
||||||
targetSocketPath: string,
|
targetSocketPath: string,
|
||||||
message: string | Record<string, unknown>,
|
message: string | Record<string, unknown>,
|
||||||
|
timeoutMs = 5000,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { parseUdsTarget } = await import('./udsMessaging.js')
|
const { parseUdsTarget } = await import('./udsMessaging.js')
|
||||||
const target = parseUdsTarget(targetSocketPath)
|
const target = parseUdsTarget(targetSocketPath)
|
||||||
@@ -252,8 +253,13 @@ export async function sendToUdsSocket(
|
|||||||
formatSocketError: err =>
|
formatSocketError: err =>
|
||||||
new UdsPeerConnectionError(target.socketPath, err),
|
new UdsPeerConnectionError(target.socketPath, err),
|
||||||
})
|
})
|
||||||
conn.setTimeout(5000, () => {
|
conn.setTimeout(timeoutMs, () => {
|
||||||
finish(new Error('Connection timed out'))
|
finish(
|
||||||
|
new UdsPeerConnectionError(
|
||||||
|
target.socketPath,
|
||||||
|
new Error('Connection timed out'),
|
||||||
|
),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user