test(fs): close abort/concurrency/observed coverage gaps + with-key e2e
Behavioral gaps from the coverage audit (line coverage was already 100%; these
close BEHAVIOR gaps):
- fs-local: service-level writeText/editText pre-abort → FS_ABORTED (file
unchanged); concurrent guarded-write race and mixed write-vs-edit race (one
wins, one FS_STALE_VERSION, locks released); edit→edit version refresh at the
provider; the replaceIfVersion post-write version matches a fresh stat. fsio:
a mid-stream abort → FS_ABORTED (previously only pre-abort was covered).
- fs-policy: the agent-without-session owner rung ({agent:{}} → no owner →
createIfAbsent / FS_NOT_OBSERVED); fs/write-intent first-wins (symmetric to
the existing edit-intent test).
- tool-fs: abort-through-the-tool for read/write/edit (isError FS_ABORTED, file
unchanged); a deterministic tool-tier concurrent-edit race via a shared read;
the throwing-fs/observed contract (a throwing listener surfaces as isError but
the mutation already hit disk); the replace_all edit message; parseReadArgs
rejects fractional/NaN offset and zero/negative limit.
- dsh-fs: FsError chains a cause through ErrorOptions.
New with-key e2e (packages/fs/tool-fs/tests/fs-tools.e2e.ts, self-skips without
DEEPSEEK_API_KEY): a real model drives the real read/write/edit tools to create
→ read → edit a file, verified on disk; a second test proves a relative path
resolves against the per-session cwd (factory meta.cwd) not config.cwd. Booted
via a plain tests/harness.ts. Added dsh-agent-loop + dsh-llm-deepseek devDeps.
This commit is contained in:
@@ -222,6 +222,22 @@ describe('streamWholeText', () => {
|
||||
await writeFile(file, 'one\ntwo')
|
||||
expect(await collect(streamWholeText(localTarget(file), new AbortController().signal))).toBe('one\ntwo')
|
||||
})
|
||||
|
||||
it('translates a mid-stream abort into FS_ABORTED', async () => {
|
||||
// A multi-chunk file so the stream yields more than once; abort after the
|
||||
// first chunk and assert the structured code, not a raw AbortError.
|
||||
const file = join(dir, 'big.txt')
|
||||
await writeFile(file, 'x'.repeat(256 * 1024))
|
||||
const ac = new AbortController()
|
||||
const run = async (): Promise<void> => {
|
||||
let seen = 0
|
||||
for await (const _chunk of streamWholeText(localTarget(file), ac.signal)) {
|
||||
seen += 1
|
||||
if (seen === 1) ac.abort()
|
||||
}
|
||||
}
|
||||
await expect(run()).rejects.toMatchObject({ code: 'FS_ABORTED' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('writeFileAtomic — temp-file safety', () => {
|
||||
|
||||
Reference in New Issue
Block a user