Files
orca/src/shared/ripgrep-search-diagnostics.test.ts
T
Neil be4cea1584 perf(wsl): search Windows-drive projects with host ripgrep (#27690)
* perf(wsl): run ripgrep on the Windows host for drive-path projects

A project stored on a Windows drive (C:\...) with the WSL runtime selected
ran quick open, file-path search, content search and Markdown listing
through wsl.exe and the Linux rg reading /mnt/c over drvfs. rg only reads
files, so it has no git index whose stat cache two writers could thrash;
the host binary reads NTFS directly.

Measured on a 21.6k-file clone on C: (Windows 11, Ubuntu-24.04):
  content search  WSL rg 3.5 s  -> host rg.exe 0.19 s
  file listing    WSL rg 0.14 s + ~65 ms wsl.exe spawn -> host 0.03 s

Git routing is intentionally unchanged: alternating Windows git and WSL git
on the same index forced a full ~250 s rehash on the next WSL git status.

WSL UNC roots and non-drive roots keep their existing routing.

* fix(search): keep host rg results whole when files only WSL can open exist

Windows rg cannot open a 'nul' file, Win32-trimmed names, or WSL-created
symlinks; treat those per-file errors as skipped rather than failing or
truncating the search, and keep symlink-following scans in WSL.
2026-10-11 19:35:46 -07:00

77 lines
3.2 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { createAccumulator } from './text-search'
import { RipgrepSearchDiagnostics } from './ripgrep-search-diagnostics'
describe('ripgrep search diagnostics', () => {
it('reports invalid regex diagnostics instead of an empty successful search', () => {
const diagnostics = new RipgrepSearchDiagnostics()
diagnostics.append(Buffer.from('regex parse error: unclosed character class'))
expect(diagnostics.failure(2, null, createAccumulator())?.message).toContain(
'unclosed character class'
)
})
it('limits retained diagnostics even for large stderr chunks', () => {
const diagnostics = new RipgrepSearchDiagnostics()
diagnostics.append('x'.repeat(100_000))
diagnostics.append('must not be retained')
const error = diagnostics.failure(2, null, createAccumulator())
expect(error?.message).toBe(`Search failed (2): ${'x'.repeat(4096)}`)
})
it('marks permission-error results as incomplete', () => {
const acc = createAccumulator()
acc.totalMatches = 1
expect(new RipgrepSearchDiagnostics().failure(2, null, acc)).toBeNull()
expect(acc.truncated).toBe(true)
})
it('distinguishes a killed search from intentional truncation', () => {
const diagnostics = new RipgrepSearchDiagnostics()
const acc = createAccumulator()
expect(diagnostics.failure(null, 'SIGTERM', acc)).toBeInstanceOf(Error)
acc.truncated = true
expect(diagnostics.failure(null, 'SIGTERM', acc)).toBeNull()
})
it.each([0, 1])('accepts normal exit %i without inventing truncation', (code) => {
const acc = createAccumulator()
expect(new RipgrepSearchDiagnostics().failure(code, null, acc)).toBeNull()
expect(acc.truncated).toBe(false)
})
describe('skippable per-path OS errors', () => {
const skippable = new Set([1, 1920])
it('does not fail or truncate a search whose only errors are unopenable paths', () => {
const diagnostics = new RipgrepSearchDiagnostics(skippable)
diagnostics.append('rg: .\\nul: Incorrect function. (os error 1)\r\nrg: .\\li')
diagnostics.append('nk: The file cannot be accessed by the system. (os error 1920)')
const acc = createAccumulator()
acc.totalMatches = 3
expect(diagnostics.failure(2, null, acc)).toBeNull()
expect(acc.truncated).toBe(false)
expect(diagnostics.failure(2, null, createAccumulator())).toBeNull()
})
it('still fails on any other diagnostic', () => {
const diagnostics = new RipgrepSearchDiagnostics(skippable)
diagnostics.append('rg: .\\nul: Incorrect function. (os error 1)\n')
diagnostics.append('rg: ./secret: Access is denied. (os error 5)\n')
expect(diagnostics.failure(2, null, createAccumulator())).toBeInstanceOf(Error)
})
it('fails when exit 2 left no diagnostic to classify', () => {
expect(
new RipgrepSearchDiagnostics(skippable).failure(2, null, createAccumulator())
).toBeInstanceOf(Error)
})
it('keeps the default policy when no errors are skippable', () => {
const diagnostics = new RipgrepSearchDiagnostics()
diagnostics.append('rg: .\\nul: Incorrect function. (os error 1)\n')
expect(diagnostics.failure(2, null, createAccumulator())).toBeInstanceOf(Error)
})
})
})