// Tests for the filesystem preflight (lib/preflight.js).
//
// pgh requires a POSIX filesystem with unix domain sockets + symlinks
// (hardlinks are a soft dedup optimization). The preflight probes a dir and
// reports capability so `pgh init` can fail fast on exfat/NTFS/FAT or the WSL
// /mnt Windows-drive bridge instead of crashing mid-materialize / on UDS bind.
//
// We can't mount an unsupported fs in CI, so these tests assert the happy path
// on the real (POSIX) test fs and the report/format shape.
import test from 'brittle'
import { mkdtempSync, rmSync } from '#node:fs'
import { tmpdir } from '#node:os'
import { join } from '#node:path'
import { checkFilesystem, formatReport } from '../lib/preflight.js'
test('checkFilesystem: passes on a normal POSIX fs', async (t) => {
const dir = mkdtempSync(join(tmpdir(), 'pgh-preflight-'))
try {
const r = await checkFilesystem(dir)
t.ok(r.ok, 'ok on POSIX fs')
t.ok(r.symlink, 'symlinks supported')
t.ok(r.unixSocket, 'unix sockets supported')
t.ok(r.hardlink, 'hardlinks supported')
t.is(r.errors.length, 0, 'no errors')
} finally {
rmSync(dir, { recursive: true, force: true })
}
})
test('checkFilesystem: cleans up its scratch dir', async (t) => {
const { readdirSync } = await import('#node:fs')
const dir = mkdtempSync(join(tmpdir(), 'pgh-preflight-'))
try {
await checkFilesystem(dir)
const leftovers = readdirSync(dir).filter((n) => n.startsWith('.pgh-fscheck-'))
t.is(leftovers.length, 0, 'no .pgh-fscheck- scratch dir left behind')
} finally {
rmSync(dir, { recursive: true, force: true })
}
})
test('checkFilesystem: does not flag a normal dir as a Windows drive', async (t) => {
const dir = mkdtempSync(join(tmpdir(), 'pgh-preflight-'))
try {
const r = await checkFilesystem(dir)
t.absent(r.onWindowsDrive, 'tmpdir is not under /mnt')
} finally {
rmSync(dir, { recursive: true, force: true })
}
})
test('formatReport: ok=true report renders all three capabilities', (t) => {
const r = { ok: true, hardlink: true, symlink: true, unixSocket: true, onWindowsDrive: false, errors: [] }
const out = formatReport(r, '/some/store')
t.ok(out.includes('unix sockets: ok'), 'unix sockets line')
t.ok(out.includes('symlinks: ok'), 'symlinks line')
t.ok(out.includes('hardlinks: ok'), 'hardlinks line')
t.absent(out.includes('required'), 'no required-marker when ok')
})
test('formatReport: failures are marked required, hardlink-loss noted, /mnt warned', (t) => {
const r = {
ok: false,
hardlink: false,
symlink: false,
unixSocket: false,
onWindowsDrive: true,
errors: ['symlinks not supported (EPERM)', 'unix domain sockets not supported']
}
const out = formatReport(r, '/mnt/c/store')
t.ok(out.includes('unix sockets: NO'), 'unix sockets NO')
t.ok(out.includes('required'), 'required marker present for missing hard reqs')
t.ok(out.includes('dedup disabled'), 'hardlink loss noted')
t.ok(out.includes('Windows drive'), 'windows-drive warning present')
})