test: keep review assertions tied to real failure paths

CodeRabbit flagged three non-blocking but valid review gaps: platform-specific mailbox errno checks, brittle UDS connection-failure message assertions, and missing AgentSummary reschedule proof after fork errors. This keeps the fixes narrow by tightening the affected assertions and adding a structured UDS connection error for tests to assert behavior instead of prose.

Constraint: PR #374 is a review follow-up and must not hide warnings, skip tests, or merge the PR.

Rejected: Matching the UDS failure message literal | preserves the brittle coupling CodeRabbit flagged.

Rejected: Asserting only that mailbox writes throw | would allow unrelated pre-path failures to pass.

Confidence: high

Scope-risk: narrow

Directive: Keep UDS connection-failure tests on structured error data, not display wording.

Tested: bun test src/services/AgentSummary/__tests__/agentSummary.test.ts src/utils/__tests__/teammateMailbox.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:
unraid
2026-04-27 15:54:13 +08:00
parent bc72dc2b09
commit 5ad3b316d5
4 changed files with 44 additions and 11 deletions

View File

@@ -33,6 +33,7 @@ describe('startAgentSummarization', () => {
let debugLogs: string[]
let loggedErrors: Error[]
let clearedHandles: unknown[]
let scheduledCount: number
function startTestSummarization(
dependencies: AgentSummaryDependencies = {},
@@ -81,8 +82,9 @@ describe('startAgentSummarization', () => {
if (typeof callback !== 'function') {
throw new Error('Expected timer callback')
}
scheduledCount += 1
scheduled = callback as () => void | Promise<void>
return 1 as unknown as ReturnType<typeof setTimeout>
return scheduledCount as unknown as ReturnType<typeof setTimeout>
}) as unknown as typeof setTimeout,
updateAgentSummary: (taskId: string, summary: string) => {
updateCalls.push({ taskId, summary })
@@ -101,6 +103,7 @@ describe('startAgentSummarization', () => {
debugLogs = []
loggedErrors = []
clearedHandles = []
scheduledCount = 0
})
test('summarizes bounded transcript once and skips unchanged fingerprints', async () => {
@@ -175,6 +178,7 @@ describe('startAgentSummarization', () => {
})
expect(typeof scheduled).toBe('function')
const initialScheduledCount = scheduledCount
await scheduled!()
expect(forkCalls).toEqual([])
@@ -182,6 +186,7 @@ describe('startAgentSummarization', () => {
expect(debugLogs).toContain(
'[AgentSummary] Skipping summary — poor mode active',
)
expect(scheduledCount).toBe(initialScheduledCount + 1)
})
test('logs summary errors and keeps the next timer owned by the summarizer', async () => {
@@ -193,10 +198,12 @@ describe('startAgentSummarization', () => {
})
expect(typeof scheduled).toBe('function')
const initialScheduledCount = scheduledCount
await scheduled!()
expect(loggedErrors).toEqual([error])
expect(updateCalls).toEqual([])
expect(scheduledCount).toBe(initialScheduledCount + 1)
})
test('stop clears the pending summary timer', () => {

View File

@@ -1,9 +1,10 @@
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises'
import { mkdtempSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import type { Message } from 'src/types/message.js'
import { getErrnoCode } from 'src/utils/errors.js'
import {
compactMailboxMessages,
getLastPeerDmSummary,
@@ -356,10 +357,16 @@ describe('teammate mailbox retention', () => {
'alpha',
).then(
() => undefined,
error => error as NodeJS.ErrnoException,
err => err,
)
expect(error?.code).toBe('EISDIR')
const code = getErrnoCode(error)
expect(code).toBeDefined()
if (code === undefined) {
throw new Error('Expected filesystem errno code')
}
expect(['EISDIR', 'EPERM', 'EACCES']).toContain(code)
expect((await stat(inboxPath)).isDirectory()).toBe(true)
})
test('readMailbox fails closed on corrupt mailbox content', async () => {

View File

@@ -227,11 +227,20 @@ describe('UDS inbox retention', () => {
JSON.stringify({ socketPath: path, authToken: 'test-token' }),
'utf-8',
)
const { sendToUdsSocket } = await import('../udsClient.js')
await expect(sendToUdsSocket(path, 'hello')).rejects.toThrow(
'Failed to connect to peer',
const { sendToUdsSocket, UdsPeerConnectionError } = await import(
'../udsClient.js'
)
const error = await sendToUdsSocket(path, 'hello').then(
() => undefined,
err => err,
)
expect(error).toBeInstanceOf(UdsPeerConnectionError)
if (!(error instanceof UdsPeerConnectionError)) {
throw new Error('Expected UDS peer connection error')
}
expect(error.socketPath).toBe(path)
expect(error.message).not.toContain('test-token')
})
test('sendUdsMessage fails closed before connecting without an auth token', async () => {

View File

@@ -36,6 +36,18 @@ export type PeerSession = {
alive: boolean
}
export class UdsPeerConnectionError extends Error {
readonly socketPath: string
readonly cause: unknown
constructor(socketPath: string, cause: unknown) {
super(`Failed to connect to peer at ${socketPath}: ${errorMessage(cause)}`)
this.name = 'UdsPeerConnectionError'
this.socketPath = socketPath
this.cause = cause
}
}
// ---------------------------------------------------------------------------
// Session directory
// ---------------------------------------------------------------------------
@@ -237,9 +249,7 @@ export async function sendToUdsSocket(
maxFrameBytes: MAX_UDS_FRAME_BYTES,
onSettled: finish,
formatSocketError: err =>
new Error(
`Failed to connect to peer at ${target.socketPath}: ${errorMessage(err)}`,
),
new UdsPeerConnectionError(target.socketPath, err),
})
conn.setTimeout(5000, () => {
finish(new Error('Connection timed out'))