fix(test): harden findInstalledFtsExtension for cross-OS filesystem quirks

Wrap the version-directory scan in try/catch so a transient FS error
(permission denial, an AV file lock on Windows, a directory vanishing
mid-scan) fails closed to null instead of throwing — matching the
original callers' contract, and safer across the Windows/macOS/Linux
CI matrix where these error modes differ.

Also drop the redundant USERPROFILE/HOME manual chain in
extension-binary-real.test.ts in favor of the repo's established
os.homedir() convention (already used ~15 other places here), which
Node resolves correctly per-OS and already honors env overrides.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Gergo Magyar 2026-07-21 06:14:58 +00:00
parent b751418985
commit 30ec68fa7a
2 changed files with 26 additions and 15 deletions

View file

@ -18,20 +18,27 @@ const MIN_VALID_FTS_EXTENSION_BYTES = 1024 * 1024;
* actually just resolved), or null when nothing is installed.
*/
export const findInstalledFtsExtension = (extensionRoot: string): string | null => {
if (!existsSync(extensionRoot)) return null;
let best: { path: string; mtimeMs: number } | null = null;
for (const versionEntry of readdirSync(extensionRoot)) {
const versionDir = join(extensionRoot, versionEntry);
if (!statSync(versionDir).isDirectory()) continue;
for (const platformEntry of readdirSync(versionDir)) {
const candidate = join(versionDir, platformEntry, 'fts', 'libfts.lbug_extension');
if (!existsSync(candidate)) continue;
const stat = statSync(candidate);
if (stat.size < MIN_VALID_FTS_EXTENSION_BYTES) continue;
if (!best || stat.mtimeMs > best.mtimeMs) best = { path: candidate, mtimeMs: stat.mtimeMs };
// Fail closed on any FS error (permission quirks, AV file locks on Windows,
// a directory vanishing mid-scan) — same contract as the callers this
// replaces: "not found" is a valid outcome, a thrown exception is not.
try {
if (!existsSync(extensionRoot)) return null;
let best: { path: string; mtimeMs: number } | null = null;
for (const versionEntry of readdirSync(extensionRoot)) {
const versionDir = join(extensionRoot, versionEntry);
if (!statSync(versionDir).isDirectory()) continue;
for (const platformEntry of readdirSync(versionDir)) {
const candidate = join(versionDir, platformEntry, 'fts', 'libfts.lbug_extension');
if (!existsSync(candidate)) continue;
const stat = statSync(candidate);
if (stat.size < MIN_VALID_FTS_EXTENSION_BYTES) continue;
if (!best || stat.mtimeMs > best.mtimeMs) best = { path: candidate, mtimeMs: stat.mtimeMs };
}
}
return best?.path ?? null;
} catch {
return null;
}
return best?.path ?? null;
};
export const FTS_UNAVAILABLE_NOTE =

View file

@ -46,10 +46,14 @@ function resolveLbugNative(): string | null {
return null;
}
/** The actual installed FTS extension binary for the running lbug version. */
/**
* The actual installed FTS extension binary for the running lbug version.
* `os.homedir()` already honors `$HOME` (POSIX) / `%USERPROFILE%` (Windows)
* the same resolution LadybugDB's native layer uses so it stays correct
* under the hermetic-home overrides other tests in this suite set via env vars.
*/
function resolveInstalledFtsExtension(): string | null {
const home = process.env.USERPROFILE ?? process.env.HOME ?? homedir();
return findInstalledFtsExtension(join(home, '.lbdb', 'extension'));
return findInstalledFtsExtension(join(homedir(), '.lbdb', 'extension'));
}
const lbugNative = resolveLbugNative();