Files
orca/src/main/codex/codex-session-bridge.test.ts
T
slashdevcorpse f80704cc60 [perf] Speed up CLI launch through Orca
Speed up Windows CLI launch by delivering short startup commands through shell args, falling back to stdin for oversized commands, and moving Codex historical session bridging into an incremental background task. Includes review fixes for Windows symlink and WSL test reliability.
2026-06-18 22:21:48 -07:00

368 lines
12 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
existsSync,
lstatSync,
mkdtempSync,
mkdirSync,
readFileSync,
readlinkSync,
rmSync,
symlinkSync,
writeFileSync
} from 'node:fs'
import type * as NodeFs from 'node:fs'
import type * as NodeOs from 'node:os'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
const { homedirMock } = vi.hoisted(() => ({
homedirMock: vi.fn<() => string>()
}))
const { fsMockState } = vi.hoisted(() => ({
fsMockState: {
failLink: false,
failSymlink: false,
fakeSymlinks: new Map<string, string>()
}
}))
function isWindowsSymlinkPrivilegeError(error: unknown): boolean {
if (process.platform !== 'win32' || !(error instanceof Error)) {
return false
}
const errorWithCode = error as Error & { code?: string }
return errorWithCode.code === 'EPERM' || errorWithCode.code === 'EACCES'
}
vi.mock('node:fs', async () => {
const actual = await vi.importActual<typeof NodeFs>('node:fs')
return {
...actual,
linkSync: (...args: Parameters<typeof actual.linkSync>) => {
if (fsMockState.failLink) {
throw new Error('hardlink disabled for test')
}
return actual.linkSync(...args)
},
lstatSync: ((path: Parameters<typeof actual.lstatSync>[0]) => {
const stat = actual.lstatSync(path)
if (!fsMockState.fakeSymlinks.has(String(path))) {
return stat
}
// Why: Windows often disallows file symlink creation outside Developer
// Mode; tests simulate the link metadata while keeping a real path.
return { ...stat, isSymbolicLink: () => true }
}) as typeof actual.lstatSync,
readlinkSync: ((path: Parameters<typeof actual.readlinkSync>[0]) => {
const fakeTarget = fsMockState.fakeSymlinks.get(String(path))
if (fakeTarget !== undefined) {
return fakeTarget
}
return actual.readlinkSync(path)
}) as typeof actual.readlinkSync,
renameSync: (...args: Parameters<typeof actual.renameSync>) => {
const [oldPath, newPath] = args
const fakeTarget = fsMockState.fakeSymlinks.get(String(oldPath))
const result = actual.renameSync(...args)
if (fakeTarget !== undefined) {
fsMockState.fakeSymlinks.delete(String(oldPath))
fsMockState.fakeSymlinks.set(String(newPath), fakeTarget)
} else {
fsMockState.fakeSymlinks.delete(String(newPath))
}
return result
},
rmSync: (...args: Parameters<typeof actual.rmSync>) => {
fsMockState.fakeSymlinks.delete(String(args[0]))
return actual.rmSync(...args)
},
symlinkSync: (...args: Parameters<typeof actual.symlinkSync>) => {
if (fsMockState.failSymlink) {
throw new Error('symlink disabled for test')
}
try {
return actual.symlinkSync(...args)
} catch (error) {
if (!isWindowsSymlinkPrivilegeError(error)) {
throw error
}
const [target, path] = args
fsMockState.fakeSymlinks.set(String(path), String(target))
actual.writeFileSync(path, '', 'utf-8')
}
}
}
})
vi.mock('node:os', async () => {
const actual = await vi.importActual<typeof NodeOs>('node:os')
return {
...actual,
homedir: homedirMock
}
})
import {
syncSystemCodexSessionsIntoManagedHome,
syncSystemCodexSessionsIntoManagedHomeIncrementally
} from './codex-session-bridge'
let fakeHomeDir: string
let userDataDir: string
let previousUserDataPath: string | undefined
function getSystemCodexHomePath(): string {
return join(fakeHomeDir, '.codex')
}
function getRuntimeCodexHomePath(): string {
return join(userDataDir, 'codex-runtime-home', 'home')
}
function normalizeLinkTarget(linkTarget: string): string {
return process.platform === 'win32'
? linkTarget.replace(/^\\\\\?\\/, '').toLowerCase()
: linkTarget
}
function expectResourceLinked(targetPath: string, sourcePath: string): void {
if (lstatSync(targetPath).isSymbolicLink()) {
expect(normalizeLinkTarget(readlinkSync(targetPath))).toBe(normalizeLinkTarget(sourcePath))
return
}
expect(lstatSync(targetPath).ino).toBe(lstatSync(sourcePath).ino)
}
function writeLegacyCopyMarker(relativePath: string, sourcePath: string, targetPath: string): void {
const sourceStat = lstatSync(sourcePath)
const targetStat = lstatSync(targetPath)
const markerPath = join(getRuntimeCodexHomePath(), '.orca-session-copies', `${relativePath}.json`)
mkdirSync(dirname(markerPath), { recursive: true })
writeFileSync(
markerPath,
`${JSON.stringify(
{
sourcePath,
sourceSize: sourceStat.size,
sourceMtimeMs: sourceStat.mtimeMs,
targetSize: targetStat.size,
targetMtimeMs: targetStat.mtimeMs
},
null,
2
)}\n`,
'utf-8'
)
}
beforeEach(() => {
fsMockState.failLink = false
fsMockState.failSymlink = false
fsMockState.fakeSymlinks.clear()
fakeHomeDir = mkdtempSync(join(tmpdir(), 'orca-codex-session-home-'))
userDataDir = mkdtempSync(join(tmpdir(), 'orca-codex-session-user-data-'))
previousUserDataPath = process.env.ORCA_USER_DATA_PATH
process.env.ORCA_USER_DATA_PATH = userDataDir
homedirMock.mockReturnValue(fakeHomeDir)
mkdirSync(getSystemCodexHomePath(), { recursive: true })
})
afterEach(() => {
rmSync(fakeHomeDir, { recursive: true, force: true })
rmSync(userDataDir, { recursive: true, force: true })
if (previousUserDataPath === undefined) {
delete process.env.ORCA_USER_DATA_PATH
} else {
process.env.ORCA_USER_DATA_PATH = previousUserDataPath
}
vi.clearAllMocks()
})
describe('syncSystemCodexSessionsIntoManagedHome', () => {
it('bridges system Codex session jsonl files into the managed runtime home', () => {
const systemSessionPath = join(
getSystemCodexHomePath(),
'sessions',
'2026',
'05',
'26',
'rollout-old.jsonl'
)
mkdirSync(dirname(systemSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"type":"session_meta","id":"old"}\n', 'utf-8')
writeFileSync(
join(getSystemCodexHomePath(), 'sessions', '2026', '05', '26', 'scratch.txt'),
'not a session\n',
'utf-8'
)
syncSystemCodexSessionsIntoManagedHome()
const runtimeSessionPath = join(
getRuntimeCodexHomePath(),
'sessions',
'2026',
'05',
'26',
'rollout-old.jsonl'
)
expect(readFileSync(runtimeSessionPath, 'utf-8')).toBe('{"type":"session_meta","id":"old"}\n')
expect(lstatSync(runtimeSessionPath).isSymbolicLink()).toBe(false)
expectResourceLinked(runtimeSessionPath, systemSessionPath)
expect(
existsSync(join(getRuntimeCodexHomePath(), 'sessions', '2026', '05', '26', 'scratch.txt'))
).toBe(false)
})
it('falls back to symlinks when hardlinks are unavailable', () => {
fsMockState.failLink = true
const systemSessionPath = join(
getSystemCodexHomePath(),
'sessions',
'2026',
'05',
'26',
'rollout-symlink-fallback.jsonl'
)
mkdirSync(dirname(systemSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"id":"system"}\n', 'utf-8')
syncSystemCodexSessionsIntoManagedHome()
const runtimeSessionPath = join(
getRuntimeCodexHomePath(),
'sessions',
'2026',
'05',
'26',
'rollout-symlink-fallback.jsonl'
)
expect(lstatSync(runtimeSessionPath).isSymbolicLink()).toBe(true)
expect(normalizeLinkTarget(readlinkSync(runtimeSessionPath))).toBe(
normalizeLinkTarget(systemSessionPath)
)
})
it('does not overwrite runtime-owned session files', () => {
const relativeSessionPath = join('sessions', '2026', '05', '26', 'rollout-conflict.jsonl')
const systemSessionPath = join(getSystemCodexHomePath(), relativeSessionPath)
const runtimeSessionPath = join(getRuntimeCodexHomePath(), relativeSessionPath)
mkdirSync(dirname(systemSessionPath), { recursive: true })
mkdirSync(dirname(runtimeSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"id":"system"}\n', 'utf-8')
writeFileSync(runtimeSessionPath, '{"id":"runtime"}\n', 'utf-8')
syncSystemCodexSessionsIntoManagedHome()
expect(readFileSync(runtimeSessionPath, 'utf-8')).toBe('{"id":"runtime"}\n')
})
it('replaces existing symlink bridges with hardlinks', () => {
const relativeSessionPath = join('sessions', '2026', '05', '26', 'rollout-symlink.jsonl')
const systemSessionPath = join(getSystemCodexHomePath(), relativeSessionPath)
const runtimeSessionPath = join(getRuntimeCodexHomePath(), relativeSessionPath)
mkdirSync(dirname(systemSessionPath), { recursive: true })
mkdirSync(dirname(runtimeSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"id":"system"}\n', 'utf-8')
symlinkSync(
systemSessionPath,
runtimeSessionPath,
process.platform === 'win32' ? 'file' : undefined
)
syncSystemCodexSessionsIntoManagedHome()
expect(lstatSync(runtimeSessionPath).isSymbolicLink()).toBe(false)
expectResourceLinked(runtimeSessionPath, systemSessionPath)
})
it('does not create independent session copies when file links are unavailable', () => {
fsMockState.failLink = true
fsMockState.failSymlink = true
const systemSessionPath = join(
getSystemCodexHomePath(),
'sessions',
'2026',
'05',
'26',
'rollout-unlinked.jsonl'
)
mkdirSync(dirname(systemSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"id":"system"}\n', 'utf-8')
syncSystemCodexSessionsIntoManagedHome()
expect(
existsSync(
join(getRuntimeCodexHomePath(), 'sessions', '2026', '05', '26', 'rollout-unlinked.jsonl')
)
).toBe(false)
})
it('replaces unchanged legacy copied sessions with links', () => {
const relativeSessionPath = join('2026', '05', '26', 'rollout-legacy.jsonl')
const systemSessionPath = join(getSystemCodexHomePath(), 'sessions', relativeSessionPath)
const runtimeSessionPath = join(getRuntimeCodexHomePath(), 'sessions', relativeSessionPath)
mkdirSync(dirname(systemSessionPath), { recursive: true })
mkdirSync(dirname(runtimeSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"id":"legacy"}\n', 'utf-8')
writeFileSync(runtimeSessionPath, '{"id":"legacy"}\n', 'utf-8')
writeLegacyCopyMarker(relativeSessionPath, systemSessionPath, runtimeSessionPath)
syncSystemCodexSessionsIntoManagedHome()
expect(readFileSync(runtimeSessionPath, 'utf-8')).toBe('{"id":"legacy"}\n')
expectResourceLinked(runtimeSessionPath, systemSessionPath)
})
it('preserves unchanged legacy copied sessions when relinking fails', () => {
const relativeSessionPath = join('2026', '05', '26', 'rollout-legacy-unlinked.jsonl')
const systemSessionPath = join(getSystemCodexHomePath(), 'sessions', relativeSessionPath)
const runtimeSessionPath = join(getRuntimeCodexHomePath(), 'sessions', relativeSessionPath)
mkdirSync(dirname(systemSessionPath), { recursive: true })
mkdirSync(dirname(runtimeSessionPath), { recursive: true })
writeFileSync(systemSessionPath, '{"id":"legacy"}\n', 'utf-8')
writeFileSync(runtimeSessionPath, '{"id":"legacy"}\n', 'utf-8')
writeLegacyCopyMarker(relativeSessionPath, systemSessionPath, runtimeSessionPath)
fsMockState.failLink = true
fsMockState.failSymlink = true
syncSystemCodexSessionsIntoManagedHome()
expect(lstatSync(runtimeSessionPath).isSymbolicLink()).toBe(false)
expect(readFileSync(runtimeSessionPath, 'utf-8')).toBe('{"id":"legacy"}\n')
})
it('incrementally bridges session files without requiring the synchronous launch path', async () => {
const systemSessionRoot = join(getSystemCodexHomePath(), 'sessions', '2026', '06', '18')
mkdirSync(systemSessionRoot, { recursive: true })
for (let index = 0; index < 5; index += 1) {
writeFileSync(
join(systemSessionRoot, `rollout-incremental-${index}.jsonl`),
`{"id":"incremental-${index}"}\n`,
'utf-8'
)
}
const summary = await syncSystemCodexSessionsIntoManagedHomeIncrementally({
batchSize: 2,
yieldMs: 0
})
expect(summary).toEqual({ scannedFiles: 5, linkedFiles: 5 })
for (let index = 0; index < 5; index += 1) {
const systemSessionPath = join(systemSessionRoot, `rollout-incremental-${index}.jsonl`)
const runtimeSessionPath = join(
getRuntimeCodexHomePath(),
'sessions',
'2026',
'06',
'18',
`rollout-incremental-${index}.jsonl`
)
expectResourceLinked(runtimeSessionPath, systemSessionPath)
}
})
})