fix(tests): adapt spill replay to unified shell execution

This commit is contained in:
Yichen Jiang committed 2026-09-09 14:46:41 +08:00
1 parent ab6dacc80e
commit dd7ea38578
4 files changed
+34 -22

No files matched your search

+5 -5
View File
@@ -40,24 +40,24 @@ it.skipIf(process.platform === 'win32')('resolves the exact spill verifier, reta
await adapter
const command = 'file="' + saved.locator + '"' + "; grep -Fq request/header \"$file\" && grep -Fq session_event_search \"$file\" && printf 'SPILL_CANONICAL_OK\\n'"
const spec = ctx.shell.resolve({ command })
const output = await ctx.shell.run(spec)
const output = await ctx.shell.execute(spec).result()
expect(output.timedOut).toBe(false)
expect(output.exitCode).toBe(0)
expect(output.stdout.text).toBe('SPILL_CANONICAL_OK\n')
expect(spec.command).toBe(command)
const other = await ctx.shell.run(ctx.shell.resolve({ command: 'printf ordinary; exit 7' }))
const other = await ctx.shell.execute(ctx.shell.resolve({ command: 'printf ordinary; exit 7' })).result()
expect(other.exitCode).toBe(7)
expect(other.stdout.text).toBe('ordinary')
const unmatched = await ctx.shell.run(ctx.shell.resolve({ command: command + '; exit 9' }))
const unmatched = await ctx.shell.execute(ctx.shell.resolve({ command: command + '; exit 9' })).result()
expect(unmatched.exitCode).toBe(9)
expect(unmatched.stderr.text).toContain('No such file')
const physical = ctx.fs.processPath(await ctx.fs.resolve(saved.locator))
await rm(physical)
const missing = await ctx.shell.run(spec)
const missing = await ctx.shell.execute(spec).result()
expect(missing.exitCode).not.toBe(0)
expect(missing.stdout.text).toBe('')
await adapter.dispose()
const restored = await ctx.shell.run(spec)
const restored = await ctx.shell.execute(spec).result()
expect(restored.exitCode).not.toBe(0)
expect(restored.stderr.text).toContain(saved.locator)
} finally {
+4
View File
@@ -44,15 +44,19 @@ it.each([false, true])('keeps concurrent physical spill files private while reta
expect(target.displayPath).toBe(ref.locator)
const physicalPath = ctx.fs.processPath(target)
expect(physicalPath.startsWith(await realpath(root))).toBe(true)
expect(await realpath(ctx.fs.processPathFromHostPath(ref.locator)!)).toBe(physicalPath)
expect(await readFile(physicalPath, 'utf8')).toBe(content)
expect(await ctx.fs.readText(target)).toBe(content)
await expect(ctx.fs.resolve(join(locatorRoot, 'missing.txt'))).rejects.toThrow('not saved by this run')
expect(() => ctx.fs.processPathFromHostPath(join(locatorRoot, 'missing.txt'))).toThrow('not saved by this run')
const ordinary = join(root, 'ordinary.txt')
await writeFile(ordinary, 'ordinary')
expect(ctx.fs.processPathFromHostPath(ordinary)).toBe(ordinary)
expect(await ctx.fs.readText(await ctx.fs.resolve(ordinary))).toBe('ordinary')
await fork.dispose()
const restored = await ctx.fs.resolve(ref.locator)
expect(ctx.fs.processPath(restored)).not.toBe(physicalPath)
expect(ctx.fs.processPathFromHostPath(ref.locator)).toBe(ref.locator)
expect(await ctx.fs.stat(restored)).toBeUndefined()
return { root, physicalPath, locator: ref.locator, content }
}))
+17 -10
View File
@@ -1,4 +1,4 @@
/** Fixture-only logical locators over real local spill files; preview budgets retain recorded path lengths. */
/** Fixture-only logical locators for filesystem and subprocess reads of real spill files; preview budgets retain recorded path lengths. */
import type { Context } from '@deepseek-ai/cordis'
import { join, relative, resolve, sep } from 'node:path'
import type { SpillLocator } from '@deepseek-ai/dsh-spill'
@@ -28,6 +28,17 @@ export function apply(ctx: Context, config: Config): void {
const saveText = store.saveText
// oxlint-disable-next-line typescript/unbound-method -- preserve method identity for restoration; calls bind the receiver.
const resolvePath = fs.resolve
// oxlint-disable-next-line typescript/unbound-method -- preserve method identity for restoration; calls bind the receiver.
const processPathFromHostPath = fs.processPathFromHostPath
const mappedPath = (path: string): string => {
const live = paths.get(path)
if (live !== undefined) return live
if (path.startsWith(locatorRoot + sep)) {
throw new Error('snapshot spill locator was not saved by this run')
}
return path
}
ctx.effect(() => {
store.saveText = async (input) => {
const saved = await saveText.call(store, input)
@@ -40,19 +51,15 @@ export function apply(ctx: Context, config: Config): void {
return { ...saved, locator }
}
fs.resolve = async (path, opts) => {
const live = paths.get(path)
if (live !== undefined) {
const target = await resolvePath.call(fs, live, opts)
return { ...target, displayPath: path }
}
if (path.startsWith(locatorRoot + sep)) {
throw new Error('snapshot spill locator was not saved by this run')
}
return resolvePath.call(fs, path, opts)
const live = mappedPath(path)
const target = await resolvePath.call(fs, live, opts)
return live === path ? target : { ...target, displayPath: path }
}
fs.processPathFromHostPath = path => processPathFromHostPath.call(fs, mappedPath(path))
return () => {
store.saveText = saveText
fs.resolve = resolvePath
fs.processPathFromHostPath = processPathFromHostPath
paths.clear()
}
})
@@ -6,16 +6,17 @@ export const inject = ['shell', 'fs']
export function apply(ctx) {
const shell = ctx.shell
const fs = ctx.fs
const run = shell.run
const execute = shell.execute
const suffix = "; grep -Fq request/header \"$file\" && grep -Fq session_event_search \"$file\" && printf 'SPILL_CANONICAL_OK\\n'"
ctx.effect(() => {
shell.run = async (spec) => {
shell.execute = (spec) => {
const match = /^file="([^"]+)"/.exec(spec.command)
if (match === null || spec.command !== match[0] + suffix) return run.call(shell, spec)
const target = await fs.resolve(match[1])
const path = fs.processPath(target).replaceAll("'", "'\"'\"'")
return run.call(shell, { ...spec, command: "file='" + path + "'" + suffix })
if (match === null || spec.command !== match[0] + suffix) return execute.call(shell, spec)
const physical = fs.processPathFromHostPath(match[1])
if (physical === undefined) throw new Error('snapshot spill path is not readable by the shell')
const path = physical.replaceAll("'", "'\"'\"'")
return execute.call(shell, { ...spec, command: "file='" + path + "'" + suffix })
}
return () => { shell.run = run }
return () => { shell.execute = execute }
})
}