diff --git a/scripts/ad-hoc/codemod-rm-maxretries.mjs b/scripts/ad-hoc/codemod-rm-maxretries.mjs new file mode 100644 index 0000000000..e7ac344656 --- /dev/null +++ b/scripts/ad-hoc/codemod-rm-maxretries.mjs @@ -0,0 +1,101 @@ +#!/usr/bin/env node +/** + * One-shot codemod (#11966): give every recursive temp-dir removal in tests the retry + * options Node already supports, so a WAL/backup/worker still writing into the directory + * turns into a retried delete instead of a red shard: + * + * rmSync(dir, { recursive: true, force: true }) + * → rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }) + * + * Applies to `rmSync(`, `fs.rmSync(`, `rm(` / `fs.rm(` / `fs.promises.rm(` (async) and + * `rmdirSync(` calls whose option object literal contains `recursive: true` and no + * `maxRetries`. Only the option object is touched — call sites, assertions and imports are + * left as they are. Usage: node scripts/ad-hoc/codemod-rm-maxretries.mjs [dir=tests] + */ +import fs from "node:fs"; +import path from "node:path"; + +const root = process.argv[2] || "tests"; +const CALL = /\b(?:fs\.promises\.|fsp\.|fs\.|promises\.)?(?:rmSync|rmdirSync|rm)\(/g; +let files = 0; +let sites = 0; + +function walk(dir, out = []) { + for (const e of fs.readdirSync(dir, { withFileTypes: true })) { + const p = path.join(dir, e.name); + if (e.isDirectory()) { + if (e.name === "node_modules" || e.name === "fixtures") continue; + walk(p, out); + } else if (/\.(ts|tsx|mts|cts|js|mjs|cjs)$/.test(e.name)) out.push(p); + } + return out; +} + +// Find the closing brace of the option object literal that starts at `open`. +function objectEnd(src, open) { + let depth = 0; + for (let i = open; i < src.length; i++) { + const c = src[i]; + if (c === "{") depth++; + else if (c === "}") { + depth--; + if (depth === 0) return i; + } else if (c === '"' || c === "'" || c === "`") { + const q = c; + i++; + while (i < src.length && src[i] !== q) { + if (src[i] === "\\") i++; + i++; + } + } + } + return -1; +} + +for (const file of walk(root)) { + const src = fs.readFileSync(file, "utf8"); + let out = ""; + let last = 0; + let touched = 0; + for (const m of src.matchAll(CALL)) { + const callStart = m.index + m[0].length; + // Locate the option object: the first `{` before the call's closing paren at depth 0. + let depth = 0; + let objOpen = -1; + for (let i = callStart; i < src.length; i++) { + const c = src[i]; + if (c === "(" || c === "[") depth++; + else if (c === ")" || c === "]") { + if (depth === 0) break; + depth--; + } else if (c === "{" && depth === 0) { + objOpen = i; + break; + } + } + if (objOpen === -1) continue; + const objClose = objectEnd(src, objOpen); + if (objClose === -1) continue; + const obj = src.slice(objOpen, objClose + 1); + if (!/\brecursive:\s*true\b/.test(obj) || /\bmaxRetries\b/.test(obj)) continue; + // Insert before the closing brace, respecting an existing trailing comma / newline. + const inner = obj.slice(1, -1); + const trimmed = inner.replace(/\s+$/, ""); + const trailing = inner.slice(trimmed.length); + const sep = trimmed.endsWith(",") ? " " : ", "; + const multiline = /\n/.test(trailing); + const insert = multiline + ? `${trimmed}${trimmed.endsWith(",") ? "" : ","}\n${trailing.replace(/\n$/, "")} maxRetries: 5,\n retryDelay: 100,${trailing}` + : `${trimmed}${sep}maxRetries: 5, retryDelay: 100${trailing}`; + out += src.slice(last, objOpen + 1) + insert; + last = objClose; + touched++; + } + if (touched) { + out += src.slice(last); + fs.writeFileSync(file, out); + files++; + sites += touched; + } +} +console.log(`[codemod-rm-maxretries] ${sites} call site(s) in ${files} file(s) under ${root}`); diff --git a/tests/_setup/isolateDataDir.ts b/tests/_setup/isolateDataDir.ts index 528930d7c2..b1add14b89 100644 --- a/tests/_setup/isolateDataDir.ts +++ b/tests/_setup/isolateDataDir.ts @@ -33,7 +33,7 @@ if (!process.env.DATA_DIR) { // Best-effort cleanup so a long suite run does not leak hundreds of temp DBs. process.on("exit", () => { try { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore — the OS reaps its temp dir eventually. } diff --git a/tests/e2e/system-failover.test.ts b/tests/e2e/system-failover.test.ts index 5141fadb7f..175deab5b5 100644 --- a/tests/e2e/system-failover.test.ts +++ b/tests/e2e/system-failover.test.ts @@ -366,7 +366,7 @@ test.after(async () => { await serverA.stop(); await serverB.stop(); core.closeDbInstance(); - await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true }); + await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("primary healthy: request routes to Server A only", async () => { diff --git a/tests/integration/_chatPipelineHarness.ts b/tests/integration/_chatPipelineHarness.ts index 3eb7c2fb72..c154255914 100644 --- a/tests/integration/_chatPipelineHarness.ts +++ b/tests/integration/_chatPipelineHarness.ts @@ -286,7 +286,7 @@ export async function createChatPipelineHarness(prefix) { clearSkillState(); await new Promise((resolve) => setTimeout(resolve, 20)); core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(testDataDir, { recursive: true }); initTranslators(); } @@ -300,7 +300,7 @@ export async function createChatPipelineHarness(prefix) { clearSkillState(); resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } async function seedConnection(provider: string, overrides: SeedConnectionOverrides = {}) { diff --git a/tests/integration/agent-bridge-bypass-flow.test.ts b/tests/integration/agent-bridge-bypass-flow.test.ts index 9abe58e3b5..e16f208658 100644 --- a/tests/integration/agent-bridge-bypass-flow.test.ts +++ b/tests/integration/agent-bridge-bypass-flow.test.ts @@ -24,7 +24,7 @@ const DEFAULT_PATTERNS = [".bank.", ".gov.", "okta.com", "auth0.com"]; function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,11 @@ test.beforeEach(() => { }); test.after(() => { - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch { /* noop */ } + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch { + /* noop */ + } }); // ── POST patterns ────────────────────────────────────────────────────────── @@ -48,7 +52,10 @@ test("POST /bypass: stores user patterns", async () => { }) ); assert.equal(res.status, 200); - const body = await res.json() as { ok: boolean; patterns: Array<{ pattern: string; source: string }> }; + const body = (await res.json()) as { + ok: boolean; + patterns: Array<{ pattern: string; source: string }>; + }; assert.equal(body.ok, true); assert.ok(Array.isArray(body.patterns)); const userPatterns = body.patterns.filter((p) => p.source === "user"); @@ -64,7 +71,7 @@ test("POST /bypass: invalid body returns 400", async () => { }) ); assert.equal(res.status, 400); - const body = await res.json() as Record; + const body = (await res.json()) as Record; const errMsg = (body.error as Record)?.message as string; assert.ok(!errMsg.includes("at /"), "stack trace leaked in 400 error"); }); @@ -83,7 +90,7 @@ test("GET /bypass: shows default + user patterns", async () => { const res = await bypassRoute.GET(); assert.equal(res.status, 200); - const body = await res.json() as { patterns: Array<{ pattern: string; source: string }> }; + const body = (await res.json()) as { patterns: Array<{ pattern: string; source: string }> }; assert.ok(Array.isArray(body.patterns)); const sources = new Set(body.patterns.map((p) => p.source)); @@ -119,7 +126,10 @@ test("DELETE /bypass?pattern=X: removes a user pattern", async () => { }) ); assert.equal(deleteRes.status, 200); - const deleteBody = await deleteRes.json() as { ok: boolean; patterns: Array<{ pattern: string; source: string }> }; + const deleteBody = (await deleteRes.json()) as { + ok: boolean; + patterns: Array<{ pattern: string; source: string }>; + }; assert.equal(deleteBody.ok, true); // Verify it's gone @@ -142,19 +152,18 @@ test("DELETE /bypass: missing pattern param returns 400", async () => { }) ); assert.equal(res.status, 400); - const body = await res.json() as Record; + const body = (await res.json()) as Record; const errMsg = (body.error as Record)?.message as string; assert.ok(!errMsg.includes("at /"), "stack trace leaked in DELETE 400"); }); test("DELETE /bypass?pattern=X: no-op when pattern not in user list", async () => { const res = await bypassRoute.DELETE( - new Request( - "http://localhost/api/tools/agent-bridge/bypass?pattern=not-in-list.com", - { method: "DELETE" } - ) + new Request("http://localhost/api/tools/agent-bridge/bypass?pattern=not-in-list.com", { + method: "DELETE", + }) ); assert.equal(res.status, 200); - const body = await res.json() as { ok: boolean }; + const body = (await res.json()) as { ok: boolean }; assert.equal(body.ok, true); }); diff --git a/tests/integration/agent-bridge-cert-flow.test.ts b/tests/integration/agent-bridge-cert-flow.test.ts index ee26b9fade..717e66dae0 100644 --- a/tests/integration/agent-bridge-cert-flow.test.ts +++ b/tests/integration/agent-bridge-cert-flow.test.ts @@ -19,7 +19,8 @@ process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; const certRoute = await import("../../src/app/api/tools/agent-bridge/cert/route.ts"); const downloadRoute = await import("../../src/app/api/tools/agent-bridge/cert/download/route.ts"); -const regenerateRoute = await import("../../src/app/api/tools/agent-bridge/cert/regenerate/route.ts"); +const regenerateRoute = + await import("../../src/app/api/tools/agent-bridge/cert/regenerate/route.ts"); function certDir() { return path.join(TEST_DATA_DIR, "mitm"); @@ -30,7 +31,7 @@ function certFilePath() { } function resetCertDir() { - fs.rmSync(certDir(), { recursive: true, force: true }); + fs.rmSync(certDir(), { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(certDir(), { recursive: true }); } @@ -39,7 +40,11 @@ test.beforeEach(() => { }); test.after(() => { - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch { /* noop */ } + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch { + /* noop */ + } }); // ── GET /cert ───────────────────────────────────────────────────────────── @@ -47,7 +52,7 @@ test.after(() => { test("GET /cert: returns exists:false when no cert file", async () => { const res = await certRoute.GET(); assert.equal(res.status, 200); - const body = await res.json() as Record; + const body = (await res.json()) as Record; assert.equal(body.exists, false); assert.equal(body.trusted, false); assert.equal(body.path, null); @@ -59,7 +64,7 @@ test("GET /cert: returns exists:true when cert file present", async () => { const res = await certRoute.GET(); assert.equal(res.status, 200); - const body = await res.json() as Record; + const body = (await res.json()) as Record; assert.equal(body.exists, true); // trusted may be false in test env (no system store) assert.ok(typeof body.trusted === "boolean"); @@ -83,7 +88,7 @@ test("POST /cert: returns 404 when no cert file", async () => { }) ); assert.equal(res.status, 404); - const body = await res.json() as Record; + const body = (await res.json()) as Record; const errMsg = (body.error as Record)?.message as string; assert.ok(!errMsg.includes("at /"), "stack trace leaked in 404 error message"); }); @@ -106,7 +111,7 @@ MIIBpDCCAQ2gAwIBAgIUFakeMITMCertForTestingOnlyXX== // In test env: installCert may throw because the PEM is fake; we accept // either 200 (mocked) or 500 (real OS failure) — NOT a 500 with stack trace - const body = await res.json() as Record; + const body = (await res.json()) as Record; const errMsg = (body.error as Record)?.message as string | undefined; if (errMsg) { assert.ok(!errMsg.includes("at /"), "stack trace leaked in POST /cert error"); @@ -118,7 +123,7 @@ MIIBpDCCAQ2gAwIBAgIUFakeMITMCertForTestingOnlyXX== test("GET /cert/download: 404 when no cert file", async () => { const res = await downloadRoute.GET(); assert.equal(res.status, 404); - const body = await res.json() as Record; + const body = (await res.json()) as Record; const errMsg = (body.error as Record)?.message as string; assert.ok(!errMsg.includes("at /"), "stack trace leaked in download 404"); }); diff --git a/tests/integration/agent-bridge-mappings.test.ts b/tests/integration/agent-bridge-mappings.test.ts index 0dec4bb1e4..9c5d8773a6 100644 --- a/tests/integration/agent-bridge-mappings.test.ts +++ b/tests/integration/agent-bridge-mappings.test.ts @@ -18,13 +18,12 @@ process.env.DATA_DIR = TEST_DATA_DIR; process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; const core = await import("../../src/lib/db/core.ts"); -const mappingsRoute = await import( - "../../src/app/api/tools/agent-bridge/agents/[id]/mappings/route.ts" -); +const mappingsRoute = + await import("../../src/app/api/tools/agent-bridge/agents/[id]/mappings/route.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,18 +32,21 @@ test.beforeEach(() => { }); test.after(() => { - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch { /* noop */ } + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch { + /* noop */ + } }); // ── GET (empty) ──────────────────────────────────────────────────────────── test("GET /mappings: returns empty array for new agent", async () => { - const res = await mappingsRoute.GET( - new Request("http://localhost/"), - { params: { id: "copilot" } } - ); + const res = await mappingsRoute.GET(new Request("http://localhost/"), { + params: { id: "copilot" }, + }); assert.equal(res.status, 200); - const body = await res.json() as { mappings: unknown[] }; + const body = (await res.json()) as { mappings: unknown[] }; assert.ok(Array.isArray(body.mappings)); assert.equal(body.mappings.length, 0); }); @@ -66,17 +68,21 @@ test("PUT → GET round-trip: stores and retrieves mappings", async () => { { params: { id: "copilot" } } ); assert.equal(putRes.status, 200); - const putBody = await putRes.json() as { ok: boolean; mappings: Array<{ agent_id: string; source_model: string; target_model: string }> }; + const putBody = (await putRes.json()) as { + ok: boolean; + mappings: Array<{ agent_id: string; source_model: string; target_model: string }>; + }; assert.equal(putBody.ok, true); assert.equal(putBody.mappings.length, 2); // GET reads back the same data - const getRes = await mappingsRoute.GET( - new Request("http://localhost/"), - { params: { id: "copilot" } } - ); + const getRes = await mappingsRoute.GET(new Request("http://localhost/"), { + params: { id: "copilot" }, + }); assert.equal(getRes.status, 200); - const getBody = await getRes.json() as { mappings: Array<{ source_model: string; target_model: string }> }; + const getBody = (await getRes.json()) as { + mappings: Array<{ source_model: string; target_model: string }>; + }; assert.equal(getBody.mappings.length, 2); const sources = getBody.mappings.map((m) => m.source_model).sort(); @@ -108,11 +114,10 @@ test("PUT: replaces all previous mappings", async () => { ); assert.equal(putRes.status, 200); - const getRes = await mappingsRoute.GET( - new Request("http://localhost/"), - { params: { id: "cursor" } } - ); - const body = await getRes.json() as { mappings: Array<{ source_model: string }> }; + const getRes = await mappingsRoute.GET(new Request("http://localhost/"), { + params: { id: "cursor" }, + }); + const body = (await getRes.json()) as { mappings: Array<{ source_model: string }> }; assert.equal(body.mappings.length, 1); assert.equal(body.mappings[0].source_model, "new-model"); }); @@ -136,7 +141,7 @@ test("PUT: empty mappings array clears all mappings", async () => { { params: { id: "zed" } } ); assert.equal(putRes.status, 200); - const body = await putRes.json() as { mappings: unknown[] }; + const body = (await putRes.json()) as { mappings: unknown[] }; assert.equal(body.mappings.length, 0); }); @@ -152,7 +157,7 @@ test("PUT: invalid body (missing mappings) returns 400", async () => { { params: { id: "antigravity" } } ); assert.equal(res.status, 400); - const body = await res.json() as Record; + const body = (await res.json()) as Record; const errMsg = (body.error as Record)?.message as string; assert.ok(!errMsg.includes("at /"), "stack trace leaked in 400 error"); }); @@ -183,10 +188,9 @@ test("PUT: error responses do not leak stack traces", async () => { }); test("GET: error responses do not leak stack traces", async () => { - const res = await mappingsRoute.GET( - new Request("http://localhost/"), - { params: { id: "antigravity" } } - ); + const res = await mappingsRoute.GET(new Request("http://localhost/"), { + params: { id: "antigravity" }, + }); const text = await res.text(); assert.ok(!text.includes("at /"), "stack trace leaked in GET /mappings response"); }); diff --git a/tests/integration/agent-bridge-routes.test.ts b/tests/integration/agent-bridge-routes.test.ts index 21b59b20c7..d4f18138ac 100644 --- a/tests/integration/agent-bridge-routes.test.ts +++ b/tests/integration/agent-bridge-routes.test.ts @@ -39,7 +39,7 @@ const routeGuard = await import("../../src/server/authz/routeGuard.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -49,7 +49,7 @@ test.beforeEach(() => { test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* noop */ } diff --git a/tests/integration/all-statuses-route.test.ts b/tests/integration/all-statuses-route.test.ts index 858b09e993..4c3924020c 100644 --- a/tests/integration/all-statuses-route.test.ts +++ b/tests/integration/all-statuses-route.test.ts @@ -39,7 +39,7 @@ async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Auth tests ──────────────────────────────────────────────────────────────── @@ -288,6 +288,6 @@ test("grok-build status uses GROK_HOME and returns its managed endpoint", async } finally { if (original === undefined) delete process.env.GROK_HOME; else process.env.GROK_HOME = original; - fs.rmSync(grokHome, { recursive: true, force: true }); + fs.rmSync(grokHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/integration/antigravity-projectid-discovery-persist-8491.test.ts b/tests/integration/antigravity-projectid-discovery-persist-8491.test.ts index e2d5b402b5..96dae418c3 100644 --- a/tests/integration/antigravity-projectid-discovery-persist-8491.test.ts +++ b/tests/integration/antigravity-projectid-discovery-persist-8491.test.ts @@ -25,14 +25,13 @@ process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-8491-antigravit const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const { AntigravityExecutor } = await import("../../open-sse/executors/antigravity.ts"); -const { clearAntigravityProjectCache } = await import( - "../../open-sse/services/antigravityProjectBootstrap.ts" -); +const { clearAntigravityProjectCache } = + await import("../../open-sse/services/antigravityProjectBootstrap.ts"); test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -91,7 +90,11 @@ test("#8491 PART A: runtime-discovered projectId must be persisted to the connec throw new Error(`Expected an envelope but got a ${result.status} Response`); } assert.equal(loadCodeAssistCalls, 1, "loadCodeAssist must be called to recover the project"); - assert.equal(result.project, DISCOVERED_PROJECT_ID, "the in-flight request uses the discovered id"); + assert.equal( + result.project, + DISCOVERED_PROJECT_ID, + "the in-flight request uses the discovered id" + ); const persisted = await providersDb.getProviderConnectionById(connection.id); assert.equal( diff --git a/tests/integration/api-keys.test.ts b/tests/integration/api-keys.test.ts index 0dfc6c3371..51e667e1bd 100644 --- a/tests/integration/api-keys.test.ts +++ b/tests/integration/api-keys.test.ts @@ -25,7 +25,7 @@ async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -63,7 +63,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("API keys routes require management auth when login protection is enabled", async () => { diff --git a/tests/integration/api-routes-critical.test.ts b/tests/integration/api-routes-critical.test.ts index 10534d2808..7f04c9245b 100644 --- a/tests/integration/api-routes-critical.test.ts +++ b/tests/integration/api-routes-critical.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { delete process.env.ENABLE_SOCKS5_PROXY; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -59,7 +59,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("critical routes: v1 management proxies covers auth, lookup, where-used, patch, and delete branches", async () => { diff --git a/tests/integration/audit-log-level-filter.test.ts b/tests/integration/audit-log-level-filter.test.ts index 2517da850d..d694fe44be 100644 --- a/tests/integration/audit-log-level-filter.test.ts +++ b/tests/integration/audit-log-level-filter.test.ts @@ -20,7 +20,7 @@ const auditRoute = await import("../../src/app/api/compliance/audit-log/route.ts function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** diff --git a/tests/integration/batch-e2e-rate-limit.test.ts b/tests/integration/batch-e2e-rate-limit.test.ts index beeaea7e62..3460efbf95 100644 --- a/tests/integration/batch-e2e-rate-limit.test.ts +++ b/tests/integration/batch-e2e-rate-limit.test.ts @@ -268,7 +268,7 @@ async function stopProcess(child: ReturnType) { async function removeDirWithRetry(dir: string) { for (let attempt = 0; attempt < 5; attempt++) { try { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error) { if (attempt === 4) throw error; diff --git a/tests/integration/chat-pipeline.test.ts b/tests/integration/chat-pipeline.test.ts index c17ce8eb6e..a7d441a9a5 100644 --- a/tests/integration/chat-pipeline.test.ts +++ b/tests/integration/chat-pipeline.test.ts @@ -373,7 +373,7 @@ async function resetStorage() { invalidateMemorySettingsCache(); await new Promise((resolve) => setTimeout(resolve, 20)); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); initTranslators(); } @@ -512,7 +512,7 @@ test.after(async () => { clearInflight(); resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("chat pipeline handles OpenAI passthrough with valid API key auth", async () => { diff --git a/tests/integration/chatcore-compression-integration.test.ts b/tests/integration/chatcore-compression-integration.test.ts index ab59dc0347..fd5038e711 100644 --- a/tests/integration/chatcore-compression-integration.test.ts +++ b/tests/integration/chatcore-compression-integration.test.ts @@ -28,7 +28,7 @@ async function resetStorage() { readCacheDb.invalidateDbCache(); await new Promise((resolve) => setTimeout(resolve, 20)); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -40,7 +40,7 @@ test.after(async () => { globalThis.fetch = originalFetch; core.closeDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/integration/chatcore-context-window-boundary.test.ts b/tests/integration/chatcore-context-window-boundary.test.ts index 9d48704a6f..5d517e8337 100644 --- a/tests/integration/chatcore-context-window-boundary.test.ts +++ b/tests/integration/chatcore-context-window-boundary.test.ts @@ -21,7 +21,7 @@ test.after(async () => { globalThis.fetch = originalFetch; core.closeDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/integration/cli-settings-codewhale.test.ts b/tests/integration/cli-settings-codewhale.test.ts index 8a98ff547b..ed843a1373 100644 --- a/tests/integration/cli-settings-codewhale.test.ts +++ b/tests/integration/cli-settings-codewhale.test.ts @@ -22,12 +22,13 @@ process.env.JWT_SECRET = "test-jwt-secret-codewhale"; const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); -const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/codewhale-settings/route.ts"); +const { GET, POST, DELETE } = + await import("../../src/app/api/cli-tools/codewhale-settings/route.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -126,7 +127,7 @@ test("codewhale-settings POST: writes primary ~/.codewhale/config.toml for a fre } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -173,7 +174,7 @@ test("codewhale-settings POST: syncs an existing legacy ~/.deepseek/config.toml" } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -201,7 +202,7 @@ test("codewhale-settings GET: falls back to legacy ~/.deepseek/config.toml when } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -238,7 +239,7 @@ test("codewhale-settings DELETE: removes primary and legacy config files", async } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -272,7 +273,7 @@ test("codewhale-settings route.ts: does not call exec() or spawn() directly", () test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-deepseek-tui.test.ts b/tests/integration/cli-settings-deepseek-tui.test.ts index 7bd6b83944..a4d7ffee60 100644 --- a/tests/integration/cli-settings-deepseek-tui.test.ts +++ b/tests/integration/cli-settings-deepseek-tui.test.ts @@ -8,9 +8,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-deepseek-tui-settings-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-deepseek-tui-settings-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = "test-api-key-secret-deepseek-tui"; process.env.JWT_SECRET = "test-jwt-secret-deepseek-tui"; @@ -18,14 +16,13 @@ process.env.JWT_SECRET = "test-jwt-secret-deepseek-tui"; const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); -const { GET, POST, DELETE } = await import( - "../../src/app/api/cli-tools/deepseek-tui-settings/route.ts" -); +const { GET, POST, DELETE } = + await import("../../src/app/api/cli-tools/deepseek-tui-settings/route.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -103,10 +100,7 @@ test("deepseek-tui-settings POST: writes config.toml with valid body", async () }), }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Unexpected status ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`); if (res.status === 200) { const body = await res.json(); assert.equal(body.success, true); @@ -120,7 +114,7 @@ test("deepseek-tui-settings POST: writes config.toml with valid body", async () } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -136,23 +130,20 @@ test("deepseek-tui-settings DELETE: removes config file", async () => { fs.mkdirSync(configDir, { recursive: true }); fs.writeFileSync( path.join(configDir, "config.toml"), - "# managed by OmniRoute (plan 14)\n[openai]\nbase_url = \"http://localhost:20128\"\n" + '# managed by OmniRoute (plan 14)\n[openai]\nbase_url = "http://localhost:20128"\n' ); const res = await DELETE( new Request("http://localhost/api/cli-tools/deepseek-tui-settings", { method: "DELETE" }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Expected 200/403/500, got ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Expected 200/403/500, got ${res.status}`); if (res.status === 200) { const body = await res.json(); assert.equal(body.success, true); } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -186,7 +177,7 @@ test("deepseek-tui-settings route.ts: does not call exec() or spawn() directly", test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-forge.test.ts b/tests/integration/cli-settings-forge.test.ts index 1398b03544..8cb4b7538e 100644 --- a/tests/integration/cli-settings-forge.test.ts +++ b/tests/integration/cli-settings-forge.test.ts @@ -19,14 +19,12 @@ const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); // Import route handlers -const { GET, POST, DELETE } = await import( - "../../src/app/api/cli-tools/forge-settings/route.ts" -); +const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/forge-settings/route.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -107,10 +105,7 @@ test("forge-settings POST: writes config.toml with valid body", async () => { ); // 200 = success; 403 = write guard active (test env); 500 = backup dir issue - assert.ok( - [200, 403, 500].includes(res.status), - `Unexpected status ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`); if (res.status === 200) { const body = await res.json(); @@ -126,7 +121,7 @@ test("forge-settings POST: writes config.toml with valid body", async () => { } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -143,16 +138,13 @@ test("forge-settings DELETE: removes config file when it exists", async () => { fs.mkdirSync(forgeDir, { recursive: true }); fs.writeFileSync( path.join(forgeDir, "config.toml"), - "# managed by OmniRoute (plan 14)\n[openai]\nbase_url = \"http://localhost:20128\"\n" + '# managed by OmniRoute (plan 14)\n[openai]\nbase_url = "http://localhost:20128"\n' ); const res = await DELETE( new Request("http://localhost/api/cli-tools/forge-settings", { method: "DELETE" }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Expected 200/403/500, got ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Expected 200/403/500, got ${res.status}`); if (res.status === 200) { const body = await res.json(); @@ -160,7 +152,7 @@ test("forge-settings DELETE: removes config file when it exists", async () => { } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -194,7 +186,7 @@ test("forge-settings route.ts: does not call exec() or spawn() directly", () => test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-grok-build.test.ts b/tests/integration/cli-settings-grok-build.test.ts index 3353d3602a..8ab679d9c2 100644 --- a/tests/integration/cli-settings-grok-build.test.ts +++ b/tests/integration/cli-settings-grok-build.test.ts @@ -39,7 +39,7 @@ const { GET, POST, DELETE } = async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -163,7 +163,7 @@ test("grok-build-settings POST: writes [model.omniroute] section and preserves e } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -219,7 +219,7 @@ test("grok-build-settings DELETE: removes our section, preserves the rest, resto } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -237,7 +237,7 @@ test("grok-build-settings DELETE: no-op success when no config file exists", asy assert.equal(body.success, true); } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -289,7 +289,7 @@ test("grok-build-settings: honors GROK_HOME and rejects a relative value", async } finally { if (original === undefined) delete process.env.GROK_HOME; else process.env.GROK_HOME = original; - fs.rmSync(grokHome, { recursive: true, force: true }); + fs.rmSync(grokHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -313,7 +313,7 @@ test("grok-build-settings POST: returns 409 for an unowned omniroute slot", asyn } finally { if (original === undefined) delete process.env.GROK_HOME; else process.env.GROK_HOME = original; - fs.rmSync(grokHome, { recursive: true, force: true }); + fs.rmSync(grokHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -342,7 +342,7 @@ test("grok-build-settings POST: resolves keyId to an unmasked key", async () => } finally { if (original === undefined) delete process.env.GROK_HOME; else process.env.GROK_HOME = original; - fs.rmSync(grokHome, { recursive: true, force: true }); + fs.rmSync(grokHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -376,7 +376,7 @@ test("grok-build-settings route.ts: does not call exec() or spawn() directly", ( test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-jcode.test.ts b/tests/integration/cli-settings-jcode.test.ts index 712b4186ba..6d1930aa83 100644 --- a/tests/integration/cli-settings-jcode.test.ts +++ b/tests/integration/cli-settings-jcode.test.ts @@ -21,7 +21,7 @@ const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/jcode-se async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -115,7 +115,7 @@ test("jcode-settings POST: writes [providers.omniroute] into config.toml", async } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -159,7 +159,7 @@ test("jcode-settings DELETE: removes only the OmniRoute-managed block", async () } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -193,7 +193,7 @@ test("jcode-settings route.ts: does not call exec() or spawn() directly", () => test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-letta.test.ts b/tests/integration/cli-settings-letta.test.ts index 881e8a32bf..d6a07ddc69 100644 --- a/tests/integration/cli-settings-letta.test.ts +++ b/tests/integration/cli-settings-letta.test.ts @@ -22,9 +22,7 @@ process.env.JWT_SECRET = "test-jwt-secret-letta"; const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); -const { GET, POST, DELETE } = await import( - "../../src/app/api/cli-tools/letta-settings/route.ts" -); +const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/letta-settings/route.ts"); let tmpHome: string; let origHome: string | undefined; @@ -40,7 +38,7 @@ function req(init?: RequestInit) { async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -58,7 +56,7 @@ test.beforeEach(async () => { test.afterEach(() => { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Test 1: GET without auth → 401 ────────────────────────────────────────── @@ -189,7 +187,7 @@ test("letta-settings: error responses do not leak stack traces", async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-omp.test.ts b/tests/integration/cli-settings-omp.test.ts index 54ae67f3a1..c07715ff4f 100644 --- a/tests/integration/cli-settings-omp.test.ts +++ b/tests/integration/cli-settings-omp.test.ts @@ -59,7 +59,7 @@ function seedOmpDb() { async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -77,7 +77,7 @@ test.beforeEach(async () => { test.afterEach(() => { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Test 1: GET without auth → 401 ────────────────────────────────────────── @@ -190,7 +190,7 @@ test("omp-settings: error responses do not leak stack traces", async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-pi.test.ts b/tests/integration/cli-settings-pi.test.ts index 92faea9b0a..29133efd51 100644 --- a/tests/integration/cli-settings-pi.test.ts +++ b/tests/integration/cli-settings-pi.test.ts @@ -16,14 +16,12 @@ process.env.JWT_SECRET = "test-jwt-secret-pi"; const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); -const { GET, POST, DELETE } = await import( - "../../src/app/api/cli-tools/pi-settings/route.ts" -); +const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/pi-settings/route.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -101,10 +99,7 @@ test("pi-settings POST: writes config.json with valid body", async () => { }), }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Unexpected status ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`); if (res.status === 200) { const body = await res.json(); assert.equal(body.success, true); @@ -118,7 +113,7 @@ test("pi-settings POST: writes config.json with valid body", async () => { } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -145,17 +140,14 @@ test("pi-settings DELETE: removes OmniRoute fields from existing config", async const res = await DELETE( new Request("http://localhost/api/cli-tools/pi-settings", { method: "DELETE" }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Expected 200/403/500, got ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Expected 200/403/500, got ${res.status}`); if (res.status === 200) { const body = await res.json(); assert.equal(body.success, true); } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -189,7 +181,7 @@ test("pi-settings route.ts: does not call exec() or spawn() directly", () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/cli-settings-smelt.test.ts b/tests/integration/cli-settings-smelt.test.ts index 7689fb58da..8395b4f1eb 100644 --- a/tests/integration/cli-settings-smelt.test.ts +++ b/tests/integration/cli-settings-smelt.test.ts @@ -16,14 +16,12 @@ process.env.JWT_SECRET = "test-jwt-secret-smelt"; const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); -const { GET, POST, DELETE } = await import( - "../../src/app/api/cli-tools/smelt-settings/route.ts" -); +const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/smelt-settings/route.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -101,10 +99,7 @@ test("smelt-settings POST: writes config.json with valid body", async () => { }), }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Unexpected status ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`); if (res.status === 200) { const body = await res.json(); assert.equal(body.success, true); @@ -118,7 +113,7 @@ test("smelt-settings POST: writes config.json with valid body", async () => { } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -145,17 +140,14 @@ test("smelt-settings DELETE: removes OmniRoute fields from existing config", asy const res = await DELETE( new Request("http://localhost/api/cli-tools/smelt-settings", { method: "DELETE" }) ); - assert.ok( - [200, 403, 500].includes(res.status), - `Expected 200/403/500, got ${res.status}` - ); + assert.ok([200, 403, 500].includes(res.status), `Expected 200/403/500, got ${res.status}`); if (res.status === 200) { const body = await res.json(); assert.equal(body.success, true); } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -189,7 +181,7 @@ test("smelt-settings route.ts: does not call exec() or spawn() directly", () => test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/integration/codex-account-pool-restart-http.test.ts b/tests/integration/codex-account-pool-restart-http.test.ts index 66018cc93f..2787c8d293 100644 --- a/tests/integration/codex-account-pool-restart-http.test.ts +++ b/tests/integration/codex-account-pool-restart-http.test.ts @@ -44,6 +44,6 @@ test("Codex Spark cooldown survives a fresh process without creating child conne assert.equal(after.connectionId, before.connectionId); assert.deepEqual(after.upstreamModels, ["gpt-5.5"]); } finally { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/integration/codex-chat-reasoning-http-e2e.test.ts b/tests/integration/codex-chat-reasoning-http-e2e.test.ts index 051b5ba235..28bea94534 100644 --- a/tests/integration/codex-chat-reasoning-http-e2e.test.ts +++ b/tests/integration/codex-chat-reasoning-http-e2e.test.ts @@ -305,6 +305,6 @@ test("chat completions streams Codex Responses reasoning through real route HTTP globalThis.fetch = originalFetch; if (routeServer) await closeServer(routeServer); core.closeDbInstance({ checkpointMode: null }); - await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true }); + await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/integration/combo-live/_liveHarness.ts b/tests/integration/combo-live/_liveHarness.ts index c415bc648b..98f6a05f5b 100644 --- a/tests/integration/combo-live/_liveHarness.ts +++ b/tests/integration/combo-live/_liveHarness.ts @@ -46,18 +46,18 @@ const IN_SCOPE_PROVIDERS = new Set([ // Provider → sensible default model (fallback when default_model is null). const PROVIDER_DEFAULT_MODELS: Record = { - "claude": "claude-3-5-haiku-20241022", - "glm": "glm-4-flash", - "minimax": "minimax-text-01", + claude: "claude-3-5-haiku-20241022", + glm: "glm-4-flash", + minimax: "minimax-text-01", "kimi-coding-apikey": "moonshot-v1-8k", "ollama-cloud": "llama3.2:3b", "opencode-go": "gpt-4o-mini", - "gemini": "gemini-2.0-flash-lite", - "deepseek": "deepseek-chat", - "groq": "llama-3.1-8b-instant", - "cerebras": "llama-3.1-8b", - "openrouter": "openai/gpt-4o-mini", - "together": "meta-llama/Llama-3-8b-chat-hf", + gemini: "gemini-2.0-flash-lite", + deepseek: "deepseek-chat", + groq: "llama-3.1-8b-instant", + cerebras: "llama-3.1-8b", + openrouter: "openai/gpt-4o-mini", + together: "meta-llama/Llama-3-8b-chat-hf", }; // --------------------------------------------------------------------------- @@ -79,9 +79,11 @@ export type ComboModelEntry = { connectionId: string; }; -export type LiveHarness = { - LIVE_ENABLED: false; -} | LiveHarnessEnabled; +export type LiveHarness = + | { + LIVE_ENABLED: false; + } + | LiveHarnessEnabled; export type LiveHarnessEnabled = { LIVE_ENABLED: true; @@ -146,12 +148,12 @@ export async function createLiveHarness(prefix: string): Promise { } } } catch (err: any) { - fs.rmSync(snapshotDir, { recursive: true, force: true }); + fs.rmSync(snapshotDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); throw new Error(`[liveHarness] Failed to fetch VPS secrets via ssh: ${err.message}`); } if (!storageEncryptionKey || !apiKeySecret) { - fs.rmSync(snapshotDir, { recursive: true, force: true }); + fs.rmSync(snapshotDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); throw new Error( "[liveHarness] Could not parse STORAGE_ENCRYPTION_KEY or API_KEY_SECRET from VPS .env" ); @@ -176,13 +178,11 @@ export async function createLiveHarness(prefix: string): Promise { const snapshotDbPath = path.join(snapshotDir, "storage.sqlite"); try { - execFileSync( - "scp", - ["root@192.168.0.15:/root/.omniroute/storage.sqlite", snapshotDbPath], - { timeout: 60_000 } - ); + execFileSync("scp", ["root@192.168.0.15:/root/.omniroute/storage.sqlite", snapshotDbPath], { + timeout: 60_000, + }); } catch (err: any) { - fs.rmSync(snapshotDir, { recursive: true, force: true }); + fs.rmSync(snapshotDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); throw new Error(`[liveHarness] Failed to scp production DB: ${err.message}`); } @@ -262,7 +262,10 @@ export async function createLiveHarness(prefix: string): Promise { }); } - function liveBody(model: string, overrides: Record = {}): Record { + function liveBody( + model: string, + overrides: Record = {} + ): Record { return { model, stream: false, @@ -400,7 +403,7 @@ export async function createLiveHarness(prefix: string): Promise { resetAllCircuitBreakers(); core.resetDbInstance(); // Destroy the snapshot — targets only the temp dir, NEVER /root/.omniroute. - fs.rmSync(snapshotDir, { recursive: true, force: true }); + fs.rmSync(snapshotDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } // Populate the map eagerly so servedProvider (sync) works right after diff --git a/tests/integration/fingerprint-expansion.test.ts b/tests/integration/fingerprint-expansion.test.ts index 0bfed13cc5..70dc0cf7c8 100644 --- a/tests/integration/fingerprint-expansion.test.ts +++ b/tests/integration/fingerprint-expansion.test.ts @@ -280,7 +280,7 @@ test.after(async () => { if (app) await stopProcess(app.child); await upstream.stop(); core.closeDbInstance(); - await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true }); + await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ────────────────────────────────────────────────────────────────── diff --git a/tests/integration/heap-growth.test.ts b/tests/integration/heap-growth.test.ts index d541a9e9a2..9c23eef9e5 100644 --- a/tests/integration/heap-growth.test.ts +++ b/tests/integration/heap-growth.test.ts @@ -14,7 +14,7 @@ const { createSSEStream } = await import("../../open-sse/utils/stream.ts"); test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/integration/llama-cpp-provider.test.ts b/tests/integration/llama-cpp-provider.test.ts index 7c1cf517d1..c39ed2190b 100644 --- a/tests/integration/llama-cpp-provider.test.ts +++ b/tests/integration/llama-cpp-provider.test.ts @@ -88,7 +88,7 @@ test.afterEach(() => { clearInflight(); resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -112,7 +112,10 @@ test("llama-cpp provider: routes request to custom baseUrl with no auth header", headers: toPlainHeaders(init.headers), body: init.body ? JSON.parse(String(init.body)) : null, }); - return buildLlamaResponse("Why did the programmer go broke? Because he used up all his cache!", "unsloth/gemma-4-26B-A4B-it-GGUF:UD-IQ2_M"); + return buildLlamaResponse( + "Why did the programmer go broke? Because he used up all his cache!", + "unsloth/gemma-4-26B-A4B-it-GGUF:UD-IQ2_M" + ); }; const response = await handleChat( @@ -135,7 +138,10 @@ test("llama-cpp provider: routes request to custom baseUrl with no auth header", assert.equal(upstream.headers.Authorization, undefined, "no auth header for local provider"); assert.equal(upstream.body.messages[0].content, "Tell me a joke."); assert.equal(upstream.body.model, "unsloth/gemma-4-26B-A4B-it-GGUF:UD-IQ2_M"); - assert.equal(json.choices[0].message.content, "Why did the programmer go broke? Because he used up all his cache!"); + assert.equal( + json.choices[0].message.content, + "Why did the programmer go broke? Because he used up all his cache!" + ); }); test("llama-cpp provider: alias matching works via model catalog prefix", async () => { @@ -152,7 +158,12 @@ test("llama-cpp provider: alias matching works via model catalog prefix", async const fetchCalls: FetchCall[] = []; globalThis.fetch = async (url, init: RequestInit = {}) => { - fetchCalls.push({ url: String(url), method: init.method, headers: toPlainHeaders(init.headers), body: init.body ? JSON.parse(String(init.body)) : null }); + fetchCalls.push({ + url: String(url), + method: init.method, + headers: toPlainHeaders(init.headers), + body: init.body ? JSON.parse(String(init.body)) : null, + }); return buildLlamaResponse("42", "unsloth/gemma-4-26B-A4B-it-GGUF:UD-IQ2_M"); }; @@ -167,7 +178,11 @@ test("llama-cpp provider: alias matching works via model catalog prefix", async ); const json = (await response.json()) as any; - assert.equal(response.status, 200, `expected 200, got ${response.status}: ${JSON.stringify(json)}`); + assert.equal( + response.status, + 200, + `expected 200, got ${response.status}: ${JSON.stringify(json)}` + ); assert.equal(json.choices[0].message.content, "42"); }); diff --git a/tests/integration/memory-embedding-providers.test.ts b/tests/integration/memory-embedding-providers.test.ts index 1481f0bad9..74bf51fe79 100644 --- a/tests/integration/memory-embedding-providers.test.ts +++ b/tests/integration/memory-embedding-providers.test.ts @@ -22,16 +22,15 @@ const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); // Import route AFTER setting DATA_DIR -const embeddingProvidersRoute = await import( - "../../src/app/api/memory/embedding-providers/route.ts" -); +const embeddingProvidersRoute = + await import("../../src/app/api/memory/embedding-providers/route.ts"); const { GET } = embeddingProvidersRoute; // ── Helpers ── async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +43,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ── diff --git a/tests/integration/memory-engine-status.test.ts b/tests/integration/memory-engine-status.test.ts index e40079628a..3cff56385b 100644 --- a/tests/integration/memory-engine-status.test.ts +++ b/tests/integration/memory-engine-status.test.ts @@ -22,16 +22,14 @@ const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); // Import route AFTER setting DATA_DIR -const engineStatusRoute = await import( - "../../src/app/api/memory/engine-status/route.ts" -); +const engineStatusRoute = await import("../../src/app/api/memory/engine-status/route.ts"); const { GET } = engineStatusRoute; // ── Helpers ── async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +42,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ── @@ -67,7 +65,11 @@ test("GET /api/memory/engine-status — 200 + valid MemoryEngineStatusSchema sha assert.strictEqual(body.keyword.backend, "FTS5", "keyword.backend should be FTS5"); assert.ok(body.embedding, "should have embedding section"); - assert.strictEqual(typeof body.embedding.available, "boolean", "embedding.available should be boolean"); + assert.strictEqual( + typeof body.embedding.available, + "boolean", + "embedding.available should be boolean" + ); assert.ok(typeof body.embedding.reason === "string", "embedding.reason should be a string"); assert.ok(body.embedding.cacheStats, "should have cacheStats in embedding"); assert.strictEqual(typeof body.embedding.cacheStats.hits, "number"); @@ -77,7 +79,7 @@ test("GET /api/memory/engine-status — 200 + valid MemoryEngineStatusSchema sha assert.ok(body.vectorStore, "should have vectorStore section"); assert.ok( ["sqlite-vec", "qdrant", "none"].includes(body.vectorStore.backend), - `vectorStore.backend should be valid: ${body.vectorStore.backend}`, + `vectorStore.backend should be valid: ${body.vectorStore.backend}` ); assert.strictEqual(typeof body.vectorStore.available, "boolean"); assert.strictEqual(typeof body.vectorStore.rowCount, "number"); diff --git a/tests/integration/memory-reindex.test.ts b/tests/integration/memory-reindex.test.ts index 6f11dc6083..4eb2188c98 100644 --- a/tests/integration/memory-reindex.test.ts +++ b/tests/integration/memory-reindex.test.ts @@ -13,9 +13,7 @@ import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { - makeManagementSessionRequest, -} from "../helpers/managementSession.ts"; +import { makeManagementSessionRequest } from "../helpers/managementSession.ts"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-reindex-")); process.env.DATA_DIR = TEST_DATA_DIR; @@ -25,16 +23,14 @@ const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); const memoryStore = await import("../../src/lib/memory/store.ts"); -const reindexRoute = await import( - "../../src/app/api/memory/reindex/route.ts" -); +const reindexRoute = await import("../../src/app/api/memory/reindex/route.ts"); const { POST } = reindexRoute; // ── Helpers ── async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -66,7 +62,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ── diff --git a/tests/integration/memory-retrieve-preview.test.ts b/tests/integration/memory-retrieve-preview.test.ts index 3a403ff4d4..36c4437d05 100644 --- a/tests/integration/memory-retrieve-preview.test.ts +++ b/tests/integration/memory-retrieve-preview.test.ts @@ -12,9 +12,7 @@ import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { - makeManagementSessionRequest, -} from "../helpers/managementSession.ts"; +import { makeManagementSessionRequest } from "../helpers/managementSession.ts"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-retrieve-preview-")); process.env.DATA_DIR = TEST_DATA_DIR; @@ -24,16 +22,14 @@ const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); // Import route AFTER setting DATA_DIR -const retrieveRoute = await import( - "../../src/app/api/memory/retrieve-preview/route.ts" -); +const retrieveRoute = await import("../../src/app/api/memory/retrieve-preview/route.ts"); const { POST } = retrieveRoute; // ── Helpers ── async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -53,7 +49,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ── @@ -106,9 +102,7 @@ test("POST /api/memory/retrieve-preview — 401 without auth when requireLogin=t test("POST /api/memory/retrieve-preview — error path: no stack trace (invalid JSON)", async () => { // Test via invalid JSON body — the parse step should return 400 without a stack trace - const { createManagementSessionHeaders } = await import( - "../helpers/managementSession.ts" - ); + const { createManagementSessionHeaders } = await import("../helpers/managementSession.ts"); const headers = await createManagementSessionHeaders(); const req = new Request("http://localhost/api/memory/retrieve-preview", { diff --git a/tests/integration/memory-route-put.test.ts b/tests/integration/memory-route-put.test.ts index 8ab591ac8e..3d952cb002 100644 --- a/tests/integration/memory-route-put.test.ts +++ b/tests/integration/memory-route-put.test.ts @@ -33,7 +33,7 @@ const { createMemory, getMemory } = memoryStore; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -69,7 +69,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ── diff --git a/tests/integration/memory-summarize.test.ts b/tests/integration/memory-summarize.test.ts index 6771ca4719..fa8c3b131e 100644 --- a/tests/integration/memory-summarize.test.ts +++ b/tests/integration/memory-summarize.test.ts @@ -12,9 +12,7 @@ import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { - makeManagementSessionRequest, -} from "../helpers/managementSession.ts"; +import { makeManagementSessionRequest } from "../helpers/managementSession.ts"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-summarize-")); process.env.DATA_DIR = TEST_DATA_DIR; @@ -24,16 +22,14 @@ const core = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); const memoryStore = await import("../../src/lib/memory/store.ts"); -const summarizeRoute = await import( - "../../src/app/api/memory/summarize/route.ts" -); +const summarizeRoute = await import("../../src/app/api/memory/summarize/route.ts"); const { POST } = summarizeRoute; // ── Helpers ── async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -61,7 +57,7 @@ async function seedOldMemory(daysAgo: number, apiKeyId = "api-key-1") { db.prepare("UPDATE memories SET created_at = ?, updated_at = ? WHERE id = ?").run( oldTs, oldTs, - mem.id, + mem.id ); return mem; } @@ -75,7 +71,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Tests ── diff --git a/tests/integration/model-catalog-responsiveness-9199.test.ts b/tests/integration/model-catalog-responsiveness-9199.test.ts index 89c0cd5750..19608b1d3c 100644 --- a/tests/integration/model-catalog-responsiveness-9199.test.ts +++ b/tests/integration/model-catalog-responsiveness-9199.test.ts @@ -19,7 +19,7 @@ const healthRoute = await import("../../src/app/api/health/ping/route.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); modelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -30,7 +30,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test( diff --git a/tests/integration/opencode-config-startup.test.ts b/tests/integration/opencode-config-startup.test.ts index 09161d8186..b0bbb3f76b 100644 --- a/tests/integration/opencode-config-startup.test.ts +++ b/tests/integration/opencode-config-startup.test.ts @@ -23,7 +23,7 @@ after(() => { globalThis.fetch = originalFetch; if (originalHome === undefined) delete process.env.HOME; else process.env.HOME = originalHome; - fs.rmSync(testHome, { recursive: true, force: true }); + fs.rmSync(testHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function runOpencode(binary: string, args: string[]) { diff --git a/tests/integration/performance-regression.test.ts b/tests/integration/performance-regression.test.ts index 87f80215d9..641e869f97 100644 --- a/tests/integration/performance-regression.test.ts +++ b/tests/integration/performance-regression.test.ts @@ -226,7 +226,7 @@ describe("Performance: memory API route handler (1000 records)", () => { db.prepare("DELETE FROM memories WHERE api_key_id = ?").run(TEST_API_KEY_ID); // Final cleanup: reset DB instance and remove temp dir core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it(`should handle GET /api/memory?limit=50 in <${THRESHOLD_API_ROUTE_MS}ms`, async () => { diff --git a/tests/integration/playground-improve-prompt.test.ts b/tests/integration/playground-improve-prompt.test.ts index aaa67d67cc..e962184b95 100644 --- a/tests/integration/playground-improve-prompt.test.ts +++ b/tests/integration/playground-improve-prompt.test.ts @@ -19,16 +19,12 @@ import os from "node:os"; import path from "node:path"; // Set up a temp DATA_DIR so getDbInstance() initialises cleanly -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-improve-prompt-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-improve-prompt-")); process.env.DATA_DIR = TEST_DATA_DIR; // Disable mandatory auth for most tests process.env.REQUIRE_API_KEY = "false"; -const { POST, OPTIONS } = await import( - "../../src/app/api/playground/improve-prompt/route.ts" -); +const { POST, OPTIONS } = await import("../../src/app/api/playground/improve-prompt/route.ts"); const BASE_URL = "http://localhost:20128"; @@ -61,7 +57,7 @@ function postRequest(body: unknown): Request { // ─── Cleanup ───────────────────────────────────────────────────────────────── test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── OPTIONS ───────────────────────────────────────────────────────────────── @@ -84,7 +80,11 @@ test("happy path: system + prompt both provided", async () => { ) as typeof fetch; const res = await POST( - postRequest({ system: "You are a helper.", prompt: "Tell me about AI.", model: "gpt-4o-mini" }) + postRequest({ + system: "You are a helper.", + prompt: "Tell me about AI.", + model: "gpt-4o-mini", + }) ); assert.equal(res.status, 200); @@ -161,15 +161,13 @@ test("happy path: usage defaults to 0 when not in upstream response", async () = try { // Return response without usage field globalThis.fetch = (async (_url: unknown, _opts: unknown) => { - return new Response( - JSON.stringify({ choices: [{ message: { content: "improved" } }] }), - { status: 200, headers: { "Content-Type": "application/json" } } - ); + return new Response(JSON.stringify({ choices: [{ message: { content: "improved" } }] }), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); }) as typeof fetch; - const res = await POST( - postRequest({ prompt: "Hello world", model: "gpt-4o-mini" }) - ); + const res = await POST(postRequest({ prompt: "Hello world", model: "gpt-4o-mini" })); assert.equal(res.status, 200); const body = (await res.json()) as { tokensIn: number; tokensOut: number }; @@ -245,9 +243,7 @@ test("upstream error returns sanitized error message — no stack trace in body" "Internal error\n at /home/user/project/src/handler.ts:42:10\n at process.nextTick" ) as typeof fetch; - const res = await POST( - postRequest({ prompt: "Hello", model: "gpt-4o-mini" }) - ); + const res = await POST(postRequest({ prompt: "Hello", model: "gpt-4o-mini" })); // Should be an error response (not 200) assert.ok(res.status >= 400); @@ -270,9 +266,7 @@ test("upstream network error is sanitized", async () => { throw new Error("ECONNREFUSED connect ECONNREFUSED 127.0.0.1:20128"); }) as typeof fetch; - const res = await POST( - postRequest({ prompt: "Hello", model: "gpt-4o-mini" }) - ); + const res = await POST(postRequest({ prompt: "Hello", model: "gpt-4o-mini" })); assert.ok(res.status >= 500); const body = (await res.json()) as { error: { message: string } }; @@ -289,9 +283,7 @@ test("401 when REQUIRE_API_KEY=true and no key provided", async () => { const originalRequired = process.env.REQUIRE_API_KEY; try { process.env.REQUIRE_API_KEY = "true"; - const res = await POST( - postRequest({ prompt: "Test", model: "gpt-4o-mini" }) - ); + const res = await POST(postRequest({ prompt: "Test", model: "gpt-4o-mini" })); assert.equal(res.status, 401); const body = (await res.json()) as { error: { message: string } }; diff --git a/tests/integration/playground-presets-crud.test.ts b/tests/integration/playground-presets-crud.test.ts index 655fdfdc53..57377ec0ab 100644 --- a/tests/integration/playground-presets-crud.test.ts +++ b/tests/integration/playground-presets-crud.test.ts @@ -22,26 +22,28 @@ import os from "node:os"; import path from "node:path"; // Isolated DB per test file -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-presets-crud-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-presets-crud-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.REQUIRE_API_KEY = "false"; const core = await import("../../src/lib/db/core.ts"); // Import route handlers -const { GET: listGet, POST: createPost, OPTIONS: listOptions } = await import( - "../../src/app/api/playground/presets/route.ts" -); -const { GET: idGet, PUT: idPut, DELETE: idDelete, OPTIONS: idOptions } = await import( - "../../src/app/api/playground/presets/[id]/route.ts" -); +const { + GET: listGet, + POST: createPost, + OPTIONS: listOptions, +} = await import("../../src/app/api/playground/presets/route.ts"); +const { + GET: idGet, + PUT: idPut, + DELETE: idDelete, + OPTIONS: idOptions, +} = await import("../../src/app/api/playground/presets/[id]/route.ts"); const BASE_URL = "http://localhost:20128"; -const UUID_V4_REGEX = - /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; +const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; // ─── Helpers ───────────────────────────────────────────────────────────────── @@ -86,7 +88,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── OPTIONS ───────────────────────────────────────────────────────────────── @@ -186,7 +188,12 @@ test("PUT /presets/[id] partial patch (name only) updates correctly", async () = ); assert.equal(putRes.status, 200); - const updated = (await putRes.json()) as { id: string; name: string; endpoint: string; model: string }; + const updated = (await putRes.json()) as { + id: string; + name: string; + endpoint: string; + model: string; + }; assert.equal(updated.id, created.id); assert.equal(updated.name, "Updated Name"); // Other fields should be preserved @@ -295,10 +302,7 @@ test("GET /presets/[id] with non-UUID id → 400", async () => { test("PUT /presets/[id] with non-UUID id → 400", async () => { const badId = "also-not-a-uuid"; - const res = await idPut( - putReq(badId, { name: "Whatever" }), - await resolveParams(badId) - ); + const res = await idPut(putReq(badId, { name: "Whatever" }), await resolveParams(badId)); assert.equal(res.status, 400); const body = (await res.json()) as { error: { message: string } }; diff --git a/tests/integration/playground-presets-zod.test.ts b/tests/integration/playground-presets-zod.test.ts index 3150eaed15..6010921de5 100644 --- a/tests/integration/playground-presets-zod.test.ts +++ b/tests/integration/playground-presets-zod.test.ts @@ -19,20 +19,18 @@ import os from "node:os"; import path from "node:path"; // Isolated DB per test file -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-presets-zod-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-presets-zod-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.REQUIRE_API_KEY = "false"; const core = await import("../../src/lib/db/core.ts"); -const { POST: createPost } = await import( - "../../src/app/api/playground/presets/route.ts" -); -const { GET: idGet, PUT: idPut, DELETE: idDelete } = await import( - "../../src/app/api/playground/presets/[id]/route.ts" -); +const { POST: createPost } = await import("../../src/app/api/playground/presets/route.ts"); +const { + GET: idGet, + PUT: idPut, + DELETE: idDelete, +} = await import("../../src/app/api/playground/presets/[id]/route.ts"); const BASE_URL = "http://localhost:20128"; @@ -83,7 +81,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── POST validation ───────────────────────────────────────────────────────── @@ -133,9 +131,7 @@ test("POST with missing model → 400", async () => { }); test("POST with empty model → 400", async () => { - const res = await createPost( - postReq({ name: "Test", endpoint: "chat.completions", model: "" }) - ); + const res = await createPost(postReq({ name: "Test", endpoint: "chat.completions", model: "" })); assert.equal(res.status, 400); const body = (await res.json()) as { error: { message: string } }; assert.ok(body.error); @@ -145,7 +141,12 @@ test("POST with empty model → 400", async () => { test("POST with system > 50000 chars → 400", async () => { const longSystem = "x".repeat(50001); const res = await createPost( - postReq({ name: "Big System", endpoint: "chat.completions", model: "gpt-4o", system: longSystem }) + postReq({ + name: "Big System", + endpoint: "chat.completions", + model: "gpt-4o", + system: longSystem, + }) ); assert.equal(res.status, 400); const body = (await res.json()) as { error: { message: string } }; @@ -156,7 +157,12 @@ test("POST with system > 50000 chars → 400", async () => { test("POST with system exactly 50000 chars → 201 (boundary: valid)", async () => { const maxSystem = "x".repeat(50000); const res = await createPost( - postReq({ name: "Max System", endpoint: "chat.completions", model: "gpt-4o", system: maxSystem }) + postReq({ + name: "Max System", + endpoint: "chat.completions", + model: "gpt-4o", + system: maxSystem, + }) ); assert.equal(res.status, 201); }); @@ -205,10 +211,7 @@ test("PUT with empty name → 400", async () => { test("PUT with system > 50000 chars → 400", async () => { const validId = "00000000-0000-4000-8000-000000000001"; const longSystem = "y".repeat(50001); - const res = await idPut( - putReq(validId, { system: longSystem }), - await resolveParams(validId) - ); + const res = await idPut(putReq(validId, { system: longSystem }), await resolveParams(validId)); assert.equal(res.status, 400); const body = (await res.json()) as { error: { message: string } }; assert.ok(body.error); diff --git a/tests/integration/plugins-lifecycle.test.ts b/tests/integration/plugins-lifecycle.test.ts index 7e3fe91e61..539578d05e 100644 --- a/tests/integration/plugins-lifecycle.test.ts +++ b/tests/integration/plugins-lifecycle.test.ts @@ -20,7 +20,11 @@ const { pluginManager } = await import("../../src/lib/plugins/manager.ts"); // Scanner expects: sourceDir//plugin.json + index.js // Returns the sourceDir (parent) to pass to pluginManager.install() -function writeTestPlugin(opts?: { name?: string; onRequest?: boolean; enabledByDefault?: boolean }) { +function writeTestPlugin(opts?: { + name?: string; + onRequest?: boolean; + enabledByDefault?: boolean; +}) { const name = opts?.name ?? "test-lifecycle-plugin"; const onRequest = opts?.onRequest ?? true; const enabledByDefault = opts?.enabledByDefault ?? false; @@ -57,7 +61,7 @@ function writeTestPlugin(opts?: { name?: string; onRequest?: boolean; enabledByD // ── Helpers ── function cleanupDir(dir: string) { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } // Track temp source dirs for cleanup @@ -65,7 +69,9 @@ const activeSourceDirs: string[] = []; function cleanupSourceDirs() { for (const dir of activeSourceDirs) { - try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} } activeSourceDirs.length = 0; } @@ -83,7 +89,9 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); cleanupSourceDirs(); - try { cleanupDir(TEST_DATA_DIR); } catch {} + try { + cleanupDir(TEST_DATA_DIR); + } catch {} }); // ── Tests: Install ── @@ -230,7 +238,11 @@ test("deactivate: unregisters all hooks for the plugin", async () => { // Hook should be gone const after = hooks.getHooks("onRequest"); - assert.equal(after.find((r) => r.pluginName === name), undefined, "hook should be unregistered"); + assert.equal( + after.find((r) => r.pluginName === name), + undefined, + "hook should be unregistered" + ); await pluginManager.uninstall(name); }); @@ -300,7 +312,10 @@ test("uninstall: deactivates before removing if active", async () => { // Plugin should be fully gone assert.equal(dbPlugins.getPluginByName(name), null); - assert.equal(hooks.getHooks("onRequest").find((r) => r.pluginName === name), undefined); + assert.equal( + hooks.getHooks("onRequest").find((r) => r.pluginName === name), + undefined + ); }); test("uninstall: throws for nonexistent plugin", async () => { @@ -322,7 +337,10 @@ test("full lifecycle: install -> activate -> hook fires -> deactivate -> uninsta await pluginManager.activate(name); const afterActivate = dbPlugins.getPluginByName(name); assert.equal(afterActivate!.status, "active"); - assert.ok(hooks.getHooks("onRequest").find((r) => r.pluginName === name), "hook registered"); + assert.ok( + hooks.getHooks("onRequest").find((r) => r.pluginName === name), + "hook registered" + ); // 3. Fire hook (use emitHookBlocking — child-process isolation means plugins cannot // mutate the parent's in-memory payload object; check the returned merged result). @@ -370,8 +388,14 @@ test("multiple plugins: hooks are isolated per plugin", async () => { await pluginManager.deactivate("multi-p1"); const afterDeactivate = hooks.getHooks("onRequest"); - assert.equal(afterDeactivate.find((r) => r.pluginName === "multi-p1"), undefined); - assert.ok(afterDeactivate.find((r) => r.pluginName === "multi-p2"), "p2 hook still registered"); + assert.equal( + afterDeactivate.find((r) => r.pluginName === "multi-p1"), + undefined + ); + assert.ok( + afterDeactivate.find((r) => r.pluginName === "multi-p2"), + "p2 hook still registered" + ); // Cleanup await pluginManager.uninstall("multi-p1"); diff --git a/tests/integration/provider-journey.contract.test.ts b/tests/integration/provider-journey.contract.test.ts index 8f88f273c6..655f6f7b8f 100644 --- a/tests/integration/provider-journey.contract.test.ts +++ b/tests/integration/provider-journey.contract.test.ts @@ -118,7 +118,7 @@ async function fetchCatalog( test.before(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // requireLogin + requireAuthForModels ON so the API-key surface is gated. await localDb.updateSettings({ requireLogin: true, requireAuthForModels: true, password: "" }); @@ -127,7 +127,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.describe("provider journey — in-process contract (#8330)", () => { diff --git a/tests/integration/proxy-registry-flow.test.ts b/tests/integration/proxy-registry-flow.test.ts index 4de8f0b1a2..6a33c22732 100644 --- a/tests/integration/proxy-registry-flow.test.ts +++ b/tests/integration/proxy-registry-flow.test.ts @@ -23,13 +23,13 @@ const proxyLogger = await import("../../src/lib/proxyLogger.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("integration: proxy create with inline assignment is atomic and clears legacy config", async () => { diff --git a/tests/integration/qdrant-routes.test.ts b/tests/integration/qdrant-routes.test.ts index 34444154d5..451074ffea 100644 --- a/tests/integration/qdrant-routes.test.ts +++ b/tests/integration/qdrant-routes.test.ts @@ -45,7 +45,7 @@ const asNextRequest = (req: Request) => req as unknown as import("next/server"). async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // #5597 follow-up: the memory-settings cache is a module-level singleton that // survives per-test DB resets — bust it so each test starts from a clean read. @@ -88,7 +88,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Settings GET ── diff --git a/tests/integration/quota-plans-crud.test.ts b/tests/integration/quota-plans-crud.test.ts index c580c3613d..77c2943303 100644 --- a/tests/integration/quota-plans-crud.test.ts +++ b/tests/integration/quota-plans-crud.test.ts @@ -35,7 +35,7 @@ async function enableManagementAuth() { function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -46,7 +46,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -91,7 +91,9 @@ test("GET /api/quota/plans includes DB override plans", async () => { // List should include the override const listReq = await makeManagementSessionRequest("http://localhost/api/quota/plans"); const listRes = await plansRoute.GET(listReq); - const body = (await listRes.json()) as { plans: Array<{ connectionId: string | null; source: string }> }; + const body = (await listRes.json()) as { + plans: Array<{ connectionId: string | null; source: string }>; + }; const override = body.plans.find((p) => p.connectionId === "conn-override-1"); assert.ok(override, "Override plan should appear in list"); assert.equal(override?.source, "manual"); @@ -160,13 +162,10 @@ test("PUT /api/quota/plans/[connectionId] without auth → 401", async () => { }); test("PUT /api/quota/plans/[connectionId] with invalid body → 400", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/quota/plans/conn-bad-body", - { - method: "PUT", - body: { dimensions: [] }, // PlanUpsertSchema requires min(1) dimensions - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/quota/plans/conn-bad-body", { + method: "PUT", + body: { dimensions: [] }, // PlanUpsertSchema requires min(1) dimensions + }); const res = await planIdRoute.PUT(req, { params: Promise.resolve({ connectionId: "conn-bad-body" }), }); @@ -226,7 +225,9 @@ test("DELETE /api/quota/plans/[connectionId] clears override → 204; GET revert `http://localhost/api/quota/plans/${connectionId}`, { method: "DELETE" } ); - const deleteRes = await planIdRoute.DELETE(deleteReq, { params: Promise.resolve({ connectionId }) }); + const deleteRes = await planIdRoute.DELETE(deleteReq, { + params: Promise.resolve({ connectionId }), + }); assert.equal(deleteRes.status, 204); // GET should now return auto/empty plan (no DB override) @@ -250,7 +251,10 @@ test("DELETE /api/quota/plans/[connectionId] clears override → 204; GET revert (e as Record).target === connectionId && (e as { metadata?: { reverted?: boolean } }).metadata?.reverted === true ); - assert.ok(deleteEvt, "quota.plan.updated audit event (reverted=true) must be present after DELETE"); + assert.ok( + deleteEvt, + "quota.plan.updated audit event (reverted=true) must be present after DELETE" + ); }); test("DELETE /api/quota/plans/[connectionId] is idempotent → 204 even when not found", async () => { diff --git a/tests/integration/quota-pool-delete-combo-cleanup.test.ts b/tests/integration/quota-pool-delete-combo-cleanup.test.ts index e9d6b2d966..e09f923c48 100644 --- a/tests/integration/quota-pool-delete-combo-cleanup.test.ts +++ b/tests/integration/quota-pool-delete-combo-cleanup.test.ts @@ -36,7 +36,7 @@ type Db = { function resetDb() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -95,7 +95,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("DELETE pool waits for scoped quota-combo cleanup before returning 204", async () => { diff --git a/tests/integration/quota-pool-usage-provider-resolution.test.ts b/tests/integration/quota-pool-usage-provider-resolution.test.ts index c45784cce5..533ddb642f 100644 --- a/tests/integration/quota-pool-usage-provider-resolution.test.ts +++ b/tests/integration/quota-pool-usage-provider-resolution.test.ts @@ -35,7 +35,7 @@ const usageRoute = await import("../../src/app/api/quota/pools/[id]/usage/route. function resetDb() { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -46,7 +46,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /usage surfaces catalog dimensions for a catalog-only pool (provider resolved from connection)", async () => { diff --git a/tests/integration/quota-pools-crud.test.ts b/tests/integration/quota-pools-crud.test.ts index dad624cece..da3d3e8bb2 100644 --- a/tests/integration/quota-pools-crud.test.ts +++ b/tests/integration/quota-pools-crud.test.ts @@ -38,7 +38,7 @@ async function enableManagementAuth() { function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -49,7 +49,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -91,7 +91,7 @@ test("POST /api/quota/pools with auth + valid body → 201 + pool returned", asy }); const res = await poolsRoute.POST(req); assert.equal(res.status, 201); - const body = await res.json() as { pool: { id: string; name: string; connectionId: string } }; + const body = (await res.json()) as { pool: { id: string; name: string; connectionId: string } }; assert.ok(body.pool.id, "Pool should have an id"); assert.equal(body.pool.name, "Test Pool Alpha"); assert.equal(body.pool.connectionId, "conn-test-1"); @@ -109,7 +109,10 @@ test("POST /api/quota/pools → audit event logged", async () => { const events = Array.isArray(logs) ? logs : []; assert.ok(events.length >= 1, "Should have at least one quota.pool.created audit event"); const evt = events.find( - (e) => typeof e === "object" && e !== null && (e as Record).action === "quota.pool.created" + (e) => + typeof e === "object" && + e !== null && + (e as Record).action === "quota.pool.created" ); assert.ok(evt, "quota.pool.created audit event must be present"); }); @@ -267,9 +270,7 @@ test("DELETE /api/quota/pools/[id] → 204 + audit event; subsequent GET → 404 assert.ok(evt, "quota.pool.deleted audit event must be present"); // Subsequent GET → 404 - const getReq = await makeManagementSessionRequest( - `http://localhost/api/quota/pools/${poolId}` - ); + const getReq = await makeManagementSessionRequest(`http://localhost/api/quota/pools/${poolId}`); const getRes = await poolIdRoute.GET(getReq, { params: Promise.resolve({ id: poolId }) }); assert.equal(getRes.status, 404); }); diff --git a/tests/integration/quota-pools-usage.test.ts b/tests/integration/quota-pools-usage.test.ts index 08a8471830..9672958e25 100644 --- a/tests/integration/quota-pools-usage.test.ts +++ b/tests/integration/quota-pools-usage.test.ts @@ -42,7 +42,7 @@ async function enableManagementAuth() { function resetDb() { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/quota/pools/[id]/usage without auth → 401", async () => { @@ -137,11 +137,7 @@ test("GET /api/quota/pools/[id]/usage → PoolUsageSnapshot shape with correct f // Even with no plan dimensions (empty plan for unknown provider), the response // is valid with an empty dimensions array — endpoint falls back to poolUsage() // which returns what's available from the store. - assert.doesNotMatch( - JSON.stringify(body), - /\s+at\s+\//, - "No stack trace in usage response" - ); + assert.doesNotMatch(JSON.stringify(body), /\s+at\s+\//, "No stack trace in usage response"); }); test("GET /api/quota/pools/[id]/usage response has required PoolUsageSnapshot fields", async () => { diff --git a/tests/integration/quota-preview.test.ts b/tests/integration/quota-preview.test.ts index 2afd58547a..867d95ba7d 100644 --- a/tests/integration/quota-preview.test.ts +++ b/tests/integration/quota-preview.test.ts @@ -40,7 +40,7 @@ async function enableManagementAuth() { function resetDb() { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -52,14 +52,12 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/quota/preview without auth → 401", async () => { await enableManagementAuth(); - const req = new Request( - "http://localhost/api/quota/preview?apiKeyId=k1&poolId=p1" - ); + const req = new Request("http://localhost/api/quota/preview?apiKeyId=k1&poolId=p1"); const res = await previewRoute.GET(req); assert.equal(res.status, 401); }); @@ -89,9 +87,7 @@ test("GET /api/quota/preview with nonexistent poolId → 404", async () => { test("GET /api/quota/preview with valid params → { decision } with kind", async () => { // Create a real pool const pool = createPool({ connectionId: "conn-preview", name: "Preview Pool" }); - upsertAllocations(pool.id, [ - { apiKeyId: "preview-key-1", weight: 100, policy: "soft" }, - ]); + upsertAllocations(pool.id, [{ apiKeyId: "preview-key-1", weight: 100, policy: "soft" }]); const req = await makeManagementSessionRequest( `http://localhost/api/quota/preview?apiKeyId=preview-key-1&poolId=${pool.id}&estimatedTokens=100` @@ -110,9 +106,7 @@ test("GET /api/quota/preview with valid params → { decision } with kind", asyn test("GET /api/quota/preview is dry-run: store counters unchanged after call", async () => { // Create pool and seed some consumption const pool = createPool({ connectionId: "conn-dryrun", name: "Dry Run Pool" }); - upsertAllocations(pool.id, [ - { apiKeyId: "dryrun-key", weight: 100, policy: "hard" }, - ]); + upsertAllocations(pool.id, [{ apiKeyId: "dryrun-key", weight: 100, policy: "hard" }]); const store = getSqliteQuotaStore(); const dim = { poolId: pool.id, unit: "tokens" as const, window: "daily" as const }; diff --git a/tests/integration/quota-routes-error-sanitization.test.ts b/tests/integration/quota-routes-error-sanitization.test.ts index b786b65898..aca138fb07 100644 --- a/tests/integration/quota-routes-error-sanitization.test.ts +++ b/tests/integration/quota-routes-error-sanitization.test.ts @@ -17,9 +17,7 @@ import os from "node:os"; import path from "node:path"; import { makeManagementSessionRequest } from "../helpers/managementSession.ts"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-quota-err-sanitization-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-quota-err-sanitization-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = "test-quota-sanitization-secret"; process.env.QUOTA_STORE_DRIVER = "sqlite"; @@ -42,7 +40,7 @@ const settingsRoute = await import("../../src/app/api/settings/quota-store/route function resetDb() { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -68,16 +66,8 @@ async function assertNoStackTrace(res: Response, label: string) { // Helper to assert secret URL not in response body text function assertNoSecretUrlText(text: string, label: string) { - assert.doesNotMatch( - text, - /secret-host/, - `${label}: Response must not contain secret Redis host` - ); - assert.doesNotMatch( - text, - /redis:\/\/secret/, - `${label}: Response must not contain Redis URL` - ); + assert.doesNotMatch(text, /secret-host/, `${label}: Response must not contain secret Redis host`); + assert.doesNotMatch(text, /redis:\/\/secret/, `${label}: Response must not contain Redis URL`); } // Reads the response body once and runs both assertions (body cannot be read twice) @@ -96,7 +86,7 @@ test.after(() => { core.resetDbInstance(); resetQuotaStoreSingleton(); delete process.env.QUOTA_STORE_REDIS_URL; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -118,9 +108,7 @@ test("POST /api/quota/pools 400 error response has no stack trace", async () => // --------------------------------------------------------------------------- test("GET /api/quota/pools/[id] 404 response has no stack trace", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/quota/pools/does-not-exist" - ); + const req = await makeManagementSessionRequest("http://localhost/api/quota/pools/does-not-exist"); const res = await poolIdRoute.GET(req, { params: Promise.resolve({ id: "does-not-exist" }), }); @@ -179,13 +167,10 @@ test("GET /api/quota/plans 200 response has no stack trace or path leak", async // --------------------------------------------------------------------------- test("PUT /api/quota/plans/[connectionId] 400 error response has no stack trace", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/quota/plans/conn-bad", - { - method: "PUT", - body: { dimensions: [] }, // PlanUpsertSchema requires min(1) - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/quota/plans/conn-bad", { + method: "PUT", + body: { dimensions: [] }, // PlanUpsertSchema requires min(1) + }); const res = await planIdRoute.PUT(req, { params: Promise.resolve({ connectionId: "conn-bad" }), }); @@ -212,9 +197,7 @@ test("GET /api/quota/preview 400 error response has no stack trace", async () => // --------------------------------------------------------------------------- test("GET /api/settings/quota-store response does not contain Redis URL (Hard Rule #12/#1)", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store" - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store"); const res = await settingsRoute.GET(req); assert.equal(res.status, 200); await assertNoStackTraceAndNoSecretUrl(res, "GET /api/settings/quota-store 200"); @@ -225,13 +208,10 @@ test("GET /api/settings/quota-store response does not contain Redis URL (Hard Ru // --------------------------------------------------------------------------- test("PUT /api/settings/quota-store 400 error response has no stack trace", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store", - { - method: "PUT", - body: { driver: "baddriver" }, - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store", { + method: "PUT", + body: { driver: "baddriver" }, + }); const res = await settingsRoute.PUT(req); assert.equal(res.status, 400); await assertNoStackTrace(res, "PUT /api/settings/quota-store 400"); @@ -242,13 +222,10 @@ test("PUT /api/settings/quota-store 400 error response has no stack trace", asyn // --------------------------------------------------------------------------- test("PUT /api/settings/quota-store redis+no-URL error response does not leak Redis URL", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store", - { - method: "PUT", - body: { driver: "redis" }, // No URL provided - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store", { + method: "PUT", + body: { driver: "redis" }, // No URL provided + }); const res = await settingsRoute.PUT(req); assert.equal(res.status, 400); await assertNoStackTraceAndNoSecretUrl(res, "PUT /api/settings/quota-store redis-no-url 400"); diff --git a/tests/integration/quota-store-settings.test.ts b/tests/integration/quota-store-settings.test.ts index bcf2e6bc75..aceaaca3e3 100644 --- a/tests/integration/quota-store-settings.test.ts +++ b/tests/integration/quota-store-settings.test.ts @@ -41,7 +41,7 @@ function resetDb() { resetQuotaStoreSingleton(); delete process.env.QUOTA_STORE_REDIS_URL; delete process.env.INITIAL_PASSWORD; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -53,7 +53,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); resetQuotaStoreSingleton(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -68,9 +68,7 @@ test("GET /api/settings/quota-store without auth → 401", async () => { }); test("GET /api/settings/quota-store returns driver + redisUrlConfigured (not URL)", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store" - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store"); const res = await settingsRoute.GET(req); assert.equal(res.status, 200); const body = (await res.json()) as { @@ -93,9 +91,7 @@ test("GET /api/settings/quota-store returns driver + redisUrlConfigured (not URL test("GET /api/settings/quota-store redisUrlConfigured=false when no URL configured", async () => { delete process.env.QUOTA_STORE_REDIS_URL; - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store" - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store"); const res = await settingsRoute.GET(req); const body = (await res.json()) as { redisUrlConfigured: boolean }; assert.equal(body.redisUrlConfigured, false); @@ -117,13 +113,10 @@ test("PUT /api/settings/quota-store without auth → 401", async () => { }); test("PUT /api/settings/quota-store driver=sqlite → 200", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store", - { - method: "PUT", - body: { driver: "sqlite" }, - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store", { + method: "PUT", + body: { driver: "sqlite" }, + }); const res = await settingsRoute.PUT(req); assert.equal(res.status, 200); const body = (await res.json()) as { driver: string; redisUrl: null }; @@ -132,13 +125,10 @@ test("PUT /api/settings/quota-store driver=sqlite → 200", async () => { }); test("PUT /api/settings/quota-store driver=redis without URL → 400", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store", - { - method: "PUT", - body: { driver: "redis" }, // No redisUrl - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store", { + method: "PUT", + body: { driver: "redis" }, // No redisUrl + }); const res = await settingsRoute.PUT(req); assert.equal(res.status, 400); const body = await res.json(); @@ -147,13 +137,10 @@ test("PUT /api/settings/quota-store driver=redis without URL → 400", async () }); test("PUT /api/settings/quota-store driver=redis with valid URL → 200 + audit event", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store", - { - method: "PUT", - body: { driver: "redis", redisUrl: "redis://localhost:6379" }, - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store", { + method: "PUT", + body: { driver: "redis", redisUrl: "redis://localhost:6379" }, + }); const res = await settingsRoute.PUT(req); assert.equal(res.status, 200); const body = (await res.json()) as { @@ -187,13 +174,10 @@ test("PUT /api/settings/quota-store driver=redis with valid URL → 200 + audit }); test("PUT /api/settings/quota-store with invalid driver → 400 (Zod)", async () => { - const req = await makeManagementSessionRequest( - "http://localhost/api/settings/quota-store", - { - method: "PUT", - body: { driver: "memcached" }, // Not in enum - } - ); + const req = await makeManagementSessionRequest("http://localhost/api/settings/quota-store", { + method: "PUT", + body: { driver: "memcached" }, // Not in enum + }); const res = await settingsRoute.PUT(req); assert.equal(res.status, 400); const body = await res.json(); diff --git a/tests/integration/resilience-http-e2e.test.ts b/tests/integration/resilience-http-e2e.test.ts index 6f94fc02f6..c3d0b65566 100644 --- a/tests/integration/resilience-http-e2e.test.ts +++ b/tests/integration/resilience-http-e2e.test.ts @@ -547,7 +547,7 @@ test.after(async () => { } await relay.stop(); core.closeDbInstance(); - await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true }); + await fsp.rm(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("resilience API only exposes configuration, not runtime breaker state", async () => { diff --git a/tests/integration/search-providers-catalog.test.ts b/tests/integration/search-providers-catalog.test.ts index 86c47e7e0b..bab5557fa7 100644 --- a/tests/integration/search-providers-catalog.test.ts +++ b/tests/integration/search-providers-catalog.test.ts @@ -102,7 +102,7 @@ async function seedRateLimitedConnection(provider: string) { /** Reset DB state between tests. */ async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -116,7 +116,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/integration/test-model-compression-off-6240.test.ts b/tests/integration/test-model-compression-off-6240.test.ts index 7934050342..c4bb43cd2e 100644 --- a/tests/integration/test-model-compression-off-6240.test.ts +++ b/tests/integration/test-model-compression-off-6240.test.ts @@ -37,7 +37,7 @@ async function resetStorage() { readCacheDb.invalidateDbCache(); await new Promise((resolve) => setTimeout(resolve, 20)); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -49,7 +49,7 @@ test.after(async () => { globalThis.fetch = originalFetch; core.closeDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/integration/traffic-inspector-capture-modes.test.ts b/tests/integration/traffic-inspector-capture-modes.test.ts index bf9b46c7a2..86148eb7c4 100644 --- a/tests/integration/traffic-inspector-capture-modes.test.ts +++ b/tests/integration/traffic-inspector-capture-modes.test.ts @@ -19,30 +19,25 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ti-captur process.env.DATA_DIR = TEST_DATA_DIR; process.env.INSPECTOR_HTTP_PROXY_PORT = "0"; // ephemeral port -const captureModesRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/route.ts" -); -const httpProxyRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/http-proxy/route.ts" -); -const systemProxyRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/system-proxy/route.ts" -); -const tlsInterceptRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/tls-intercept/route.ts" -); -const { setHttpProxyHandle, getHttpProxyHandle, clearSystemProxy } = await import( - "../../src/lib/inspector/captureState.ts" -); -const { __setExec } = await import( - "../../src/mitm/inspector/systemProxyConfig.ts" -); +const captureModesRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/route.ts"); +const httpProxyRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/http-proxy/route.ts"); +const systemProxyRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/system-proxy/route.ts"); +const tlsInterceptRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/tls-intercept/route.ts"); +const { setHttpProxyHandle, getHttpProxyHandle, clearSystemProxy } = + await import("../../src/lib/inspector/captureState.ts"); +const { __setExec } = await import("../../src/mitm/inspector/systemProxyConfig.ts"); test.beforeEach(() => { // Ensure no running proxy handle leaks between tests const handle = getHttpProxyHandle(); if (handle) { - handle.stop().catch(() => {/* ignore */}); + handle.stop().catch(() => { + /* ignore */ + }); setHttpProxyHandle(null); } clearSystemProxy(); @@ -52,10 +47,12 @@ test.after(() => { // Clean up any running proxy const handle = getHttpProxyHandle(); if (handle) { - handle.stop().catch(() => {/* ignore */}); + handle.stop().catch(() => { + /* ignore */ + }); setHttpProxyHandle(null); } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── GET /capture-modes ────────────────────────────────────────────────────── @@ -63,7 +60,7 @@ test.after(() => { test("GET /capture-modes: returns status of all modes", async () => { const res = await captureModesRoute.GET(); assert.equal(res.status, 200); - const body = await res.json() as { + const body = (await res.json()) as { agentBridge: boolean; httpProxy: { running: boolean; port: number | null }; systemProxy: { applied: boolean }; @@ -78,17 +75,14 @@ test("GET /capture-modes: returns status of all modes", async () => { // ── POST /capture-modes/http-proxy ───────────────────────────────────────── test("http-proxy: start binds an ephemeral port", async () => { - const req = new Request( - "http://localhost/api/tools/traffic-inspector/capture-modes/http-proxy", - { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ action: "start" }), - } - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/capture-modes/http-proxy", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ action: "start" }), + }); const res = await httpProxyRoute.POST(req); assert.equal(res.status, 201); - const body = await res.json() as { ok: boolean; running: boolean; port: number }; + const body = (await res.json()) as { ok: boolean; running: boolean; port: number }; assert.equal(body.ok, true); assert.equal(body.running, true); assert.ok(body.port > 0, "should have a bound port"); @@ -102,17 +96,14 @@ test("http-proxy: start binds an ephemeral port", async () => { }); test("http-proxy: stop when not running returns ok", async () => { - const req = new Request( - "http://localhost/api/tools/traffic-inspector/capture-modes/http-proxy", - { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ action: "stop" }), - } - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/capture-modes/http-proxy", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ action: "stop" }), + }); const res = await httpProxyRoute.POST(req); assert.equal(res.status, 200); - const body = await res.json() as { ok: boolean; running: boolean }; + const body = (await res.json()) as { ok: boolean; running: boolean }; assert.equal(body.ok, true); assert.equal(body.running, false); }); @@ -139,16 +130,14 @@ test("http-proxy: start then stop lifecycle", async () => { ); const stopRes = await httpProxyRoute.POST(stopReq); assert.equal(stopRes.status, 200); - const body = await stopRes.json() as { running: boolean }; + const body = (await stopRes.json()) as { running: boolean }; assert.equal(body.running, false); }); test("http-proxy: EADDRINUSE returns 409 with structured error", async () => { // Import startHttpProxyServer directly so we can test the low-level error path // without depending on the module-cached DEFAULT_PORT. - const { startHttpProxyServer } = await import( - "../../src/mitm/inspector/httpProxyServer.ts" - ); + const { startHttpProxyServer } = await import("../../src/mitm/inspector/httpProxyServer.ts"); // Occupy a random port const blocker = net.createServer(); @@ -173,7 +162,10 @@ test("http-proxy: EADDRINUSE returns 409 with structured error", async () => { // ── POST /capture-modes/system-proxy ─────────────────────────────────────── test("system-proxy: apply with mocked OS commands", async () => { - const restore = __setExec(async (_file, _args) => ({ stdout: "Enabled: No\nServer: \nPort: 0", stderr: "" })); + const restore = __setExec(async (_file, _args) => ({ + stdout: "Enabled: No\nServer: \nPort: 0", + stderr: "", + })); try { const req = new Request( "http://localhost/api/tools/traffic-inspector/capture-modes/system-proxy", @@ -185,7 +177,7 @@ test("system-proxy: apply with mocked OS commands", async () => { ); const res = await systemProxyRoute.POST(req); assert.equal(res.status, 200); - const body = await res.json() as { ok: boolean; applied: boolean }; + const body = (await res.json()) as { ok: boolean; applied: boolean }; assert.equal(body.ok, true); assert.equal(body.applied, true); } finally { @@ -207,7 +199,7 @@ test("system-proxy: revert without prior apply is a no-op", async () => { ); const res = await systemProxyRoute.POST(req); assert.equal(res.status, 200); - const body = await res.json() as { applied: boolean }; + const body = (await res.json()) as { applied: boolean }; assert.equal(body.applied, false); } finally { restore(); @@ -240,7 +232,7 @@ test("tls-intercept: toggle on/off", async () => { ); const enableRes = await tlsInterceptRoute.POST(enableReq); assert.equal(enableRes.status, 200); - const enableBody = await enableRes.json() as { tlsIntercept: { enabled: boolean } }; + const enableBody = (await enableRes.json()) as { tlsIntercept: { enabled: boolean } }; assert.equal(enableBody.tlsIntercept.enabled, true); const disableReq = new Request( @@ -253,6 +245,6 @@ test("tls-intercept: toggle on/off", async () => { ); const disableRes = await tlsInterceptRoute.POST(disableReq); assert.equal(disableRes.status, 200); - const disableBody = await disableRes.json() as { tlsIntercept: { enabled: boolean } }; + const disableBody = (await disableRes.json()) as { tlsIntercept: { enabled: boolean } }; assert.equal(disableBody.tlsIntercept.enabled, false); }); diff --git a/tests/integration/traffic-inspector-error-sanitization.test.ts b/tests/integration/traffic-inspector-error-sanitization.test.ts index fd076bd3ca..6b2883cbc0 100644 --- a/tests/integration/traffic-inspector-error-sanitization.test.ts +++ b/tests/integration/traffic-inspector-error-sanitization.test.ts @@ -17,53 +17,36 @@ process.env.DATA_DIR = TEST_DATA_DIR; const { globalTrafficBuffer } = await import("../../src/mitm/inspector/buffer.ts"); -const requestsRoute = await import( - "../../src/app/api/tools/traffic-inspector/requests/route.ts" -); -const requestDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/requests/[id]/route.ts" -); -const annotationRoute = await import( - "../../src/app/api/tools/traffic-inspector/requests/[id]/annotation/route.ts" -); -const hostsRoute = await import( - "../../src/app/api/tools/traffic-inspector/hosts/route.ts" -); -const hostDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/hosts/[host]/route.ts" -); -const sessionsRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/route.ts" -); -const sessionDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/[id]/route.ts" -); -const ingestRoute = await import( - "../../src/app/api/tools/traffic-inspector/internal/ingest/route.ts" -); -const httpProxyRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/http-proxy/route.ts" -); -const systemProxyRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/system-proxy/route.ts" -); -const tlsInterceptRoute = await import( - "../../src/app/api/tools/traffic-inspector/capture-modes/tls-intercept/route.ts" -); +const requestsRoute = await import("../../src/app/api/tools/traffic-inspector/requests/route.ts"); +const requestDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/requests/[id]/route.ts"); +const annotationRoute = + await import("../../src/app/api/tools/traffic-inspector/requests/[id]/annotation/route.ts"); +const hostsRoute = await import("../../src/app/api/tools/traffic-inspector/hosts/route.ts"); +const hostDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/hosts/[host]/route.ts"); +const sessionsRoute = await import("../../src/app/api/tools/traffic-inspector/sessions/route.ts"); +const sessionDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/sessions/[id]/route.ts"); +const ingestRoute = + await import("../../src/app/api/tools/traffic-inspector/internal/ingest/route.ts"); +const httpProxyRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/http-proxy/route.ts"); +const systemProxyRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/system-proxy/route.ts"); +const tlsInterceptRoute = + await import("../../src/app/api/tools/traffic-inspector/capture-modes/tls-intercept/route.ts"); function noStackTrace(msg: string, label: string): void { assert.ok( !msg.includes("at /"), `${label}: error message must not contain stack trace (found "at /")` ); - assert.ok( - !msg.includes(".ts:"), - `${label}: error message must not include TS file paths` - ); + assert.ok(!msg.includes(".ts:"), `${label}: error message must not include TS file paths`); } async function getErrorMessage(res: Response): Promise { - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; return body.error?.message ?? ""; } @@ -72,23 +55,20 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("requests: invalid profile param does not leak stack", async () => { - const req = new Request( - "http://localhost/api/tools/traffic-inspector/requests?profile=BAD" - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/requests?profile=BAD"); const res = await requestsRoute.GET(req); assert.equal(res.status, 400); noStackTrace(await getErrorMessage(res), "GET /requests"); }); test("requests/[id]: unknown id does not leak stack", async () => { - const res = await requestDetailRoute.GET( - new Request("http://localhost/"), - { params: Promise.resolve({ id: randomUUID() }) } - ); + const res = await requestDetailRoute.GET(new Request("http://localhost/"), { + params: Promise.resolve({ id: randomUUID() }), + }); assert.equal(res.status, 404); noStackTrace(await getErrorMessage(res), "GET /requests/[id]"); }); @@ -148,40 +128,33 @@ test("hosts/[host] PATCH: invalid body does not leak stack", async () => { }); test("sessions: 404 does not leak stack", async () => { - const res = await sessionDetailRoute.GET( - new Request("http://localhost/"), - { params: Promise.resolve({ id: randomUUID() }) } - ); + const res = await sessionDetailRoute.GET(new Request("http://localhost/"), { + params: Promise.resolve({ id: randomUUID() }), + }); assert.equal(res.status, 404); noStackTrace(await getErrorMessage(res), "GET /sessions/[id]"); }); test("ingest: 403 does not leak stack", async () => { - const req = new Request( - "http://localhost/api/tools/traffic-inspector/internal/ingest", - { - method: "POST", - headers: { - "content-type": "application/json", - authorization: "Bearer wrong-token", - }, - body: JSON.stringify({}), - } - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/internal/ingest", { + method: "POST", + headers: { + "content-type": "application/json", + authorization: "Bearer wrong-token", + }, + body: JSON.stringify({}), + }); const res = await ingestRoute.POST(req); assert.equal(res.status, 403); noStackTrace(await getErrorMessage(res), "POST /internal/ingest (403)"); }); test("http-proxy: invalid action does not leak stack", async () => { - const req = new Request( - "http://localhost/api/tools/traffic-inspector/capture-modes/http-proxy", - { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ action: "invalid" }), - } - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/capture-modes/http-proxy", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ action: "invalid" }), + }); const res = await httpProxyRoute.POST(req); assert.equal(res.status, 400); noStackTrace(await getErrorMessage(res), "POST /capture-modes/http-proxy"); diff --git a/tests/integration/traffic-inspector-hosts.test.ts b/tests/integration/traffic-inspector-hosts.test.ts index 234eb8be61..f6efcc57a6 100644 --- a/tests/integration/traffic-inspector-hosts.test.ts +++ b/tests/integration/traffic-inspector-hosts.test.ts @@ -18,29 +18,26 @@ process.env.DATA_DIR = TEST_DATA_DIR; const { resetDbInstance } = await import("../../src/lib/db/core.ts"); const localDb = await import("../../src/lib/localDb.ts"); -const hostsRoute = await import( - "../../src/app/api/tools/traffic-inspector/hosts/route.ts" -); -const hostDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/hosts/[host]/route.ts" -); +const hostsRoute = await import("../../src/app/api/tools/traffic-inspector/hosts/route.ts"); +const hostDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/hosts/[host]/route.ts"); test.beforeEach(async () => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // Re-init DB with fresh migrations await import("../../src/lib/db/core.ts").then((m) => m.getDbInstance()); }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /hosts: returns empty list initially", async () => { const res = await hostsRoute.GET(); assert.equal(res.status, 200); - const body = await res.json() as { hosts: unknown[] }; + const body = (await res.json()) as { hosts: unknown[] }; assert.deepEqual(body.hosts, []); }); @@ -52,13 +49,13 @@ test("POST /hosts: adds a host", async () => { }); const res = await hostsRoute.POST(req); assert.equal(res.status, 201); - const body = await res.json() as { ok: boolean; host: string }; + const body = (await res.json()) as { ok: boolean; host: string }; assert.equal(body.ok, true); assert.equal(body.host, "api.openai.com"); // Verify it appears in list const listRes = await hostsRoute.GET(); - const list = await listRes.json() as { hosts: Array<{ host: string }> }; + const list = (await listRes.json()) as { hosts: Array<{ host: string }> }; assert.ok(list.hosts.some((h) => h.host === "api.openai.com")); }); @@ -70,7 +67,7 @@ test("POST /hosts: rejects empty host string", async () => { }); const res = await hostsRoute.POST(req); assert.equal(res.status, 400); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(!body.error.message.includes("at /"), "must not leak stack trace"); }); @@ -94,15 +91,14 @@ test("DELETE /hosts/[host]: removes existing host", async () => { await hostsRoute.POST(addReq); // Now delete it - const delRes = await hostDetailRoute.DELETE( - new Request("http://localhost/"), - { params: Promise.resolve({ host: "remove-me.example.com" }) } - ); + const delRes = await hostDetailRoute.DELETE(new Request("http://localhost/"), { + params: Promise.resolve({ host: "remove-me.example.com" }), + }); assert.equal(delRes.status, 204); // Verify gone const listRes = await hostsRoute.GET(); - const list = await listRes.json() as { hosts: Array<{ host: string }> }; + const list = (await listRes.json()) as { hosts: Array<{ host: string }> }; assert.ok(!list.hosts.some((h) => h.host === "remove-me.example.com")); }); @@ -125,7 +121,7 @@ test("PATCH /hosts/[host]: toggles enabled flag", async () => { { params: Promise.resolve({ host: "toggle-me.example.com" }) } ); assert.equal(patchRes.status, 200); - const body = await patchRes.json() as { enabled: boolean }; + const body = (await patchRes.json()) as { enabled: boolean }; assert.equal(body.enabled, false); }); diff --git a/tests/integration/traffic-inspector-internal-ingest.test.ts b/tests/integration/traffic-inspector-internal-ingest.test.ts index 3cf2ef1048..8690993d38 100644 --- a/tests/integration/traffic-inspector-internal-ingest.test.ts +++ b/tests/integration/traffic-inspector-internal-ingest.test.ts @@ -23,9 +23,8 @@ const VALID_TOKEN = "test-ingest-token-abc123xyz789-longer-than-16"; process.env.INSPECTOR_INTERNAL_INGEST_TOKEN = VALID_TOKEN; const { globalTrafficBuffer } = await import("../../src/mitm/inspector/buffer.ts"); -const ingestRoute = await import( - "../../src/app/api/tools/traffic-inspector/internal/ingest/route.ts" -); +const ingestRoute = + await import("../../src/app/api/tools/traffic-inspector/internal/ingest/route.ts"); function makeIngestRequest(token: string | null, body: unknown): Request { const headers: Record = { @@ -34,14 +33,11 @@ function makeIngestRequest(token: string | null, body: unknown): Request { if (token !== null) { headers["authorization"] = `Bearer ${token}`; } - return new Request( - "http://localhost/api/tools/traffic-inspector/internal/ingest", - { - method: "POST", - headers, - body: JSON.stringify(body), - } - ); + return new Request("http://localhost/api/tools/traffic-inspector/internal/ingest", { + method: "POST", + headers, + body: JSON.stringify(body), + }); } function minimalEntry(overrides: Record = {}): Record { @@ -66,14 +62,14 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("ingest: POST without Authorization header → 403", async () => { const req = makeIngestRequest(null, minimalEntry()); const res = await ingestRoute.POST(req); assert.equal(res.status, 403); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(!body.error.message.includes("at /"), "must not leak stack trace"); }); @@ -94,7 +90,7 @@ test("ingest: POST with valid token + valid body → 200 + buffer push", async ( const req = makeIngestRequest(VALID_TOKEN, minimalEntry({ id })); const res = await ingestRoute.POST(req); assert.equal(res.status, 200); - const body = await res.json() as { ok: boolean; id: string }; + const body = (await res.json()) as { ok: boolean; id: string }; assert.equal(body.ok, true); assert.equal(body.id, id); @@ -113,23 +109,20 @@ test("ingest: valid token + missing required field → 400", async () => { }); const res = await ingestRoute.POST(req); assert.equal(res.status, 400); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(!body.error.message.includes("at /"), "must not leak stack trace"); }); test("ingest: valid token + invalid JSON → 400", async () => { const headers: Record = { "content-type": "application/json", - "authorization": `Bearer ${VALID_TOKEN}`, + authorization: `Bearer ${VALID_TOKEN}`, }; - const req = new Request( - "http://localhost/api/tools/traffic-inspector/internal/ingest", - { - method: "POST", - headers, - body: "not valid json", - } - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/internal/ingest", { + method: "POST", + headers, + body: "not valid json", + }); const res = await ingestRoute.POST(req); assert.equal(res.status, 400); }); diff --git a/tests/integration/traffic-inspector-localonly.test.ts b/tests/integration/traffic-inspector-localonly.test.ts index 0fc352b51d..396ee1043f 100644 --- a/tests/integration/traffic-inspector-localonly.test.ts +++ b/tests/integration/traffic-inspector-localonly.test.ts @@ -14,12 +14,10 @@ import path from "node:path"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ti-local-")); process.env.DATA_DIR = TEST_DATA_DIR; -const { isLocalOnlyPath, isLoopbackHost } = await import( - "../../src/server/authz/routeGuard.ts" -); +const { isLocalOnlyPath, isLoopbackHost } = await import("../../src/server/authz/routeGuard.ts"); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── isLocalOnlyPath assertions ────────────────────────────────────────────── diff --git a/tests/integration/traffic-inspector-requests.test.ts b/tests/integration/traffic-inspector-requests.test.ts index 9f894c441f..7f46042abf 100644 --- a/tests/integration/traffic-inspector-requests.test.ts +++ b/tests/integration/traffic-inspector-requests.test.ts @@ -16,23 +16,21 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ti-reqs-" process.env.DATA_DIR = TEST_DATA_DIR; const { globalTrafficBuffer } = await import("../../src/mitm/inspector/buffer.ts"); -const requestsRoute = await import( - "../../src/app/api/tools/traffic-inspector/requests/route.ts" -); -const requestDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/requests/[id]/route.ts" -); -const annotationRoute = await import( - "../../src/app/api/tools/traffic-inspector/requests/[id]/annotation/route.ts" -); +const requestsRoute = await import("../../src/app/api/tools/traffic-inspector/requests/route.ts"); +const requestDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/requests/[id]/route.ts"); +const annotationRoute = + await import("../../src/app/api/tools/traffic-inspector/requests/[id]/annotation/route.ts"); -function makeEntry(overrides: Partial<{ - id: string; - host: string; - detectedKind: "llm" | "app" | "unknown"; - status: number | "in-flight" | "error"; - source: "agent-bridge" | "custom-host" | "http-proxy" | "system-proxy"; -}> = {}) { +function makeEntry( + overrides: Partial<{ + id: string; + host: string; + detectedKind: "llm" | "app" | "unknown"; + status: number | "in-flight" | "error"; + source: "agent-bridge" | "custom-host" | "http-proxy" | "system-proxy"; + }> = {} +) { return { id: randomUUID(), source: "agent-bridge" as const, @@ -57,14 +55,14 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /requests: returns empty list when buffer is empty", async () => { const req = new Request("http://localhost/api/tools/traffic-inspector/requests"); const res = await requestsRoute.GET(req); assert.equal(res.status, 200); - const body = await res.json() as { requests: unknown[]; total: number }; + const body = (await res.json()) as { requests: unknown[]; total: number }; assert.deepEqual(body.requests, []); assert.equal(body.total, 0); }); @@ -76,7 +74,7 @@ test("GET /requests: returns all entries without filter", async () => { const req = new Request("http://localhost/api/tools/traffic-inspector/requests"); const res = await requestsRoute.GET(req); assert.equal(res.status, 200); - const body = await res.json() as { requests: unknown[]; total: number }; + const body = (await res.json()) as { requests: unknown[]; total: number }; assert.equal(body.total, 2); }); @@ -84,12 +82,10 @@ test("GET /requests: filters by profile=llm", async () => { globalTrafficBuffer.push(makeEntry({ id: randomUUID(), detectedKind: "llm" })); globalTrafficBuffer.push(makeEntry({ id: randomUUID(), detectedKind: "app" })); - const req = new Request( - "http://localhost/api/tools/traffic-inspector/requests?profile=llm" - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/requests?profile=llm"); const res = await requestsRoute.GET(req); assert.equal(res.status, 200); - const body = await res.json() as { requests: unknown[]; total: number }; + const body = (await res.json()) as { requests: unknown[]; total: number }; assert.equal(body.total, 1); }); @@ -97,23 +93,19 @@ test("GET /requests: filters by host", async () => { globalTrafficBuffer.push(makeEntry({ id: randomUUID(), host: "target.com" })); globalTrafficBuffer.push(makeEntry({ id: randomUUID(), host: "other.com" })); - const req = new Request( - "http://localhost/api/tools/traffic-inspector/requests?host=target.com" - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/requests?host=target.com"); const res = await requestsRoute.GET(req); assert.equal(res.status, 200); - const body = await res.json() as { requests: Array<{ host: string }>; total: number }; + const body = (await res.json()) as { requests: Array<{ host: string }>; total: number }; assert.equal(body.total, 1); assert.equal(body.requests[0]?.host, "target.com"); }); test("GET /requests: rejects invalid profile param with 400", async () => { - const req = new Request( - "http://localhost/api/tools/traffic-inspector/requests?profile=invalid" - ); + const req = new Request("http://localhost/api/tools/traffic-inspector/requests?profile=invalid"); const res = await requestsRoute.GET(req); assert.equal(res.status, 400); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(!body.error.message.includes("at /"), "must not leak stack trace"); }); @@ -134,19 +126,17 @@ test("GET /requests/[id]: returns entry by id", async () => { params: Promise.resolve({ id: entry.id }), }); assert.equal(res.status, 200); - const body = await res.json() as { id: string }; + const body = (await res.json()) as { id: string }; assert.equal(body.id, entry.id); }); test("GET /requests/[id]: returns 404 for unknown id", async () => { - const req = new Request( - `http://localhost/api/tools/traffic-inspector/requests/${randomUUID()}` - ); + const req = new Request(`http://localhost/api/tools/traffic-inspector/requests/${randomUUID()}`); const res = await requestDetailRoute.GET(req, { params: Promise.resolve({ id: randomUUID() }), }); assert.equal(res.status, 404); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(!body.error.message.includes("at /"), "must not leak stack trace"); }); @@ -166,7 +156,7 @@ test("PUT /requests/[id]/annotation: attaches annotation", async () => { params: Promise.resolve({ id: entry.id }), }); assert.equal(res.status, 200); - const body = await res.json() as { annotation: string }; + const body = (await res.json()) as { annotation: string }; assert.equal(body.annotation, "my note"); // Confirm buffer was updated diff --git a/tests/integration/traffic-inspector-session-requests.test.ts b/tests/integration/traffic-inspector-session-requests.test.ts index d0b9bcb14e..0da46d1ae8 100644 --- a/tests/integration/traffic-inspector-session-requests.test.ts +++ b/tests/integration/traffic-inspector-session-requests.test.ts @@ -17,20 +17,16 @@ const { resetDbInstance, getDbInstance } = await import("../../src/lib/db/core.t async function resetStorage() { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); getDbInstance(); } -const sessionsRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/route.ts" -); -const sessionDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/[id]/route.ts" -); -const sessionRequestsRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/[id]/requests/route.ts" -); +const sessionsRoute = await import("../../src/app/api/tools/traffic-inspector/sessions/route.ts"); +const sessionDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/sessions/[id]/route.ts"); +const sessionRequestsRoute = + await import("../../src/app/api/tools/traffic-inspector/sessions/[id]/requests/route.ts"); async function createSession(name?: string): Promise { const res = await sessionsRoute.POST( @@ -61,7 +57,7 @@ test.beforeEach(async () => { test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("POST /sessions/[id]/requests: seq increments 1, 2, 3", async () => { @@ -131,7 +127,7 @@ test("POST /sessions/[id]/requests: error response does not leak stack trace", a // POST to non-existent session — exercises the 404 path error body const res = await postRequest("00000000-0000-4000-8000-000000000099", "data"); assert.equal(res.status, 404); - const body = await res.json() as { error?: { message?: string } }; + const body = (await res.json()) as { error?: { message?: string } }; const msg = body?.error?.message ?? ""; assert.ok(!msg.includes("at /"), "should not contain stack trace"); }); diff --git a/tests/integration/traffic-inspector-sessions.test.ts b/tests/integration/traffic-inspector-sessions.test.ts index 3687b170b8..f2bb759b97 100644 --- a/tests/integration/traffic-inspector-sessions.test.ts +++ b/tests/integration/traffic-inspector-sessions.test.ts @@ -18,21 +18,17 @@ const { resetDbInstance, getDbInstance } = await import("../../src/lib/db/core.t async function resetStorage() { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // Re-initialize db getDbInstance(); } -const sessionsRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/route.ts" -); -const sessionDetailRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/[id]/route.ts" -); -const sessionHarRoute = await import( - "../../src/app/api/tools/traffic-inspector/sessions/[id]/export.har/route.ts" -); +const sessionsRoute = await import("../../src/app/api/tools/traffic-inspector/sessions/route.ts"); +const sessionDetailRoute = + await import("../../src/app/api/tools/traffic-inspector/sessions/[id]/route.ts"); +const sessionHarRoute = + await import("../../src/app/api/tools/traffic-inspector/sessions/[id]/export.har/route.ts"); const { appendSessionRequest } = await import("../../src/lib/db/inspectorSessions.ts"); test.beforeEach(async () => { @@ -40,7 +36,7 @@ test.beforeEach(async () => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("POST /sessions: creates a session", async () => { @@ -51,7 +47,7 @@ test("POST /sessions: creates a session", async () => { }); const res = await sessionsRoute.POST(req); assert.equal(res.status, 201); - const body = await res.json() as { id: string; started_at: string }; + const body = (await res.json()) as { id: string; started_at: string }; assert.ok(body.id, "should have an id"); assert.ok(body.started_at, "should have started_at"); }); @@ -85,7 +81,7 @@ test("GET /sessions: lists all sessions", async () => { const res = await sessionsRoute.GET(); assert.equal(res.status, 200); - const body = await res.json() as { sessions: unknown[] }; + const body = (await res.json()) as { sessions: unknown[] }; assert.equal(body.sessions.length, 2); }); @@ -97,7 +93,7 @@ test("PATCH /sessions/[id]: stop adds ended_at", async () => { body: JSON.stringify({}), }) ); - const session = await createRes.json() as { id: string }; + const session = (await createRes.json()) as { id: string }; const patchReq = new Request("http://localhost/", { method: "PATCH", @@ -108,7 +104,7 @@ test("PATCH /sessions/[id]: stop adds ended_at", async () => { params: Promise.resolve({ id: session.id }), }); assert.equal(patchRes.status, 200); - const body = await patchRes.json() as { ended_at: string | null }; + const body = (await patchRes.json()) as { ended_at: string | null }; assert.ok(body.ended_at !== null, "ended_at should be set after stop"); }); @@ -120,7 +116,7 @@ test("PATCH /sessions/[id]: rename updates name", async () => { body: JSON.stringify({ name: "old-name" }), }) ); - const session = await createRes.json() as { id: string }; + const session = (await createRes.json()) as { id: string }; const patchRes = await sessionDetailRoute.PATCH( new Request("http://localhost/", { @@ -131,7 +127,7 @@ test("PATCH /sessions/[id]: rename updates name", async () => { { params: Promise.resolve({ id: session.id }) } ); assert.equal(patchRes.status, 200); - const body = await patchRes.json() as { name: string }; + const body = (await patchRes.json()) as { name: string }; assert.equal(body.name, "new-name"); }); @@ -143,7 +139,7 @@ test("GET /sessions/[id]: returns session with requests", async () => { body: JSON.stringify({ name: "with-reqs" }), }) ); - const session = await createRes.json() as { id: string }; + const session = (await createRes.json()) as { id: string }; // Append a fake request const payload = JSON.stringify({ @@ -163,12 +159,11 @@ test("GET /sessions/[id]: returns session with requests", async () => { }); appendSessionRequest(session.id, payload); - const getRes = await sessionDetailRoute.GET( - new Request("http://localhost/"), - { params: Promise.resolve({ id: session.id }) } - ); + const getRes = await sessionDetailRoute.GET(new Request("http://localhost/"), { + params: Promise.resolve({ id: session.id }), + }); assert.equal(getRes.status, 200); - const body = await getRes.json() as { session: { id: string }; requests: unknown[] }; + const body = (await getRes.json()) as { session: { id: string }; requests: unknown[] }; assert.equal(body.session.id, session.id); assert.equal(body.requests.length, 1); }); @@ -181,21 +176,19 @@ test("DELETE /sessions/[id]: cascades requests", async () => { body: JSON.stringify({}), }) ); - const session = await createRes.json() as { id: string }; + const session = (await createRes.json()) as { id: string }; appendSessionRequest(session.id, JSON.stringify({ note: "test" })); - const delRes = await sessionDetailRoute.DELETE( - new Request("http://localhost/"), - { params: Promise.resolve({ id: session.id }) } - ); + const delRes = await sessionDetailRoute.DELETE(new Request("http://localhost/"), { + params: Promise.resolve({ id: session.id }), + }); assert.equal(delRes.status, 204); // Session should be gone - const getRes = await sessionDetailRoute.GET( - new Request("http://localhost/"), - { params: Promise.resolve({ id: session.id }) } - ); + const getRes = await sessionDetailRoute.GET(new Request("http://localhost/"), { + params: Promise.resolve({ id: session.id }), + }); assert.equal(getRes.status, 404); }); @@ -207,7 +200,7 @@ test("GET /sessions/[id]/export.har: returns HAR file", async () => { body: JSON.stringify({ name: "har-test" }), }) ); - const session = await createRes.json() as { id: string }; + const session = (await createRes.json()) as { id: string }; const reqPayload = { id: randomUUID(), @@ -226,16 +219,15 @@ test("GET /sessions/[id]/export.har: returns HAR file", async () => { }; appendSessionRequest(session.id, JSON.stringify(reqPayload)); - const harRes = await sessionHarRoute.GET( - new Request("http://localhost/"), - { params: Promise.resolve({ id: session.id }) } - ); + const harRes = await sessionHarRoute.GET(new Request("http://localhost/"), { + params: Promise.resolve({ id: session.id }), + }); assert.equal(harRes.status, 200); assert.ok( harRes.headers.get("content-disposition")?.includes(".har"), "should have .har filename" ); - const har = await harRes.json() as { log: { entries: unknown[] } }; + const har = (await harRes.json()) as { log: { entries: unknown[] } }; assert.ok(har.log, "should be a HAR object"); assert.equal(har.log.entries.length, 1); }); diff --git a/tests/integration/traffic-inspector-ws.test.ts b/tests/integration/traffic-inspector-ws.test.ts index 8bd12cad5c..656d6ebf86 100644 --- a/tests/integration/traffic-inspector-ws.test.ts +++ b/tests/integration/traffic-inspector-ws.test.ts @@ -18,9 +18,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; process.env.INSPECTOR_BUFFER_SIZE = "100"; const { TrafficBuffer } = await import("../../src/mitm/inspector/buffer.ts"); -const wsRoute = await import( - "../../src/app/api/tools/traffic-inspector/ws/route.ts" -); +const wsRoute = await import("../../src/app/api/tools/traffic-inspector/ws/route.ts"); function makeRequest(upgrade = "websocket", clientKey = "dGhlIHNhbXBsZSBub25jZQ=="): Request { return new Request("http://localhost/api/tools/traffic-inspector/ws", { @@ -33,14 +31,14 @@ function makeRequest(upgrade = "websocket", clientKey = "dGhlIHNhbXBsZSBub25jZQ= } test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("ws/route: rejects non-WebSocket GET with 426", async () => { const req = new Request("http://localhost/api/tools/traffic-inspector/ws"); const res = await wsRoute.GET(req); assert.equal(res.status, 426); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(body.error.message.includes("Upgrade"), "should mention upgrade"); }); @@ -57,7 +55,7 @@ test("ws/route: rejects when no raw socket available with 500", async () => { // No `.socket` property injected — Next.js standalone would attach it const res = await wsRoute.GET(req); assert.equal(res.status, 500); - const body = await res.json() as { error: { message: string } }; + const body = (await res.json()) as { error: { message: string } }; assert.ok(!body.error.message.includes("at /"), "must not leak stack trace"); }); diff --git a/tests/integration/v1-models-swr-response-flush-8728.test.ts b/tests/integration/v1-models-swr-response-flush-8728.test.ts index 60aa72c894..e876244bbb 100644 --- a/tests/integration/v1-models-swr-response-flush-8728.test.ts +++ b/tests/integration/v1-models-swr-response-flush-8728.test.ts @@ -81,7 +81,7 @@ function productionShapedSynchronousRefresh() { } test.after(() => { - fs.rmSync(CACHE_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(CACHE_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("the /v1/models route wires Next after() as its response-flush-safe scheduler", () => { @@ -152,7 +152,7 @@ test("an external client receives the stale body before synchronous refresh fini } catch (error) { if ((error as NodeJS.ErrnoException).code === "EPERM") { t.skip("sandbox does not permit opening HTTP listener sockets"); - fs.rmSync(socketDir, { recursive: true, force: true }); + fs.rmSync(socketDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } throw error; @@ -177,7 +177,7 @@ test("an external client receives the stale body before synchronous refresh fini ); } finally { await close(server); - fs.rmSync(socketDir, { recursive: true, force: true }); + fs.rmSync(socketDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); catalogCache.__resetCatalogBuilderRunsForTest(); } }); diff --git a/tests/integration/video-bridge-sampler-ffmpeg.test.ts b/tests/integration/video-bridge-sampler-ffmpeg.test.ts index c33bb770d9..e864786bbe 100644 --- a/tests/integration/video-bridge-sampler-ffmpeg.test.ts +++ b/tests/integration/video-bridge-sampler-ffmpeg.test.ts @@ -112,7 +112,9 @@ test( { skip: REAL_FFMPEG_SKIP }, async (context) => { const directory = await mkdtemp(join(tmpdir(), "omniroute-video-sampler-fixtures-")); - context.after(async () => rm(directory, { force: true, recursive: true })); + context.after(async () => + rm(directory, { force: true, recursive: true, maxRetries: 5, retryDelay: 100 }) + ); const rapidCuts = await createRapidEdgeCutFixture(directory); await context.test("rapid cuts near both ends retain coverage within the cap", async () => { diff --git a/tests/unit/10017-sse-control-lines-leak-openai-clients.test.ts b/tests/unit/10017-sse-control-lines-leak-openai-clients.test.ts index 8e3e4f9495..47ade4adc8 100644 --- a/tests/unit/10017-sse-control-lines-leak-openai-clients.test.ts +++ b/tests/unit/10017-sse-control-lines-leak-openai-clients.test.ts @@ -49,7 +49,7 @@ async function readTransformed(chunks: string[], options: object): Promise { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -59,7 +59,8 @@ function leakedUpstreamControlLines(output: string): string[] { .trim() .split("\n") .filter( - (l) => /^(?:id:|event:|retry:)/i.test(l) || (l.startsWith(":") && !l.startsWith(": x-omniroute-")) + (l) => + /^(?:id:|event:|retry:)/i.test(l) || (l.startsWith(":") && !l.startsWith(": x-omniroute-")) ); } @@ -166,7 +167,9 @@ test("#10017: OpenAI Responses passthrough KEEPS event framing (regression guard "Responses output_text.delta event framing must be preserved" ); assert.ok( - !lines.some((l) => l.startsWith("id:") || (l.startsWith(":") && !l.startsWith(": x-omniroute-"))), + !lines.some( + (l) => l.startsWith("id:") || (l.startsWith(":") && !l.startsWith(": x-omniroute-")) + ), "Responses passthrough must still strip id:/comment control lines" ); }); @@ -191,5 +194,8 @@ test("#10017: Claude Messages passthrough KEEPS event framing", async () => { const lines = text.trim().split("\n"); assert.ok(lines.includes("event: message_start"), "Claude event framing must be preserved"); - assert.ok(lines.includes("event: content_block_delta"), "Claude delta event framing must be preserved"); -}); \ No newline at end of file + assert.ok( + lines.includes("event: content_block_delta"), + "Claude delta event framing must be preserved" + ); +}); diff --git a/tests/unit/10085-compatible-generic-vs-uuid-credential.test.ts b/tests/unit/10085-compatible-generic-vs-uuid-credential.test.ts index cf1a72ad7e..5bb697f88d 100644 --- a/tests/unit/10085-compatible-generic-vs-uuid-credential.test.ts +++ b/tests/unit/10085-compatible-generic-vs-uuid-credential.test.ts @@ -33,13 +33,13 @@ const NODE_B_ID = `openai-compatible-chat-558d982b-0000-4000-8000-000000000000`; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function seedNode() { diff --git a/tests/unit/10197-openrouter-image-edits-route.test.ts b/tests/unit/10197-openrouter-image-edits-route.test.ts index a99846ef3a..eaf8c969a2 100644 --- a/tests/unit/10197-openrouter-image-edits-route.test.ts +++ b/tests/unit/10197-openrouter-image-edits-route.test.ts @@ -37,7 +37,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -68,7 +68,7 @@ test.after(() => { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10197 v1 image edit POST forwards built-in openrouter edits to the unified Image API", async () => { @@ -95,10 +95,14 @@ test("#10197 v1 image edit POST forwards built-in openrouter edits to the unifie else if (raw instanceof Uint8Array) hitBody = Buffer.from(raw).toString("utf8"); else if (raw instanceof ArrayBuffer) hitBody = Buffer.from(raw).toString("utf8"); else if (raw && typeof (raw as { arrayBuffer?: unknown }).arrayBuffer === "function") { - hitBody = Buffer.from(await (raw as { arrayBuffer(): Promise }).arrayBuffer()).toString("utf8"); + hitBody = Buffer.from( + await (raw as { arrayBuffer(): Promise }).arrayBuffer() + ).toString("utf8"); } return new Response( - JSON.stringify({ data: [{ b64_json: Buffer.from([0x89, 0x50, 0x4e, 0x47]).toString("base64") }] }), + JSON.stringify({ + data: [{ b64_json: Buffer.from([0x89, 0x50, 0x4e, 0x47]).toString("base64") }], + }), { status: 200, headers: { "content-type": "application/json" } } ); }; diff --git a/tests/unit/10313-catalog-cache-key-hashing.test.ts b/tests/unit/10313-catalog-cache-key-hashing.test.ts index 265fed1150..ca5b4d1947 100644 --- a/tests/unit/10313-catalog-cache-key-hashing.test.ts +++ b/tests/unit/10313-catalog-cache-key-hashing.test.ts @@ -18,7 +18,7 @@ const SECRET = "sk-live-PROBE-10313-SUPER-SECRET-TOKEN"; test.beforeEach(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); }); @@ -26,7 +26,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function captureMapKeys(): { keys: string[]; restore: () => void } { @@ -118,14 +118,26 @@ test("cache keys embed the sha256 digest of the secret, never the raw secret (#1 // The hashed fingerprint, not the raw secret, rides in the cache keys. const keysWithDigestA = catalogKeys.filter((k) => k.includes(digestA)); const keysWithDigestB = catalogKeys.filter((k) => k.includes(digestB)); - assert.ok(keysWithDigestA.length > 0, `expected a cache key embedding the fingerprint of A: ${catalogKeys.join(",")}`); - assert.ok(keysWithDigestB.length > 0, `expected a cache key embedding the fingerprint of B: ${catalogKeys.join(",")}`); + assert.ok( + keysWithDigestA.length > 0, + `expected a cache key embedding the fingerprint of A: ${catalogKeys.join(",")}` + ); + assert.ok( + keysWithDigestB.length > 0, + `expected a cache key embedding the fingerprint of B: ${catalogKeys.join(",")}` + ); // Raw secrets must never appear (issue #10313 root cause). assert.ok(!catalogKeys.some((k) => k.includes(rawA) || k.includes(rawB))); // Identical secrets ⇒ identical key (memoized reuse); different ⇒ distinct. - assert.ok(keysWithDigestA.every((k) => k === keysWithDigestA[0]), "all A keys must be identical"); - assert.ok(keysWithDigestB.every((k) => k === keysWithDigestB[0]), "all B keys must be identical"); + assert.ok( + keysWithDigestA.every((k) => k === keysWithDigestA[0]), + "all A keys must be identical" + ); + assert.ok( + keysWithDigestB.every((k) => k === keysWithDigestB[0]), + "all B keys must be identical" + ); assert.notEqual(keysWithDigestA[0], keysWithDigestB[0]); -}); \ No newline at end of file +}); diff --git a/tests/unit/10347-embed-402-cooldown.test.ts b/tests/unit/10347-embed-402-cooldown.test.ts index ddb98259ba..4392ea0f7c 100644 --- a/tests/unit/10347-embed-402-cooldown.test.ts +++ b/tests/unit/10347-embed-402-cooldown.test.ts @@ -27,17 +27,19 @@ const { handleEmbedding } = await import("../../open-sse/handlers/embeddings.ts" test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function readConnectionRow(connId: string) { const db = core.getDbInstance() as unknown as { prepare: (sql: string) => { - get: (id: string) => { - test_status: unknown; - rate_limited_until: unknown; - last_error_type: unknown; - } | undefined; + get: (id: string) => + | { + test_status: unknown; + rate_limited_until: unknown; + last_error_type: unknown; + } + | undefined; }; }; return db @@ -100,4 +102,4 @@ test("embed 402 marks the connection terminal credits_exhausted (stops re-select } finally { globalThis.fetch = originalFetch; } -}); \ No newline at end of file +}); diff --git a/tests/unit/7993-noauth-proxy-routing.test.ts b/tests/unit/7993-noauth-proxy-routing.test.ts index 32467f14e2..dec0ac47a8 100644 --- a/tests/unit/7993-noauth-proxy-routing.test.ts +++ b/tests/unit/7993-noauth-proxy-routing.test.ts @@ -79,7 +79,7 @@ test.before(async () => { test.after(() => { proxyServer?.close(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7993 getProviderCredentials('opencode-zen') hydrates the proxy saved under the sibling 'opencode' connection", async () => { diff --git a/tests/unit/8200-perplexity-web-401-cooldown.test.ts b/tests/unit/8200-perplexity-web-401-cooldown.test.ts index d98b22351b..ee65e5b817 100644 --- a/tests/unit/8200-perplexity-web-401-cooldown.test.ts +++ b/tests/unit/8200-perplexity-web-401-cooldown.test.ts @@ -20,13 +20,13 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("BUG #8200: single perplexity-web 401 (cookie expiry) does not terminal-expire the only connection", async () => { diff --git a/tests/unit/8326-compatible-id-regex.test.ts b/tests/unit/8326-compatible-id-regex.test.ts index 35901f861b..a3d491e734 100644 --- a/tests/unit/8326-compatible-id-regex.test.ts +++ b/tests/unit/8326-compatible-id-regex.test.ts @@ -29,9 +29,8 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const routeModule = await import("../../src/app/api/v1/providers/[provider]/models/route.ts"); -const { isCompatibleProviderConnectionId } = await import( - "../../src/shared/utils/compatibleProviderId.ts" -); +const { isCompatibleProviderConnectionId } = + await import("../../src/shared/utils/compatibleProviderId.ts"); const { getProviderDisplayName } = await import("../../src/lib/display/names.ts"); function makeRequest(provider: string) { @@ -50,7 +49,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const UUID = "02669115-2545-4896-b003-cb4dac09d441"; @@ -105,10 +104,7 @@ test("GET /v1/providers/:provider/models still rejects unrelated look-alike pref }); test("getProviderDisplayName simplifies all 4 generated compatible id shapes", () => { - assert.equal( - getProviderDisplayName("openai-compatible-chat-" + UUID), - "Compatible (openai)" - ); + assert.equal(getProviderDisplayName("openai-compatible-chat-" + UUID), "Compatible (openai)"); assert.equal( getProviderDisplayName("openai-compatible-responses-" + UUID), "Compatible (openai)" diff --git a/tests/unit/8327-models-owned-by-prefix.test.ts b/tests/unit/8327-models-owned-by-prefix.test.ts index 464845dc90..8a4147ffaa 100644 --- a/tests/unit/8327-models-owned-by-prefix.test.ts +++ b/tests/unit/8327-models-owned-by-prefix.test.ts @@ -39,7 +39,7 @@ const CONFIGURED_PREFIX = "pix4k-talk"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -50,7 +50,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8327: synced models on a compatible provider node expose the configured prefix as owned_by, not the raw UUID", async () => { @@ -361,10 +361,7 @@ test("#9416: provider with configured prefix still uses the configured prefix (r // Must still use the configured prefix, NOT slugified name const entry = body.data.find((m) => m.id === `${CONFIGURED_PREFIX}/glm-5.2`); - assert.ok( - entry, - `expected entry with configured prefix "${CONFIGURED_PREFIX}/glm-5.2"` - ); + assert.ok(entry, `expected entry with configured prefix "${CONFIGURED_PREFIX}/glm-5.2"`); assert.equal(entry!.owned_by, CONFIGURED_PREFIX); assert.notEqual(entry!.owned_by, "pix4k-talk-probe"); // not slugified }); diff --git a/tests/unit/8332-combo-vision-fallback.test.ts b/tests/unit/8332-combo-vision-fallback.test.ts index 2e04b8194c..86ec24e9f2 100644 --- a/tests/unit/8332-combo-vision-fallback.test.ts +++ b/tests/unit/8332-combo-vision-fallback.test.ts @@ -96,7 +96,7 @@ test.after(() => { clearModelsDevCapabilities(); settingsDb.clearAllLKGP(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { @@ -153,7 +153,11 @@ test( [], "vision-incapable rr-blind must never receive the image_url body, even as a last-resort fallback" ); - assert.notEqual(result.status, 200, "must not silently succeed via the vision-incapable target"); + assert.notEqual( + result.status, + 200, + "must not silently succeed via the vision-incapable target" + ); } ); diff --git a/tests/unit/8336-audit-loopback-login.test.ts b/tests/unit/8336-audit-loopback-login.test.ts index 2159bac0ba..038311cf1b 100644 --- a/tests/unit/8336-audit-loopback-login.test.ts +++ b/tests/unit/8336-audit-loopback-login.test.ts @@ -36,7 +36,7 @@ const originalGetCookieStore = loginRoute.authRouteInternals.getCookieStore; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); process.env.INITIAL_PASSWORD = "correct-secret-8336"; } @@ -52,7 +52,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) { delete process.env.INITIAL_PASSWORD; } else { diff --git a/tests/unit/8374-plugins-status-optional.test.ts b/tests/unit/8374-plugins-status-optional.test.ts index f5936b7e87..5c5bae11d5 100644 --- a/tests/unit/8374-plugins-status-optional.test.ts +++ b/tests/unit/8374-plugins-status-optional.test.ts @@ -44,7 +44,7 @@ before(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/8385-perkey-proxy-global-toggle.test.ts b/tests/unit/8385-perkey-proxy-global-toggle.test.ts index 84a0226ca8..264518c8e7 100644 --- a/tests/unit/8385-perkey-proxy-global-toggle.test.ts +++ b/tests/unit/8385-perkey-proxy-global-toggle.test.ts @@ -27,13 +27,13 @@ async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("issue #8385: global perKeyProxyEnabled=false must override a connection's per_key_proxy_enabled=1", async () => { diff --git a/tests/unit/8388-compression-detail-persist.test.ts b/tests/unit/8388-compression-detail-persist.test.ts index c65d29ba95..cdddcf219b 100644 --- a/tests/unit/8388-compression-detail-persist.test.ts +++ b/tests/unit/8388-compression-detail-persist.test.ts @@ -18,17 +18,15 @@ import path from "node:path"; const tmpDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-8388-")); process.env.DATA_DIR = tmpDataDir; -const { compressionSettingsUpdateSchema } = await import( - "../../src/shared/validation/compressionConfigSchemas.ts" -); +const { compressionSettingsUpdateSchema } = + await import("../../src/shared/validation/compressionConfigSchemas.ts"); const { resetDbInstance } = await import("../../src/lib/db/core.ts"); -const { getCompressionSettings, updateCompressionSettings } = await import( - "../../src/lib/db/compression.ts" -); +const { getCompressionSettings, updateCompressionSettings } = + await import("../../src/lib/db/compression.ts"); test.after(() => { resetDbInstance(); - fs.rmSync(tmpDataDir, { recursive: true, force: true }); + fs.rmSync(tmpDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8388: PUT body carrying ccr detail (minChars/retrievalRampFactor) is ACCEPTED by the schema", () => { diff --git a/tests/unit/8395-plugin-hooks-fire.test.ts b/tests/unit/8395-plugin-hooks-fire.test.ts index 2d91d3611e..1d8c2b561e 100644 --- a/tests/unit/8395-plugin-hooks-fire.test.ts +++ b/tests/unit/8395-plugin-hooks-fire.test.ts @@ -26,7 +26,7 @@ test( t.after(async () => { loaded?.cleanup(); - await rm(pluginDir, { recursive: true, force: true }); + await rm(pluginDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); await writeFile( @@ -98,23 +98,20 @@ export async function onRequest(ctx) { } ); -test( - "loadPlugin no longer spawns the plugin host with stdout/stderr fully ignored", - async () => { - const source = await readFile( - join(import.meta.dirname, "../../src/lib/plugins/loader.ts"), - "utf-8" - ); - // The original bug: stdio: ["ignore", "ignore", "ignore", "ipc"] discards - // stdout (fd 1) and stderr (fd 2) at the OS level unconditionally. - assert.doesNotMatch( - source, - /stdio:\s*\[\s*["']ignore["']\s*,\s*["']ignore["']\s*,\s*["']ignore["']\s*,\s*["']ipc["']\s*\]/, - "loader.ts must not spawn the plugin host with stdout+stderr both set to " + - "'ignore' — that silently discards all plugin console.log/console.error output" - ); - } -); +test("loadPlugin no longer spawns the plugin host with stdout/stderr fully ignored", async () => { + const source = await readFile( + join(import.meta.dirname, "../../src/lib/plugins/loader.ts"), + "utf-8" + ); + // The original bug: stdio: ["ignore", "ignore", "ignore", "ipc"] discards + // stdout (fd 1) and stderr (fd 2) at the OS level unconditionally. + assert.doesNotMatch( + source, + /stdio:\s*\[\s*["']ignore["']\s*,\s*["']ignore["']\s*,\s*["']ignore["']\s*,\s*["']ipc["']\s*\]/, + "loader.ts must not spawn the plugin host with stdout+stderr both set to " + + "'ignore' — that silently discards all plugin console.log/console.error output" + ); +}); // Secondary #8395 finding: runPluginOnResponseHook was only wired into chatCore.ts's // STREAMING success path — the non-streaming (stream:false) JSON-return branch @@ -131,7 +128,9 @@ test("chatCore.ts calls runPluginOnResponseHook from both the non-streaming and "utf-8" ); - const nonStreamingReturnIndex = source.indexOf("buildNonStreamingJsonResponse(translatedResponse"); + const nonStreamingReturnIndex = source.indexOf( + "buildNonStreamingJsonResponse(translatedResponse" + ); const hookCallNeedle = "await runPluginOnResponseHook({"; const hookCallIndex = source.indexOf(hookCallNeedle); const secondHookCallIndex = source.indexOf(hookCallNeedle, hookCallIndex + 1); diff --git a/tests/unit/8431-multiwindow-quota-eviction.test.ts b/tests/unit/8431-multiwindow-quota-eviction.test.ts index ebe0767a50..f62306db6b 100644 --- a/tests/unit/8431-multiwindow-quota-eviction.test.ts +++ b/tests/unit/8431-multiwindow-quota-eviction.test.ts @@ -35,10 +35,17 @@ const quotaCache = await import("../../src/domain/quotaCache.ts"); test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); -const COLD_WINDOWS = ["Bonus Pack 1", "Bonus Pack 2", "Bonus Pack 3", "Bonus Pack 4", "Weekly", "Daily"]; +const COLD_WINDOWS = [ + "Bonus Pack 1", + "Bonus Pack 2", + "Bonus Pack 3", + "Bonus Pack 4", + "Weekly", + "Daily", +]; const HOT_WINDOWS = ["Monthly", "Bonus Pack 5", "Bonus Pack 6"]; test("#8431 idle healthy windows survive rehydration even when hot windows accumulate >200 rows", () => { diff --git a/tests/unit/8488-capability-filter-fail-closed.test.ts b/tests/unit/8488-capability-filter-fail-closed.test.ts index 6a77e10434..2be07aa7e7 100644 --- a/tests/unit/8488-capability-filter-fail-closed.test.ts +++ b/tests/unit/8488-capability-filter-fail-closed.test.ts @@ -67,13 +67,13 @@ const log = { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8488 filter: some tool-capable targets kept (unchanged)", () => { diff --git a/tests/unit/8510-adobe-firefly-edits-route.test.ts b/tests/unit/8510-adobe-firefly-edits-route.test.ts index 5e80cad4d4..edbb8c4b24 100644 --- a/tests/unit/8510-adobe-firefly-edits-route.test.ts +++ b/tests/unit/8510-adobe-firefly-edits-route.test.ts @@ -19,10 +19,8 @@ const providersDb = await import("../../src/lib/db/providers.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); const imageEditRoute = await import("../../src/app/api/v1/images/edits/route.ts"); const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); -const { - ADOBE_FIREFLY_IMAGE_UPLOAD_URL, - ADOBE_FIREFLY_IMAGE_SUBMIT_URL, -} = await import("../../open-sse/services/adobeFireflyClient.ts"); +const { ADOBE_FIREFLY_IMAGE_UPLOAD_URL, ADOBE_FIREFLY_IMAGE_SUBMIT_URL } = + await import("../../open-sse/services/adobeFireflyClient.ts"); interface ErrorResponseBody { error: { message: string; code?: string }; @@ -38,7 +36,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -86,7 +84,7 @@ test.after(() => { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8510 v1 image edit POST uploads Adobe Firefly reference images and dispatches referenceBlobs", async () => { @@ -148,10 +146,7 @@ test("#8510 v1 image edit POST uploads Adobe Firefly reference images and dispat id: string; }>; assert.ok(Array.isArray(referenceBlobs), "generate-async payload must carry referenceBlobs"); - assert.deepEqual( - referenceBlobs.map((r) => r.id).sort(), - [...uploadedIds].sort() - ); + assert.deepEqual(referenceBlobs.map((r) => r.id).sort(), [...uploadedIds].sort()); }); test("#8510 v1 image edit POST rejects more than 4 Adobe Firefly reference images", async () => { @@ -206,7 +201,9 @@ test("#8510 v1 image edit POST surfaces missing Adobe Firefly credentials", asyn }); test("#8510 v1 image edit POST surfaces Adobe Firefly rate-limit sentinel", async () => { - await seedAdobeFireflyConnection({ rateLimitedUntil: new Date(Date.now() + 60_000).toISOString() }); + await seedAdobeFireflyConnection({ + rateLimitedUntil: new Date(Date.now() + 60_000).toISOString(), + }); globalThis.fetch = async () => { throw new Error("Rate-limited path must not reach upstream"); }; diff --git a/tests/unit/8779-agy-prefix-credential-lookup.test.ts b/tests/unit/8779-agy-prefix-credential-lookup.test.ts index 446f1e708b..0a9ddb81d5 100644 --- a/tests/unit/8779-agy-prefix-credential-lookup.test.ts +++ b/tests/unit/8779-agy-prefix-credential-lookup.test.ts @@ -33,7 +33,7 @@ const model = await import("../../open-sse/services/model.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -52,7 +52,7 @@ async function seedOnly(provider: string) { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("the agy/ prefix still canonicalizes to antigravity (#8013 unchanged)", () => { diff --git a/tests/unit/8958-alias-backed-node-prefix.test.ts b/tests/unit/8958-alias-backed-node-prefix.test.ts index f823d7dd62..1ec37506f7 100644 --- a/tests/unit/8958-alias-backed-node-prefix.test.ts +++ b/tests/unit/8958-alias-backed-node-prefix.test.ts @@ -38,7 +38,7 @@ const MODEL_ID = "opc/big-pickle"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -85,7 +85,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8958: alias-backed model on a compatible node is not duplicated under the raw UUID prefix (alias mode)", async () => { diff --git a/tests/unit/9034-alias-backed-prefix-id-repro.test.ts b/tests/unit/9034-alias-backed-prefix-id-repro.test.ts index 76188b69bd..81d470c7ff 100644 --- a/tests/unit/9034-alias-backed-prefix-id-repro.test.ts +++ b/tests/unit/9034-alias-backed-prefix-id-repro.test.ts @@ -29,7 +29,8 @@ type CoreModule = typeof import("../../src/lib/db/core.ts"); type ProvidersDbModule = typeof import("../../src/lib/db/providers.ts"); type ModelsDbModule = typeof import("../../src/lib/db/models.ts"); type CatalogModule = typeof import("../../src/app/api/v1/models/catalog.ts"); -type ManagedAvailableModelsModule = typeof import("../../src/lib/providerModels/managedAvailableModels.ts"); +type ManagedAvailableModelsModule = + typeof import("../../src/lib/providerModels/managedAvailableModels.ts"); let core: CoreModule; let providersDb: ProvidersDbModule; @@ -45,7 +46,7 @@ const MODEL_NAME = "kimi-k2"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -61,7 +62,7 @@ test.before(async () => { test.after(async () => { if (core) core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9034: alias-backed model id must use the configured prefix, not the raw provider-node UUID", async () => { @@ -117,4 +118,4 @@ test("#9034: alias-backed model id must use the configured prefix, not the raw p `entry id "${id}" must not start with the raw provider-node UUID "${NODE_ID}" when a prefix ("${CONFIGURED_PREFIX}") is configured` ); } -}); \ No newline at end of file +}); diff --git a/tests/unit/9134-repro-audio-combo-rejection.test.ts b/tests/unit/9134-repro-audio-combo-rejection.test.ts index cdf26933cd..a54a637651 100644 --- a/tests/unit/9134-repro-audio-combo-rejection.test.ts +++ b/tests/unit/9134-repro-audio-combo-rejection.test.ts @@ -22,7 +22,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** Minimal but structurally valid WAV so nothing rejects the upload shape. */ @@ -72,8 +72,7 @@ test("#9134 combo name is rejected instead of resolved", async () => { new Response(JSON.stringify({ text: "ok" }), { status: 200, headers: { "Content-Type": "application/json" }, - }) - ) as typeof fetch; + })) as typeof fetch; const res = await route.POST(transcriptionRequest("transcricao")); const body = await res.text(); @@ -92,4 +91,4 @@ test("#9134 combo name is rejected instead of resolved", async () => { !body.includes("Invalid transcription model"), `BUG #9134: combo name was not resolved — got: ${body}` ); -}); \ No newline at end of file +}); diff --git a/tests/unit/9147-catalog-eventloop-yield.test.ts b/tests/unit/9147-catalog-eventloop-yield.test.ts index 91068f367e..a5102eebc6 100644 --- a/tests/unit/9147-catalog-eventloop-yield.test.ts +++ b/tests/unit/9147-catalog-eventloop-yield.test.ts @@ -18,7 +18,7 @@ const MODELS_PER_CONNECTION = 12; // ~720 synced models total async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9147 — catalog build at catalog-scale must not pin the event loop for a long stretch", async (t) => { diff --git a/tests/unit/9201-search-proxy-bypass.test.ts b/tests/unit/9201-search-proxy-bypass.test.ts index 48fcff4858..98440bd35d 100644 --- a/tests/unit/9201-search-proxy-bypass.test.ts +++ b/tests/unit/9201-search-proxy-bypass.test.ts @@ -66,7 +66,7 @@ test.after(async () => { searchRegistry.SEARCH_PROVIDERS["serper-search"].baseUrl = originalSerperBaseUrl; await new Promise((resolve) => proxyServer.close(() => resolve())); core.resetDbInstance(); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function installProxyResponseCounter() { diff --git a/tests/unit/9232-purge-proxy-assignments-on-delete.test.ts b/tests/unit/9232-purge-proxy-assignments-on-delete.test.ts index aad652d005..2c56c8d6f3 100644 --- a/tests/unit/9232-purge-proxy-assignments-on-delete.test.ts +++ b/tests/unit/9232-purge-proxy-assignments-on-delete.test.ts @@ -17,7 +17,8 @@ async function resetStorage() { core.resetDbInstance(); for (let attempt = 0; attempt < 10; attempt++) { try { - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); break; } catch (error: unknown) { const code = (error as { code?: string } | undefined)?.code; @@ -34,7 +35,7 @@ test.beforeEach(async () => { }); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function setupConnectionWithAssignment() { diff --git a/tests/unit/_mocks/settings.ts b/tests/unit/_mocks/settings.ts index 2ccd31da52..d3d249f1fb 100644 --- a/tests/unit/_mocks/settings.ts +++ b/tests/unit/_mocks/settings.ts @@ -46,11 +46,11 @@ export function setupSettingsFixture(slug: string): SettingsFixture { const runtime = await import("../../../src/lib/config/runtimeSettings.ts"); core.resetDbInstance(); runtime.resetRuntimeSettingsStateForTests(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(testDataDir, { recursive: true }); }, cleanup() { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }, }; activeFixture = fixture; diff --git a/tests/unit/a2a-auth-timing-safe.test.ts b/tests/unit/a2a-auth-timing-safe.test.ts index 57ecbb4995..3e14c90cb8 100644 --- a/tests/unit/a2a-auth-timing-safe.test.ts +++ b/tests/unit/a2a-auth-timing-safe.test.ts @@ -34,14 +34,14 @@ function makeJsonRpcRequest(token?: string): NextRequest { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); process.env.OMNIROUTE_API_KEY = API_KEY; }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/a2a-enabled-route.test.ts b/tests/unit/a2a-enabled-route.test.ts index 2c52cdf9ac..a5a6a44111 100644 --- a/tests/unit/a2a-enabled-route.test.ts +++ b/tests/unit/a2a-enabled-route.test.ts @@ -19,7 +19,7 @@ const a2aRoute = await import("../../src/app/a2a/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/a2a-route-require-api-key.test.ts b/tests/unit/a2a-route-require-api-key.test.ts index 4fec1a55c8..592aeec9dd 100644 --- a/tests/unit/a2a-route-require-api-key.test.ts +++ b/tests/unit/a2a-route-require-api-key.test.ts @@ -24,7 +24,7 @@ const ORIGINAL_A2A_KEY = process.env.OMNIROUTE_API_KEY; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_REQUIRE === undefined) delete process.env.REQUIRE_API_KEY; else process.env.REQUIRE_API_KEY = ORIGINAL_REQUIRE; if (ORIGINAL_A2A_KEY === undefined) delete process.env.OMNIROUTE_API_KEY; diff --git a/tests/unit/a2a-task-owner-idor.test.ts b/tests/unit/a2a-task-owner-idor.test.ts index 365744ed33..aaa35142c8 100644 --- a/tests/unit/a2a-task-owner-idor.test.ts +++ b/tests/unit/a2a-task-owner-idor.test.ts @@ -35,7 +35,7 @@ const ORIGINAL_REQUIRE = process.env.REQUIRE_API_KEY; after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_REQUIRE === undefined) delete process.env.REQUIRE_API_KEY; else process.env.REQUIRE_API_KEY = ORIGINAL_REQUIRE; }); diff --git a/tests/unit/a2a-v1-compat-10839.test.ts b/tests/unit/a2a-v1-compat-10839.test.ts index 7aeea86542..6df10dbbc9 100644 --- a/tests/unit/a2a-v1-compat-10839.test.ts +++ b/tests/unit/a2a-v1-compat-10839.test.ts @@ -37,14 +37,14 @@ function makeJsonRpcRequest(body: unknown): NextRequest { test.beforeEach(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ a2aEnabled: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10839: v1.0 SendMessage is aliased to message/send and reshapes the response", async () => { diff --git a/tests/unit/access-tokens-db.test.ts b/tests/unit/access-tokens-db.test.ts index 9593b51613..d0d6c4c890 100644 --- a/tests/unit/access-tokens-db.test.ts +++ b/tests/unit/access-tokens-db.test.ts @@ -18,7 +18,7 @@ test.after(() => { core.resetDbInstance(); } catch {} try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/account-concurrency-cap.test.ts b/tests/unit/account-concurrency-cap.test.ts index 425f27b565..0179f93350 100644 --- a/tests/unit/account-concurrency-cap.test.ts +++ b/tests/unit/account-concurrency-cap.test.ts @@ -31,7 +31,7 @@ function getConnectionId(connection: NonNullable): string { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,7 +51,7 @@ beforeEach(async () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("maxConcurrent DB round-trip", () => { diff --git a/tests/unit/account-fallback-service.test.ts b/tests/unit/account-fallback-service.test.ts index 266179ec7a..d28075545a 100644 --- a/tests/unit/account-fallback-service.test.ts +++ b/tests/unit/account-fallback-service.test.ts @@ -1617,7 +1617,7 @@ test("isAccountDeactivated matches a custom signal after setCustomBannedSignals" async function resetStorage10460() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR_10460, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR_10460, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR_10460, { recursive: true }); } @@ -1634,7 +1634,7 @@ async function seedConn10460(provider: string): Promise { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR_10460, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR_10460, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10460: model-unsupported 400 returns shouldFallback:false (no account cooldown)", async () => { diff --git a/tests/unit/acp-agents-route.test.ts b/tests/unit/acp-agents-route.test.ts index 2d3065a9a8..a64a2f0f9d 100644 --- a/tests/unit/acp-agents-route.test.ts +++ b/tests/unit/acp-agents-route.test.ts @@ -18,7 +18,7 @@ const ORIGINAL_JWT_SECRET = process.env.JWT_SECRET; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; delete process.env.JWT_SECRET; @@ -50,7 +50,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) { delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/active-request-stream-chunks-lifecycle.test.ts b/tests/unit/active-request-stream-chunks-lifecycle.test.ts index 95547d8e61..35fd1cbc2d 100644 --- a/tests/unit/active-request-stream-chunks-lifecycle.test.ts +++ b/tests/unit/active-request-stream-chunks-lifecycle.test.ts @@ -18,7 +18,7 @@ const stripChunkTs = (chunk: string): string => chunk.replace(/^\[\d{2}:\d{2}:\d test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Helper: Simulates /api/logs/[id] API route logic ────────────────────── diff --git a/tests/unit/admin-audit-events.test.ts b/tests/unit/admin-audit-events.test.ts index b8aa06710b..d521d2a0d4 100644 --- a/tests/unit/admin-audit-events.test.ts +++ b/tests/unit/admin-audit-events.test.ts @@ -24,7 +24,7 @@ const originalGetLogoutCookieStore = logoutRoute.logoutRouteInternals.getCookieS function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("auth login/logout routes emit structured audit events with ip and request id", async () => { diff --git a/tests/unit/agent-bridge-cert-regenerate-force-10467.test.ts b/tests/unit/agent-bridge-cert-regenerate-force-10467.test.ts index fc600982c6..b8af604efc 100644 --- a/tests/unit/agent-bridge-cert-regenerate-force-10467.test.ts +++ b/tests/unit/agent-bridge-cert-regenerate-force-10467.test.ts @@ -23,7 +23,7 @@ async function withTempDataDir(fn: (dir: string) => Promise): Promise { } finally { if (previous === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = previous; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/agent-bridge-config-portability.test.ts b/tests/unit/agent-bridge-config-portability.test.ts index 8a01a90167..a398ad980f 100644 --- a/tests/unit/agent-bridge-config-portability.test.ts +++ b/tests/unit/agent-bridge-config-portability.test.ts @@ -10,9 +10,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-agentbridge-config-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-agentbridge-config-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -22,7 +20,8 @@ async function resetStorage() { core.resetDbInstance(); for (let attempt = 0; attempt < 10; attempt++) { try { - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); break; } catch (error: unknown) { const code = (error as { code?: string } | null)?.code; @@ -39,7 +38,7 @@ test.beforeEach(async () => { }); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("AgentBridgeConfigSchema accepts a well-formed config", () => { @@ -76,9 +75,7 @@ test("import then export roundtrips bypass + custom hosts + mappings", () => { const config = { version: 1 as const, bypassPatterns: ["*.bank.test", "literal.example.com"], - customHosts: [ - { host: "api.internal.test", kind: "custom" as const, label: "Internal LLM" }, - ], + customHosts: [{ host: "api.internal.test", kind: "custom" as const, label: "Internal LLM" }], agentMappings: { cursor: [{ source: "gpt-4o", target: "claude-sonnet-4-5" }], }, diff --git a/tests/unit/agent-bridge-mappings-sync-8656.test.ts b/tests/unit/agent-bridge-mappings-sync-8656.test.ts index 7d98ef82b4..ce477ef33e 100644 --- a/tests/unit/agent-bridge-mappings-sync-8656.test.ts +++ b/tests/unit/agent-bridge-mappings-sync-8656.test.ts @@ -25,7 +25,7 @@ const { getMitmAlias } = await import("../../src/lib/db/models/mitmAlias.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(() => { test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* noop */ } diff --git a/tests/unit/agent-bridge-server-route-dynamic-import.test.ts b/tests/unit/agent-bridge-server-route-dynamic-import.test.ts index a207fd890a..0970e0e902 100644 --- a/tests/unit/agent-bridge-server-route-dynamic-import.test.ts +++ b/tests/unit/agent-bridge-server-route-dynamic-import.test.ts @@ -20,14 +20,14 @@ const serverRoute = await import("../../src/app/api/tools/agent-bridge/server/ro function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(() => resetDb()); test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* noop */ } diff --git a/tests/unit/agent-bridge-state-full-payload-8656.test.ts b/tests/unit/agent-bridge-state-full-payload-8656.test.ts index c53bc040c0..885248f16e 100644 --- a/tests/unit/agent-bridge-state-full-payload-8656.test.ts +++ b/tests/unit/agent-bridge-state-full-payload-8656.test.ts @@ -30,7 +30,7 @@ const { replaceUserBypassPatterns } = await import("../../src/lib/db/agentBridge function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -40,7 +40,7 @@ test.beforeEach(() => { test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* noop */ } diff --git a/tests/unit/agentSkills-cliRegistryParser.test.ts b/tests/unit/agentSkills-cliRegistryParser.test.ts index 0e18080e70..1990c591d6 100644 --- a/tests/unit/agentSkills-cliRegistryParser.test.ts +++ b/tests/unit/agentSkills-cliRegistryParser.test.ts @@ -29,7 +29,7 @@ function withFixtureCli(files: Record): { cleanup: () => void } return { cleanup() { process.chdir(originalCwd); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }, }; } @@ -315,7 +315,7 @@ test("parseCliRegistry() throws if commands directory is missing", () => { ); } finally { process.chdir(originalCwd); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/agentSkills-generator.test.ts b/tests/unit/agentSkills-generator.test.ts index 9391af4a7f..66360b34ce 100644 --- a/tests/unit/agentSkills-generator.test.ts +++ b/tests/unit/agentSkills-generator.test.ts @@ -30,7 +30,7 @@ function mkTmpDir(): string { /** Cleanup a tmp directory. */ function rmTmpDir(dir: string): void { try { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/agentSkills-openapiParser.test.ts b/tests/unit/agentSkills-openapiParser.test.ts index a3273dbce8..c5988644dc 100644 --- a/tests/unit/agentSkills-openapiParser.test.ts +++ b/tests/unit/agentSkills-openapiParser.test.ts @@ -28,7 +28,7 @@ function withFixtureOpenapi(yamlContent: string): { cleanup: () => void } { return { cleanup() { process.chdir(originalCwd); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }, }; } @@ -191,7 +191,7 @@ test("parseOpenapi() throws if openapi.yaml is missing", () => { ); } finally { process.chdir(originalCwd); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/agentSkills-routes.test.ts b/tests/unit/agentSkills-routes.test.ts index d2eaa5fbb8..18ab884fbc 100644 --- a/tests/unit/agentSkills-routes.test.ts +++ b/tests/unit/agentSkills-routes.test.ts @@ -46,7 +46,7 @@ const generateRoute = await import("../../src/app/api/agent-skills/generate/rout async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } @@ -76,7 +76,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/agentbridge-antigravity-cert-hosts-6494.test.ts b/tests/unit/agentbridge-antigravity-cert-hosts-6494.test.ts index 16802be699..3218daa0b0 100644 --- a/tests/unit/agentbridge-antigravity-cert-hosts-6494.test.ts +++ b/tests/unit/agentbridge-antigravity-cert-hosts-6494.test.ts @@ -38,7 +38,7 @@ test("generateCert() issues a cert whose SAN list covers all 4 antigravity hosts t.after(() => { if (previousDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = previousDataDir; - fs.rmSync(tmpDataDir, { recursive: true, force: true }); + fs.rmSync(tmpDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Fresh module instance so it re-reads process.env.DATA_DIR via resolveMitmDataDir(). @@ -50,9 +50,6 @@ test("generateCert() issues a cert whose SAN list covers all 4 antigravity hosts const san = cert.subjectAltName ?? ""; for (const host of EXPECTED_HOSTS) { - assert.ok( - san.includes(host), - `expected generated cert SAN to include "${host}" — got: ${san}` - ); + assert.ok(san.includes(host), `expected generated cert SAN to include "${host}" — got: ${san}`); } }); diff --git a/tests/unit/agentbridge-mitm-router-key-6403.test.ts b/tests/unit/agentbridge-mitm-router-key-6403.test.ts index 593ce713ba..5f2009abaf 100644 --- a/tests/unit/agentbridge-mitm-router-key-6403.test.ts +++ b/tests/unit/agentbridge-mitm-router-key-6403.test.ts @@ -27,13 +27,12 @@ process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-secret-for-agen const core = await import("../../src/lib/db/core.ts"); const { createApiKey } = await import("../../src/lib/db/apiKeys.ts"); -const { resolveRouterApiKey } = await import( - "../../src/app/api/tools/agent-bridge/server/route.ts" -); +const { resolveRouterApiKey } = + await import("../../src/app/api/tools/agent-bridge/server/route.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -45,7 +44,7 @@ test.beforeEach(() => { test.after(() => { delete process.env.ROUTER_API_KEY; try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* noop */ } diff --git a/tests/unit/agentrouter-chatcore-protocols.test.ts b/tests/unit/agentrouter-chatcore-protocols.test.ts index ece0f7c5f5..27c40bb8c5 100644 --- a/tests/unit/agentrouter-chatcore-protocols.test.ts +++ b/tests/unit/agentrouter-chatcore-protocols.test.ts @@ -38,14 +38,14 @@ test.afterEach(async () => { globalThis.fetch = originalFetch; await flushAsyncSideEffects(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("AgentRouter Responses requests automatically use the native Responses protocol", async () => { diff --git a/tests/unit/agentrouter-lock-scope-10334.test.ts b/tests/unit/agentrouter-lock-scope-10334.test.ts index 1205ec5cd2..843627fa33 100644 --- a/tests/unit/agentrouter-lock-scope-10334.test.ts +++ b/tests/unit/agentrouter-lock-scope-10334.test.ts @@ -21,9 +21,8 @@ const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const auth = await import("../../src/sse/services/auth.ts"); const accountFallback = await import("../../open-sse/services/accountFallback.ts"); -const { applyComboTargetExhaustion } = await import( - "../../open-sse/services/combo/targetExhaustion.ts" -); +const { applyComboTargetExhaustion } = + await import("../../open-sse/services/combo/targetExhaustion.ts"); const { classifyProviderError } = await import("../../open-sse/services/errorClassifier.ts"); const QUOTA_EXHAUSTED_429 = '{"error":{"message":"账户额度不足,请充值后重试"}}'; @@ -31,7 +30,7 @@ const MODEL_ACCESS_DENIED_403 = '{"error":{"message":"无权访问模型 claude- async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -52,7 +51,7 @@ async function seedConnection( test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("agentrouter 429 account quota exhausted -> connection cooldown, never terminal", async () => { diff --git a/tests/unit/agnes-provider.test.ts b/tests/unit/agnes-provider.test.ts index 8d4bdc52e0..bc15ab9e8c 100644 --- a/tests/unit/agnes-provider.test.ts +++ b/tests/unit/agnes-provider.test.ts @@ -24,7 +24,7 @@ const dbCore = await import("../../src/lib/db/core.ts"); test.after(() => { dbCore.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const AGNES_CHAT_URL = "https://apihub.agnes-ai.com/v1/chat/completions"; diff --git a/tests/unit/aihorde-optional-api-key.test.ts b/tests/unit/aihorde-optional-api-key.test.ts index 9a69669860..cdede1c226 100644 --- a/tests/unit/aihorde-optional-api-key.test.ts +++ b/tests/unit/aihorde-optional-api-key.test.ts @@ -20,7 +20,7 @@ const { isManagedProviderConnectionId } = await import("../../src/lib/providers/ test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("aihorde treats a registered key as optional, not required", () => { diff --git a/tests/unit/airforce-v1-double-prefix-5899.test.ts b/tests/unit/airforce-v1-double-prefix-5899.test.ts index 288fbd0d03..2daf282311 100644 --- a/tests/unit/airforce-v1-double-prefix-5899.test.ts +++ b/tests/unit/airforce-v1-double-prefix-5899.test.ts @@ -23,7 +23,7 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5899 openai gateway baseUrl ending in /v1/chat/completions never probes /v1/v1/models", async () => { diff --git a/tests/unit/alibaba-free-tier-allowlist.test.ts b/tests/unit/alibaba-free-tier-allowlist.test.ts index df468d82e5..71a31a470c 100644 --- a/tests/unit/alibaba-free-tier-allowlist.test.ts +++ b/tests/unit/alibaba-free-tier-allowlist.test.ts @@ -41,10 +41,7 @@ test("built-in allowlist includes operator free models and excludes paid blockli * the expiry, with packs this test owns and dates it controls — never the * freshness of the catalog that ships in the repo. */ -function withAllowlistPack( - pack: Record, - assertions: () => void -): void { +function withAllowlistPack(pack: Record, assertions: () => void): void { const dir = mkdtempSync(join(tmpdir(), "alibaba-allowlist-")); const packPath = join(dir, "allowlist.json"); writeFileSync(packPath, JSON.stringify(pack), "utf8"); @@ -58,7 +55,7 @@ function withAllowlistPack( if (previousPath) process.env.ALIBABA_FREE_TIER_ALLOWLIST_PATH = previousPath; else delete process.env.ALIBABA_FREE_TIER_ALLOWLIST_PATH; resetAlibabaFreeTierAllowlistCache(); - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/antigravity-429-quota-cooldown.test.ts b/tests/unit/antigravity-429-quota-cooldown.test.ts index c420781f0d..0191391d8a 100644 --- a/tests/unit/antigravity-429-quota-cooldown.test.ts +++ b/tests/unit/antigravity-429-quota-cooldown.test.ts @@ -42,7 +42,7 @@ import { test.after(() => { clearAllModelLockouts(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Engine contract (regression guard) ─────────────────────────────────────── diff --git a/tests/unit/antigravity-client-identity-paths.test.ts b/tests/unit/antigravity-client-identity-paths.test.ts index 8801750201..9ce32df8a5 100644 --- a/tests/unit/antigravity-client-identity-paths.test.ts +++ b/tests/unit/antigravity-client-identity-paths.test.ts @@ -32,7 +32,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("executor token refresh uses the selected CLI identity", async () => { diff --git a/tests/unit/antigravity-local-usage-fallback-3821.test.ts b/tests/unit/antigravity-local-usage-fallback-3821.test.ts index 38c5f1464d..23ba88bfef 100644 --- a/tests/unit/antigravity-local-usage-fallback-3821.test.ts +++ b/tests/unit/antigravity-local-usage-fallback-3821.test.ts @@ -30,7 +30,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Antigravity fetchAvailableModels(used=0) → localUsageHistory when usage_history has rows", async () => { diff --git a/tests/unit/antigravity-missing-project-autodisable.test.ts b/tests/unit/antigravity-missing-project-autodisable.test.ts index aff0172790..bcf024e854 100644 --- a/tests/unit/antigravity-missing-project-autodisable.test.ts +++ b/tests/unit/antigravity-missing-project-autodisable.test.ts @@ -27,14 +27,12 @@ process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "ag-11284-test-secret const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); -const { - markAntigravityMissingCloudCodeProject, - persistDiscoveredAntigravityProjectId, -} = await import("../../open-sse/services/antigravityProjectPersistence.ts"); +const { markAntigravityMissingCloudCodeProject, persistDiscoveredAntigravityProjectId } = + await import("../../open-sse/services/antigravityProjectPersistence.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/antigravity-mitm-model-resolution.test.ts b/tests/unit/antigravity-mitm-model-resolution.test.ts index 86a06718a2..8facfe6262 100644 --- a/tests/unit/antigravity-mitm-model-resolution.test.ts +++ b/tests/unit/antigravity-mitm-model-resolution.test.ts @@ -17,7 +17,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // #3144: the executor resolves the upstream model through the dynamic MITM alias diff --git a/tests/unit/antigravity-project-persistence.test.ts b/tests/unit/antigravity-project-persistence.test.ts index 1dd30c712f..c0e20d86f1 100644 --- a/tests/unit/antigravity-project-persistence.test.ts +++ b/tests/unit/antigravity-project-persistence.test.ts @@ -28,7 +28,7 @@ const { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/antigravity-quota-host-8965.test.ts b/tests/unit/antigravity-quota-host-8965.test.ts index a383292d85..c5d7be291b 100644 --- a/tests/unit/antigravity-quota-host-8965.test.ts +++ b/tests/unit/antigravity-quota-host-8965.test.ts @@ -32,7 +32,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const RESET_IN_2_HOURS = new Date(Date.now() + 2 * 60 * 60 * 1000).toISOString(); @@ -57,7 +57,8 @@ test("#8965: quota reads use the runtime host (daily-cloudcode-pa), not cloudcod const cloudcodeCount = { value: 0 }; globalThis.fetch = (async (input: RequestInfo | URL) => { - const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; + const url = + typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; if (url.includes("daily-cloudcode-pa.googleapis.com")) { dailyCount.value++; @@ -167,7 +168,8 @@ test("#8965 behavioral impact: live quota source + weekly bucket unreachable whe core.resetDbInstance(); globalThis.fetch = (async (input: RequestInfo | URL) => { - const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; + const url = + typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; if (url.includes("daily-cloudcode-pa.googleapis.com")) { if (url.includes("retrieveUserQuotaSummary")) { diff --git a/tests/unit/antigravity-quota-skipping.test.ts b/tests/unit/antigravity-quota-skipping.test.ts index f23a43883a..6f585bb3bc 100644 --- a/tests/unit/antigravity-quota-skipping.test.ts +++ b/tests/unit/antigravity-quota-skipping.test.ts @@ -12,7 +12,7 @@ const quotaCache = await import("../../src/domain/quotaCache.ts"); test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("isQuotaExhaustedForRequest isolates Claude and Gemini quota families for antigravity & agy", () => { diff --git a/tests/unit/antigravity-weekly-quota-4017.test.ts b/tests/unit/antigravity-weekly-quota-4017.test.ts index ee29b1c52d..3a33142229 100644 --- a/tests/unit/antigravity-weekly-quota-4017.test.ts +++ b/tests/unit/antigravity-weekly-quota-4017.test.ts @@ -33,7 +33,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const RESET_IN_3_DAYS = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString(); diff --git a/tests/unit/api-auth.test.ts b/tests/unit/api-auth.test.ts index dd4f874f3b..a472e6db4d 100644 --- a/tests/unit/api-auth.test.ts +++ b/tests/unit/api-auth.test.ts @@ -24,7 +24,7 @@ const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.JWT_SECRET; delete process.env.INITIAL_PASSWORD; @@ -48,7 +48,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_JWT_SECRET === undefined) { delete process.env.JWT_SECRET; diff --git a/tests/unit/api-key-compression-enabled-2101.test.ts b/tests/unit/api-key-compression-enabled-2101.test.ts index ddef25de9f..05145738f4 100644 --- a/tests/unit/api-key-compression-enabled-2101.test.ts +++ b/tests/unit/api-key-compression-enabled-2101.test.ts @@ -15,7 +15,7 @@ const { updateKeyPermissionsSchema } = await import("../../src/shared/validation async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -25,7 +25,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("API key prompt compression defaults on and round-trips an explicit opt-out", async () => { diff --git a/tests/unit/api-key-lifecycle.test.ts b/tests/unit/api-key-lifecycle.test.ts index 126856b56e..5cb73eb767 100644 --- a/tests/unit/api-key-lifecycle.test.ts +++ b/tests/unit/api-key-lifecycle.test.ts @@ -17,7 +17,7 @@ const ORIGINAL_ROUTER_API_KEY = process.env.ROUTER_API_KEY; function reset() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.OMNIROUTE_API_KEY; delete process.env.ROUTER_API_KEY; @@ -28,7 +28,7 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_OMNIROUTE_API_KEY === undefined) delete process.env.OMNIROUTE_API_KEY; else process.env.OMNIROUTE_API_KEY = ORIGINAL_OMNIROUTE_API_KEY; if (ORIGINAL_ROUTER_API_KEY === undefined) delete process.env.ROUTER_API_KEY; diff --git a/tests/unit/api-key-policy-noauth-allowed-connections.test.ts b/tests/unit/api-key-policy-noauth-allowed-connections.test.ts index 985c341c37..55a693a1a2 100644 --- a/tests/unit/api-key-policy-noauth-allowed-connections.test.ts +++ b/tests/unit/api-key-policy-noauth-allowed-connections.test.ts @@ -26,7 +26,7 @@ const RESTRICTED_CONNECTION_UUID = "00000000-0000-4000-8000-000000000001"; test.after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/api-key-policy.test.ts b/tests/unit/api-key-policy.test.ts index 63cf63be7b..eff769271f 100644 --- a/tests/unit/api-key-policy.test.ts +++ b/tests/unit/api-key-policy.test.ts @@ -48,7 +48,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -129,7 +129,7 @@ test.after(async () => { apiKeysDb.resetApiKeyState(); costRules.resetCostData(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Replicate the isWithinSchedule logic for pure unit testing ─────────────── diff --git a/tests/unit/api-key-regeneration.test.ts b/tests/unit/api-key-regeneration.test.ts index a492424498..920a835902 100644 --- a/tests/unit/api-key-regeneration.test.ts +++ b/tests/unit/api-key-regeneration.test.ts @@ -15,7 +15,7 @@ function reset() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -25,7 +25,7 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("regenerateApiKey creates a new key and invalidates the old one", async () => { diff --git a/tests/unit/api-key-reveal-route.test.ts b/tests/unit/api-key-reveal-route.test.ts index 34be3d41ad..0c34f02bfb 100644 --- a/tests/unit/api-key-reveal-route.test.ts +++ b/tests/unit/api-key-reveal-route.test.ts @@ -21,7 +21,7 @@ async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.after(async () => { delete process.env.ALLOW_API_KEY_REVEAL; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/keys stays masked even when reveal is enabled", async () => { diff --git a/tests/unit/api-key-usage-limits.test.ts b/tests/unit/api-key-usage-limits.test.ts index 5a3c277887..7221cc883c 100644 --- a/tests/unit/api-key-usage-limits.test.ts +++ b/tests/unit/api-key-usage-limits.test.ts @@ -20,7 +20,7 @@ async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); usageHistory.clearPendingRequests(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("API key USD usage limits persist and default off", async () => { diff --git a/tests/unit/api-keys-create-no-hang-6570.test.ts b/tests/unit/api-keys-create-no-hang-6570.test.ts index 7ba196ea48..3a5d5bd536 100644 --- a/tests/unit/api-keys-create-no-hang-6570.test.ts +++ b/tests/unit/api-keys-create-no-hang-6570.test.ts @@ -34,7 +34,7 @@ async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -49,7 +49,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); core.resetDbInstance(); }); diff --git a/tests/unit/api-malformed-json-400.test.ts b/tests/unit/api-malformed-json-400.test.ts index 1b0cce21c1..a4cbb58999 100644 --- a/tests/unit/api-malformed-json-400.test.ts +++ b/tests/unit/api-malformed-json-400.test.ts @@ -65,7 +65,7 @@ function jsonRequest(url: string, body: unknown, method = "POST"): Request { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/api-manager-provider-permissions.test.ts b/tests/unit/api-manager-provider-permissions.test.ts index 5169219a24..4df4b7adbf 100644 --- a/tests/unit/api-manager-provider-permissions.test.ts +++ b/tests/unit/api-manager-provider-permissions.test.ts @@ -45,7 +45,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { @@ -63,7 +63,7 @@ test.after(async () => { apiKeys.resetApiKeyState(); core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } @@ -258,7 +258,7 @@ test("R2/R5: JSON import preserves explicit restricted + empty and infers legacy test("R2/R5: startup db.json migration preserves explicit restricted-empty mode", async () => { apiKeys.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); fs.writeFileSync( path.join(TEST_DATA_DIR, "db.json"), diff --git a/tests/unit/api-models-hide-paid-6328.test.ts b/tests/unit/api-models-hide-paid-6328.test.ts index f2e509c864..6e4e4a0fbc 100644 --- a/tests/unit/api-models-hide-paid-6328.test.ts +++ b/tests/unit/api-models-hide-paid-6328.test.ts @@ -32,7 +32,7 @@ async function fetchModels(): Promise< test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best-effort */ } diff --git a/tests/unit/api-models-v1-models-mismatch-10615.test.ts b/tests/unit/api-models-v1-models-mismatch-10615.test.ts index b6a241844a..f41976e346 100644 --- a/tests/unit/api-models-v1-models-mismatch-10615.test.ts +++ b/tests/unit/api-models-v1-models-mismatch-10615.test.ts @@ -16,7 +16,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/api/auto-combo-candidates-route-7819.test.ts b/tests/unit/api/auto-combo-candidates-route-7819.test.ts index bc5c8df474..1679f4383a 100644 --- a/tests/unit/api/auto-combo-candidates-route-7819.test.ts +++ b/tests/unit/api/auto-combo-candidates-route-7819.test.ts @@ -12,12 +12,13 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-7819-rout process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); -const routeModule = await import( - "../../../src/app/api/v1/auto-combo/[channel]/candidates/route.ts" -); +const routeModule = + await import("../../../src/app/api/v1/auto-combo/[channel]/candidates/route.ts"); function makeRequest(channel: string) { - return new Request(`http://localhost/api/v1/auto-combo/${encodeURIComponent(channel)}/candidates`); + return new Request( + `http://localhost/api/v1/auto-combo/${encodeURIComponent(channel)}/candidates` + ); } async function callGET(channel: string) { @@ -30,7 +31,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7819: GET /candidates for the base 'auto' channel returns 200 with a candidates array", async () => { diff --git a/tests/unit/api/cli-tools/apply-container-guard.test.ts b/tests/unit/api/cli-tools/apply-container-guard.test.ts index 5ef03013b8..74cceb6ae4 100644 --- a/tests/unit/api/cli-tools/apply-container-guard.test.ts +++ b/tests/unit/api/cli-tools/apply-container-guard.test.ts @@ -89,8 +89,8 @@ describe("POST /api/cli-tools/apply — container guard", () => { after(() => { catalogServer?.close(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); - fs.rmSync(TEST_XDG_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(TEST_XDG_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; if (originalXdg === undefined) delete process.env.XDG_CONFIG_HOME; diff --git a/tests/unit/api/cli-tools/detect.test.ts b/tests/unit/api/cli-tools/detect.test.ts index 25b4905d68..b2835ecdb1 100644 --- a/tests/unit/api/cli-tools/detect.test.ts +++ b/tests/unit/api/cli-tools/detect.test.ts @@ -28,7 +28,7 @@ describe("GET /api/cli-tools/detect", () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/api/compression-engines-route.test.ts b/tests/unit/api/compression-engines-route.test.ts index 4ad921252e..ef7a88283b 100644 --- a/tests/unit/api/compression-engines-route.test.ts +++ b/tests/unit/api/compression-engines-route.test.ts @@ -31,7 +31,7 @@ const enginesRoute = await import("../../../src/app/api/compression/engines/rout async function setupAuth(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -53,7 +53,7 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── tests ──────────────────────────────────────────────────────────────────── diff --git a/tests/unit/api/compression-preview-caveman-and-stacked-6425.test.ts b/tests/unit/api/compression-preview-caveman-and-stacked-6425.test.ts index 409ba2077d..009088d723 100644 --- a/tests/unit/api/compression-preview-caveman-and-stacked-6425.test.ts +++ b/tests/unit/api/compression-preview-caveman-and-stacked-6425.test.ts @@ -26,9 +26,7 @@ import { makeManagementSessionRequest } from "../../helpers/managementSession.ts // ─── temp DB isolation ──────────────────────────────────────────────────────── -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-compression-preview-6425-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-compression-preview-6425-")); const originalDataDir = process.env.DATA_DIR; const originalJwtSecret = process.env.JWT_SECRET; @@ -46,7 +44,7 @@ const CAVEMAN_TRIGGER = async function setupAuth(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -68,22 +66,19 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── tests ──────────────────────────────────────────────────────────────────── test("#6425 (a): POST /api/compression/preview accepts mode:'caveman' and produces >0% savings", async () => { - const request = await makeManagementSessionRequest( - "http://localhost/api/compression/preview", - { - method: "POST", - body: { - messages: [{ role: "user", content: CAVEMAN_TRIGGER }], - mode: "caveman", - }, - } - ); + const request = await makeManagementSessionRequest("http://localhost/api/compression/preview", { + method: "POST", + body: { + messages: [{ role: "user", content: CAVEMAN_TRIGGER }], + mode: "caveman", + }, + }); const response = await previewRoute.POST(request); assert.equal( @@ -109,16 +104,13 @@ test("#6425 (a): POST /api/compression/preview accepts mode:'caveman' and produc }); test("#6425 (b): POST /api/compression/preview mode:'stacked' returns >0% on caveman-trigger prose", async () => { - const request = await makeManagementSessionRequest( - "http://localhost/api/compression/preview", - { - method: "POST", - body: { - messages: [{ role: "user", content: CAVEMAN_TRIGGER }], - mode: "stacked", - }, - } - ); + const request = await makeManagementSessionRequest("http://localhost/api/compression/preview", { + method: "POST", + body: { + messages: [{ role: "user", content: CAVEMAN_TRIGGER }], + mode: "stacked", + }, + }); const response = await previewRoute.POST(request); assert.equal(response.status, 200, `Expected 200, got ${response.status}`); diff --git a/tests/unit/api/compression-preview-engine.test.ts b/tests/unit/api/compression-preview-engine.test.ts index 847939fbd5..026eb118d3 100644 --- a/tests/unit/api/compression-preview-engine.test.ts +++ b/tests/unit/api/compression-preview-engine.test.ts @@ -31,7 +31,7 @@ const previewRoute = await import("../../../src/app/api/compression/preview/rout async function setupAuth(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -71,7 +71,7 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── tests ──────────────────────────────────────────────────────────────────── diff --git a/tests/unit/api/compression/compression-api.test.ts b/tests/unit/api/compression/compression-api.test.ts index 85f735d564..90c08a7601 100644 --- a/tests/unit/api/compression/compression-api.test.ts +++ b/tests/unit/api/compression/compression-api.test.ts @@ -21,7 +21,6 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../../src/lib/db/core.ts"); const route = await import("../../../../src/app/api/settings/compression/route.ts"); - describe("Compression Settings API Schema Validation", () => { const compressionModeValues = [ "off", @@ -140,13 +139,13 @@ function makeRequest(method: string, body?: unknown): Request { describe("settings/compression route — engines + activeComboId", () => { beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/api/compression/rtk-learn-discover-routes.test.ts b/tests/unit/api/compression/rtk-learn-discover-routes.test.ts index 42b3cd30c5..6c9d020bd0 100644 --- a/tests/unit/api/compression/rtk-learn-discover-routes.test.ts +++ b/tests/unit/api/compression/rtk-learn-discover-routes.test.ts @@ -24,9 +24,8 @@ const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD; process.env.DATA_DIR = TEST_DATA_DIR; delete process.env.INITIAL_PASSWORD; -const { maybePersistRtkRawOutput } = await import( - "../../../../open-sse/services/compression/engines/rtk/index.ts" -); +const { maybePersistRtkRawOutput } = + await import("../../../../open-sse/services/compression/engines/rtk/index.ts"); const discoverRoute = await import("../../../../src/app/api/context/rtk/discover/route.ts"); const learnRoute = await import("../../../../src/app/api/context/rtk/learn/route.ts"); @@ -45,12 +44,12 @@ function get(url: string): Request { } test.beforeEach(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; if (ORIGINAL_INITIAL_PASSWORD !== undefined) diff --git a/tests/unit/api/compression/rtk-toml-import-route.test.ts b/tests/unit/api/compression/rtk-toml-import-route.test.ts index 959e43453a..c09dc4f4c3 100644 --- a/tests/unit/api/compression/rtk-toml-import-route.test.ts +++ b/tests/unit/api/compression/rtk-toml-import-route.test.ts @@ -29,7 +29,7 @@ expected = "kept" async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } @@ -47,7 +47,7 @@ test.beforeEach(reset); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/api/context-analytics-engine-route.test.ts b/tests/unit/api/context-analytics-engine-route.test.ts index ef583ddcc2..a26f4337bf 100644 --- a/tests/unit/api/context-analytics-engine-route.test.ts +++ b/tests/unit/api/context-analytics-engine-route.test.ts @@ -31,7 +31,7 @@ const engineRoute = await import("../../../src/app/api/context/analytics/engine/ async function setupAuth(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -53,7 +53,7 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── tests ──────────────────────────────────────────────────────────────────── diff --git a/tests/unit/api/context-combos-default-route.test.ts b/tests/unit/api/context-combos-default-route.test.ts index c5b0da6af3..67407075af 100644 --- a/tests/unit/api/context-combos-default-route.test.ts +++ b/tests/unit/api/context-combos-default-route.test.ts @@ -36,7 +36,7 @@ const defaultRoute = await import("../../../src/app/api/context/combos/default/r async function setupAuth(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -58,7 +58,7 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── tests ──────────────────────────────────────────────────────────────────── @@ -110,7 +110,10 @@ test("GET /api/context/combos/default returns the derived stacked pipeline (refl assert.equal(body.mode, "stacked"); assert.deepEqual(body.pipeline, expected.stackedPipeline); const engineIds = body.pipeline.map((s) => s.engine); - assert.ok(engineIds.includes("caveman"), `expected caveman in derived pipeline, got: ${engineIds}`); + assert.ok( + engineIds.includes("caveman"), + `expected caveman in derived pipeline, got: ${engineIds}` + ); }); test("GET /api/context/combos/default returns off when master switch is disabled", async () => { diff --git a/tests/unit/api/discovery-routes.test.ts b/tests/unit/api/discovery-routes.test.ts index 99dc8dddcc..ff135cc068 100644 --- a/tests/unit/api/discovery-routes.test.ts +++ b/tests/unit/api/discovery-routes.test.ts @@ -38,7 +38,8 @@ before(async () => { after(() => { core.resetDbInstance(); - if (tmpDataDir) rmSync(tmpDataDir, { recursive: true, force: true }); + if (tmpDataDir) + rmSync(tmpDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("discovery API routes", () => { @@ -135,13 +136,19 @@ describe("discovery API routes", () => { riskLevel: "none", status: "pending", }); - const first = await resultByIdRoute.DELETE(req("DELETE", `/api/discovery/results/${created.id}`), { - params: Promise.resolve({ id: String(created.id) }), - }); + const first = await resultByIdRoute.DELETE( + req("DELETE", `/api/discovery/results/${created.id}`), + { + params: Promise.resolve({ id: String(created.id) }), + } + ); assert.equal(first.status, 200); - const second = await resultByIdRoute.DELETE(req("DELETE", `/api/discovery/results/${created.id}`), { - params: Promise.resolve({ id: String(created.id) }), - }); + const second = await resultByIdRoute.DELETE( + req("DELETE", `/api/discovery/results/${created.id}`), + { + params: Promise.resolve({ id: String(created.id) }), + } + ); assert.equal(second.status, 404); }); diff --git a/tests/unit/api/free-proxies-list-route.test.ts b/tests/unit/api/free-proxies-list-route.test.ts index 334148de5b..d3664c5217 100644 --- a/tests/unit/api/free-proxies-list-route.test.ts +++ b/tests/unit/api/free-proxies-list-route.test.ts @@ -19,7 +19,7 @@ const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD; async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ function make(host: string, quality: number, latency: number): FreeProxyItem { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD; else process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD; }); diff --git a/tests/unit/api/free-proxies-route.test.ts b/tests/unit/api/free-proxies-route.test.ts index 77f3c034ee..85555bcfbb 100644 --- a/tests/unit/api/free-proxies-route.test.ts +++ b/tests/unit/api/free-proxies-route.test.ts @@ -19,7 +19,7 @@ const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -29,7 +29,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD; else process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD; }); diff --git a/tests/unit/api/jobs.test.ts b/tests/unit/api/jobs.test.ts index 53ff2b1474..f135810d0c 100644 --- a/tests/unit/api/jobs.test.ts +++ b/tests/unit/api/jobs.test.ts @@ -29,7 +29,7 @@ function resetAll() { } __resetJobRegistry(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function params(id: string) { diff --git a/tests/unit/api/providers-import-route-6836.test.ts b/tests/unit/api/providers-import-route-6836.test.ts index 48c0cb6977..0ec3f3b1e3 100644 --- a/tests/unit/api/providers-import-route-6836.test.ts +++ b/tests/unit/api/providers-import-route-6836.test.ts @@ -26,13 +26,13 @@ type ImportRouteResponse = { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function postImport(body: unknown) { @@ -100,10 +100,7 @@ test("providers import route imports a heterogeneous list with 200 + per-row res assert.equal(body.created.length, 2); // Never echo the raw apiKey back. assert.ok(body.created.every((c) => c.apiKey === undefined)); - assert.deepEqual( - body.created.map((c) => c.provider).sort(), - ["anthropic", "openai"] - ); + assert.deepEqual(body.created.map((c) => c.provider).sort(), ["anthropic", "openai"]); }); test("providers import route: partial-failure — unresolvable compatible node fails its own row only", async () => { @@ -140,7 +137,11 @@ test("providers import route: same-batch (provider,name) collision does not over assert.equal(response.status, 200); const body = (await response.json()) as ImportRouteResponse; assert.equal(body.total, 2); - assert.equal(body.success, 2, "both rows must be created — the second must not silently upsert into the first"); + assert.equal( + body.success, + 2, + "both rows must be created — the second must not silently upsert into the first" + ); assert.equal(body.failed, 0); assert.equal(body.created.length, 2); @@ -148,7 +149,11 @@ test("providers import route: same-batch (provider,name) collision does not over const connections = (await providersDb.getProviderConnections({ provider: "openai", })) as Array<{ id: string; name?: string | null; apiKey?: string }>; - assert.equal(connections.length, 2, "the collision must produce TWO distinct connections, never one"); + assert.equal( + connections.length, + 2, + "the collision must produce TWO distinct connections, never one" + ); const first = connections.find((c) => c.apiKey === "sk-openai-first"); const second = connections.find((c) => c.apiKey === "sk-openai-second"); @@ -185,19 +190,45 @@ test("providers import route: re-importing an existing (provider,name) does not const connections = (await providersDb.getProviderConnections({ provider: "openai", - })) as Array<{ id: string; name?: string | null; apiKey?: string; testStatus?: string; lastError?: string }>; - assert.equal(connections.length, 2, "re-import must APPEND a new connection, not replace the existing one"); + })) as Array<{ + id: string; + name?: string | null; + apiKey?: string; + testStatus?: string; + lastError?: string; + }>; + assert.equal( + connections.length, + 2, + "re-import must APPEND a new connection, not replace the existing one" + ); const survivor = connections.find((c) => c.id === existing!.id); assert.ok(survivor, "the pre-existing connection must still exist, unreplaced"); - assert.equal(survivor!.apiKey, "sk-existing", "existing apiKey must not be overwritten by the re-import"); - assert.equal(survivor!.testStatus, "unavailable", "existing testStatus must survive the re-import"); - assert.equal(survivor!.lastError, "429 rate limited", "existing lastError must survive the re-import"); + assert.equal( + survivor!.apiKey, + "sk-existing", + "existing apiKey must not be overwritten by the re-import" + ); + assert.equal( + survivor!.testStatus, + "unavailable", + "existing testStatus must survive the re-import" + ); + assert.equal( + survivor!.lastError, + "429 rate limited", + "existing lastError must survive the re-import" + ); const imported = connections.find((c) => c.id !== existing!.id); assert.ok(imported, "the newly imported row must exist as a distinct connection"); assert.equal(imported!.apiKey, "sk-reimported"); - assert.notEqual(imported!.name, "Prod OpenAI", "the re-imported row must be disambiguated, not collide on name"); + assert.notEqual( + imported!.name, + "Prod OpenAI", + "the re-imported row must be disambiguated, not collide on name" + ); }); test("providers import route applies a per-entry baseUrl override for compatible providers", async () => { diff --git a/tests/unit/api/proxies-repair-relay.test.ts b/tests/unit/api/proxies-repair-relay.test.ts index 39d89ab6c4..f6645c0d64 100644 --- a/tests/unit/api/proxies-repair-relay.test.ts +++ b/tests/unit/api/proxies-repair-relay.test.ts @@ -20,7 +20,7 @@ const repairRelayRoute = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -30,7 +30,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_KEY === undefined) delete process.env.STORAGE_ENCRYPTION_KEY; else process.env.STORAGE_ENCRYPTION_KEY = ORIGINAL_KEY; }); diff --git a/tests/unit/api/services/9router-models.test.ts b/tests/unit/api/services/9router-models.test.ts index a71df4d2eb..2956f9bc45 100644 --- a/tests/unit/api/services/9router-models.test.ts +++ b/tests/unit/api/services/9router-models.test.ts @@ -28,7 +28,7 @@ const originalFetch = globalThis.fetch; function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/api/services/9router-provider-expose.test.ts b/tests/unit/api/services/9router-provider-expose.test.ts index bd51066aac..737f6357be 100644 --- a/tests/unit/api/services/9router-provider-expose.test.ts +++ b/tests/unit/api/services/9router-provider-expose.test.ts @@ -23,7 +23,7 @@ const { POST } = await import("../../../../src/app/api/services/9router/provider function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/api/services/9router-status-reveal.test.ts b/tests/unit/api/services/9router-status-reveal.test.ts index ad66f63050..8d4927ed8f 100644 --- a/tests/unit/api/services/9router-status-reveal.test.ts +++ b/tests/unit/api/services/9router-status-reveal.test.ts @@ -46,7 +46,7 @@ function makeRequest(url: string, headers?: Record): Request { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("GET /api/services/9router/status", () => { diff --git a/tests/unit/api/services/cliproxy-accounts.test.ts b/tests/unit/api/services/cliproxy-accounts.test.ts index d282b7d11c..c287528d5b 100644 --- a/tests/unit/api/services/cliproxy-accounts.test.ts +++ b/tests/unit/api/services/cliproxy-accounts.test.ts @@ -22,13 +22,11 @@ before(async () => { after(() => { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("requires OmniRoute management authentication", async () => { - const response = await GET( - new Request("http://localhost/api/services/cliproxy/accounts") - ); + const response = await GET(new Request("http://localhost/api/services/cliproxy/accounts")); assert.equal(response.status, 401); }); diff --git a/tests/unit/api/services/cliproxy-provider-expose.test.ts b/tests/unit/api/services/cliproxy-provider-expose.test.ts index 3376c532df..ade24ad231 100644 --- a/tests/unit/api/services/cliproxy-provider-expose.test.ts +++ b/tests/unit/api/services/cliproxy-provider-expose.test.ts @@ -22,7 +22,7 @@ const { POST } = await import("../../../../src/app/api/services/cliproxy/provide function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/api/webhooks/webhook-url-ssrf-guard.test.ts b/tests/unit/api/webhooks/webhook-url-ssrf-guard.test.ts index 26028cf697..44339f3d54 100644 --- a/tests/unit/api/webhooks/webhook-url-ssrf-guard.test.ts +++ b/tests/unit/api/webhooks/webhook-url-ssrf-guard.test.ts @@ -35,7 +35,7 @@ const { createWebhook } = await import("../../../../src/lib/db/webhooks.ts"); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function jsonRequest(url: string, method: string, body: unknown): Request { diff --git a/tests/unit/apikey-connection-health-check.test.ts b/tests/unit/apikey-connection-health-check.test.ts index 572e10b161..87d3152342 100644 --- a/tests/unit/apikey-connection-health-check.test.ts +++ b/tests/unit/apikey-connection-health-check.test.ts @@ -29,7 +29,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -45,7 +45,7 @@ async function resetStorage() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("API-key-only gemini connection is NOT marked expired by health check", async () => { diff --git a/tests/unit/apikey-policy-default-rate-limits.test.ts b/tests/unit/apikey-policy-default-rate-limits.test.ts index 75c276e7f7..d4c9237327 100644 --- a/tests/unit/apikey-policy-default-rate-limits.test.ts +++ b/tests/unit/apikey-policy-default-rate-limits.test.ts @@ -20,7 +20,7 @@ const LEGACY_DEFAULT = [ test.after(async () => { const coreDb = await import("../../src/lib/db/core.ts"); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { @@ -43,7 +43,10 @@ test("buildDefaultRateLimits: unset / empty env disables implicit fallback limit }); test("ENVIRONMENT.md documents unset DEFAULT_RATE_LIMIT_PER_DAY as unlimited (#11017)", () => { - const md = fs.readFileSync(new URL("../../docs/reference/ENVIRONMENT.md", import.meta.url), "utf8"); + const md = fs.readFileSync( + new URL("../../docs/reference/ENVIRONMENT.md", import.meta.url), + "utf8" + ); const row = md.split("\n").find((line) => line.includes("`DEFAULT_RATE_LIMIT_PER_DAY`")); assert.ok(row, "ENVIRONMENT.md must document DEFAULT_RATE_LIMIT_PER_DAY"); assert.match( diff --git a/tests/unit/apikeypolicy-disable-non-public.test.ts b/tests/unit/apikeypolicy-disable-non-public.test.ts index 04a7ff9981..61a19ccaa3 100644 --- a/tests/unit/apikeypolicy-disable-non-public.test.ts +++ b/tests/unit/apikeypolicy-disable-non-public.test.ts @@ -45,7 +45,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -109,7 +109,7 @@ test.beforeEach(async () => { test.after(async () => { apiKeysDb.resetApiKeyState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/unit/apikeypolicy-quota-only.test.ts b/tests/unit/apikeypolicy-quota-only.test.ts index 3c2641cb10..4caa4691b2 100644 --- a/tests/unit/apikeypolicy-quota-only.test.ts +++ b/tests/unit/apikeypolicy-quota-only.test.ts @@ -21,9 +21,7 @@ import os from "node:os"; import path from "node:path"; import { pathToFileURL } from "node:url"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-apikeypolicy-quota-only-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-apikeypolicy-quota-only-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "quota-only-test-secret"; @@ -49,7 +47,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -91,7 +89,7 @@ test.beforeEach(async () => { test.after(async () => { apiKeysDb.resetApiKeyState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -194,7 +192,10 @@ test("quota-only key requesting a quotaShared-* model from a different pool is r const result = await policy.enforceApiKeyPolicy(makeRequest(created.key), otherPoolVirtualModel); - assert.ok(result.rejection, "should produce a rejection Response for other-pool quotaShared-* model"); + assert.ok( + result.rejection, + "should produce a rejection Response for other-pool quotaShared-* model" + ); assert.equal(result.rejection.status, 403, "rejection should be 403 Forbidden"); const body = await readBody(result.rejection); @@ -218,14 +219,13 @@ test("key with empty allowedQuotas is subject to normal model restriction checks // Allowed model should pass const allowed = await policy.enforceApiKeyPolicy(makeRequest(created.key), "openai/gpt-4.1"); - assert.equal( - allowed.rejection, - null, - "model in allowedModels should pass for a non-quota key" - ); + assert.equal(allowed.rejection, null, "model in allowedModels should pass for a non-quota key"); // Disallowed model should be rejected via the normal allowedModels path - const blocked = await policy.enforceApiKeyPolicy(makeRequest(created.key), "anthropic/claude-3-7-sonnet"); + const blocked = await policy.enforceApiKeyPolicy( + makeRequest(created.key), + "anthropic/claude-3-7-sonnet" + ); assert.ok(blocked.rejection, "disallowed model should be rejected"); assert.equal(blocked.rejection.status, 403); @@ -233,7 +233,11 @@ test("key with empty allowedQuotas is subject to normal model restriction checks assert.match(body.error.message, /not allowed for this API key/); // The code for this case comes from errorConfig (403 → "insufficient_quota") // rather than QUOTA_ONLY — confirming paths are separate - assert.notEqual(body.error.code, "QUOTA_ONLY", "normal key rejection must NOT use QUOTA_ONLY code"); + assert.notEqual( + body.error.code, + "QUOTA_ONLY", + "normal key rejection must NOT use QUOTA_ONLY code" + ); }); test("non-quota key (empty allowedQuotas) requesting a qtSd model is rejected 403 QUOTA_NOT_ALLOCATED", async () => { diff --git a/tests/unit/apikeys-allowed-quotas.test.ts b/tests/unit/apikeys-allowed-quotas.test.ts index 2f42565c40..9010aeda6b 100644 --- a/tests/unit/apikeys-allowed-quotas.test.ts +++ b/tests/unit/apikeys-allowed-quotas.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("allowedQuotas round-trips: create with pool IDs and read them back via getApiKeyMetadata", async () => { diff --git a/tests/unit/apikeys-disable-non-public.test.ts b/tests/unit/apikeys-disable-non-public.test.ts index e757eb0734..9a9e8fa96f 100644 --- a/tests/unit/apikeys-disable-non-public.test.ts +++ b/tests/unit/apikeys-disable-non-public.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("disableNonPublicModels: set to true via updateApiKeyPermissions, read back via getApiKeyMetadata", async () => { @@ -97,10 +97,7 @@ test("3 columns coexist: disableNonPublicModels, allowedQuotas, streamDefaultMod ); // Verify streamDefaultMode is still present - assert.ok( - metadata.streamDefaultMode !== undefined, - "streamDefaultMode should be present" - ); + assert.ok(metadata.streamDefaultMode !== undefined, "streamDefaultMode should be present"); assert.equal(metadata.streamDefaultMode, "json", "streamDefaultMode should be 'json'"); }); diff --git a/tests/unit/apikeys-usage-command.test.ts b/tests/unit/apikeys-usage-command.test.ts index 479e9f6424..fe733d8213 100644 --- a/tests/unit/apikeys-usage-command.test.ts +++ b/tests/unit/apikeys-usage-command.test.ts @@ -14,7 +14,7 @@ const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -25,7 +25,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("allowUsageCommand defaults to false for new API keys", async () => { diff --git a/tests/unit/assemble-standalone-onnxruntime-native-asset.test.ts b/tests/unit/assemble-standalone-onnxruntime-native-asset.test.ts index d39beb8127..63e623eb3b 100644 --- a/tests/unit/assemble-standalone-onnxruntime-native-asset.test.ts +++ b/tests/unit/assemble-standalone-onnxruntime-native-asset.test.ts @@ -60,6 +60,6 @@ test("syncStandaloneNativeAssets copies onnxruntime-node's libonnxruntime.so.1 i ); assert.ok(existsSync(destSo), "libonnxruntime.so.1 must be copied into the standalone bundle"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/attempt-logging-early-keepalive-merge.test.ts b/tests/unit/attempt-logging-early-keepalive-merge.test.ts index da9ef6fbfe..2c346b4e22 100644 --- a/tests/unit/attempt-logging-early-keepalive-merge.test.ts +++ b/tests/unit/attempt-logging-early-keepalive-merge.test.ts @@ -63,7 +63,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("bytes recorded before persistAttemptLogs are prepended into pipeline.streamChunks.client", async () => { diff --git a/tests/unit/audio-transcriptions-combo-resolution.test.ts b/tests/unit/audio-transcriptions-combo-resolution.test.ts index 15d7bfe4ea..84daa5a331 100644 --- a/tests/unit/audio-transcriptions-combo-resolution.test.ts +++ b/tests/unit/audio-transcriptions-combo-resolution.test.ts @@ -29,7 +29,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** Minimal but structurally valid WAV so nothing rejects the upload shape. */ diff --git a/tests/unit/auggie-executor.test.ts b/tests/unit/auggie-executor.test.ts index b44c3ec94f..cf8bc07d31 100644 --- a/tests/unit/auggie-executor.test.ts +++ b/tests/unit/auggie-executor.test.ts @@ -39,7 +39,7 @@ async function readSseEvents(response: Response): Promise { - fs.rmSync(TMP_DIR, { recursive: true, force: true }); + fs.rmSync(TMP_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── buildAuggiePrompt ──────────────────────────────────────────────────── diff --git a/tests/unit/auth-anonymous-fallback-toggle.test.ts b/tests/unit/auth-anonymous-fallback-toggle.test.ts index 6795a24c97..9382f01645 100644 --- a/tests/unit/auth-anonymous-fallback-toggle.test.ts +++ b/tests/unit/auth-anonymous-fallback-toggle.test.ts @@ -33,7 +33,7 @@ const { updateSettings } = await import("../../src/lib/db/settings.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** Set the opt-out list; pass null to remove the key entirely (absent setting). */ diff --git a/tests/unit/auth-antigravity-account-retry-v2.test.ts b/tests/unit/auth-antigravity-account-retry-v2.test.ts index 59aa1e3e71..2827876327 100644 --- a/tests/unit/auth-antigravity-account-retry-v2.test.ts +++ b/tests/unit/auth-antigravity-account-retry-v2.test.ts @@ -23,13 +23,13 @@ function connectionId(connection: unknown): string { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("round-robin same-model retry treats multi-exclude as fallback LRU and skips all excluded accounts", async () => { @@ -152,12 +152,7 @@ test("Antigravity 429 rate-limited locks only the exact model so siblings stay e // The exhausted model itself is locked: getProviderCredentials reports // model-scope cooldown for that exact model on the only connection. - const sameModel = await auth.getProviderCredentials( - "antigravity", - null, - null, - "gemini-3-pro" - ); + const sameModel = await auth.getProviderCredentials("antigravity", null, null, "gemini-3-pro"); assert.ok(sameModel); assert.ok("allRateLimited" in sameModel && sameModel.allRateLimited); assert.equal(sameModel.cooldownScope, "model"); diff --git a/tests/unit/auth-clear-account-error.test.ts b/tests/unit/auth-clear-account-error.test.ts index a303da4e7e..6bfd0b0dda 100644 --- a/tests/unit/auth-clear-account-error.test.ts +++ b/tests/unit/auth-clear-account-error.test.ts @@ -13,13 +13,13 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("clearAccountError clears stale provider error metadata after recovery", async () => { diff --git a/tests/unit/auth-clear-provider-routes.test.ts b/tests/unit/auth-clear-provider-routes.test.ts index a81b13c17d..ba536cc466 100644 --- a/tests/unit/auth-clear-provider-routes.test.ts +++ b/tests/unit/auth-clear-provider-routes.test.ts @@ -33,7 +33,7 @@ async function withEnv(name, value, fn) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -60,7 +60,7 @@ async function readConnection(id) { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("moderations route clears stale provider error metadata on success", async () => { diff --git a/tests/unit/auth-disable-cooling-2997.test.ts b/tests/unit/auth-disable-cooling-2997.test.ts index 8c5dc95a57..30a6023903 100644 --- a/tests/unit/auth-disable-cooling-2997.test.ts +++ b/tests/unit/auth-disable-cooling-2997.test.ts @@ -13,13 +13,13 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // #2997 — Test 1: a recoverable error on a connection flagged disableCooling diff --git a/tests/unit/auth-login-route.test.ts b/tests/unit/auth-login-route.test.ts index b44f54a3fc..e309cafc56 100644 --- a/tests/unit/auth-login-route.test.ts +++ b/tests/unit/auth-login-route.test.ts @@ -19,7 +19,7 @@ const originalGetCookieStore = loginRoute.authRouteInternals.getCookieStore; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } @@ -37,7 +37,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) { delete process.env.INITIAL_PASSWORD; } else { diff --git a/tests/unit/auth-noauth-fallback-loop-3061.test.ts b/tests/unit/auth-noauth-fallback-loop-3061.test.ts index d640ffb1e2..f0c95f67a9 100644 --- a/tests/unit/auth-noauth-fallback-loop-3061.test.ts +++ b/tests/unit/auth-noauth-fallback-loop-3061.test.ts @@ -31,7 +31,7 @@ const { getProviderCredentials } = await import("../../src/sse/services/auth.ts" test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Happy path preserved: first selection (nothing excluded) still works ── @@ -73,4 +73,3 @@ test("#3061 opencode-zen no-auth: excluding 'noauth' returns null (breaks the fa "excluded synthetic noauth must not be re-selected for the opencode-zen keyless path" ); }); - diff --git a/tests/unit/auth-ollama-cloud-per-model-403-3027.test.ts b/tests/unit/auth-ollama-cloud-per-model-403-3027.test.ts index 177989419d..83e589b7c9 100644 --- a/tests/unit/auth-ollama-cloud-per-model-403-3027.test.ts +++ b/tests/unit/auth-ollama-cloud-per-model-403-3027.test.ts @@ -22,7 +22,7 @@ const SUBSCRIPTION_403 = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ async function seedOllamaCloud() { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("per-model subscription 403 locks only the paid model, connection stays active", async () => { diff --git a/tests/unit/auth-opencode-zen-noauth-fallback.test.ts b/tests/unit/auth-opencode-zen-noauth-fallback.test.ts index 218e186bcb..8d747949f3 100644 --- a/tests/unit/auth-opencode-zen-noauth-fallback.test.ts +++ b/tests/unit/auth-opencode-zen-noauth-fallback.test.ts @@ -23,7 +23,7 @@ const { createProviderConnection } = await import("../../src/lib/db/providers.ts test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#2962 opencode-zen with no connection falls back to anonymous no-auth credentials", async () => { diff --git a/tests/unit/auth-policy-embeddings-webfetch-7785.test.ts b/tests/unit/auth-policy-embeddings-webfetch-7785.test.ts index fe252cdf4a..3766604816 100644 --- a/tests/unit/auth-policy-embeddings-webfetch-7785.test.ts +++ b/tests/unit/auth-policy-embeddings-webfetch-7785.test.ts @@ -38,7 +38,7 @@ const INVALID_BEARER = "Bearer sk-invalid-key-that-does-not-exist-7785"; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function embeddingsRequest(): Request { diff --git a/tests/unit/auth-terminal-status.test.ts b/tests/unit/auth-terminal-status.test.ts index 28e36217c6..6be5ae2473 100644 --- a/tests/unit/auth-terminal-status.test.ts +++ b/tests/unit/auth-terminal-status.test.ts @@ -14,13 +14,13 @@ const accountFallback = await import("../../open-sse/services/accountFallback.ts async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getProviderCredentials skips credits_exhausted connections", async () => { diff --git a/tests/unit/authz/client-api-policy-fallback.test.ts b/tests/unit/authz/client-api-policy-fallback.test.ts index ddb7e34935..163e3e85f2 100644 --- a/tests/unit/authz/client-api-policy-fallback.test.ts +++ b/tests/unit/authz/client-api-policy-fallback.test.ts @@ -65,7 +65,7 @@ test.after(() => { } catch { /* ignore */ } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); @@ -235,9 +235,7 @@ test("#3504 — empty 'Bearer ' Authorization falls through to the URL path toke process.env.REQUIRE_API_KEY = "true"; const policy = await loadPolicy(); const headers = new Headers({ authorization: "Bearer " }); - const out = await policy.evaluate( - ctx(headers, "/api/v1/vscode/sk-url-token/chat/completions") - ); + const out = await policy.evaluate(ctx(headers, "/api/v1/vscode/sk-url-token/chat/completions")); assert.equal(out.allow, false); if (!out.allow) { assert.equal(out.status, 401); @@ -253,9 +251,7 @@ test("#3504 — a non-Bearer scheme (Basic) also falls through to the URL token" process.env.REQUIRE_API_KEY = "true"; const policy = await loadPolicy(); const headers = new Headers({ authorization: "Basic Zm9vOmJhcg==" }); - const out = await policy.evaluate( - ctx(headers, "/api/v1/vscode/sk-url-token/chat/completions") - ); + const out = await policy.evaluate(ctx(headers, "/api/v1/vscode/sk-url-token/chat/completions")); assert.equal(out.allow, false); if (!out.allow) assert.equal(out.message, "Invalid API key"); }); diff --git a/tests/unit/authz/client-api-policy.test.ts b/tests/unit/authz/client-api-policy.test.ts index 95613bad15..68cf3b0a25 100644 --- a/tests/unit/authz/client-api-policy.test.ts +++ b/tests/unit/authz/client-api-policy.test.ts @@ -21,7 +21,7 @@ const ORIGINAL_REQUIRE_API_KEY = process.env.REQUIRE_API_KEY; function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.OMNIROUTE_API_KEY; delete process.env.ROUTER_API_KEY; @@ -34,7 +34,7 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_OMNIROUTE_API_KEY === undefined) delete process.env.OMNIROUTE_API_KEY; else process.env.OMNIROUTE_API_KEY = ORIGINAL_OMNIROUTE_API_KEY; if (ORIGINAL_ROUTER_API_KEY === undefined) delete process.env.ROUTER_API_KEY; diff --git a/tests/unit/authz/ip-filter-enforcement-6131.test.ts b/tests/unit/authz/ip-filter-enforcement-6131.test.ts index da55ff11ff..d68ce86f7c 100644 --- a/tests/unit/authz/ip-filter-enforcement-6131.test.ts +++ b/tests/unit/authz/ip-filter-enforcement-6131.test.ts @@ -22,14 +22,14 @@ const ORIGINAL_STAMP_TOKEN = process.env.OMNIROUTE_PEER_STAMP_TOKEN; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_STAMP_TOKEN === undefined) delete process.env.OMNIROUTE_PEER_STAMP_TOKEN; else process.env.OMNIROUTE_PEER_STAMP_TOKEN = ORIGINAL_STAMP_TOKEN; }); test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); ipFilter.resetIPFilter(); delete process.env.OMNIROUTE_PEER_STAMP_TOKEN; diff --git a/tests/unit/authz/management-policy.test.ts b/tests/unit/authz/management-policy.test.ts index 2e0e69a558..6e8feda318 100644 --- a/tests/unit/authz/management-policy.test.ts +++ b/tests/unit/authz/management-policy.test.ts @@ -24,7 +24,7 @@ const ORIGINAL_INITIAL = process.env.INITIAL_PASSWORD; function reset() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.JWT_SECRET; delete process.env.INITIAL_PASSWORD; @@ -35,7 +35,7 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_JWT === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = ORIGINAL_JWT; if (ORIGINAL_INITIAL === undefined) delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/authz/pipeline.test.ts b/tests/unit/authz/pipeline.test.ts index 6f6469e804..d89b152219 100644 --- a/tests/unit/authz/pipeline.test.ts +++ b/tests/unit/authz/pipeline.test.ts @@ -30,7 +30,7 @@ const ORIGINAL_OMNIROUTE_PEER_STAMP_TOKEN = process.env.OMNIROUTE_PEER_STAMP_TOK function resetEnvironment() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); process.env.JWT_SECRET = "pipeline-jwt-secret"; process.env.INITIAL_PASSWORD = "pipeline-initial-password"; @@ -67,7 +67,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_JWT === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = ORIGINAL_JWT; if (ORIGINAL_INITIAL === undefined) delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/authz/probe-9033-repro.test.ts b/tests/unit/authz/probe-9033-repro.test.ts index 22d299eb59..02886ecdb0 100644 --- a/tests/unit/authz/probe-9033-repro.test.ts +++ b/tests/unit/authz/probe-9033-repro.test.ts @@ -28,14 +28,14 @@ const ORIGINAL_STAMP_TOKEN = process.env.OMNIROUTE_PEER_STAMP_TOKEN; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_STAMP_TOKEN === undefined) delete process.env.OMNIROUTE_PEER_STAMP_TOKEN; else process.env.OMNIROUTE_PEER_STAMP_TOKEN = ORIGINAL_STAMP_TOKEN; }); test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); ipFilter.resetIPFilter(); delete process.env.OMNIROUTE_PEER_STAMP_TOKEN; diff --git a/tests/unit/auto-candidate-overrides-7819.test.ts b/tests/unit/auto-candidate-overrides-7819.test.ts index 50b21f2839..3b5ce76b59 100644 --- a/tests/unit/auto-candidate-overrides-7819.test.ts +++ b/tests/unit/auto-candidate-overrides-7819.test.ts @@ -19,7 +19,7 @@ const overridesDb = await import("../../src/lib/db/autoCandidateOverrides.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -29,7 +29,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/auto-candidate-overrides-regression-7819.test.ts b/tests/unit/auto-candidate-overrides-regression-7819.test.ts index ca1ba0c5ce..f36dc7a2e4 100644 --- a/tests/unit/auto-candidate-overrides-regression-7819.test.ts +++ b/tests/unit/auto-candidate-overrides-regression-7819.test.ts @@ -28,7 +28,7 @@ const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFa async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/auto-combo-context-advertising.test.ts b/tests/unit/auto-combo-context-advertising.test.ts index 9e324c1766..cdac54d0a5 100644 --- a/tests/unit/auto-combo-context-advertising.test.ts +++ b/tests/unit/auto-combo-context-advertising.test.ts @@ -44,7 +44,7 @@ const combosAutoRoute = await import("../../src/app/api/combos/auto/route.ts"); test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/auto-combo-credentialed-model-pool.test.ts b/tests/unit/auto-combo-credentialed-model-pool.test.ts index fb39b0d7c5..daea5e672e 100644 --- a/tests/unit/auto-combo-credentialed-model-pool.test.ts +++ b/tests/unit/auto-combo-credentialed-model-pool.test.ts @@ -25,7 +25,7 @@ type LogicalCandidate = { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -63,7 +63,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/auto-combo-hidden-models-4558.test.ts b/tests/unit/auto-combo-hidden-models-4558.test.ts index 29439b2698..f66da030fd 100644 --- a/tests/unit/auto-combo-hidden-models-4558.test.ts +++ b/tests/unit/auto-combo-hidden-models-4558.test.ts @@ -42,7 +42,7 @@ before(() => { after(() => { resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const PROVIDER = "openai"; diff --git a/tests/unit/auto-combos-enhanced-4235.test.ts b/tests/unit/auto-combos-enhanced-4235.test.ts index 262819c2d1..85a72992b8 100644 --- a/tests/unit/auto-combos-enhanced-4235.test.ts +++ b/tests/unit/auto-combos-enhanced-4235.test.ts @@ -24,7 +24,7 @@ const builtinCatalog = await import("../../open-sse/services/autoCombo/builtinCa function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4235 Phase A: README-advertised cheap/offline/smart are in the built-in catalog", () => { diff --git a/tests/unit/auto-combos-free-models-routes.test.ts b/tests/unit/auto-combos-free-models-routes.test.ts index ca7fa6772d..882d35ada9 100644 --- a/tests/unit/auto-combos-free-models-routes.test.ts +++ b/tests/unit/auto-combos-free-models-routes.test.ts @@ -12,9 +12,7 @@ import path from "node:path"; // ── DB / auth setup ─────────────────────────────────────────────────────────── -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-auto-combos-free-models-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-auto-combos-free-models-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET ?? "auto-combos-free-models-test-secret"; @@ -38,7 +36,7 @@ function makeRequest(url: string, apiKey?: string): Request { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/auto-combos-suffixes-4235.test.ts b/tests/unit/auto-combos-suffixes-4235.test.ts index 6a2eaad834..e09e7e9a46 100644 --- a/tests/unit/auto-combos-suffixes-4235.test.ts +++ b/tests/unit/auto-combos-suffixes-4235.test.ts @@ -22,14 +22,14 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(() => resetStorage()); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4235 parseAutoSuffix parses category and category:tier", () => { diff --git a/tests/unit/auto-custom-provider-5873.test.ts b/tests/unit/auto-custom-provider-5873.test.ts index 2dfbd9ae72..907bebd162 100644 --- a/tests/unit/auto-custom-provider-5873.test.ts +++ b/tests/unit/auto-custom-provider-5873.test.ts @@ -24,7 +24,7 @@ type VirtualComboResult = Awaited { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/auto-empty-pool-fastfail-6458.test.ts b/tests/unit/auto-empty-pool-fastfail-6458.test.ts index 4db304bab9..89ad0d284b 100644 --- a/tests/unit/auto-empty-pool-fastfail-6458.test.ts +++ b/tests/unit/auto-empty-pool-fastfail-6458.test.ts @@ -19,12 +19,14 @@ const { resolveModelOrError } = await import("../../src/sse/handlers/chatHelpers test.beforeEach(() => core.resetDbInstance()); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6458 empty auto-combo pool returns a 503 instead of an empty combo", async () => { // No provider connections seeded → any auto category resolves to an empty pool. - const result = await resolveModelOrError("auto/coding:pro", { messages: [{ role: "user", content: "hi" }] }); + const result = await resolveModelOrError("auto/coding:pro", { + messages: [{ role: "user", content: "hi" }], + }); assert.ok(result.error, "expected an error result, not a combo"); assert.equal(result.error.status, 503, "empty auto pool must fail fast with 503"); assert.equal(result.combo, undefined, "must not return a combo for an empty pool"); diff --git a/tests/unit/auto-keyless-custom-provider-11180.test.ts b/tests/unit/auto-keyless-custom-provider-11180.test.ts index c2e97e8158..c6070e4b0a 100644 --- a/tests/unit/auto-keyless-custom-provider-11180.test.ts +++ b/tests/unit/auto-keyless-custom-provider-11180.test.ts @@ -28,7 +28,7 @@ type VirtualComboResult = Awaited { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/auto-routing-analytics-db.test.ts b/tests/unit/auto-routing-analytics-db.test.ts index 8216f535f3..55dac3ed6d 100644 --- a/tests/unit/auto-routing-analytics-db.test.ts +++ b/tests/unit/auto-routing-analytics-db.test.ts @@ -17,7 +17,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/auto-update.test.ts b/tests/unit/auto-update.test.ts index 55112bae62..4b14e209e3 100644 --- a/tests/unit/auto-update.test.ts +++ b/tests/unit/auto-update.test.ts @@ -396,7 +396,7 @@ test("launchAutoUpdate returns validation failures and starts detached update sc assert.equal(spawnCalls[0].unrefCalled, true); assert.match(spawnCalls[0].args[1], /git cherry-pick --keep-redundant-commits 'abc123'/); } finally { - fs.rmSync(tempRoot, { recursive: true, force: true }); + fs.rmSync(tempRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -419,6 +419,6 @@ test("resolveProjectRoot walks up from start dir to nearest package.json or .git const lonelyResult = autoUpdate.resolveProjectRoot("/my-fallback", lonely); assert.equal(lonelyResult, "/my-fallback"); } finally { - fs.rmSync(tempRoot, { recursive: true, force: true }); + fs.rmSync(tempRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/autoCombo/provider-family-combos.test.ts b/tests/unit/autoCombo/provider-family-combos.test.ts index 45ff7eec94..bdb492e6a3 100644 --- a/tests/unit/autoCombo/provider-family-combos.test.ts +++ b/tests/unit/autoCombo/provider-family-combos.test.ts @@ -34,7 +34,7 @@ const builtinCatalog = await import("../../../open-sse/services/autoCombo/builti async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ beforeEach(async () => { afterAll(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/bai-provider.test.ts b/tests/unit/bai-provider.test.ts index 3669d53998..abb91d31e2 100644 --- a/tests/unit/bai-provider.test.ts +++ b/tests/unit/bai-provider.test.ts @@ -72,13 +72,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { diff --git a/tests/unit/batch-file-download.test.ts b/tests/unit/batch-file-download.test.ts index 00c5288a18..5cc891cb43 100644 --- a/tests/unit/batch-file-download.test.ts +++ b/tests/unit/batch-file-download.test.ts @@ -23,7 +23,7 @@ const fileContentRoute = await import("../../src/app/api/files/[id]/content/rout async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Helper: create a real file in the DB ─────────────────────────────────── diff --git a/tests/unit/batch-processor.test.ts b/tests/unit/batch-processor.test.ts index b96df59ffb..243fa6f904 100644 --- a/tests/unit/batch-processor.test.ts +++ b/tests/unit/batch-processor.test.ts @@ -35,7 +35,7 @@ async function reset() { // Clean up the temp DB directory if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(async () => { await reset(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/bedrock-image-log-redaction-7297.test.ts b/tests/unit/bedrock-image-log-redaction-7297.test.ts index 074301e233..ce86e3393d 100644 --- a/tests/unit/bedrock-image-log-redaction-7297.test.ts +++ b/tests/unit/bedrock-image-log-redaction-7297.test.ts @@ -14,7 +14,7 @@ const bedrockExecutor = await import("../../open-sse/executors/bedrock.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function bedrockConverseBodyWithImages(nImages: number, imageBytes: number) { @@ -57,9 +57,8 @@ test("#7297 protectPayloadForLog stays fast on a 3-image Bedrock Converse body", `opaque buffer (see #7297)` ); - const redactedBytes = ( - result as { messages: Array<{ content: Array> }> } - ).messages[0].content[0] as { image?: { source?: { bytes?: unknown } } }; + const redactedBytes = (result as { messages: Array<{ content: Array> }> }) + .messages[0].content[0] as { image?: { source?: { bytes?: unknown } } }; assert.ok( !(redactedBytes.image?.source?.bytes instanceof Uint8Array) && !Array.isArray(redactedBytes.image?.source?.bytes), diff --git a/tests/unit/binaryManager.test.ts b/tests/unit/binaryManager.test.ts index 4165a326c7..f8aeffdc14 100644 --- a/tests/unit/binaryManager.test.ts +++ b/tests/unit/binaryManager.test.ts @@ -11,13 +11,15 @@ process.env.DATA_DIR = tmpDir; afterEach(() => { const binDir = path.join(tmpDir, "bin"); try { - if (fs.existsSync(binDir)) fs.rmSync(binDir, { recursive: true, force: true }); + if (fs.existsSync(binDir)) + fs.rmSync(binDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); after(() => { process.env.DATA_DIR = originalDataDir; - if (fs.existsSync(tmpDir)) fs.rmSync(tmpDir, { recursive: true, force: true }); + if (fs.existsSync(tmpDir)) + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("binaryManager", () => { @@ -170,8 +172,8 @@ describe("binaryManager", () => { fs.mkdirSync(fakePowerShellDir, { recursive: true }); fs.writeFileSync( path.join(fakePowerShellDir, "powershell"), - "#!/bin/sh\nprintf '%s\\n' \"$@\" > \"$OMNI_TEST_COMMAND_LOG\"\n" - + "mkdir -p \"$OMNI_TEST_EXTRACT_DIR\"\nprintf 'installed-binary' > \"$OMNI_TEST_EXTRACT_DIR/cli-proxy-api\"\n" + '#!/bin/sh\nprintf \'%s\\n\' "$@" > "$OMNI_TEST_COMMAND_LOG"\n' + + 'mkdir -p "$OMNI_TEST_EXTRACT_DIR"\nprintf \'installed-binary\' > "$OMNI_TEST_EXTRACT_DIR/cli-proxy-api"\n' ); fs.chmodSync(path.join(fakePowerShellDir, "powershell"), 0o755); process.env.PATH = `${fakePowerShellDir}:${originalPath || ""}`; @@ -276,8 +278,8 @@ describe("binaryManager", () => { fs.mkdirSync(fakePowerShellDir, { recursive: true }); fs.writeFileSync( path.join(fakePowerShellDir, "powershell"), - "#!/bin/sh\nprintf '%s\\n' \"$@\" > \"$OMNI_TEST_COMMAND_LOG_PT\"\n" - + "mkdir -p \"$OMNI_TEST_EXTRACT_DIR_PT\"\nprintf 'installed-binary' > \"$OMNI_TEST_EXTRACT_DIR_PT/cli-proxy-api\"\n" + '#!/bin/sh\nprintf \'%s\\n\' "$@" > "$OMNI_TEST_COMMAND_LOG_PT"\n' + + 'mkdir -p "$OMNI_TEST_EXTRACT_DIR_PT"\nprintf \'installed-binary\' > "$OMNI_TEST_EXTRACT_DIR_PT/cli-proxy-api"\n' ); fs.chmodSync(path.join(fakePowerShellDir, "powershell"), 0o755); process.env.PATH = `${fakePowerShellDir}:${originalPath || ""}`; diff --git a/tests/unit/bootstrap-env.test.ts b/tests/unit/bootstrap-env.test.ts index cc997c6e2a..f72a5d9b83 100644 --- a/tests/unit/bootstrap-env.test.ts +++ b/tests/unit/bootstrap-env.test.ts @@ -48,7 +48,7 @@ function withTempEnv(fn) { for (const [key, value] of Object.entries(originalEnv)) { process.env[key] = value; } - fs.rmSync(tempRoot, { recursive: true, force: true }); + fs.rmSync(tempRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/bug-9204-agy-provider-alias-credentials.test.ts b/tests/unit/bug-9204-agy-provider-alias-credentials.test.ts index e45d020e66..f35d197bc8 100644 --- a/tests/unit/bug-9204-agy-provider-alias-credentials.test.ts +++ b/tests/unit/bug-9204-agy-provider-alias-credentials.test.ts @@ -8,15 +8,13 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-9204-agy- process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); -const { createConnectionFromAgyToken } = await import( - "../../src/lib/oauth/utils/agyAuthImport.ts" -); +const { createConnectionFromAgyToken } = await import("../../src/lib/oauth/utils/agyAuthImport.ts"); const { parseModel } = await import("../../open-sse/services/model.ts"); const { getProviderCredentials } = await import("../../src/sse/services/auth.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9204: an Antigravity CLI login is eligible for an agy model request", async () => { @@ -45,4 +43,4 @@ test("#9204: an Antigravity CLI login is eligible for an agy model request", asy assert.ok(credentials, "the active Antigravity CLI connection must remain selectable"); assert.equal(credentials.connectionId, connection.id); assert.equal(credentials.accessToken, "fresh-access-token"); -}); \ No newline at end of file +}); diff --git a/tests/unit/bug-9204-agy-reimport-reactivates.test.ts b/tests/unit/bug-9204-agy-reimport-reactivates.test.ts index b57538663a..29a668ce2c 100644 --- a/tests/unit/bug-9204-agy-reimport-reactivates.test.ts +++ b/tests/unit/bug-9204-agy-reimport-reactivates.test.ts @@ -9,13 +9,11 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); -const { createConnectionFromAgyToken } = await import( - "../../src/lib/oauth/utils/agyAuthImport.ts" -); +const { createConnectionFromAgyToken } = await import("../../src/lib/oauth/utils/agyAuthImport.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9204: reimporting an inactive Antigravity CLI account reactivates it", async () => { @@ -49,5 +47,8 @@ test("#9204: reimporting an inactive Antigravity CLI account reactivates it", as assert.equal(stored?.isActive, true, "a successful reimport must reactivate the account"); const active = await providersDb.getProviderConnections({ provider: "agy", isActive: true }); - assert.deepEqual(active.map((connection) => connection.id), [existing.id]); -}); \ No newline at end of file + assert.deepEqual( + active.map((connection) => connection.id), + [existing.id] + ); +}); diff --git a/tests/unit/build-next-isolated-windows-home-2402.test.ts b/tests/unit/build-next-isolated-windows-home-2402.test.ts index 7c52ae7325..b1b2bcd8f8 100644 --- a/tests/unit/build-next-isolated-windows-home-2402.test.ts +++ b/tests/unit/build-next-isolated-windows-home-2402.test.ts @@ -5,11 +5,8 @@ import fsSync from "node:fs"; import os from "node:os"; import path from "node:path"; -const { - ensureWindowsBuildProfileDirs, - getWindowsBuildProfileDir, - resolveNextBuildEnv, -} = await import("../../scripts/build/build-next-isolated.mjs"); +const { ensureWindowsBuildProfileDirs, getWindowsBuildProfileDir, resolveNextBuildEnv } = + await import("../../scripts/build/build-next-isolated.mjs"); // Port of decolua/9router#2402 ("fix(build): isolate Windows HOME/AppData during // next build"). Upstream wraps `npm run build` in a new `scripts/build-app.js` @@ -88,6 +85,6 @@ test("ensureWindowsBuildProfileDirs creates the isolated AppData directories", a assert.equal(fsSync.existsSync(env.APPDATA), true); assert.equal(fsSync.existsSync(env.LOCALAPPDATA), true); } finally { - await fs.rm(tempDir, { recursive: true, force: true }); + await fs.rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build-next-isolated.test.ts b/tests/unit/build-next-isolated.test.ts index 13b2f8598c..70806b13eb 100644 --- a/tests/unit/build-next-isolated.test.ts +++ b/tests/unit/build-next-isolated.test.ts @@ -13,14 +13,13 @@ import { syncStandaloneNativeAssets, } from "../../scripts/build/build-next-isolated.mjs"; - async function withTempDir(fn) { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "omniroute-build-next-isolated-")); try { await fn(tempDir); } finally { - await fs.rm(tempDir, { recursive: true, force: true }); + await fs.rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/build-sha-provenance-10427.test.ts b/tests/unit/build-sha-provenance-10427.test.ts index e7b3afb675..2b4c562338 100644 --- a/tests/unit/build-sha-provenance-10427.test.ts +++ b/tests/unit/build-sha-provenance-10427.test.ts @@ -92,7 +92,7 @@ test("P6: readBuildSha returns the trimmed sentinel, or empty when absent", asyn fs.writeFileSync(path.join(repo, "dist", "BUILD_SHA"), "e05ac345da\n"); assert.equal(readBuildSha(repo), "e05ac345da"); } finally { - fs.rmSync(repo, { recursive: true, force: true }); + fs.rmSync(repo, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/assemble-standalone.test.ts b/tests/unit/build/assemble-standalone.test.ts index 14a8de854b..5894c3d82b 100644 --- a/tests/unit/build/assemble-standalone.test.ts +++ b/tests/unit/build/assemble-standalone.test.ts @@ -96,7 +96,7 @@ test("assembleStandalone copies standalone + static + public + sidecars into out "static is NOT placed under a literal .next (would 404 against distDir server)" ); assert.ok(fs.existsSync(path.join(outDir, "public/logo.svg")), "public copied"); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("patchTurbopackChunks restores canonical external package names in a custom distDir", () => { @@ -116,7 +116,7 @@ test("patchTurbopackChunks restores canonical external package names in a custom assert.match(patched, /require\("ws"\)/); assert.match(patched, /require\("@ngrok\/ngrok"\)/); assert.doesNotMatch(patched, /-[0-9a-f]{16}/); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Drift guard: the async path (syncStandaloneNativeAssets / syncStandaloneExtraModules, @@ -173,7 +173,7 @@ test("async and sync sidecar copy paths produce identical bundle trees", async ( ]) { assert.ok(asyncTree.includes(sqlJsFile), `sql.js runtime file copied: ${sqlJsFile}`); } - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("the TPROXY addon source is skipped gracefully when it was not built (non-Linux)", async () => { @@ -189,7 +189,7 @@ test("the TPROXY addon source is skipped gracefully when it was not built (non-L !fs.existsSync(path.join(out, "src/mitm/tproxy/native/build/Release/transparent.node")), "absent addon is simply not copied (graceful skip)" ); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression guard (#deploy 2026-07-11): server-ws.mjs gained an import of @@ -214,7 +214,7 @@ test("every relative import of standalone-server-ws.mjs is shipped into the bund `server-ws.mjs imports ./${imp} but EXTRA_MODULE_ENTRIES does not ship it — the bundle would crash at boot (ERR_MODULE_NOT_FOUND)` ); } - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression guard (deploy 2026-08-19): under heavy concurrent build I/O the bulk @@ -287,5 +287,5 @@ test("copy passes tolerate a dest that already resolves to src, or a stale-typed "sql.js content reachable through the pre-existing symlink" ); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/build/build-tool-runner-win-shim.test.ts b/tests/unit/build/build-tool-runner-win-shim.test.ts index ffc406bc4c..d1f3a06444 100644 --- a/tests/unit/build/build-tool-runner-win-shim.test.ts +++ b/tests/unit/build/build-tool-runner-win-shim.test.ts @@ -124,7 +124,7 @@ test("resolveLocalBinEntry reads the package's own bin map, never node_modules/. "the resolved entry must bypass the platform-specific .bin shim" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -145,7 +145,7 @@ test("resolveLocalBinEntry returns null for a missing package or a missing entry "an advertised entry that is not on disk must not be spawned" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -164,7 +164,7 @@ test("isNativeExecutable distinguishes an executable image from a JS shim", () = assert.equal(isNativeExecutable(pe), true); assert.equal(isNativeExecutable(join(root, "absent")), false, "a missing file is not native"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -186,7 +186,7 @@ test("runBuildTool actually runs esbuild from this repo's dependency tree", () = assert.match(readFileSync(dest, "utf8"), /42/, "esbuild produced the bundle"); } finally { - rmSync(out, { recursive: true, force: true }); + rmSync(out, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/check-bundle-size.test.ts b/tests/unit/build/check-bundle-size.test.ts index 35b9f63884..a6924ef6a0 100644 --- a/tests/unit/build/check-bundle-size.test.ts +++ b/tests/unit/build/check-bundle-size.test.ts @@ -196,7 +196,7 @@ function withTmpBundleBaseline(content: string | null, fn: (p: string) => void) try { fn(p); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/build/check-lockfile.test.ts b/tests/unit/build/check-lockfile.test.ts index 860734a7d4..5bc03459e3 100644 --- a/tests/unit/build/check-lockfile.test.ts +++ b/tests/unit/build/check-lockfile.test.ts @@ -253,7 +253,7 @@ test("runWorkspaceDependencyCheck: reports npm ls failures without masking diagn test("workspace check validates lock entries independently of node_modules", (t) => { const root = mkdtempSync(path.join(os.tmpdir(), "omniroute-lockfile-check-")); - t.after(() => rmSync(root, { recursive: true, force: true })); + t.after(() => rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })); mkdirSync(path.join(root, "packages", "example"), { recursive: true }); writeFileSync( path.join(root, "package.json"), diff --git a/tests/unit/build/check-secrets.test.ts b/tests/unit/build/check-secrets.test.ts index 9b5ce23f71..51987e8d43 100644 --- a/tests/unit/build/check-secrets.test.ts +++ b/tests/unit/build/check-secrets.test.ts @@ -298,7 +298,7 @@ function withTmpBaseline(content: string | null, fn: (p: string) => void) { try { fn(p); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/build/check-test-runner-api.test.ts b/tests/unit/build/check-test-runner-api.test.ts index 37dd15a3d1..a938dc6d3f 100644 --- a/tests/unit/build/check-test-runner-api.test.ts +++ b/tests/unit/build/check-test-runner-api.test.ts @@ -21,7 +21,7 @@ test("flags a vitest-only-dir test that imports node:test", () => { assert.equal(bad.length, 1); assert.match(bad[0].file.replace(/\\/g, "/"), /autoCombo\/bad\.test\.ts$/); assert.match(bad[0].reason, /vitest-only/); - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("accepts a vitest-only-dir test that imports vitest", () => { @@ -31,7 +31,7 @@ test("accepts a vitest-only-dir test that imports vitest", () => { `import { describe, it } from "vitest";\ndescribe("x", () => it("y", () => {}));\n` ); assert.equal(findRunnerMismatches(root).length, 0); - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("flags node:test imports in the Vitest-only config roots", () => { @@ -52,5 +52,5 @@ test("flags node:test imports in the Vitest-only config roots", () => { } assert.equal(findRunnerMismatches(root).length, dirs.length); - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/build/check-vuln-ratchet.test.ts b/tests/unit/build/check-vuln-ratchet.test.ts index 11a8b66fbd..19b20ad951 100644 --- a/tests/unit/build/check-vuln-ratchet.test.ts +++ b/tests/unit/build/check-vuln-ratchet.test.ts @@ -77,9 +77,7 @@ function makeResultTwoPkgs() { packages: [ { package: { name: "pkg-b", version: "2.0.0", ecosystem: "npm" }, - vulnerabilities: [ - { id: "GHSA-bbb-1", aliases: [], affected: [] }, - ], + vulnerabilities: [{ id: "GHSA-bbb-1", aliases: [], affected: [] }], }, ], }, @@ -183,7 +181,9 @@ test("parseOsvJson: results vazio retorna vulnCount=0", () => { }); test("parseOsvJson: result sem packages retorna vulnCount=0", () => { - const result = parseOsvJson({ results: [{ other: "data" }] } as unknown as { results: { packages: never[] }[] }); + const result = parseOsvJson({ results: [{ other: "data" }] } as unknown as { + results: { packages: never[] }[]; + }); assert.equal(result.vulnCount, 0); }); @@ -358,7 +358,7 @@ function withTmpBaseline(content: string | null, fn: (p: string) => void) { try { fn(p); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/build/check-workflows.test.ts b/tests/unit/build/check-workflows.test.ts index 3018b68600..fea3f3476e 100644 --- a/tests/unit/build/check-workflows.test.ts +++ b/tests/unit/build/check-workflows.test.ts @@ -179,7 +179,7 @@ test("collectWorkflowFiles: returns .yml files from directory", () => { assert.ok(files.some((f) => f.endsWith("deploy.yml"))); assert.ok(!files.some((f) => f.endsWith("README.md"))); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -194,7 +194,7 @@ test("collectWorkflowFiles: also collects .yaml extension", () => { assert.ok(files.some((f) => f.endsWith(".yaml"))); assert.ok(files.some((f) => f.endsWith(".yml"))); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -206,7 +206,7 @@ test("collectWorkflowFiles: returns absolute paths", () => { assert.equal(files.length, 1); assert.ok(path.isAbsolute(files[0])); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -216,7 +216,7 @@ test("collectWorkflowFiles: empty directory returns empty array", () => { const files = collectWorkflowFiles(dir); assert.deepEqual(files, []); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -282,7 +282,7 @@ function withTmpBaseline(content: string | null, fn: (p: string) => void) { try { fn(p); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/build/colocate-standalone-esm-scope.test.ts b/tests/unit/build/colocate-standalone-esm-scope.test.ts index d31772d11a..0969dd4a24 100644 --- a/tests/unit/build/colocate-standalone-esm-scope.test.ts +++ b/tests/unit/build/colocate-standalone-esm-scope.test.ts @@ -35,7 +35,7 @@ test("writeEsmWorkerScopes writes a scoped type:module beside each worker", () = assert.equal(pkg.type, "module", `${dir} declares type:module`); } } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -57,7 +57,7 @@ test("writeEsmWorkerScopes never touches the standalone root package.json", () = "root package.json stays type-less so server.js is parsed as CommonJS" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -75,7 +75,7 @@ test("writeEsmWorkerScopes is no-clobber: it leaves an existing package.json int const pkg = JSON.parse(readFileSync(join(workerDir, "package.json"), "utf8")); assert.equal(pkg.version, "9.9.9", "the traced manifest is preserved verbatim"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -124,7 +124,7 @@ test("scoped layout runs a CJS server.js and an ESM worker.js side by side", () ); assert.ok(existsSync(join(workerDir, "package.json")), "worker scope package.json exists"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -141,6 +141,6 @@ test("colocate-standalone bundles the required compression worker", () => { assert.equal(existsSync(join(workerDir, "compressionWorker.js")), true); assert.equal(JSON.parse(readFileSync(join(workerDir, "package.json"), "utf8")).type, "module"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/mcp-bundle-no-eager-ioredis.test.ts b/tests/unit/build/mcp-bundle-no-eager-ioredis.test.ts index ab382c6a83..03c5db3ef0 100644 --- a/tests/unit/build/mcp-bundle-no-eager-ioredis.test.ts +++ b/tests/unit/build/mcp-bundle-no-eager-ioredis.test.ts @@ -51,7 +51,7 @@ test("MCP server bundle has no top-level static import of ioredis", () => { bundled, /^import\s+.*["']ioredis["'];?\s*$/m, "MCP bundle must not eagerly (statically) import 'ioredis' at the top level — " + - "it must stay a lazy `await import(\"ioredis\")` (see src/lib/quota/redisQuotaStore.ts)" + 'it must stay a lazy `await import("ioredis")` (see src/lib/quota/redisQuotaStore.ts)' ); // The lazy dynamic import from redisQuotaStore.ts must still be present — @@ -62,6 +62,6 @@ test("MCP server bundle has no top-level static import of ioredis", () => { "expected the existing lazy dynamic import of ioredis to remain in the bundle" ); } finally { - rmSync(outDir, { recursive: true, force: true }); + rmSync(outDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/mcp-bundle-startup.test.ts b/tests/unit/build/mcp-bundle-startup.test.ts index a441631f9a..8ed6853f23 100644 --- a/tests/unit/build/mcp-bundle-startup.test.ts +++ b/tests/unit/build/mcp-bundle-startup.test.ts @@ -55,6 +55,6 @@ test("MCP server bundle imports successfully on Node 24", () => { }); }, "the generated MCP bundle must be importable by the supported Node runtime"); } finally { - rmSync(outDir, { recursive: true, force: true }); + rmSync(outDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/mitm-server-bundle-contents.test.ts b/tests/unit/build/mitm-server-bundle-contents.test.ts index 9253c23cbc..9bd14e27a5 100644 --- a/tests/unit/build/mitm-server-bundle-contents.test.ts +++ b/tests/unit/build/mitm-server-bundle-contents.test.ts @@ -31,7 +31,7 @@ test("EXTRA_MODULE_ENTRIES ships every relative require() of MITM server.cjs (#9 ); } } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -69,6 +69,6 @@ test("EXTRA_MODULE_ENTRIES ships every dynamic import() of MITM _internal shims ); } } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/optional-pack-installer.test.ts b/tests/unit/build/optional-pack-installer.test.ts index 2b6fdc69e9..5e7139511b 100644 --- a/tests/unit/build/optional-pack-installer.test.ts +++ b/tests/unit/build/optional-pack-installer.test.ts @@ -188,7 +188,7 @@ test("installPack accepts tarball payloads (the desktop release asset layout)", stdio: "pipe", }); assert.equal(tarred.status, 0, "fixture tarball creation must succeed"); - fs.rmSync(packDir, { recursive: true, force: true }); // only the tarball remains + fs.rmSync(packDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); // only the tarball remains const source = resolvePackSource(pack.name, sourceDir, dataDir); assert.equal(source.kind, "tarball"); diff --git a/tests/unit/build/repair-empty-external-package-dirs-nested.test.ts b/tests/unit/build/repair-empty-external-package-dirs-nested.test.ts index 50af15cadc..bd13e78406 100644 --- a/tests/unit/build/repair-empty-external-package-dirs-nested.test.ts +++ b/tests/unit/build/repair-empty-external-package-dirs-nested.test.ts @@ -35,7 +35,12 @@ test("assembleStandalone repairs a hollow externalized package dir in the nested const standaloneDir = path.join(distDir, "standalone"); fs.mkdirSync(standaloneDir, { recursive: true }); fs.writeFileSync(path.join(standaloneDir, "server.js"), "// server"); - const hollowNestedPkgDir = path.join(standaloneDir, relDistDir, "node_modules", "some-nested-pkg"); + const hollowNestedPkgDir = path.join( + standaloneDir, + relDistDir, + "node_modules", + "some-nested-pkg" + ); fs.mkdirSync(hollowNestedPkgDir, { recursive: true }); assembleStandalone({ @@ -45,11 +50,17 @@ test("assembleStandalone repairs a hollow externalized package dir in the nested copyNatives: true, }); - const repairedIndexPath = path.join(outDir, relDistDir, "node_modules", "some-nested-pkg", "index.js"); + const repairedIndexPath = path.join( + outDir, + relDistDir, + "node_modules", + "some-nested-pkg", + "index.js" + ); assert.ok( fs.existsSync(repairedIndexPath), "hollow nested externalized package dir must be repaired with the real source package (index.js present)" ); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/build/should-promote-latest-5301.test.ts b/tests/unit/build/should-promote-latest-5301.test.ts index 61d6793ef8..84341be300 100644 --- a/tests/unit/build/should-promote-latest-5301.test.ts +++ b/tests/unit/build/should-promote-latest-5301.test.ts @@ -62,7 +62,7 @@ function shouldPromote(version: string, tags: string[]): string { }).trim(); } finally { closeSync(fd); - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/build/standalone-bundle.test.ts b/tests/unit/build/standalone-bundle.test.ts index 2444469202..1c8291e443 100644 --- a/tests/unit/build/standalone-bundle.test.ts +++ b/tests/unit/build/standalone-bundle.test.ts @@ -127,9 +127,9 @@ test("pack → restore roundtrip restores the tree byte-for-byte", async () => { ); } } finally { - fs.rmSync(src, { recursive: true, force: true }); - fs.rmSync(path.dirname(out), { recursive: true, force: true }); - fs.rmSync(dst, { recursive: true, force: true }); + fs.rmSync(src, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(path.dirname(out), { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(dst, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -144,8 +144,8 @@ test("packing is byte-deterministic across runs", async () => { await runPack({ dir: src, out: b }); assert.equal(sha256File(a), sha256File(b), "two packs of the same tree must be identical"); } finally { - fs.rmSync(src, { recursive: true, force: true }); - fs.rmSync(outDir, { recursive: true, force: true }); + fs.rmSync(src, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(outDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -161,8 +161,8 @@ test("restore rejects a corrupted archive before extraction", async () => { fs.writeFileSync(out, raw); await assert.rejects(() => runRestore({ archive: out, dir: path.join(outDir, "dst") }), /sha/); } finally { - fs.rmSync(src, { recursive: true, force: true }); - fs.rmSync(outDir, { recursive: true, force: true }); + fs.rmSync(src, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(outDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -191,9 +191,9 @@ test("manifest verification flags modified and smuggled files in a restored tree `smuggled file detected: ${verdict.errors.join("; ")}` ); } finally { - fs.rmSync(src, { recursive: true, force: true }); - fs.rmSync(outDir, { recursive: true, force: true }); - fs.rmSync(dst, { recursive: true, force: true }); + fs.rmSync(src, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(outDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(dst, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -207,7 +207,7 @@ test("manifest verification rejects an unsupported manifest version", async () = assert.equal(verdict.ok, false); assert.match(verdict.errors[0] ?? "", /unsupported manifest version/); } finally { - fs.rmSync(dst, { recursive: true, force: true }); + fs.rmSync(dst, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -257,8 +257,8 @@ test("hydratePlatformNatives swaps install-machine-forked packages for this leg" "fsevents dropped on non-matching leg" ); } finally { - fs.rmSync(standalone, { recursive: true, force: true }); - fs.rmSync(source, { recursive: true, force: true }); + fs.rmSync(standalone, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(source, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -299,6 +299,6 @@ test("verifyBundledNatives asserts serviceability and honors the onnx darwin-x64 `darwin-x64 must pass via exemption: ${(exempted as { errors?: string[] }).errors?.join("; ")}` ); } finally { - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/build/sync-changelog-i18n.test.ts b/tests/unit/build/sync-changelog-i18n.test.ts index 14eb8247b0..cc00973b40 100644 --- a/tests/unit/build/sync-changelog-i18n.test.ts +++ b/tests/unit/build/sync-changelog-i18n.test.ts @@ -28,7 +28,7 @@ test("replaces the version section in every mirror with the root section", () => const fr = fs.readFileSync(path.join(root, "docs/i18n/fr/CHANGELOG.md"), "utf8"); assert.match(fr, /big new thing/); assert.doesNotMatch(fr, /_stub_/); - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("inserts the section when a mirror lacks it", () => { @@ -43,5 +43,5 @@ test("inserts the section when a mirror lacks it", () => { const fr = fs.readFileSync(path.join(root, "docs/i18n/fr/CHANGELOG.md"), "utf8"); assert.match(fr, /## \[9\.9\.9\]/); assert.match(fr, /big new thing/); - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/bulk-add-keys-no-overwrite-2587.test.ts b/tests/unit/bulk-add-keys-no-overwrite-2587.test.ts index 27927316e1..79ecf2ccef 100644 --- a/tests/unit/bulk-add-keys-no-overwrite-2587.test.ts +++ b/tests/unit/bulk-add-keys-no-overwrite-2587.test.ts @@ -37,7 +37,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -58,7 +58,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("bulk-add appends N+M connections and preserves the existing connection's state (the #2587 fix)", async () => { @@ -138,9 +138,7 @@ test("bulk-add appends N+M connections and preserves the existing connection's s assert.equal(survivor!.rateLimitedUntil, future, "existing cooldown must survive"); assert.equal(survivor!.backoffLevel, 2, "existing backoffLevel must survive"); - const newNames = after - .filter((c) => c.id !== (existing as ConnectionRow).id) - .map((c) => c.name); + const newNames = after.filter((c) => c.id !== (existing as ConnectionRow).id).map((c) => c.name); assert.equal(new Set(newNames).size, newNames.length, "no duplicate names among new entries"); assert.ok(!newNames.includes("Key 1")); }); diff --git a/tests/unit/cache-config-route-8219.test.ts b/tests/unit/cache-config-route-8219.test.ts index 8fc0030972..4e71d4d0b2 100644 --- a/tests/unit/cache-config-route-8219.test.ts +++ b/tests/unit/cache-config-route-8219.test.ts @@ -21,7 +21,7 @@ const core = await import("../../src/lib/db/core.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/call-log-artifact-worker.test.ts b/tests/unit/call-log-artifact-worker.test.ts index 948a3fd110..84cd2c241a 100644 --- a/tests/unit/call-log-artifact-worker.test.ts +++ b/tests/unit/call-log-artifact-worker.test.ts @@ -12,7 +12,7 @@ const { writeCallArtifactAsync, closeCallLogArtifactWriter, resolveCallLogArtifa test.after(async () => { await closeCallLogArtifactWriter(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function buildArtifact(id: string) { @@ -120,7 +120,7 @@ test("worker resolution covers npm, standalone, source, and missing layouts", () } ); } finally { - fs.rmSync(layoutRoot, { recursive: true, force: true }); + fs.rmSync(layoutRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } const resolved = resolveCallLogArtifactWorker(); diff --git a/tests/unit/call-log-cap.test.ts b/tests/unit/call-log-cap.test.ts index e1cbd7e958..484ac0e92e 100644 --- a/tests/unit/call-log-cap.test.ts +++ b/tests/unit/call-log-cap.test.ts @@ -21,7 +21,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -88,7 +88,7 @@ test.beforeEach(async () => { test.after(() => { restorePipelineEnv(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("saveCallLog stores only summary metadata in SQLite and writes detailed artifact", async () => { diff --git a/tests/unit/call-log-file-rotation.test.ts b/tests/unit/call-log-file-rotation.test.ts index 06fe48aa11..4e5cf80368 100644 --- a/tests/unit/call-log-file-rotation.test.ts +++ b/tests/unit/call-log-file-rotation.test.ts @@ -33,7 +33,12 @@ async function resetTestDataDir() { if (/^storage\.sqlite(?:-shm|-wal)?$/i.test(entry)) { continue; } - fs.rmSync(path.join(TEST_DATA_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(TEST_DATA_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } const db = core.getDbInstance(); db.prepare("DELETE FROM call_logs").run(); @@ -121,7 +126,7 @@ test.after(async () => { test("call log file rotation honors both retention days and file count", () => { assert.ok(CALL_LOGS_DIR, "CALL_LOGS_DIR should resolve for test data dir"); - fs.rmSync(CALL_LOGS_DIR, { recursive: true, force: true }); + fs.rmSync(CALL_LOGS_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(CALL_LOGS_DIR, { recursive: true }); const now = Date.now(); @@ -235,7 +240,7 @@ test("rotateCallLogs swallows filesystem errors during cleanup", () => { test("cleanupOverflowCallLogFiles ignores rmSync failures for old artifacts", () => { assert.ok(CALL_LOGS_DIR, "CALL_LOGS_DIR should resolve for test data dir"); - fs.rmSync(CALL_LOGS_DIR, { recursive: true, force: true }); + fs.rmSync(CALL_LOGS_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(CALL_LOGS_DIR, { recursive: true }); const dayDir = path.join(CALL_LOGS_DIR, "2026-04-02"); diff --git a/tests/unit/call-log-oom-unbounded-5618.test.ts b/tests/unit/call-log-oom-unbounded-5618.test.ts index 49d52be057..d6551378f7 100644 --- a/tests/unit/call-log-oom-unbounded-5618.test.ts +++ b/tests/unit/call-log-oom-unbounded-5618.test.ts @@ -65,13 +65,13 @@ const unboundedSelectsOnCallLogs = (sqls: string[]) => test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5618 collectReferencedArtifacts pages with LIMIT and collects across pages — no unbounded .all()", () => { diff --git a/tests/unit/call-log-provider-display.test.ts b/tests/unit/call-log-provider-display.test.ts index 4b1e9ee4ce..a5c806d2a5 100644 --- a/tests/unit/call-log-provider-display.test.ts +++ b/tests/unit/call-log-provider-display.test.ts @@ -4,7 +4,9 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-call-log-provider-display-")); +const TEST_DATA_DIR = fs.mkdtempSync( + path.join(os.tmpdir(), "omniroute-call-log-provider-display-") +); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -33,7 +35,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getCallLogs and getCallLogById expose providerDisplay from provider node name", async () => { diff --git a/tests/unit/call-log-save-drain.test.ts b/tests/unit/call-log-save-drain.test.ts index 6371d2785d..ba5c5b846c 100644 --- a/tests/unit/call-log-save-drain.test.ts +++ b/tests/unit/call-log-save-drain.test.ts @@ -17,7 +17,7 @@ const artifactWriter = await import("../../src/lib/usage/callLogArtifactWriter.t test.after(async () => { await artifactWriter.closeCallLogArtifactWriter(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("call-log drain waits for artifact metadata and summary commit", async () => { diff --git a/tests/unit/call-log-startup.test.ts b/tests/unit/call-log-startup.test.ts index 9d556f7a87..67063a07f8 100644 --- a/tests/unit/call-log-startup.test.ts +++ b/tests/unit/call-log-startup.test.ts @@ -13,7 +13,7 @@ async function removeTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: any) { lastError = error; diff --git a/tests/unit/call-log-stream-debug.test.ts b/tests/unit/call-log-stream-debug.test.ts index 33d3978f74..6af3e46f32 100644 --- a/tests/unit/call-log-stream-debug.test.ts +++ b/tests/unit/call-log-stream-debug.test.ts @@ -13,7 +13,7 @@ const callLogs = await import("../../src/lib/usage/callLogs.ts"); async function resetStorage() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -24,7 +24,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("saveCallLog preserves streamChunks in pipeline payloads", async () => { diff --git a/tests/unit/call-log-trim-sql-vars-5217.test.ts b/tests/unit/call-log-trim-sql-vars-5217.test.ts index 7f7dab57aa..46963977ef 100644 --- a/tests/unit/call-log-trim-sql-vars-5217.test.ts +++ b/tests/unit/call-log-trim-sql-vars-5217.test.ts @@ -37,13 +37,13 @@ function insertCallLog(id: string, timestamp: string) { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("trimCallLogsToMaxRows deletes >999 rows in one pass without 'too many SQL variables'", () => { diff --git a/tests/unit/call-logs-correlation-substring.test.ts b/tests/unit/call-logs-correlation-substring.test.ts index c5fe01a53e..277dbf0ddf 100644 --- a/tests/unit/call-logs-correlation-substring.test.ts +++ b/tests/unit/call-logs-correlation-substring.test.ts @@ -12,7 +12,7 @@ const callLogs = await import("../../src/lib/usage/callLogs.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Seed test data diff --git a/tests/unit/call-logs-exclude-tests-allowlist.test.ts b/tests/unit/call-logs-exclude-tests-allowlist.test.ts index 78aa5728af..cec5b07d4d 100644 --- a/tests/unit/call-logs-exclude-tests-allowlist.test.ts +++ b/tests/unit/call-logs-exclude-tests-allowlist.test.ts @@ -51,13 +51,13 @@ function insertCallLog(row: SeedRow) { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("excludeTests keeps only /v1 and /api/v1 inference rows, drops all backend/management rows", async () => { diff --git a/tests/unit/call-logs-pagination.test.ts b/tests/unit/call-logs-pagination.test.ts index 99835b08f1..41559a6434 100644 --- a/tests/unit/call-logs-pagination.test.ts +++ b/tests/unit/call-logs-pagination.test.ts @@ -70,7 +70,7 @@ function insertCallLog(row: Record) { test.before(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // Seed 25 rows with strictly increasing timestamps (id N -> minute N). for (let i = 0; i < 25; i++) { @@ -81,7 +81,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#2565: getCallLogs honors limit and returns newest-first", async () => { diff --git a/tests/unit/call-logs-requested-model.test.ts b/tests/unit/call-logs-requested-model.test.ts index 745854ad32..bf89c1183a 100644 --- a/tests/unit/call-logs-requested-model.test.ts +++ b/tests/unit/call-logs-requested-model.test.ts @@ -13,7 +13,7 @@ const providers = await import("../../src/lib/db/providers.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -23,7 +23,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("call logs persist requestedModel and allow filtering by requested model", async () => { diff --git a/tests/unit/call-logs-session-tag.test.ts b/tests/unit/call-logs-session-tag.test.ts index 4e466af1f2..3fb92e035a 100644 --- a/tests/unit/call-logs-session-tag.test.ts +++ b/tests/unit/call-logs-session-tag.test.ts @@ -15,7 +15,7 @@ const callLogs = await import("../../src/lib/usage/callLogs.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("saveCallLog persists sessionTag when explicitly supplied", async () => { diff --git a/tests/unit/capture-critical-db-state.test.ts b/tests/unit/capture-critical-db-state.test.ts index 6ded65793e..4f8a2ecbff 100644 --- a/tests/unit/capture-critical-db-state.test.ts +++ b/tests/unit/capture-critical-db-state.test.ts @@ -37,7 +37,7 @@ after(() => { delete process.env.DATA_DIR; } try { - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore cleanup errors } diff --git a/tests/unit/catalog-auto-routing-disabled-10831.test.ts b/tests/unit/catalog-auto-routing-disabled-10831.test.ts index f2f96ef95f..cd40b633c3 100644 --- a/tests/unit/catalog-auto-routing-disabled-10831.test.ts +++ b/tests/unit/catalog-auto-routing-disabled-10831.test.ts @@ -40,7 +40,7 @@ const isAutoId = (m: { id: string }) => m.id.startsWith("auto/"); test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best-effort */ } diff --git a/tests/unit/catalog-hide-auto-no-think.test.ts b/tests/unit/catalog-hide-auto-no-think.test.ts index c0db3cffa7..e4f2bff114 100644 --- a/tests/unit/catalog-hide-auto-no-think.test.ts +++ b/tests/unit/catalog-hide-auto-no-think.test.ts @@ -33,7 +33,7 @@ async function fetchCatalog(): Promise> { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best-effort */ } @@ -60,7 +60,11 @@ test("hideAutoCombos=true removes auto/* ids from /v1/models", async () => { await settingsDb.updateSettings({ hideAutoCombos: false, hideNoThinkVariants: false }); const off = await fetchCatalog(); const autoWhenOff = off.filter(isAutoId).map((m) => m.id); - assert.equal(autoWhenOff.length > 0, true, `expected auto/* ids when toggle off, got ${autoWhenOff.length}`); + assert.equal( + autoWhenOff.length > 0, + true, + `expected auto/* ids when toggle off, got ${autoWhenOff.length}` + ); await settingsDb.updateSettings({ hideAutoCombos: true, hideNoThinkVariants: false }); const on = await fetchCatalog(); @@ -69,7 +73,11 @@ test("hideAutoCombos=true removes auto/* ids from /v1/models", async () => { // Original provider models must still be present const hasProviderModel = on.some((m) => m.id.startsWith("openai/") || m.id.startsWith("oa/")); - assert.equal(hasProviderModel, true, "original provider models must remain when hideAutoCombos=true"); + assert.equal( + hasProviderModel, + true, + "original provider models must remain when hideAutoCombos=true" + ); }); test("hideNoThinkVariants=true removes no-think/* ids from /v1/models", async () => { @@ -97,20 +105,32 @@ test("hideNoThinkVariants=true removes no-think/* ids from /v1/models", async () const hasProviderModel = on.some( (m) => m.id.startsWith("claude/") || m.id.startsWith("anthropic/") ); - assert.equal(hasProviderModel, true, "original provider models must remain when hideNoThinkVariants=true"); + assert.equal( + hasProviderModel, + true, + "original provider models must remain when hideNoThinkVariants=true" + ); return; } await settingsDb.updateSettings({ hideAutoCombos: false, hideNoThinkVariants: true }); const on = await fetchCatalog(); const leaked = on.filter(isNoThinkId).map((m) => m.id); - assert.deepEqual(leaked, [], `no-think/* ids leaked when hideNoThinkVariants=true: ${leaked.join(", ")}`); + assert.deepEqual( + leaked, + [], + `no-think/* ids leaked when hideNoThinkVariants=true: ${leaked.join(", ")}` + ); // Original provider models must still be present const hasProviderModel = on.some( (m) => m.id.startsWith("claude/") || m.id.startsWith("anthropic/") ); - assert.equal(hasProviderModel, true, "original provider models must remain when hideNoThinkVariants=true"); + assert.equal( + hasProviderModel, + true, + "original provider models must remain when hideNoThinkVariants=true" + ); }); test("both toggles on: neither auto/* nor no-think/* appear; original models present", async () => { @@ -125,7 +145,15 @@ test("both toggles on: neither auto/* nor no-think/* appear; original models pre assert.deepEqual(noThinkLeaked, [], `no-think/* ids leaked: ${noThinkLeaked.join(", ")}`); const hasProviderModel = on.some( - (m) => m.id.startsWith("openai/") || m.id.startsWith("oa/") || m.id.startsWith("claude/") || m.id.startsWith("anthropic/") + (m) => + m.id.startsWith("openai/") || + m.id.startsWith("oa/") || + m.id.startsWith("claude/") || + m.id.startsWith("anthropic/") + ); + assert.equal( + hasProviderModel, + true, + "original provider models must remain when both toggles are on" ); - assert.equal(hasProviderModel, true, "original provider models must remain when both toggles are on"); }); diff --git a/tests/unit/catalog-order-contract.test.ts b/tests/unit/catalog-order-contract.test.ts index e1c5c0248b..d18dd13d72 100644 --- a/tests/unit/catalog-order-contract.test.ts +++ b/tests/unit/catalog-order-contract.test.ts @@ -29,7 +29,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function seedConnection(provider: string, overrides: Record = {}) { @@ -83,13 +83,19 @@ test("catalog /v1/models: exact provider-grouped order (blocks === distinct owne { id: "gpt-4", name: "GPT-4" }, { id: "gpt-3.5-turbo", name: "GPT-3.5 Turbo" }, ]); - await modelsDb.replaceSyncedAvailableModelsForConnection("anthropic", (conn2 as { id: string }).id, [ - { id: "claude-3-opus", name: "Claude 3 Opus" }, - ]); - await modelsDb.replaceSyncedAvailableModelsForConnection("opencode", (conn3 as { id: string }).id, [ - { id: "kimi-k2", name: "Kimi K2" }, - { id: "glm-4", name: "GLM-4" }, - ]); + await modelsDb.replaceSyncedAvailableModelsForConnection( + "anthropic", + (conn2 as { id: string }).id, + [{ id: "claude-3-opus", name: "Claude 3 Opus" }] + ); + await modelsDb.replaceSyncedAvailableModelsForConnection( + "opencode", + (conn3 as { id: string }).id, + [ + { id: "kimi-k2", name: "Kimi K2" }, + { id: "glm-4", name: "GLM-4" }, + ] + ); const response = await v1ModelsCatalog.getUnifiedModelsResponse( new Request("http://localhost/v1/models?configuredOnly=true") diff --git a/tests/unit/cc-compatible-model-catalog.test.ts b/tests/unit/cc-compatible-model-catalog.test.ts index 8453abed62..54fc490771 100644 --- a/tests/unit/cc-compatible-model-catalog.test.ts +++ b/tests/unit/cc-compatible-model-catalog.test.ts @@ -13,7 +13,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -23,7 +23,7 @@ test.afterEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 models exposes CC-compatible fallback models under the provider node prefix", async () => { diff --git a/tests/unit/cc-compatible-provider.test.ts b/tests/unit/cc-compatible-provider.test.ts index 8f8cc672af..e4c81bb073 100644 --- a/tests/unit/cc-compatible-provider.test.ts +++ b/tests/unit/cc-compatible-provider.test.ts @@ -34,7 +34,7 @@ const originalAllowLocalProviderUrls = process.env.OMNIROUTE_ALLOW_LOCAL_PROVIDE async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -76,7 +76,7 @@ test.after(() => { process.env.OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS = originalAllowLocalProviderUrls; } core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("buildClaudeCodeCompatibleRequest keeps prior role history while dropping trailing assistant prefill", () => { diff --git a/tests/unit/cc-discovery-alias-api.test.ts b/tests/unit/cc-discovery-alias-api.test.ts index 9f466eeed2..3e03adbe5d 100644 --- a/tests/unit/cc-discovery-alias-api.test.ts +++ b/tests/unit/cc-discovery-alias-api.test.ts @@ -14,7 +14,7 @@ const route = await import("../../src/app/api/providers/[id]/cc-alias/route.ts") function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -41,7 +41,7 @@ describe("PUT/GET /api/providers/[id]/cc-alias", () => { after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.REQUIRE_API_KEY; }); diff --git a/tests/unit/cc-discovery-aliases-gate.test.ts b/tests/unit/cc-discovery-aliases-gate.test.ts index 74e26ad653..5c4e9c67f7 100644 --- a/tests/unit/cc-discovery-aliases-gate.test.ts +++ b/tests/unit/cc-discovery-aliases-gate.test.ts @@ -24,7 +24,7 @@ const { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -95,7 +95,7 @@ describe("ccDiscoveryAliases storage", () => { after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("getCcAliasProviderSetting returns null when unset", () => { @@ -171,7 +171,7 @@ describe("global CC alias state (env / DB / default)", () => { after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.EXPOSE_CC_DISCOVERY_ALIASES; }); diff --git a/tests/unit/cc-discovery-metrics.test.ts b/tests/unit/cc-discovery-metrics.test.ts index 166ae74a79..5d39e0a1cd 100644 --- a/tests/unit/cc-discovery-metrics.test.ts +++ b/tests/unit/cc-discovery-metrics.test.ts @@ -17,7 +17,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/changelog-fragments.test.ts b/tests/unit/changelog-fragments.test.ts index 6be69c0a4d..2dddf03613 100644 --- a/tests/unit/changelog-fragments.test.ts +++ b/tests/unit/changelog-fragments.test.ts @@ -78,7 +78,7 @@ test("collectFragments reads sections sorted and flags invalid files", () => { assert.equal(c.features.length, 1); assert.equal(c.invalid.length, 1); assert.match(c.invalid[0].file, /bad\.md/); - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("insertBullets appends at the END of each living section", () => { @@ -100,7 +100,11 @@ test("insertBullets appends at the END of each living section", () => { assert.ok(maintIdx > maintHeadIdx && maintIdx < lines.indexOf("## [3.8.46] - 2026-07-04")); // Only the FIRST (living) occurrence of a heading is touched — the shipped 3.8.46 // section is byte-identical. - assert.ok(out.includes("## [3.8.46] - 2026-07-04\n\n### ✨ New Features\n\n- **old feature**: shipped (#0)")); + assert.ok( + out.includes( + "## [3.8.46] - 2026-07-04\n\n### ✨ New Features\n\n- **old feature**: shipped (#0)" + ) + ); // No existing bullet lost. for (const existing of ["#1 — thanks @a", "existing fix (#2", "existing maintenance (#3"]) { assert.ok(out.includes(existing)); @@ -108,7 +112,10 @@ test("insertBullets appends at the END of each living section", () => { }); test("insertBullets throws when a needed heading is missing", () => { - const noMaint = CHANGELOG_FIXTURE.replace("### 📝 Maintenance\n\n- chore: existing maintenance (#3)\n", ""); + const noMaint = CHANGELOG_FIXTURE.replace( + "### 📝 Maintenance\n\n- chore: existing maintenance (#3)\n", + "" + ); assert.throws( () => insertBullets(noMaint, { maintenance: [{ text: "- x" }] }), /📝 Maintenance.*not found/s @@ -134,19 +141,19 @@ test("aggregate dry-run touches nothing; real run writes and deletes fragments", const again = aggregate({ root }); assert.equal(again.total, 0); assert.equal(readFileSync(join(root, "CHANGELOG.md"), "utf8"), after); - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("aggregate refuses invalid fragments loudly", () => { const root = makeRoot({ fragments: { "features/oops.md": "forgot the dash" } }); assert.throws(() => aggregate({ root }), /invalid changelog fragments/); - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("gate findInvalidFragments: clean tree passes, bad placement/content fail", () => { const clean = makeRoot({ fragments: { "maintenance/1-ok.md": "- ok (#1)" } }); assert.deepEqual(findInvalidFragments(clean), []); - rmSync(clean, { recursive: true, force: true }); + rmSync(clean, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); const dirty = makeRoot({ fragments: { @@ -161,7 +168,7 @@ test("gate findInvalidFragments: clean tree passes, bad placement/content fail", assert.ok(files.some((f) => f.includes("stray.md"))); assert.ok(files.some((f) => f.includes("unknown-section"))); assert.ok(files.some((f) => f.includes("3-bad.md"))); - rmSync(dirty, { recursive: true, force: true }); + rmSync(dirty, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("gate skips README.md and .gitkeep; absent changelog.d is fine", () => { @@ -170,11 +177,11 @@ test("gate skips README.md and .gitkeep; absent changelog.d is fine", () => { mkdirSync(join(root, "changelog.d/fixes"), { recursive: true }); writeFileSync(join(root, "changelog.d/fixes/.gitkeep"), ""); assert.deepEqual(findInvalidFragments(root), []); - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); const bare = mkdtempSync(join(tmpdir(), "chfrag-bare-")); assert.deepEqual(findInvalidFragments(bare), []); - rmSync(bare, { recursive: true, force: true }); + rmSync(bare, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("SECTIONS maps every dir to a real living-section heading in the fixture", () => { diff --git a/tests/unit/chaos-api-routes.test.ts b/tests/unit/chaos-api-routes.test.ts index 650ad2ed59..358270f282 100644 --- a/tests/unit/chaos-api-routes.test.ts +++ b/tests/unit/chaos-api-routes.test.ts @@ -40,12 +40,17 @@ async function resetStorage() { // config cache too, or getChaosConfig() keeps serving a stale value (e.g. a // prior test's `enabled: true`) after resetDbInstance() below. chaosConfig.invalidateChaosConfigCache(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } -function makeRequest(method: string, url: string, body?: unknown, headers: Record = {}) { +function makeRequest( + method: string, + url: string, + body?: unknown, + headers: Record = {} +) { return new Request(url, { method, headers: { @@ -74,7 +79,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; @@ -114,10 +119,7 @@ test("GET /api/chaos/config — returns defaults, PUT updates, DELETE resets", a const getBody = (await getRes.json()) as { config: typeof chaosConfig.DEFAULT_CHAOS_CONFIG }; // JSON.stringify drops keys whose value is `undefined` (systemPrompt), so compare // against the JSON round-tripped shape rather than the raw in-memory default. - assert.deepEqual( - getBody.config, - JSON.parse(JSON.stringify(chaosConfig.DEFAULT_CHAOS_CONFIG)) - ); + assert.deepEqual(getBody.config, JSON.parse(JSON.stringify(chaosConfig.DEFAULT_CHAOS_CONFIG))); const putRes = await configRoute.PUT( makeRequest("PUT", "http://localhost/api/chaos/config", { @@ -137,12 +139,11 @@ test("GET /api/chaos/config — returns defaults, PUT updates, DELETE resets", a makeRequest("DELETE", "http://localhost/api/chaos/config") ); assert.equal(deleteRes.status, 200); - const deleteBody = (await deleteRes.json()) as { config: typeof chaosConfig.DEFAULT_CHAOS_CONFIG }; + const deleteBody = (await deleteRes.json()) as { + config: typeof chaosConfig.DEFAULT_CHAOS_CONFIG; + }; // Same JSON.stringify undefined-key drop as the GET assertion above. - assert.deepEqual( - deleteBody.config, - JSON.parse(JSON.stringify(chaosConfig.DEFAULT_CHAOS_CONFIG)) - ); + assert.deepEqual(deleteBody.config, JSON.parse(JSON.stringify(chaosConfig.DEFAULT_CHAOS_CONFIG))); }); test("PUT /api/chaos/config — 400 on schema validation failure", async () => { diff --git a/tests/unit/chaos-config.test.ts b/tests/unit/chaos-config.test.ts index 3f37e7a406..e90a76ad5e 100644 --- a/tests/unit/chaos-config.test.ts +++ b/tests/unit/chaos-config.test.ts @@ -24,7 +24,7 @@ const chaosConfig = await import("../../src/lib/chaos/chaosConfig.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/chaos-executor.test.ts b/tests/unit/chaos-executor.test.ts index b67bf0bad5..ae44c2f0bd 100644 --- a/tests/unit/chaos-executor.test.ts +++ b/tests/unit/chaos-executor.test.ts @@ -28,7 +28,7 @@ const chaosExecutor = await import("../../src/lib/chaos/chaosExecutor.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/chat-combo-live-test.test.ts b/tests/unit/chat-combo-live-test.test.ts index 348154c40a..36952cb04a 100644 --- a/tests/unit/chat-combo-live-test.test.ts +++ b/tests/unit/chat-combo-live-test.test.ts @@ -25,7 +25,7 @@ async function flushBackgroundWork() { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); resetAllCircuitBreakers(); } @@ -132,7 +132,7 @@ test.after(async () => { globalThis.fetch = originalFetch; resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("combo live test bypasses connection cooldown and breaker state to perform a real upstream request", async () => { diff --git a/tests/unit/chat-completions-parse-once-7847.test.ts b/tests/unit/chat-completions-parse-once-7847.test.ts index fd8f50fc99..5c014fac0d 100644 --- a/tests/unit/chat-completions-parse-once-7847.test.ts +++ b/tests/unit/chat-completions-parse-once-7847.test.ts @@ -119,5 +119,5 @@ test("#7847 downstream body resolution preserves the parsed object's identity", test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/chat-completions-route-shape-gate.test.ts b/tests/unit/chat-completions-route-shape-gate.test.ts index 38d8beea76..b0f7922a70 100644 --- a/tests/unit/chat-completions-route-shape-gate.test.ts +++ b/tests/unit/chat-completions-route-shape-gate.test.ts @@ -45,7 +45,7 @@ async function flushBackgroundWork() { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -63,7 +63,7 @@ test.after(async () => { await flushBackgroundWork(); globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function makeCountingRequest(body: string) { diff --git a/tests/unit/chat-core-intercept-fetch.test.ts b/tests/unit/chat-core-intercept-fetch.test.ts index 7c9dfa774d..50ec13d062 100644 --- a/tests/unit/chat-core-intercept-fetch.test.ts +++ b/tests/unit/chat-core-intercept-fetch.test.ts @@ -15,12 +15,10 @@ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-test-chatcore-in process.env.DATA_DIR = tmpDir; const core = await import("../../src/lib/db/core.ts"); -const { setInterceptionRules, resolveInterceptFetch } = await import( - "../../src/lib/db/interceptionRules.ts" -); -const { prepareWebFetchFallbackBody } = await import( - "../../open-sse/services/webFetchInterception.ts" -); +const { setInterceptionRules, resolveInterceptFetch } = + await import("../../src/lib/db/interceptionRules.ts"); +const { prepareWebFetchFallbackBody } = + await import("../../open-sse/services/webFetchInterception.ts"); function buildRequestBody() { return { @@ -51,7 +49,7 @@ function runChatCoreInterceptFetchStep( describe("chatCore.ts interceptFetch call site — flag-off regression guard (#7339)", () => { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -61,7 +59,7 @@ describe("chatCore.ts interceptFetch call site — flag-off regression guard (#7 after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("leaves the outgoing body byte-identical when no interceptFetch rule is configured", () => { diff --git a/tests/unit/chat-helpers.test.ts b/tests/unit/chat-helpers.test.ts index 9007e0b33a..a971101891 100644 --- a/tests/unit/chat-helpers.test.ts +++ b/tests/unit/chat-helpers.test.ts @@ -28,7 +28,7 @@ const { setTlsClientForTest } = await import("../../open-sse/utils/proxyFetch.ts async function resetStorage() { resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,7 +51,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("resolveModelOrError resolves built-in auto catalog ids without persisted combo rows", async () => { diff --git a/tests/unit/chat-routing-synced-inventory-11089.test.ts b/tests/unit/chat-routing-synced-inventory-11089.test.ts index 441b14893b..269a584e72 100644 --- a/tests/unit/chat-routing-synced-inventory-11089.test.ts +++ b/tests/unit/chat-routing-synced-inventory-11089.test.ts @@ -41,13 +41,13 @@ const PROVIDER = "ollama-local"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createConnection(data: Record): Promise { diff --git a/tests/unit/chat-safetynet-reqid-6097.test.ts b/tests/unit/chat-safetynet-reqid-6097.test.ts index 78121f3f76..9989b8778f 100644 --- a/tests/unit/chat-safetynet-reqid-6097.test.ts +++ b/tests/unit/chat-safetynet-reqid-6097.test.ts @@ -45,7 +45,7 @@ async function flushBackgroundWork() { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -63,83 +63,80 @@ test.after(async () => { await flushBackgroundWork(); globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); -test( - "#6097 safety-net combo redirect does not throw ReferenceError: reqId is not defined", - async () => { - // A healthy provider connection so the inner auto/* combo has a candidate to - // dispatch to once the safety-net redirect completes. - await providersDb.createProviderConnection({ - provider: "openai", - authType: "apikey", - name: "openai-safetynet-6097", - apiKey: "sk-safetynet-6097", - isActive: true, - testStatus: "active", +test("#6097 safety-net combo redirect does not throw ReferenceError: reqId is not defined", async () => { + // A healthy provider connection so the inner auto/* combo has a candidate to + // dispatch to once the safety-net redirect completes. + await providersDb.createProviderConnection({ + provider: "openai", + authType: "apikey", + name: "openai-safetynet-6097", + apiKey: "sk-safetynet-6097", + isActive: true, + testStatus: "active", + }); + + // A persisted combo whose single member is a virtual `auto/*` combo. The + // top-level handler resolves the OUTER combo; only when handleComboChat calls + // handleSingleModelChat("auto/fast", …) does resolveModelOrError discover the + // auto combo and fire the safety-net redirect. + await combosDb.createCombo({ + name: "nested-auto-6097", + strategy: "priority", + models: [{ provider: "auto", model: "fast" }], + }); + + const fetchCalls: string[] = []; + globalThis.fetch = async (url: any) => { + fetchCalls.push(String(url)); + return Response.json({ + id: "chatcmpl-safetynet-6097", + choices: [{ message: { role: "assistant", content: "OK" } }], }); + }; - // A persisted combo whose single member is a virtual `auto/*` combo. The - // top-level handler resolves the OUTER combo; only when handleComboChat calls - // handleSingleModelChat("auto/fast", …) does resolveModelOrError discover the - // auto combo and fire the safety-net redirect. - await combosDb.createCombo({ - name: "nested-auto-6097", - strategy: "priority", - models: [{ provider: "auto", model: "fast" }], - }); + const request = new Request("http://localhost/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + // Forces the combo target to be attempted (bypasses availability + // pre-skipping) so the redirect path is exercised deterministically. + "X-Internal-Test": "combo-health-check", + }, + body: JSON.stringify({ + model: "nested-auto-6097", + messages: [{ role: "user", content: "Reply with OK only." }], + max_tokens: 16, + stream: false, + temperature: 0, + }), + }); - const fetchCalls: string[] = []; - globalThis.fetch = async (url: any) => { - fetchCalls.push(String(url)); - return Response.json({ - id: "chatcmpl-safetynet-6097", - choices: [{ message: { role: "assistant", content: "OK" } }], - }); - }; + const response = await chatRoute.POST(request); + const bodyText = await response.text(); - const request = new Request("http://localhost/v1/chat/completions", { - method: "POST", - headers: { - "Content-Type": "application/json", - // Forces the combo target to be attempted (bypasses availability - // pre-skipping) so the redirect path is exercised deterministically. - "X-Internal-Test": "combo-health-check", - }, - body: JSON.stringify({ - model: "nested-auto-6097", - messages: [{ role: "user", content: "Reply with OK only." }], - max_tokens: 16, - stream: false, - temperature: 0, - }), - }); + // Primary guard: the exact bug signature must never appear. + assert.ok( + !bodyText.includes("reqId is not defined"), + `safety-net redirect leaked a ReferenceError: ${bodyText.slice(0, 200)}` + ); - const response = await chatRoute.POST(request); - const bodyText = await response.text(); + // The redirect must complete successfully (buggy version returned 502). + assert.equal( + response.status, + 200, + `expected 200 after safety-net redirect, got ${response.status}: ${bodyText.slice(0, 200)}` + ); - // Primary guard: the exact bug signature must never appear. - assert.ok( - !bodyText.includes("reqId is not defined"), - `safety-net redirect leaked a ReferenceError: ${bodyText.slice(0, 200)}` - ); + // And it must have proceeded past the redirect into a real upstream dispatch + // (buggy version threw before any fetch → zero calls). + assert.ok( + fetchCalls.length > 0, + "expected the redirected inner combo to reach a real upstream fetch" + ); - // The redirect must complete successfully (buggy version returned 502). - assert.equal( - response.status, - 200, - `expected 200 after safety-net redirect, got ${response.status}: ${bodyText.slice(0, 200)}` - ); - - // And it must have proceeded past the redirect into a real upstream dispatch - // (buggy version threw before any fetch → zero calls). - assert.ok( - fetchCalls.length > 0, - "expected the redirected inner combo to reach a real upstream fetch" - ); - - const body = JSON.parse(bodyText) as any; - assert.equal(body.choices[0].message.content, "OK"); - } -); + const body = JSON.parse(bodyText) as any; + assert.equal(body.choices[0].message.content, "OK"); +}); diff --git a/tests/unit/chatcore-attempt-logging.test.ts b/tests/unit/chatcore-attempt-logging.test.ts index e41c58befa..b9fe57fbd3 100644 --- a/tests/unit/chatcore-attempt-logging.test.ts +++ b/tests/unit/chatcore-attempt-logging.test.ts @@ -72,7 +72,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("persists a call log row with the mapped fields (default cacheSource=upstream)", async () => { diff --git a/tests/unit/chatcore-caveman-output-analytics.test.ts b/tests/unit/chatcore-caveman-output-analytics.test.ts index e776cacb28..e0acb70dcd 100644 --- a/tests/unit/chatcore-caveman-output-analytics.test.ts +++ b/tests/unit/chatcore-caveman-output-analytics.test.ts @@ -13,9 +13,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-caveman-test-")) process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { writeCavemanOutputAnalytics } = await import( - "../../open-sse/handlers/chatCore/cavemanOutputAnalytics.ts" -); +const { writeCavemanOutputAnalytics } = + await import("../../open-sse/handlers/chatCore/cavemanOutputAnalytics.ts"); function rowFor(requestId: string): Record | undefined { return coreDb @@ -33,7 +32,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-codex-account-pool.test.ts b/tests/unit/chatcore-codex-account-pool.test.ts index a828d7357c..31439c3a1d 100644 --- a/tests/unit/chatcore-codex-account-pool.test.ts +++ b/tests/unit/chatcore-codex-account-pool.test.ts @@ -62,7 +62,7 @@ function buildResponsesResponse(text = "ok") { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -135,7 +135,7 @@ test.after(async () => { globalThis.fetch = originalFetch; await waitForAsyncSideEffects(); await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("chatCore persists child cooldown for each rotated Codex attempt", async () => { diff --git a/tests/unit/chatcore-combo-context-limit-8378.test.ts b/tests/unit/chatcore-combo-context-limit-8378.test.ts index 29011fdc55..2dd72a9b0a 100644 --- a/tests/unit/chatcore-combo-context-limit-8378.test.ts +++ b/tests/unit/chatcore-combo-context-limit-8378.test.ts @@ -37,7 +37,7 @@ const originalSiblingEnv = process.env[SIBLING_LIMIT_ENV]; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,10 +51,7 @@ test.before(async () => { await combosDb.createCombo({ name: COMBO_NAME, - models: [ - `${MAIN_PROVIDER}/${MAIN_MODEL}`, - `${SIBLING_PROVIDER}/${SIBLING_MODEL}`, - ], + models: [`${MAIN_PROVIDER}/${MAIN_MODEL}`, `${SIBLING_PROVIDER}/${SIBLING_MODEL}`], }); // Defensive: nothing in the expected (fixed) code path should ever reach @@ -77,7 +74,7 @@ test.after(() => { process.env[SIBLING_LIMIT_ENV] = originalSiblingEnv; } core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8378: enforceOutputTokenBudget honors the combo-resolved context limit, not the plain per-target lookup", async () => { diff --git a/tests/unit/chatcore-combo-context-override-rescue.test.ts b/tests/unit/chatcore-combo-context-override-rescue.test.ts index 67b716ed3c..717b8c644d 100644 --- a/tests/unit/chatcore-combo-context-override-rescue.test.ts +++ b/tests/unit/chatcore-combo-context-override-rescue.test.ts @@ -90,7 +90,7 @@ test.before(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { diff --git a/tests/unit/chatcore-compression-analytics-write.test.ts b/tests/unit/chatcore-compression-analytics-write.test.ts index ab3d056b8f..d8645451b3 100644 --- a/tests/unit/chatcore-compression-analytics-write.test.ts +++ b/tests/unit/chatcore-compression-analytics-write.test.ts @@ -85,7 +85,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-compression-cache-stats.test.ts b/tests/unit/chatcore-compression-cache-stats.test.ts index fe1e3904b2..4c21b78d5c 100644 --- a/tests/unit/chatcore-compression-cache-stats.test.ts +++ b/tests/unit/chatcore-compression-cache-stats.test.ts @@ -13,9 +13,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-comp-cache-test- process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { recordCompressionCacheStats } = await import( - "../../open-sse/handlers/chatCore/compressionCacheStats.ts" -); +const { recordCompressionCacheStats } = + await import("../../open-sse/handlers/chatCore/compressionCacheStats.ts"); function rowsFor(provider: string): Array> { return coreDb @@ -42,7 +41,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-compression-settings.test.ts b/tests/unit/chatcore-compression-settings.test.ts index ad3ddbf9c0..7299f9b6fb 100644 --- a/tests/unit/chatcore-compression-settings.test.ts +++ b/tests/unit/chatcore-compression-settings.test.ts @@ -22,7 +22,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-compression-usage-receipt.test.ts b/tests/unit/chatcore-compression-usage-receipt.test.ts index fd3cb9711a..39082a7843 100644 --- a/tests/unit/chatcore-compression-usage-receipt.test.ts +++ b/tests/unit/chatcore-compression-usage-receipt.test.ts @@ -13,12 +13,10 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-compression-rece process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { insertCompressionAnalyticsRow, getCompressionAnalyticsSummary } = await import( - "../../src/lib/db/compressionAnalytics.ts" -); -const { attachCompressionUsageReceiptAfterAnalytics } = await import( - "../../open-sse/handlers/chatCore/compressionUsageReceipt.ts" -); +const { insertCompressionAnalyticsRow, getCompressionAnalyticsSummary } = + await import("../../src/lib/db/compressionAnalytics.ts"); +const { attachCompressionUsageReceiptAfterAnalytics } = + await import("../../open-sse/handlers/chatCore/compressionUsageReceipt.ts"); const tick = (ms: number) => new Promise((r) => setTimeout(r, ms)); @@ -28,7 +26,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("attaches the usage receipt only after pendingWrite resolves", async () => { @@ -66,11 +64,10 @@ test("attaches the usage receipt only after pendingWrite resolves", async () => test("swallows the no-matching-row case without throwing or recording a receipt", async () => { assert.doesNotThrow(() => - attachCompressionUsageReceiptAfterAnalytics( - { prompt_tokens: 1, total_tokens: 1 }, - "provider", - { pendingWrite: null, skillRequestId: "does-not-exist" } - ) + attachCompressionUsageReceiptAfterAnalytics({ prompt_tokens: 1, total_tokens: 1 }, "provider", { + pendingWrite: null, + skillRequestId: "does-not-exist", + }) ); await tick(40); const summary = getCompressionAnalyticsSummary(); diff --git a/tests/unit/chatcore-context-editing-telemetry.test.ts b/tests/unit/chatcore-context-editing-telemetry.test.ts index bfb6cad524..93a2574498 100644 --- a/tests/unit/chatcore-context-editing-telemetry.test.ts +++ b/tests/unit/chatcore-context-editing-telemetry.test.ts @@ -13,9 +13,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-ctxedit-test-")) process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { recordContextEditingTelemetryHook } = await import( - "../../open-sse/handlers/chatCore/contextEditingTelemetry.ts" -); +const { recordContextEditingTelemetryHook } = + await import("../../open-sse/handlers/chatCore/contextEditingTelemetry.ts"); function makeLog() { const debug: string[] = []; @@ -45,7 +44,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-executor-proxy.test.ts b/tests/unit/chatcore-executor-proxy.test.ts index c276d5dbbf..7777227242 100644 --- a/tests/unit/chatcore-executor-proxy.test.ts +++ b/tests/unit/chatcore-executor-proxy.test.ts @@ -33,7 +33,7 @@ beforeEach(() => { after(() => { coreDb.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("no config (disabled by default) returns the provider's own executor", async () => { diff --git a/tests/unit/chatcore-gamification-event.test.ts b/tests/unit/chatcore-gamification-event.test.ts index edc5afb70c..32405782cd 100644 --- a/tests/unit/chatcore-gamification-event.test.ts +++ b/tests/unit/chatcore-gamification-event.test.ts @@ -13,9 +13,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-gamification-tes process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { emitRequestGamificationEvent } = await import( - "../../open-sse/handlers/chatCore/gamificationEvent.ts" -); +const { emitRequestGamificationEvent } = + await import("../../open-sse/handlers/chatCore/gamificationEvent.ts"); function countAuditRows(apiKeyId: string): number { const row = coreDb @@ -41,7 +40,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-memory-skills-injection.test.ts b/tests/unit/chatcore-memory-skills-injection.test.ts index 5ecf886dc8..5867efa677 100644 --- a/tests/unit/chatcore-memory-skills-injection.test.ts +++ b/tests/unit/chatcore-memory-skills-injection.test.ts @@ -16,7 +16,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── getSkillsProviderForFormat (pure switch) ──────────────────────────────── @@ -193,7 +193,8 @@ test("injectMemoryAndSkills does not inject server memory tools for stream reque }); assert.equal(result.memorySettings?.enabled, true); - const tools = (result.body.tools as { function?: { name?: string }; name?: string }[] | undefined) ?? []; + const tools = + (result.body.tools as { function?: { name?: string }; name?: string }[] | undefined) ?? []; const toolNames = tools.map((tool) => tool.function?.name ?? tool.name); for (const memoryTool of MEMORY_BUILTIN_TOOL_NAMES) { assert.equal( @@ -230,7 +231,8 @@ test("injectMemoryAndSkills does not inject memory tools when memory is disabled log: { debug: () => {} }, }); - const tools = (result.body.tools as { function?: { name?: string }; name?: string }[] | undefined) ?? []; + const tools = + (result.body.tools as { function?: { name?: string }; name?: string }[] | undefined) ?? []; const toolNames = tools.map((tool) => tool.function?.name ?? tool.name); for (const memoryTool of MEMORY_BUILTIN_TOOL_NAMES) { assert.equal( diff --git a/tests/unit/chatcore-model-output-cap-wiring.test.ts b/tests/unit/chatcore-model-output-cap-wiring.test.ts index 9cc0042a3e..9aa1b128f0 100644 --- a/tests/unit/chatcore-model-output-cap-wiring.test.ts +++ b/tests/unit/chatcore-model-output-cap-wiring.test.ts @@ -80,7 +80,7 @@ test.after(() => { globalThis.fetch = originalFetch; featureFlagsDb.removeFeatureFlagOverride("DISABLE_CONTEXT_WINDOW_CHECKS"); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("handleChatCore clamps an over-cap max_tokens to the model's output cap before dispatch", async () => { diff --git a/tests/unit/chatcore-non-streaming-usage-stats.test.ts b/tests/unit/chatcore-non-streaming-usage-stats.test.ts index 0065a83a75..766ad42dc9 100644 --- a/tests/unit/chatcore-non-streaming-usage-stats.test.ts +++ b/tests/unit/chatcore-non-streaming-usage-stats.test.ts @@ -14,9 +14,8 @@ process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); const { getUsageHistory } = await import("../../src/lib/usage/usageHistory.ts"); -const { recordNonStreamingUsageStats } = await import( - "../../open-sse/handlers/chatCore/nonStreamingUsageStats.ts" -); +const { recordNonStreamingUsageStats } = + await import("../../open-sse/handlers/chatCore/nonStreamingUsageStats.ts"); function baseCtx(overrides: Record = {}) { return { @@ -54,7 +53,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-output-style-telemetry.test.ts b/tests/unit/chatcore-output-style-telemetry.test.ts index d91b3e0910..d0db5ec27e 100644 --- a/tests/unit/chatcore-output-style-telemetry.test.ts +++ b/tests/unit/chatcore-output-style-telemetry.test.ts @@ -13,9 +13,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-os-telemetry-tes process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { emitOutputStyleTelemetry } = await import( - "../../open-sse/handlers/chatCore/outputStyleTelemetry.ts" -); +const { emitOutputStyleTelemetry } = + await import("../../open-sse/handlers/chatCore/outputStyleTelemetry.ts"); function rowFor(requestId: string): Record | undefined { try { @@ -47,7 +46,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } @@ -71,7 +70,12 @@ test("null outputStyleResult is a no-op (returns synchronously, no throw)", asyn test("applied output-style result records a run-telemetry row (source=active-profile when combo id set)", async () => { emitOutputStyleTelemetry({ - outputStyleResult: { body: {} as never, applied: true, appliedStyles: [], skippedReason: undefined }, + outputStyleResult: { + body: {} as never, + applied: true, + appliedStyles: [], + skippedReason: undefined, + }, skillRequestId: "os-req-1", traceId: "trace-1", effectiveModel: "gpt-os", diff --git a/tests/unit/chatcore-quota-share-consumption.test.ts b/tests/unit/chatcore-quota-share-consumption.test.ts index 7bf26fc207..7fb0838416 100644 --- a/tests/unit/chatcore-quota-share-consumption.test.ts +++ b/tests/unit/chatcore-quota-share-consumption.test.ts @@ -12,9 +12,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-quota-share-test process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { scheduleQuotaShareConsumption } = await import( - "../../open-sse/handlers/chatCore/quotaShareConsumption.ts" -); +const { scheduleQuotaShareConsumption } = + await import("../../open-sse/handlers/chatCore/quotaShareConsumption.ts"); const validUsage = { prompt_tokens: 10, completion_tokens: 5 }; @@ -25,7 +24,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-reasoning-cache-write-guard.test.ts b/tests/unit/chatcore-reasoning-cache-write-guard.test.ts index d53008e454..7113c8298e 100644 --- a/tests/unit/chatcore-reasoning-cache-write-guard.test.ts +++ b/tests/unit/chatcore-reasoning-cache-write-guard.test.ts @@ -168,7 +168,7 @@ test.after(() => { try { clearReasoningCacheAll(); } catch {} - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("non-streaming: a replay provider (xiaomi-mimo) populates the reasoning cache", async () => { diff --git a/tests/unit/chatcore-sanitization.test.ts b/tests/unit/chatcore-sanitization.test.ts index 90e9b1e279..c295631bae 100644 --- a/tests/unit/chatcore-sanitization.test.ts +++ b/tests/unit/chatcore-sanitization.test.ts @@ -152,7 +152,7 @@ test.after(() => { db.close(); } catch {} - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("chatCore sanitization normalizes max_output_tokens into max_tokens", async () => { diff --git a/tests/unit/chatcore-semantic-cache.test.ts b/tests/unit/chatcore-semantic-cache.test.ts index 032bfcf9f9..61b86cc4a1 100644 --- a/tests/unit/chatcore-semantic-cache.test.ts +++ b/tests/unit/chatcore-semantic-cache.test.ts @@ -22,7 +22,7 @@ const { formatOmniRouteCost } = await import("../../src/domain/omnirouteResponse test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // A reusable persistAttemptLogs spy + base args. The functions below should NEVER be diff --git a/tests/unit/chatcore-streaming-quota-share.test.ts b/tests/unit/chatcore-streaming-quota-share.test.ts index 6acc9fde7b..7e0cc297bf 100644 --- a/tests/unit/chatcore-streaming-quota-share.test.ts +++ b/tests/unit/chatcore-streaming-quota-share.test.ts @@ -13,9 +13,8 @@ const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-stream-quota-tes process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); -const { scheduleStreamingQuotaShareConsumption } = await import( - "../../open-sse/handlers/chatCore/streamingQuotaShare.ts" -); +const { scheduleStreamingQuotaShareConsumption } = + await import("../../open-sse/handlers/chatCore/streamingQuotaShare.ts"); function makeCostSpy() { const calls: Array<{ provider: string; model: string }> = []; @@ -40,7 +39,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-streaming-usage-stats.test.ts b/tests/unit/chatcore-streaming-usage-stats.test.ts index e5db383053..3aac96b7a8 100644 --- a/tests/unit/chatcore-streaming-usage-stats.test.ts +++ b/tests/unit/chatcore-streaming-usage-stats.test.ts @@ -13,9 +13,8 @@ process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); const { getUsageHistory } = await import("../../src/lib/usage/usageHistory.ts"); -const { recordStreamingUsageStats } = await import( - "../../open-sse/handlers/chatCore/streamingUsageStats.ts" -); +const { recordStreamingUsageStats } = + await import("../../open-sse/handlers/chatCore/streamingUsageStats.ts"); function baseCtx(overrides: Record = {}) { return { @@ -55,7 +54,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/chatcore-telemetry-helpers.test.ts b/tests/unit/chatcore-telemetry-helpers.test.ts index e7bc72debc..efcef8883d 100644 --- a/tests/unit/chatcore-telemetry-helpers.test.ts +++ b/tests/unit/chatcore-telemetry-helpers.test.ts @@ -28,7 +28,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── forwardDashboardEventToLiveWs ─────────────────────────────────────────── diff --git a/tests/unit/chatcore-translation-paths.test.ts b/tests/unit/chatcore-translation-paths.test.ts index 93dd323ba9..d6a660abb7 100644 --- a/tests/unit/chatcore-translation-paths.test.ts +++ b/tests/unit/chatcore-translation-paths.test.ts @@ -322,7 +322,7 @@ async function resetStorage() { resetBackgroundStats(); globalThis.setTimeout = originalSetTimeout; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -448,7 +448,7 @@ test.after(async () => { resetAccountSemaphores(); await flushAsyncSideEffects(); await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("chatCore times out upstream execution before provider response headers", async () => { // This test asserts pendingDetail.providerRequest — only attached when the diff --git a/tests/unit/chatcore-upstream-body.test.ts b/tests/unit/chatcore-upstream-body.test.ts index 6ad6bb9616..906331ab33 100644 --- a/tests/unit/chatcore-upstream-body.test.ts +++ b/tests/unit/chatcore-upstream-body.test.ts @@ -25,7 +25,7 @@ before(async () => { after(() => { coreDb.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("pins the target model when it differs from the translated body model", async () => { diff --git a/tests/unit/chatgpt-web-codex.test.ts b/tests/unit/chatgpt-web-codex.test.ts index c7ffb6319f..71118fd306 100644 --- a/tests/unit/chatgpt-web-codex.test.ts +++ b/tests/unit/chatgpt-web-codex.test.ts @@ -169,7 +169,7 @@ test("turn broker holds a tool invocation and rejects wrong or duplicate results assert.throws(() => broker.completeTool(token, request.callId, { content: [] }), /not pending/); } finally { await broker.close(); - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -207,7 +207,7 @@ test("revoking a turn rejects a pending connector invocation", async () => { await assert.rejects(invocation, /revoked/); } finally { await broker.close(); - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/chatgpt-web-management-retirement.test.ts b/tests/unit/chatgpt-web-management-retirement.test.ts index 75993ebaad..7687168662 100644 --- a/tests/unit/chatgpt-web-management-retirement.test.ts +++ b/tests/unit/chatgpt-web-management-retirement.test.ts @@ -28,7 +28,7 @@ let networkCalls = 0; async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); networkCalls = 0; } @@ -58,7 +58,7 @@ test.beforeEach(resetStorage); test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("create, bulk import and validation paths reject retired provider ids with 410", async () => { diff --git a/tests/unit/chatgpt-web-runtime-block.test.ts b/tests/unit/chatgpt-web-runtime-block.test.ts index e4f69c2bf2..ad6e4e7e61 100644 --- a/tests/unit/chatgpt-web-runtime-block.test.ts +++ b/tests/unit/chatgpt-web-runtime-block.test.ts @@ -31,7 +31,7 @@ function isRetiredError(error: unknown): boolean { async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); modelAliasResolver.invalidateAliasCache(); @@ -49,7 +49,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("retired common ChatGPT Web prefixes cannot shadow compatible nodes", async () => { diff --git a/tests/unit/check-changelog-integrity.test.ts b/tests/unit/check-changelog-integrity.test.ts index b78c1c5a82..cc247531bb 100644 --- a/tests/unit/check-changelog-integrity.test.ts +++ b/tests/unit/check-changelog-integrity.test.ts @@ -139,7 +139,7 @@ test("CLI rejects an unledgered loss", () => { assert.match(result.stderr, /1 bullet\(s\).*MISSING/s); assert.doesNotMatch(result.stderr, /reporting only, not failing/); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -152,7 +152,7 @@ test("CLI fails closed when the removed legacy bypass is still configured", () = assert.match(result.stderr, /ALLOW_CHANGELOG_REMOVALS.*removed/); assert.match(result.stderr, /changelog-reconciliations\.json/); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -179,7 +179,7 @@ test("CLI accepts only an exact, reviewable ledgered reconciliation", () => { assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); assert.match(result.stdout, /OK.*ledgered reconciliation "clarify-fix-b"/s); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -211,7 +211,7 @@ test("CLI keeps an additional loss RED after an approved result is tampered with assert.match(result.stderr, /2 bullet\(s\).*MISSING/s); assert.doesNotMatch(result.stdout, /ledgered reconciliation/); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -239,7 +239,7 @@ test("CLI rejects exact file hashes when the ledger omits one removed occurrence assert.equal(result.status, 1, `${result.stdout}\n${result.stderr}`); assert.match(result.stderr, /2 bullet\(s\).*MISSING/s); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -267,7 +267,7 @@ test("CLI rejects exact file hashes when the ledger omits one removed duplicate" assert.equal(result.status, 1, `${result.stdout}\n${result.stderr}`); assert.match(result.stderr, /2 bullet\(s\).*MISSING/s); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -294,7 +294,7 @@ test("CLI rejects exact bullet deltas when the ledger base hash is wrong", () => assert.equal(result.status, 1, `${result.stdout}\n${result.stderr}`); assert.match(result.stderr, /1 bullet\(s\).*MISSING/s); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -311,7 +311,7 @@ test("CLI validates a new fragment without treating it as a reconciliation", () assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); assert.match(result.stdout, /OK — no base bullets lost/); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -326,7 +326,7 @@ test("CLI fails closed on a malformed reconciliation ledger", () => { assert.match(result.stderr, /invalid reconciliation ledger/); assert.match(result.stderr, /reconciliations must be an array/); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -338,6 +338,6 @@ test("CLI fails closed when an explicit base ref is unreadable", () => { assert.equal(result.status, 1, `${result.stdout}\n${result.stderr}`); assert.match(result.stderr, /FAIL.*CHANGELOG\.md.*missing-explicit-base/s); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/check-fabricated-docs.test.ts b/tests/unit/check-fabricated-docs.test.ts index bcb07a4811..24b2378dff 100644 --- a/tests/unit/check-fabricated-docs.test.ts +++ b/tests/unit/check-fabricated-docs.test.ts @@ -46,7 +46,7 @@ function findingsFor(fx: Fixture): Set { } return out; } finally { - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/check-openapi-breaking-ratchet.test.ts b/tests/unit/check-openapi-breaking-ratchet.test.ts index c9d1333be0..e7641c4118 100644 --- a/tests/unit/check-openapi-breaking-ratchet.test.ts +++ b/tests/unit/check-openapi-breaking-ratchet.test.ts @@ -116,7 +116,7 @@ function withTmpBaseline(content: string | null, fn: (p: string) => void) { try { fn(p); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/check-provider-asset-provenance.test.ts b/tests/unit/check-provider-asset-provenance.test.ts index 8a834f138c..b4e06c9da2 100644 --- a/tests/unit/check-provider-asset-provenance.test.ts +++ b/tests/unit/check-provider-asset-provenance.test.ts @@ -180,7 +180,7 @@ test("provider asset provenance gate rejects a new physical asset without a mani /missing from manifest: public\/providers\/surprise\.svg/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -199,7 +199,7 @@ test("provider asset provenance gate rejects a symlink that could evade physical /non-regular provider asset entry is not allowed: public\/providers\/unregistered-link\.svg/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -222,7 +222,7 @@ test("provider asset provenance gate rejects a stale SHA-256", () => { /sha256 mismatch: public\/providers\/registered\.svg/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -246,7 +246,7 @@ test("provider asset provenance gate validates magic MIME instead of trusting th /mediaType mismatch: public\/providers\/misleading\.png \(manifest image\/png, actual image\/jpeg\)/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -270,7 +270,7 @@ test("provider asset provenance gate does not accept a truncated JPEG prefix", ( /mediaType mismatch: public\/providers\/truncated\.jpg \(manifest image\/jpeg, actual unknown\)/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -286,7 +286,7 @@ test("provider asset provenance gate recognizes an SVG with an XML doctype", () assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -308,7 +308,7 @@ test("provider asset provenance gate scans adversarial SVG comment chains within /mediaType mismatch: public\/providers\/adversarial\.svg \(manifest image\/svg\+xml, actual unknown\)/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -331,7 +331,7 @@ test("provider asset provenance gate rejects a status that implies legal clearan /invalid provenanceStatus for public\/providers\/registered\.svg: licensed/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -353,7 +353,7 @@ test("provider asset provenance gate requires an alias record for duplicate cont new RegExp(`duplicate content missing alias record: sha256:${sha256(SVG)}`) ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -376,7 +376,7 @@ test("provider asset provenance gate requires immutable source evidence for prov /proven asset requires immutable source evidence: public\/providers\/registered\.svg/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -408,7 +408,7 @@ test("provider asset provenance gate rejects malformed pinned-source integrity", /proven asset requires immutable source evidence: public\/providers\/registered\.svg/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -431,7 +431,7 @@ test("provider asset provenance gate rejects an unstructured upstream license cl /invalid upstreamLicenseClaim for public\/providers\/registered\.svg/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -464,7 +464,7 @@ test("provider asset provenance gate allows probable and unresolved records and /2\/2 registered; proven=0 probable=1 unresolved=1; duplicate-groups=1/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -484,7 +484,7 @@ test("provider asset provenance gate rejects a stale expected asset count", () = /expectedAssetCount mismatch: manifest 225, records 1, physical 1/ ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -509,7 +509,7 @@ test("provider asset provenance gate rejects a missing or non-commit auditedComm assert.ok(`${result.stdout}\n${result.stderr}`.includes(expectedError)); } } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -537,7 +537,7 @@ test("provider asset provenance gate binds auditedCommit to the physical provide /auditedCommit provider snapshot (?:is missing|differs): public\/providers\// ); } finally { - rmSync(fixture.root, { recursive: true, force: true }); + rmSync(fixture.root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/claude-classifier-compat.test.ts b/tests/unit/claude-classifier-compat.test.ts index f7f2f59950..90eddf11d9 100644 --- a/tests/unit/claude-classifier-compat.test.ts +++ b/tests/unit/claude-classifier-compat.test.ts @@ -68,7 +68,7 @@ const SEVERITY_CLASSIFIER_BODY = { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Settings default is opt-in (off) ──────────────────────────────────────── diff --git a/tests/unit/claude-code-rendering-fixes.test.ts b/tests/unit/claude-code-rendering-fixes.test.ts index fe50f4e426..dc3c689956 100644 --- a/tests/unit/claude-code-rendering-fixes.test.ts +++ b/tests/unit/claude-code-rendering-fixes.test.ts @@ -18,7 +18,7 @@ test.after(() => { resetDbInstance(); if (previousDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = previousDataDir; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Responses->Chat: output_item.done emits arguments when no delta chunks were sent", () => { diff --git a/tests/unit/claude-directive-midconv-passthrough.test.ts b/tests/unit/claude-directive-midconv-passthrough.test.ts index ca1a95684f..1a63771fd4 100644 --- a/tests/unit/claude-directive-midconv-passthrough.test.ts +++ b/tests/unit/claude-directive-midconv-passthrough.test.ts @@ -30,14 +30,14 @@ test.afterEach(async () => { globalThis.fetch = originalFetch; await flushAsyncSideEffects(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("claude mid-conversation-system passthrough relocates a directive-only messages[0]", async () => { @@ -109,9 +109,7 @@ test("claude mid-conversation-system passthrough relocates a directive-only mess // The claude identity layer prepends its own blocks; assert the client's // block survived rather than an exact count. assert.ok( - captured.body.system.some( - (block) => block.type === "text" && block.text === "You are Claude." - ) + captured.body.system.some((block) => block.type === "text" && block.text === "You are Claude.") ); assert.equal(captured.body.tools.length, 1); // The directive stays message-level; the top level (if set) is the base diff --git a/tests/unit/claude-empty-stream-error-3685.test.ts b/tests/unit/claude-empty-stream-error-3685.test.ts index 719f2cb638..d77b243777 100644 --- a/tests/unit/claude-empty-stream-error-3685.test.ts +++ b/tests/unit/claude-empty-stream-error-3685.test.ts @@ -33,7 +33,12 @@ test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { for (const entry of fs.readdirSync(TEST_DATA_DIR)) { - fs.rmSync(path.join(TEST_DATA_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(TEST_DATA_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } } }); diff --git a/tests/unit/claudeAuthImport-bootstrap-headers-10144.test.ts b/tests/unit/claudeAuthImport-bootstrap-headers-10144.test.ts index e373732908..ccdd53010e 100644 --- a/tests/unit/claudeAuthImport-bootstrap-headers-10144.test.ts +++ b/tests/unit/claudeAuthImport-bootstrap-headers-10144.test.ts @@ -14,11 +14,8 @@ process.env.APP_LOG_TO_FILE = "false"; // Import the implementation under test. In particular, do not copy any of // these helpers here: the regression must fail if claudeAuthImport.ts loses a // required header or stops persisting the device identity. -const { - createConnectionFromAuthFile, - enrichWithBootstrap, - parseAndValidateClaudeAuth, -} = await import("../../src/lib/oauth/utils/claudeAuthImport.ts"); +const { createConnectionFromAuthFile, enrichWithBootstrap, parseAndValidateClaudeAuth } = + await import("../../src/lib/oauth/utils/claudeAuthImport.ts"); import { getClaudeCodeUserAgent } from "../../src/shared/constants/claudeCodeClient.ts"; const originalFetch = globalThis.fetch; @@ -28,7 +25,7 @@ test.afterEach(() => { }); test.after(() => { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("real enrichWithBootstrap sends the required CLI headers", async () => { diff --git a/tests/unit/cli-api-generator-ref-params.test.ts b/tests/unit/cli-api-generator-ref-params.test.ts index be6b559753..5f6799e6e5 100644 --- a/tests/unit/cli-api-generator-ref-params.test.ts +++ b/tests/unit/cli-api-generator-ref-params.test.ts @@ -90,7 +90,7 @@ test("generator resolves a $ref path parameter into --id and substitutes {id} in "generated command must declare --body for the requestBody" ); } finally { - rmSync(workDir, { recursive: true, force: true }); + rmSync(workDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -126,17 +126,23 @@ components: try { assert.throws(() => runGenerator(specPath, outDir)); } finally { - rmSync(workDir, { recursive: true, force: true }); + rmSync(workDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); test("real generated bin/cli/api-commands/combos.mjs has --id and --body on the PATCH combo command (#10955)", () => { const src = readFileSync(REAL_COMBOS, "utf8"); - const patchBlockMatch = src.match(/ {2}tag\.command\("patch-[^"]*"\)[\s\S]*?\n {2}(?=tag\.command\(|\})/); + const patchBlockMatch = src.match( + / {2}tag\.command\("patch-[^"]*"\)[\s\S]*?\n {2}(?=tag\.command\(|\})/ + ); assert.ok(patchBlockMatch, "combos.mjs must have a generated patch-* command block"); const patchBlock = patchBlockMatch[0]; - assert.match(patchBlock, /\.requiredOption\("--id "/, "PATCH combo command must require --id"); + assert.match( + patchBlock, + /\.requiredOption\("--id "/, + "PATCH combo command must require --id" + ); assert.match( patchBlock, /\.option\("--body "/, diff --git a/tests/unit/cli-auth-export-command.test.ts b/tests/unit/cli-auth-export-command.test.ts index 2b3cd5ef2d..a23d9a8af9 100644 --- a/tests/unit/cli-auth-export-command.test.ts +++ b/tests/unit/cli-auth-export-command.test.ts @@ -62,7 +62,7 @@ async function withAuthExportEnv( new Database(dbPath).close(); await fn(dataDir, dbPath); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/cli-backup-command.test.ts b/tests/unit/cli-backup-command.test.ts index 5859e5ab40..d2dd9cc5c5 100644 --- a/tests/unit/cli-backup-command.test.ts +++ b/tests/unit/cli-backup-command.test.ts @@ -31,7 +31,7 @@ async function withBackupEnv(fn: (dataDir: string) => Promise) { await fn(dataDir); } finally { console.log = originalLog; - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; } diff --git a/tests/unit/cli-combo-create-models-10954.test.ts b/tests/unit/cli-combo-create-models-10954.test.ts index 52fabf8c16..66f7346ad2 100644 --- a/tests/unit/cli-combo-create-models-10954.test.ts +++ b/tests/unit/cli-combo-create-models-10954.test.ts @@ -40,7 +40,7 @@ async function withComboEnv(fn: (dataDir: string) => Promise) { } finally { console.log = originalLog; globalThis.fetch = ORIGINAL_FETCH; - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; @@ -225,7 +225,7 @@ test("combo create (HTTP) — POST /api/combos body carries the parsed models", } finally { console.log = originalLog; globalThis.fetch = ORIGINAL_FETCH; - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; } diff --git a/tests/unit/cli-contexts.test.ts b/tests/unit/cli-contexts.test.ts index 2ed45bfeba..46b778d7c2 100644 --- a/tests/unit/cli-contexts.test.ts +++ b/tests/unit/cli-contexts.test.ts @@ -17,7 +17,7 @@ test.after(() => { if (origDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = origDataDir; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/cli-data-dir-env-loading.test.ts b/tests/unit/cli-data-dir-env-loading.test.ts index c3d2ae3423..52c54f47bc 100644 --- a/tests/unit/cli-data-dir-env-loading.test.ts +++ b/tests/unit/cli-data-dir-env-loading.test.ts @@ -89,7 +89,7 @@ test("CLI data-dir resolver preserves an existing legacy ~/.omniroute before XDG } ); } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -152,6 +152,6 @@ test("CLI startup loads later non-conflicting .env files without overriding earl assert.equal(current.OMNIROUTE_HTTP_TIMEOUT_MS, "1234"); assert.equal(current.PORT, "34567"); } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-data-dir-env.test.ts b/tests/unit/cli-data-dir-env.test.ts index 798177db66..e0555a7627 100644 --- a/tests/unit/cli-data-dir-env.test.ts +++ b/tests/unit/cli-data-dir-env.test.ts @@ -38,7 +38,7 @@ async function withTempEnv( for (const [key, value] of Object.entries(originalEnv)) { process.env[key] = value; } - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } @@ -61,8 +61,5 @@ test("CLI env loader scans all env paths while preserving first value wins", () assert.match(loaderSource, /for \(const envPath of envPaths\)/); assert.match(loaderSource, /if \(process\.env\[key\] === undefined\)/); - assert.doesNotMatch( - loaderSource, - /Loaded env from \$\{envPath\}[\s\S]{0,80}\breturn;/ - ); + assert.doesNotMatch(loaderSource, /Loaded env from \$\{envPath\}[\s\S]{0,80}\breturn;/); }); diff --git a/tests/unit/cli-doctor-command.test.ts b/tests/unit/cli-doctor-command.test.ts index d23878b76b..f6f19eec32 100644 --- a/tests/unit/cli-doctor-command.test.ts +++ b/tests/unit/cli-doctor-command.test.ts @@ -48,7 +48,7 @@ async function withDoctorEnv(fn: (dataDir: string) => Promise) { try { await fn(dataDir); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/cli-doctor-prebuilt-native-binary-10083.test.ts b/tests/unit/cli-doctor-prebuilt-native-binary-10083.test.ts index 2b42faba02..ed9c950079 100644 --- a/tests/unit/cli-doctor-prebuilt-native-binary-10083.test.ts +++ b/tests/unit/cli-doctor-prebuilt-native-binary-10083.test.ts @@ -31,8 +31,8 @@ async function withTempRoot(fn: (rootDir: string) => Promise) { try { await fn(rootDir); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; } diff --git a/tests/unit/cli-electron-to-cli-migration-server-env-7302.test.ts b/tests/unit/cli-electron-to-cli-migration-server-env-7302.test.ts index 5f48f1a7de..bfc65abc55 100644 --- a/tests/unit/cli-electron-to-cli-migration-server-env-7302.test.ts +++ b/tests/unit/cli-electron-to-cli-migration-server-env-7302.test.ts @@ -37,7 +37,7 @@ function runCli(dataDir: string): { code: number | null; stdout: string; stderr: }); return { code: res.status, stdout: res.stdout ?? "", stderr: res.stderr ?? "" }; } finally { - fs.rmSync(isolatedHome, { recursive: true, force: true }); + fs.rmSync(isolatedHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } @@ -72,7 +72,8 @@ test("#7302: CLI must recognize DATA_DIR/server.env (Electron's secrets file) wh envContent, new RegExp(`STORAGE_ENCRYPTION_KEY=${electronKey}`), "the Electron-persisted STORAGE_ENCRYPTION_KEY from server.env must be honored " + - "after migrating to the CLI install — got .env content: " + JSON.stringify(envContent) + "after migrating to the CLI install — got .env content: " + + JSON.stringify(envContent) ); assert.doesNotMatch( @@ -82,7 +83,7 @@ test("#7302: CLI must recognize DATA_DIR/server.env (Electron's secrets file) wh "Electron-persisted key in server.env" ); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -109,6 +110,6 @@ test("#7302: an existing DATA_DIR/.env must still win over DATA_DIR/server.env w "server.env must not leak into an existing .env" ); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-env-collision.test.ts b/tests/unit/cli-env-collision.test.ts index cb11ac4474..4447ef4fb1 100644 --- a/tests/unit/cli-env-collision.test.ts +++ b/tests/unit/cli-env-collision.test.ts @@ -67,7 +67,7 @@ test("a key masked by an earlier .env is named, with both files and without its assert.ok(!stderr.includes("cwd.example"), "the ignored value must never be printed"); assert.ok(!stderr.includes("data.example"), "the winning value must never be printed"); } finally { - fs.rmSync(dirs.tmp, { recursive: true, force: true }); + fs.rmSync(dirs.tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -83,7 +83,7 @@ test("a key each file declares once says nothing", () => { const stderr = runCli(dirs).stderr ?? ""; assert.ok(!/OMNIROUTE_BASE_URL|PORT/.test(stderr), `nothing to report: ${stderr}`); } finally { - fs.rmSync(dirs.tmp, { recursive: true, force: true }); + fs.rmSync(dirs.tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -103,7 +103,7 @@ test("a key the environment already set is reported too — that is #6194", () = assert.ok(!stderr.includes("shell.example"), "the winning value must never be printed"); assert.ok(!stderr.includes("data.example"), "the ignored value must never be printed"); } finally { - fs.rmSync(dirs.tmp, { recursive: true, force: true }); + fs.rmSync(dirs.tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -125,6 +125,6 @@ test("an unreadable .env is reported instead of being swallowed", () => { `the unreadable file should be named: ${result.stderr}` ); } finally { - fs.rmSync(dirs.tmp, { recursive: true, force: true }); + fs.rmSync(dirs.tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-expanded-commands.test.ts b/tests/unit/cli-expanded-commands.test.ts index e631a084c6..54ca40568d 100644 --- a/tests/unit/cli-expanded-commands.test.ts +++ b/tests/unit/cli-expanded-commands.test.ts @@ -124,7 +124,7 @@ test("backup auto enable — nenhuma opção é sombreada pelo parent backup", a } finally { if (origDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = origDataDir; - rmSync(dataDir, { recursive: true, force: true }); + rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -189,7 +189,7 @@ test("backup — sem subcomando ainda cria um backup (uso legado documentado)", } finally { if (origDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = origDataDir; - rmSync(dataDir, { recursive: true, force: true }); + rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -345,11 +345,14 @@ test("test-provider --all-providers consumes the connections envelope", async () assert.ok(requests.some((url) => url.includes("/api/providers?limit=200"))); const parsed = JSON.parse(output.join("")); assert.deepEqual( - parsed.map(({ provider, model }: { provider: string; model: string }) => ({ provider, model })), + parsed.map(({ provider, model }: { provider: string; model: string }) => ({ + provider, + model, + })), [ { provider: "anthropic", model: "claude" }, { provider: "gemini", model: "gemini" }, - ], + ] ); assert.ok(parsed.every(({ success }: { success: boolean }) => success)); } finally { diff --git a/tests/unit/cli-helper/config-generator-codex.test.ts b/tests/unit/cli-helper/config-generator-codex.test.ts index 7d3843db57..af798704f3 100644 --- a/tests/unit/cli-helper/config-generator-codex.test.ts +++ b/tests/unit/cli-helper/config-generator-codex.test.ts @@ -31,7 +31,7 @@ function tempCodexHome(): string { after(() => { for (const dir of tmpDirs) { try { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/cli-helper/tool-detector-opencode-jsonc-10227.test.ts b/tests/unit/cli-helper/tool-detector-opencode-jsonc-10227.test.ts index f2039e55ef..4812f37c9d 100644 --- a/tests/unit/cli-helper/tool-detector-opencode-jsonc-10227.test.ts +++ b/tests/unit/cli-helper/tool-detector-opencode-jsonc-10227.test.ts @@ -36,6 +36,6 @@ test("detectTool reports an existing opencode.jsonc as the real config path (#10 } finally { if (previousXdg === undefined) delete process.env.XDG_CONFIG_HOME; else process.env.XDG_CONFIG_HOME = previousXdg; - fs.rmSync(xdgRoot, { recursive: true, force: true }); + fs.rmSync(xdgRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-ipv4-first-dns-2699.test.ts b/tests/unit/cli-ipv4-first-dns-2699.test.ts index 74bd4f33f5..3a0633d7b5 100644 --- a/tests/unit/cli-ipv4-first-dns-2699.test.ts +++ b/tests/unit/cli-ipv4-first-dns-2699.test.ts @@ -88,6 +88,6 @@ test("ServerSupervisor starts Node with IPv4-first DNS", async () => { else process.env.DATA_DIR = previousDataDir; if (previousNodeOptions === undefined) delete process.env.NODE_OPTIONS; else process.env.NODE_OPTIONS = previousNodeOptions; - rmSync(dataDir, { recursive: true, force: true }); + rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-keys-command.test.ts b/tests/unit/cli-keys-command.test.ts index c0175bb3b3..a2f2e73c0a 100644 --- a/tests/unit/cli-keys-command.test.ts +++ b/tests/unit/cli-keys-command.test.ts @@ -55,7 +55,7 @@ async function withCliKeysEnv(fn: (dataDir: string, dbPath: string) => Promise { if (origOmniLang === undefined) delete process.env.OMNIROUTE_LANG; else process.env.OMNIROUTE_LANG = origOmniLang; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/cli-logs-route.test.ts b/tests/unit/cli-logs-route.test.ts index 8dcf83316e..4dbba108c9 100644 --- a/tests/unit/cli-logs-route.test.ts +++ b/tests/unit/cli-logs-route.test.ts @@ -43,7 +43,7 @@ test.before(async () => { test.after(async () => { await updateSettings({ requireLogin: true }); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); try { fs.unlinkSync(logPath); } catch { diff --git a/tests/unit/cli-npm-install-runtime-allow-scripts-10713.test.ts b/tests/unit/cli-npm-install-runtime-allow-scripts-10713.test.ts index eacb1e245a..d07ee041d9 100644 --- a/tests/unit/cli-npm-install-runtime-allow-scripts-10713.test.ts +++ b/tests/unit/cli-npm-install-runtime-allow-scripts-10713.test.ts @@ -34,7 +34,7 @@ test("issue #10713: npmInstallRuntime requests --allow-scripts for its own fully process.env.PATH = originalPath; if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; - rmSync(fakeBinDir, { recursive: true, force: true }); - rmSync(fakeDataDir, { recursive: true, force: true }); + rmSync(fakeBinDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + rmSync(fakeDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-plugin-system.test.ts b/tests/unit/cli-plugin-system.test.ts index b74fdded29..4be5c03f72 100644 --- a/tests/unit/cli-plugin-system.test.ts +++ b/tests/unit/cli-plugin-system.test.ts @@ -56,7 +56,7 @@ test("discoverPlugins descobre plugin com package.json válido", async () => { if (orig === undefined) delete process.env.OMNIROUTE_PLUGIN_PATH; else process.env.OMNIROUTE_PLUGIN_PATH = orig; try { - rmSync(pluginDir, { recursive: true }); + rmSync(pluginDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); @@ -83,7 +83,7 @@ test("discoverPlugins ignora pacotes sem prefixo omniroute-cmd-", async () => { if (orig === undefined) delete process.env.OMNIROUTE_PLUGIN_PATH; else process.env.OMNIROUTE_PLUGIN_PATH = orig; try { - rmSync(pluginDir, { recursive: true }); + rmSync(pluginDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); @@ -115,7 +115,7 @@ test("loadPlugins não quebra CLI quando plugin tem erro de load (try/catch)", a if (orig === undefined) delete process.env.OMNIROUTE_PLUGIN_PATH; else process.env.OMNIROUTE_PLUGIN_PATH = orig; try { - rmSync(pluginDir, { recursive: true }); + rmSync(pluginDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); @@ -155,7 +155,7 @@ test("loadPlugins carrega plugin válido e chama register()", async () => { if (orig === undefined) delete process.env.OMNIROUTE_PLUGIN_PATH; else process.env.OMNIROUTE_PLUGIN_PATH = orig; try { - rmSync(pluginDir, { recursive: true }); + rmSync(pluginDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); diff --git a/tests/unit/cli-provider-catalog-full-10080.test.ts b/tests/unit/cli-provider-catalog-full-10080.test.ts index f7a907c690..3d65de7c95 100644 --- a/tests/unit/cli-provider-catalog-full-10080.test.ts +++ b/tests/unit/cli-provider-catalog-full-10080.test.ts @@ -128,7 +128,7 @@ test("falls back to COMMON_PROVIDERS when no catalog is present", () => { assert.equal(providers.length, COMMON_PROVIDERS.length); assert.equal(providers[0].id, "openai"); } finally { - fs.rmSync(emptyRoot, { recursive: true, force: true }); + fs.rmSync(emptyRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -147,6 +147,6 @@ test("an explicit catalogPath still overrides the directory walk", () => { ["only"] ); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-provider-test-routes-10570.test.ts b/tests/unit/cli-provider-test-routes-10570.test.ts index 36b9616ff1..56319745f6 100644 --- a/tests/unit/cli-provider-test-routes-10570.test.ts +++ b/tests/unit/cli-provider-test-routes-10570.test.ts @@ -35,7 +35,7 @@ async function withCliEnv(fn: (dataDir: string) => Promise) { await fn(dataDir); } finally { globalThis.fetch = ORIGINAL_FETCH; - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; if (ORIGINAL_API_KEY === undefined) delete process.env.OMNIROUTE_API_KEY; diff --git a/tests/unit/cli-providers-command.test.ts b/tests/unit/cli-providers-command.test.ts index 4a071f4e32..d7b8900ed5 100644 --- a/tests/unit/cli-providers-command.test.ts +++ b/tests/unit/cli-providers-command.test.ts @@ -32,7 +32,7 @@ async function withProvidersEnv(fn: (dataDir: string) => Promise) { try { await fn(dataDir); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); globalThis.fetch = ORIGINAL_FETCH; if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; diff --git a/tests/unit/cli-providers-rotate.test.ts b/tests/unit/cli-providers-rotate.test.ts index 2d85ed4878..eb74d1e7ab 100644 --- a/tests/unit/cli-providers-rotate.test.ts +++ b/tests/unit/cli-providers-rotate.test.ts @@ -30,7 +30,7 @@ async function withEnv(fn: (dataDir: string) => Promise) { try { await fn(dataDir); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); globalThis.fetch = ORIGINAL_FETCH; if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/cli-remote-mode.test.ts b/tests/unit/cli-remote-mode.test.ts index f8d060ff6d..a1fafa6c93 100644 --- a/tests/unit/cli-remote-mode.test.ts +++ b/tests/unit/cli-remote-mode.test.ts @@ -44,7 +44,7 @@ test.after(() => { if (origContext === undefined) delete process.env.OMNIROUTE_CONTEXT; else process.env.OMNIROUTE_CONTEXT = origContext; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/cli-repl.test.ts b/tests/unit/cli-repl.test.ts index 741f2c238e..1f94618f17 100644 --- a/tests/unit/cli-repl.test.ts +++ b/tests/unit/cli-repl.test.ts @@ -113,7 +113,7 @@ test("saveSession e loadSession persistem e restauram sessão", async () => { } finally { process.env.DATA_DIR = origDataDir ?? ""; try { - rmSync(tmpDir, { recursive: true }); + rmSync(tmpDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); @@ -129,7 +129,7 @@ test("loadSession lança erro se sessão não existe", async () => { } finally { process.env.DATA_DIR = origDataDir ?? ""; try { - rmSync(tmpDir, { recursive: true }); + rmSync(tmpDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); @@ -154,7 +154,7 @@ test("listSessions retorna array (vazio ou com sessões)", async () => { } finally { process.env.DATA_DIR = origDataDir ?? ""; try { - rmSync(tmpDir, { recursive: true }); + rmSync(tmpDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); @@ -172,7 +172,7 @@ test("autosave não lança erro em condições normais", async () => { } finally { process.env.DATA_DIR = origDataDir ?? ""; try { - rmSync(tmpDir, { recursive: true }); + rmSync(tmpDir, { recursive: true, maxRetries: 5, retryDelay: 100 }); } catch {} } }); diff --git a/tests/unit/cli-runtime-detection.test.ts b/tests/unit/cli-runtime-detection.test.ts index 9e9205a98e..7a76f5110d 100644 --- a/tests/unit/cli-runtime-detection.test.ts +++ b/tests/unit/cli-runtime-detection.test.ts @@ -101,7 +101,7 @@ describe("Size threshold — checkKnownPath", () => { }); after(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("should detect files >= 30 bytes via env var", async () => { @@ -164,7 +164,7 @@ describe("Healthcheck — checkRunnable", () => { }); after(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("should report runnable=true for a script that outputs version", async () => { diff --git a/tests/unit/cli-runtime-extended.test.ts b/tests/unit/cli-runtime-extended.test.ts index 8c2ef44845..00f69eab91 100644 --- a/tests/unit/cli-runtime-extended.test.ts +++ b/tests/unit/cli-runtime-extended.test.ts @@ -50,7 +50,7 @@ test.afterEach(() => { restoreEnv(); for (const dir of tempDirs) { - fs.rmSync(dir as any, { recursive: true, force: true }); + fs.rmSync(dir as any, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } tempDirs.clear(); }); diff --git a/tests/unit/cli-runtime-known-path-shortcircuit-7774.test.ts b/tests/unit/cli-runtime-known-path-shortcircuit-7774.test.ts index 6551b227f7..be95b05978 100644 --- a/tests/unit/cli-runtime-known-path-shortcircuit-7774.test.ts +++ b/tests/unit/cli-runtime-known-path-shortcircuit-7774.test.ts @@ -25,9 +25,8 @@ delete process.env.CLI_CLAUDE_BIN; delete process.env.CLI_EXTRA_PATHS; process.env.npm_config_prefix = path.join(fakeHome, "npm-prefix-unused"); -const { getCliRuntimeStatus, getKnownToolPaths } = await import( - "../../src/shared/services/cliRuntime.ts" -); +const { getCliRuntimeStatus, getKnownToolPaths } = + await import("../../src/shared/services/cliRuntime.ts"); function makeExecutable(filePath: string, content: string) { fs.writeFileSync(filePath, content); @@ -55,8 +54,8 @@ describe("#7774 — known-path short-circuit hides a genuinely runnable Claude b if (value === undefined) delete (process.env as Record)[key]; else process.env[key] = value; } - fs.rmSync(fakeHome, { recursive: true, force: true }); - fs.rmSync(realBinDir, { recursive: true, force: true }); + fs.rmSync(fakeHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(realBinDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("should still find and report Claude as installed+runnable via PATH fallback", async () => { diff --git a/tests/unit/cli-runtime.test.ts b/tests/unit/cli-runtime.test.ts index 293f6a3933..65cf129a9f 100644 --- a/tests/unit/cli-runtime.test.ts +++ b/tests/unit/cli-runtime.test.ts @@ -17,7 +17,7 @@ test.after(() => { if (origDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = origDataDir; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); @@ -99,7 +99,12 @@ test("isBetterSqliteBinaryValid rejeita binário com magic bytes válidos mas AB false, "binário com header válido mas ABI/conteúdo incompatível deve ser inválido" ); - rmSync(join(nm, "better-sqlite3"), { recursive: true, force: true }); + rmSync(join(nm, "better-sqlite3"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); }); test("isBetterSqliteBinaryValid aceita um binário nativo real e carregável", async () => { @@ -125,7 +130,12 @@ test("isBetterSqliteBinaryValid aceita um binário nativo real e carregável", a copyFileSync(realBinary, binary); const result = isBetterSqliteBinaryValid(); assert.equal(result, true, "um binário real, compatível com o Node atual, deve ser válido"); - rmSync(join(nm, "better-sqlite3"), { recursive: true, force: true }); + rmSync(join(nm, "better-sqlite3"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); }); test("commands/runtime.mjs pode ser importado sem erro", async () => { diff --git a/tests/unit/cli-serve-stop-command.test.ts b/tests/unit/cli-serve-stop-command.test.ts index efde50e186..5955ec80bd 100644 --- a/tests/unit/cli-serve-stop-command.test.ts +++ b/tests/unit/cli-serve-stop-command.test.ts @@ -26,7 +26,7 @@ async function withEnv(fn: (dataDir: string) => Promise) { } finally { console.log = originalLog; globalThis.fetch = ORIGINAL_FETCH; - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/cli-setup-command.test.ts b/tests/unit/cli-setup-command.test.ts index 0f433a59c1..5eb22d9d8b 100644 --- a/tests/unit/cli-setup-command.test.ts +++ b/tests/unit/cli-setup-command.test.ts @@ -32,7 +32,7 @@ async function withTempEnv(fn: (dataDir: string) => Promise) { try { await fn(dataDir); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/cli-setup-opencode-nested-alias-7682.test.ts b/tests/unit/cli-setup-opencode-nested-alias-7682.test.ts index 97bfdc6c8f..39b09562b1 100644 --- a/tests/unit/cli-setup-opencode-nested-alias-7682.test.ts +++ b/tests/unit/cli-setup-opencode-nested-alias-7682.test.ts @@ -37,6 +37,6 @@ test("config-generator/opencode.ts imports cleanly with no tsconfig.json in scop `stdout: ${result.stdout}\nstderr: ${result.stderr}` ); } finally { - rmSync(stage, { recursive: true, force: true }); + rmSync(stage, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-setup-opencode.test.ts b/tests/unit/cli-setup-opencode.test.ts index ac99ced134..e342087e5f 100644 --- a/tests/unit/cli-setup-opencode.test.ts +++ b/tests/unit/cli-setup-opencode.test.ts @@ -62,7 +62,7 @@ describe("omniroute setup opencode", () => { console.info = _console.info; console.warn = _console.warn; try { - fs.rmSync(FIXTURE_ROOT, { recursive: true, force: true }); + fs.rmSync(FIXTURE_ROOT, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } @@ -146,7 +146,12 @@ describe("omniroute setup opencode", () => { }); it("fails with a clear error (exit 1) when the bundled plugin dist is missing", async () => { - fs.rmSync(path.join(FAKE_PLUGIN_DIR, "dist"), { recursive: true, force: true }); + fs.rmSync(path.join(FAKE_PLUGIN_DIR, "dist"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); try { const r = await runSetupOpenCodeCommand({ configDir: CONFIG_DIR, diff --git a/tests/unit/cli-sqlite-construction-fallback-8826.test.ts b/tests/unit/cli-sqlite-construction-fallback-8826.test.ts index fc9783d85b..f604b2ba01 100644 --- a/tests/unit/cli-sqlite-construction-fallback-8826.test.ts +++ b/tests/unit/cli-sqlite-construction-fallback-8826.test.ts @@ -25,8 +25,7 @@ Module._load = function patchedLoad(request, parent, isMain) { if (request === "better-sqlite3") { function FakeBetterSqlite() { throw new Error( - "Could not locate the bindings file. Tried:\n" + - " -> /fake/path/better_sqlite3.node" + "Could not locate the bindings file. Tried:\n" + " -> /fake/path/better_sqlite3.node" ); } return FakeBetterSqlite; @@ -40,7 +39,9 @@ const { openOmniRouteDb } = await import("../../bin/cli/sqlite.mjs"); test("#8826: openOmniRouteDb() falls back to node:sqlite when better-sqlite3 native binding is missing (construction-time failure)", async (t) => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-8826-")); t.after(() => { - try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} Module._load = originalLoad; }); diff --git a/tests/unit/cli-stop-supervisor-respawn-9455.test.ts b/tests/unit/cli-stop-supervisor-respawn-9455.test.ts index badebaa3f5..c580c1fffd 100644 --- a/tests/unit/cli-stop-supervisor-respawn-9455.test.ts +++ b/tests/unit/cli-stop-supervisor-respawn-9455.test.ts @@ -140,7 +140,7 @@ test("Defect 1b: pid.mjs SERVICES array must include supervisor so killAllSubpro assert.equal(ok, true, "writePidFile('supervisor', ...) must succeed"); assert.equal(readPidFile("supervisor"), 555555); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; } diff --git a/tests/unit/cli-storage-key-bootstrap.test.ts b/tests/unit/cli-storage-key-bootstrap.test.ts index 3664ab5e8e..b6b9858ecc 100644 --- a/tests/unit/cli-storage-key-bootstrap.test.ts +++ b/tests/unit/cli-storage-key-bootstrap.test.ts @@ -41,7 +41,7 @@ function runCli(dataDir: string): { code: number | null; stderr: string } { }); return { code: res.status, stderr: res.stderr ?? "" }; } finally { - fs.rmSync(isolatedHome, { recursive: true, force: true }); + fs.rmSync(isolatedHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } @@ -63,7 +63,7 @@ test("CLI generates STORAGE_ENCRYPTION_KEY into DATA_DIR on first run (#1622)", "key persisted into DATA_DIR/.env" ); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -79,6 +79,6 @@ test("CLI refuses to auto-generate a key when a database already exists (#1622)" assert.equal(hasKey, false, "must NOT generate a key when a DB already exists"); assert.match(stderr, /already exists/i, "must warn that a database already exists"); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-tools-apply-container-422.test.ts b/tests/unit/cli-tools-apply-container-422.test.ts index b4fc5cf6bf..68213de0a7 100644 --- a/tests/unit/cli-tools-apply-container-422.test.ts +++ b/tests/unit/cli-tools-apply-container-422.test.ts @@ -38,7 +38,8 @@ test.after(async () => { } catch { // the DB was never opened } - for (const dir of tempDirs) fs.rmSync(dir, { recursive: true, force: true }); + for (const dir of tempDirs) + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function applyRequest(body: Record) { diff --git a/tests/unit/cli-tools-apply-opencode-jsonc.test.ts b/tests/unit/cli-tools-apply-opencode-jsonc.test.ts index 3abdb422b4..69dde22adb 100644 --- a/tests/unit/cli-tools-apply-opencode-jsonc.test.ts +++ b/tests/unit/cli-tools-apply-opencode-jsonc.test.ts @@ -79,14 +79,15 @@ test.afterEach(async () => { if (originalAllowContainerWrite === undefined) delete process.env.OMNIROUTE_ALLOW_CONTAINER_CONFIG_WRITE; else process.env.OMNIROUTE_ALLOW_CONTAINER_CONFIG_WRITE = originalAllowContainerWrite; - for (const root of testRoots) await fs.rm(root, { recursive: true, force: true }); + for (const root of testRoots) + await fs.rm(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); testRoots.clear(); }); test.after(async () => { if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; - await fs.rm(databaseRoot, { recursive: true, force: true }); + await fs.rm(databaseRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("apply writes back to the selected opencode.jsonc and does not create opencode.json (#10227)", async () => { diff --git a/tests/unit/cli-tools-crush.test.ts b/tests/unit/cli-tools-crush.test.ts index a3fca02851..4dbdbfde5e 100644 --- a/tests/unit/cli-tools-crush.test.ts +++ b/tests/unit/cli-tools-crush.test.ts @@ -63,7 +63,7 @@ const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/crush-se async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -151,7 +151,7 @@ test("crush-settings POST: writes crush.json with an openai-compat providers.omn } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -196,7 +196,7 @@ test("crush-settings DELETE: removes only the omniroute provider entry", async ( } } finally { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -226,7 +226,7 @@ test("crush-settings route.ts: does not call exec() or spawn() directly", () => test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.API_KEY_SECRET; delete process.env.JWT_SECRET; diff --git a/tests/unit/cli-tools-settings-jsonc.test.ts b/tests/unit/cli-tools-settings-jsonc.test.ts index c259397ec4..300d24140d 100644 --- a/tests/unit/cli-tools-settings-jsonc.test.ts +++ b/tests/unit/cli-tools-settings-jsonc.test.ts @@ -21,9 +21,8 @@ import { promises as fs } from "node:fs"; import os from "node:os"; import path from "node:path"; -const { parseJsoncOrNull, readJsoncConfig } = await import( - "../../src/app/api/cli-tools/_lib/jsoncConfig.ts" -); +const { parseJsoncOrNull, readJsoncConfig } = + await import("../../src/app/api/cli-tools/_lib/jsoncConfig.ts"); test("parseJsoncOrNull tolerates trailing commas in objects", () => { const jsonc = `{ @@ -65,7 +64,7 @@ test("readJsoncConfig parses a JSONC file with trailing commas (regression)", as assert.equal(parsed.apiKey, "sk-test"); assert.equal(parsed.model, "claude-sonnet-4-5"); } finally { - await fs.rm(dir, { recursive: true, force: true }); + await fs.rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -79,7 +78,7 @@ test("readJsoncConfig returns fallback on corrupted config instead of throwing", assert.equal(await readJsoncConfig(file), null); assert.deepEqual(await readJsoncConfig(file, {}), {}); } finally { - await fs.rm(dir, { recursive: true, force: true }); + await fs.rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -119,9 +118,6 @@ test("cli-tools settings routes use the JSONC-tolerant reader (source-guard)", a !/JSON\.parse\(\s*content\s*\)/.test(head), `${r}: read helper still calls raw JSON.parse(content) — port the JSONC fix` ); - assert.ok( - /readJsoncConfig\s*[<(]/.test(head), - `${r}: read helper must invoke readJsoncConfig` - ); + assert.ok(/readJsoncConfig\s*[<(]/.test(head), `${r}: read helper must invoke readJsoncConfig`); } }); diff --git a/tests/unit/cli-tray-systray2.test.ts b/tests/unit/cli-tray-systray2.test.ts index 33228db41a..9e0ecdea39 100644 --- a/tests/unit/cli-tray-systray2.test.ts +++ b/tests/unit/cli-tray-systray2.test.ts @@ -48,7 +48,7 @@ test("chmodSystrayBinAt sets +x on the bundled tray binary when present", () => const mode = statSync(binPath).mode & 0o777; assert.ok((mode & 0o111) !== 0, `expected exec bits on bin, got mode=${mode.toString(8)}`); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -59,7 +59,7 @@ test("chmodSystrayBinAt is a no-op when the binary doesn't exist", () => { assert.equal(result.changed, false); assert.equal(result.reason, "missing"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -70,6 +70,6 @@ test("chmodSystrayBinAt returns missing on win32 when binary is absent (#8609)", assert.equal(result.changed, false); assert.equal(result.reason, "missing"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-tray.test.ts b/tests/unit/cli-tray.test.ts index e67022bbd2..63dc79a25c 100644 --- a/tests/unit/cli-tray.test.ts +++ b/tests/unit/cli-tray.test.ts @@ -37,7 +37,7 @@ test.after(() => { if (origPath === undefined) delete process.env.PATH; else process.env.PATH = origPath; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/cli-update-global-paths-3295.test.ts b/tests/unit/cli-update-global-paths-3295.test.ts index e23a2ef3dd..5339b5278c 100644 --- a/tests/unit/cli-update-global-paths-3295.test.ts +++ b/tests/unit/cli-update-global-paths-3295.test.ts @@ -25,7 +25,7 @@ test("getCurrentVersion resolves the real version from a foreign cwd (#3295)", a assert.equal(version, REAL_VERSION); } finally { process.chdir(originalCwd); - rmSync(foreignCwd, { recursive: true, force: true }); + rmSync(foreignCwd, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -51,15 +51,12 @@ test("createBackup resolves bin/ from a foreign cwd and copies cli/ recursively const cliBackup = path.join(backupDir, "cli"); assert.ok(existsSync(cliBackup), "cli/ directory copied"); assert.ok(statSync(cliBackup).isDirectory(), "cli/ backup is a directory"); - assert.ok( - existsSync(path.join(cliBackup, "commands")), - "cli/ contents copied recursively" - ); + assert.ok(existsSync(path.join(cliBackup, "commands")), "cli/ contents copied recursively"); } finally { process.chdir(originalCwd); if (originalHome === undefined) delete process.env.HOME; else process.env.HOME = originalHome; - rmSync(foreignCwd, { recursive: true, force: true }); - rmSync(fakeHome, { recursive: true, force: true }); + rmSync(foreignCwd, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + rmSync(fakeHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli-update-shadow-install-9475.test.ts b/tests/unit/cli-update-shadow-install-9475.test.ts index f05794f211..7715d9a3ff 100644 --- a/tests/unit/cli-update-shadow-install-9475.test.ts +++ b/tests/unit/cli-update-shadow-install-9475.test.ts @@ -41,6 +41,6 @@ exit 0 console.log = origLog; if (origPath === undefined) delete process.env.PATH; else process.env.PATH = origPath; - rmSync(fakeBin, { recursive: true, force: true }); + rmSync(fakeBin, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli/alias-resolver-7791.test.ts b/tests/unit/cli/alias-resolver-7791.test.ts index d6037796f4..007fd42028 100644 --- a/tests/unit/cli/alias-resolver-7791.test.ts +++ b/tests/unit/cli/alias-resolver-7791.test.ts @@ -203,7 +203,7 @@ describe("aliasResolver.registerAliasResolver", () => { const ok = await registerAliasResolver(tmp); assert.equal(ok, false, "must return false when there is no src/ dir"); } finally { - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -214,7 +214,7 @@ describe("aliasResolver.registerAliasResolver", () => { const ok = await registerAliasResolver(tmp); assert.equal(ok, true, "must register when src/ exists"); } finally { - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli/autostart-linux.test.ts b/tests/unit/cli/autostart-linux.test.ts index 100d13828e..bf2dca7bf1 100644 --- a/tests/unit/cli/autostart-linux.test.ts +++ b/tests/unit/cli/autostart-linux.test.ts @@ -48,7 +48,7 @@ test.after(() => { if (origPath === undefined) delete process.env.PATH; else process.env.PATH = origPath; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/cli/autostart-windows.test.ts b/tests/unit/cli/autostart-windows.test.ts index 75cbd5af8f..439d00ebcb 100644 --- a/tests/unit/cli/autostart-windows.test.ts +++ b/tests/unit/cli/autostart-windows.test.ts @@ -17,7 +17,7 @@ test.after(() => { if (origAppData === undefined) delete process.env.APPDATA; else process.env.APPDATA = origAppData; try { - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/cli/launch-codex-windows-spawn-args.test.ts b/tests/unit/cli/launch-codex-windows-spawn-args.test.ts index 1cb5d8eb83..d33910a845 100644 --- a/tests/unit/cli/launch-codex-windows-spawn-args.test.ts +++ b/tests/unit/cli/launch-codex-windows-spawn-args.test.ts @@ -126,7 +126,7 @@ test( assert.deepEqual(received, args, "child argv must match what the caller passed"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); diff --git a/tests/unit/cli/launch-windows-spawn-args.test.ts b/tests/unit/cli/launch-windows-spawn-args.test.ts index 52dd9aa3ab..65abfda804 100644 --- a/tests/unit/cli/launch-windows-spawn-args.test.ts +++ b/tests/unit/cli/launch-windows-spawn-args.test.ts @@ -126,7 +126,7 @@ test( assert.deepEqual(received, args, "child argv must match what the caller passed"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); diff --git a/tests/unit/cli/run-execution.test.ts b/tests/unit/cli/run-execution.test.ts index 85b41f4ad3..7549b53ef2 100644 --- a/tests/unit/cli/run-execution.test.ts +++ b/tests/unit/cli/run-execution.test.ts @@ -66,8 +66,8 @@ process.exit(7);` if (originalPath === undefined) delete process.env.PATH; else process.env.PATH = originalPath; delete process.env.CAPTURE_PATH; - await rm(fake.dir, { recursive: true, force: true }); - await rm(capture, { recursive: true, force: true }); + await rm(fake.dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + await rm(capture, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -117,8 +117,8 @@ fs.writeFileSync(process.env.CAPTURE_PATH, JSON.stringify({ if (originalPath === undefined) delete process.env.PATH; else process.env.PATH = originalPath; delete process.env.CAPTURE_PATH; - await rm(fake.dir, { recursive: true, force: true }); - await rm(capture, { recursive: true, force: true }); + await rm(fake.dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + await rm(capture, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -164,7 +164,7 @@ fs.writeFileSync(process.env.CAPTURE_PATH, JSON.stringify({ if (originalPath === undefined) delete process.env.PATH; else process.env.PATH = originalPath; delete process.env.CAPTURE_PATH; - await rm(fake.dir, { recursive: true, force: true }); - await rm(capture, { recursive: true, force: true }); + await rm(fake.dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + await rm(capture, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli/setup-claude.test.ts b/tests/unit/cli/setup-claude.test.ts index 256dcbd317..867e62a686 100644 --- a/tests/unit/cli/setup-claude.test.ts +++ b/tests/unit/cli/setup-claude.test.ts @@ -109,7 +109,7 @@ test("syncClaudeProfilesFromModels falls back to a generic profile for unmatched // No effort tier for the generic fallback — effortLevel must be omitted. assert.equal("effortLevel" in json, false); } finally { - await fs.rm(claudeHome, { recursive: true, force: true }); + await fs.rm(claudeHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -137,7 +137,7 @@ test("syncClaudeProfilesFromModels writes directory-per-profile settings + threa // The auth token must never be written to disk. assert.equal(JSON.stringify(json).includes("ANTHROPIC_AUTH_TOKEN"), false); } finally { - await fs.rm(claudeHome, { recursive: true, force: true }); + await fs.rm(claudeHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -166,7 +166,7 @@ test("syncClaudeProfilesFromModels dry-run writes nothing and reports via the in // …and writes nothing to disk. await assert.rejects(fs.stat(settingsPath), /ENOENT/); } finally { - await fs.rm(claudeHome, { recursive: true, force: true }); + await fs.rm(claudeHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli/setup-codex.test.ts b/tests/unit/cli/setup-codex.test.ts index 2280979c8b..176dd922a1 100644 --- a/tests/unit/cli/setup-codex.test.ts +++ b/tests/unit/cli/setup-codex.test.ts @@ -76,6 +76,6 @@ test("syncCodexProfilesFromModels writes compatible profiles and skips media", a /ENOENT/ ); } finally { - await fs.rm(codexHome, { recursive: true, force: true }); + await fs.rm(codexHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cli/setup-qwen.test.ts b/tests/unit/cli/setup-qwen.test.ts index b6140c76d4..dc8d49427e 100644 --- a/tests/unit/cli/setup-qwen.test.ts +++ b/tests/unit/cli/setup-qwen.test.ts @@ -64,7 +64,7 @@ test("setup-qwen writes current V4 settings and only its dedicated env key", asy assert.match(env, /^OPENAI_API_KEY=keep-me$/m); assert.match(env, /^OMNIROUTE_API_KEY="sk-qwen-dedicated"$/m); } finally { - await fs.rm(tempDir, { recursive: true, force: true }); + await fs.rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -85,6 +85,6 @@ test("setup-qwen does not overwrite an invalid settings file", async () => { assert.equal(code, 1); assert.equal(await fs.readFile(settingsPath, "utf8"), "{ invalid JSON"); } finally { - await fs.rm(tempDir, { recursive: true, force: true }); + await fs.rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cliRuntime-codex-shebang-8036.test.ts b/tests/unit/cliRuntime-codex-shebang-8036.test.ts index e31fd28321..96ce0b5ed5 100644 --- a/tests/unit/cliRuntime-codex-shebang-8036.test.ts +++ b/tests/unit/cliRuntime-codex-shebang-8036.test.ts @@ -69,5 +69,5 @@ test("#8036: codex is reported runnable even when the launcher PATH omits node's }); test.after(async () => { - await fsp.rm(sandboxHome, { recursive: true, force: true }); + await fsp.rm(sandboxHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/cliRuntime-symlink-escape-7753.test.ts b/tests/unit/cliRuntime-symlink-escape-7753.test.ts index a36ba60ef4..64a88fb46a 100644 --- a/tests/unit/cliRuntime-symlink-escape-7753.test.ts +++ b/tests/unit/cliRuntime-symlink-escape-7753.test.ts @@ -27,9 +27,8 @@ fs.chmodSync(realBinaryPath, 0o755); const symlinkPath = path.join(localBinDir, "opencode"); fs.symlinkSync(realBinaryPath, symlinkPath); -const { getCliRuntimeStatus, checkKnownPath } = await import( - "../../src/shared/services/cliRuntime.ts" -); +const { getCliRuntimeStatus, checkKnownPath } = + await import("../../src/shared/services/cliRuntime.ts"); test("#7753: a CLI symlink located inside an expected parent dir is wrongly reported not-installed when its resolved target escapes EXPECTED_PARENT_PATHS", async () => { const status = await getCliRuntimeStatus("opencode"); @@ -51,10 +50,10 @@ test("#7753: a genuinely unsafe symlink whose ORIGINAL location is also untruste assert.equal(result.installed, false); assert.equal(result.reason, "symlink_escape"); - await fsp.rm(untrustedDir, { recursive: true, force: true }); + await fsp.rm(untrustedDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.after(async () => { - await fsp.rm(sandboxHome, { recursive: true, force: true }); - await fsp.rm(outsideDir, { recursive: true, force: true }); + await fsp.rm(sandboxHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + await fsp.rm(outsideDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/client-identity-profiles.test.ts b/tests/unit/client-identity-profiles.test.ts index 7328111fe4..54e00736a5 100644 --- a/tests/unit/client-identity-profiles.test.ts +++ b/tests/unit/client-identity-profiles.test.ts @@ -24,7 +24,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getClientIdentityProfileHeaders: default profile adds no headers", () => { diff --git a/tests/unit/cliproxy-auth-import-1934.test.ts b/tests/unit/cliproxy-auth-import-1934.test.ts index 2f664c9330..8c5a01809d 100644 --- a/tests/unit/cliproxy-auth-import-1934.test.ts +++ b/tests/unit/cliproxy-auth-import-1934.test.ts @@ -117,7 +117,7 @@ test("scanCliProxyAuthDir reads importable files and counts skips", async () => assert.equal(candidates[0].provider, "antigravity"); assert.equal(skipped, 2); // unknown type + broken json } finally { - await fs.rm(dir, { recursive: true, force: true }); + await fs.rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cliproxyapi-dedicated-credential-7645.test.ts b/tests/unit/cliproxyapi-dedicated-credential-7645.test.ts index 9a3bd2563d..f539067596 100644 --- a/tests/unit/cliproxyapi-dedicated-credential-7645.test.ts +++ b/tests/unit/cliproxyapi-dedicated-credential-7645.test.ts @@ -27,12 +27,10 @@ process.env.DATA_DIR = testDataDir; const coreDb = await import("../../src/lib/db/core.ts"); const settingsDb = await import("../../src/lib/db/settings.ts"); const upstreamProxyDb = await import("../../src/lib/db/upstreamProxy.ts"); -const { resolveExecutorWithProxy } = await import( - "../../open-sse/handlers/chatCore/executorProxy.ts" -); -const { clearUpstreamProxyConfigCache } = await import( - "../../open-sse/handlers/chatCore/comboContextCache.ts" -); +const { resolveExecutorWithProxy } = + await import("../../open-sse/handlers/chatCore/executorProxy.ts"); +const { clearUpstreamProxyConfigCache } = + await import("../../open-sse/handlers/chatCore/comboContextCache.ts"); const { updateSettingsSchema } = await import("../../src/shared/validation/settingsSchemas.ts"); const NATIVE_KEY = "sk-native-provider-key-cliproxyapi-must-not-see"; @@ -50,7 +48,8 @@ afterEach(async () => { after(() => { coreDb.resetDbInstance(); - if (fs.existsSync(testDataDir)) fs.rmSync(testDataDir, { recursive: true, force: true }); + if (fs.existsSync(testDataDir)) + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); type ExecuteInput = { @@ -68,9 +67,7 @@ type ExecutorLike = { execute: (input: ExecuteInput) => Promise }; * simulated native-provider network failure — driving the "fallback" retry * leg for real. */ -async function withCapturedCliproxyapiRequest( - fn: () => Promise -): Promise<{ +async function withCapturedCliproxyapiRequest(fn: () => Promise): Promise<{ headers: Record; body: Record; called: boolean; @@ -185,11 +182,9 @@ describe("#7645 — CLIProxyAPI fallback leg authenticates with the dedicated ke cliproxyapiModelMapping: { [sourceModel]: mappedModel }, }); - const executor = await resolveExecutorWithProxy( - "anthropic-7645-per-connection", - undefined, - { cliproxyapiMode: "claude-native" } - ); + const executor = await resolveExecutorWithProxy("anthropic-7645-per-connection", undefined, { + cliproxyapiMode: "claude-native", + }); const { headers, body, called } = await withCapturedCliproxyapiRequest(() => (executor as ExecutorLike).execute({ diff --git a/tests/unit/cliproxyapi-fallback-wiring.test.ts b/tests/unit/cliproxyapi-fallback-wiring.test.ts index 74ad11cbb5..f60764f15a 100644 --- a/tests/unit/cliproxyapi-fallback-wiring.test.ts +++ b/tests/unit/cliproxyapi-fallback-wiring.test.ts @@ -30,10 +30,8 @@ const upstreamProxyDb = await import("../../src/lib/db/upstreamProxy.ts"); // Import the executor module to get the real exported functions. // This may be a cached import if cliproxyapi-executor.test.ts ran first — that // is intentional; we test the live module state, not a fresh copy. -const { - clearCliproxyapiUrlCache, - resolveCliproxyapiBaseUrl, -} = await import("../../open-sse/executors/cliproxyapi.ts"); +const { clearCliproxyapiUrlCache, resolveCliproxyapiBaseUrl } = + await import("../../open-sse/executors/cliproxyapi.ts"); // ─── Helpers ───────────────────────────────────────────────────────────────── @@ -53,14 +51,14 @@ before(async () => { afterEach(() => { // Reset DB singleton so each test starts from a clean schema state. coreDb.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(testDataDir, { recursive: true }); }); after(() => { coreDb.resetDbInstance(); if (fs.existsSync(testDataDir)) { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -121,7 +119,10 @@ describe("CLIProxyAPI fallback wiring", () => { const url2 = await resolveCliproxyapiBaseUrl(); assert.ok(url1.endsWith(":8001"), `url1 should end with :8001, got: ${url1}`); - assert.ok(url2.endsWith(":8002"), `url2 should end with :8002 after cache clear, got: ${url2}`); + assert.ok( + url2.endsWith(":8002"), + `url2 should end with :8002 after cache clear, got: ${url2}` + ); assert.notEqual(url1, url2); }); }); diff --git a/tests/unit/cliproxyapi-model-mapping-dispatch.test.ts b/tests/unit/cliproxyapi-model-mapping-dispatch.test.ts index 1952999118..09f1b9a62b 100644 --- a/tests/unit/cliproxyapi-model-mapping-dispatch.test.ts +++ b/tests/unit/cliproxyapi-model-mapping-dispatch.test.ts @@ -37,7 +37,8 @@ afterEach(() => { after(() => { coreDb.resetDbInstance(); - if (fs.existsSync(testDataDir)) fs.rmSync(testDataDir, { recursive: true, force: true }); + if (fs.existsSync(testDataDir)) + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); type ExecuteInput = { diff --git a/tests/unit/cloud-agent-credentials.test.ts b/tests/unit/cloud-agent-credentials.test.ts index 75f6c592ff..cb09b4093a 100644 --- a/tests/unit/cloud-agent-credentials.test.ts +++ b/tests/unit/cloud-agent-credentials.test.ts @@ -24,7 +24,7 @@ const creds = await import("../../src/lib/cloudAgent/credentials.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 061 provisions cloud_agent_credentials (table exists after DB init)", () => { diff --git a/tests/unit/cloud-agent-tasks-route-auth.test.ts b/tests/unit/cloud-agent-tasks-route-auth.test.ts index c23fe9366b..fbfdfce120 100644 --- a/tests/unit/cloud-agent-tasks-route-auth.test.ts +++ b/tests/unit/cloud-agent-tasks-route-auth.test.ts @@ -21,7 +21,7 @@ type ErrorBody = { error: { message: string } }; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/cloud-sync.test.ts b/tests/unit/cloud-sync.test.ts index 5137382bcf..6123b8b678 100644 --- a/tests/unit/cloud-sync.test.ts +++ b/tests/unit/cloud-sync.test.ts @@ -37,7 +37,7 @@ async function loadCloudSync(label) { async function resetStorage() { apiKeysDb.resetApiKeyState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); globalThis.fetch = ORIGINAL_FETCH; delete process.env.CLOUD_URL; @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(() => { apiKeysDb.resetApiKeyState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); globalThis.fetch = ORIGINAL_FETCH; if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; @@ -131,11 +131,7 @@ test("cloudSync returns a generic error when the API responds with a non-OK stat const originalConsoleLog = console.log; const logged = []; console.log = (...args) => - logged.push( - args - .map((x) => (typeof x === "object" ? JSON.stringify(x) : String(x))) - .join(" ") - ); + logged.push(args.map((x) => (typeof x === "object" ? JSON.stringify(x) : String(x))).join(" ")); globalThis.fetch = async () => new Response("upstream unavailable", { status: 503, diff --git a/tests/unit/cloud-write-auth.test.ts b/tests/unit/cloud-write-auth.test.ts index 7a04b1e40b..68c1ce3ca9 100644 --- a/tests/unit/cloud-write-auth.test.ts +++ b/tests/unit/cloud-write-auth.test.ts @@ -32,7 +32,7 @@ async function resetStorage() { process.env.API_KEY_SECRET = "cloud-write-auth-api-key-secret"; core.resetDbInstance(); localDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await localDb.updateSettings({ requireLogin: true, password: "" }); } @@ -135,7 +135,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); localDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("PUT /api/cloud/credentials/update rejects valid API key without manage/admin scope and leaves credentials unchanged", async () => { diff --git a/tests/unit/cloudflare-models-uuid-4259.test.ts b/tests/unit/cloudflare-models-uuid-4259.test.ts index e14f4bc57b..6026b4971b 100644 --- a/tests/unit/cloudflare-models-uuid-4259.test.ts +++ b/tests/unit/cloudflare-models-uuid-4259.test.ts @@ -21,7 +21,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,7 +51,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4259 cloudflare-ai discovery uses the model name (slug) as id, not the UUID", async () => { diff --git a/tests/unit/cloudflaredTunnel-extended.test.ts b/tests/unit/cloudflaredTunnel-extended.test.ts index c43c5cc5e6..394e9a6a0c 100644 --- a/tests/unit/cloudflaredTunnel-extended.test.ts +++ b/tests/unit/cloudflaredTunnel-extended.test.ts @@ -101,7 +101,7 @@ test.afterEach(async () => { restoreEnv(); for (const dir of tempDirs) { - await fs.rm(dir as any, { recursive: true, force: true }); + await fs.rm(dir as any, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } tempDirs.clear(); }); diff --git a/tests/unit/cloudflaredTunnel.test.ts b/tests/unit/cloudflaredTunnel.test.ts index 72a0e526a6..02a860b8a9 100644 --- a/tests/unit/cloudflaredTunnel.test.ts +++ b/tests/unit/cloudflaredTunnel.test.ts @@ -400,6 +400,6 @@ test("getCloudflaredTunnelStatus resets stale runtime state from a previous serv process.env.CLOUDFLARED_BIN = originalBinary; } - await fs.rm(tempDir, { recursive: true, force: true }); + await fs.rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/codex-account-cooldown-write.test.ts b/tests/unit/codex-account-cooldown-write.test.ts index c24347afb7..d2a64419b0 100644 --- a/tests/unit/codex-account-cooldown-write.test.ts +++ b/tests/unit/codex-account-cooldown-write.test.ts @@ -15,7 +15,7 @@ const codexFailover = await import("../../open-sse/handlers/chatCore/codexFailov async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -65,7 +65,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("persisting Codex and Spark child cooldowns retains sibling and unrelated state", async () => { diff --git a/tests/unit/codex-auth-import-userid-dedup-6301.test.ts b/tests/unit/codex-auth-import-userid-dedup-6301.test.ts index 9f5046ed4d..ab88408957 100644 --- a/tests/unit/codex-auth-import-userid-dedup-6301.test.ts +++ b/tests/unit/codex-auth-import-userid-dedup-6301.test.ts @@ -71,7 +71,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -92,7 +92,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("parseAndValidateCodexAuth extracts userId from chatgpt_user_id claim", () => { diff --git a/tests/unit/codex-catalog-revalidation-runtime.test.ts b/tests/unit/codex-catalog-revalidation-runtime.test.ts index c7d2d78665..fa4b542a6c 100644 --- a/tests/unit/codex-catalog-revalidation-runtime.test.ts +++ b/tests/unit/codex-catalog-revalidation-runtime.test.ts @@ -25,7 +25,7 @@ const originalEnv = { async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -43,7 +43,7 @@ test.beforeEach(async () => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); for (const [key, value] of Object.entries(originalEnv)) { if (value === undefined) delete process.env[key]; else process.env[key] = value; diff --git a/tests/unit/codex-catalog-revalidation.test.ts b/tests/unit/codex-catalog-revalidation.test.ts index e70bdbc686..c00de6ca98 100644 --- a/tests/unit/codex-catalog-revalidation.test.ts +++ b/tests/unit/codex-catalog-revalidation.test.ts @@ -84,7 +84,7 @@ test("resolveCodexCatalogAppVersion uses stable, source-qualified identities", ( ); assert.equal(resolveCodexCatalogAppVersion({}, { runtimeRoot, packageVersion: null }), null); } finally { - fs.rmSync(runtimeRoot, { recursive: true, force: true }); + fs.rmSync(runtimeRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/codex-connection-defaults.test.ts b/tests/unit/codex-connection-defaults.test.ts index a05abc4803..dbfb7e4b22 100644 --- a/tests/unit/codex-connection-defaults.test.ts +++ b/tests/unit/codex-connection-defaults.test.ts @@ -15,7 +15,7 @@ const { migrateCodexConnectionDefaultsFromLegacySettings } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -25,7 +25,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration backfills Codex request defaults, preserves existing providerSpecificData, and is idempotent", async () => { @@ -150,8 +150,7 @@ test("migration does not treat explicit default global tier as legacy fast", asy assert.equal(firstRun.legacyFastEnabled, false); const providerSpecificData = byId.get(created.id)?.providerSpecificData as - | { requestDefaults?: unknown } - | undefined; + { requestDefaults?: unknown } | undefined; assert.deepEqual(providerSpecificData?.requestDefaults, { reasoningEffort: "medium", }); diff --git a/tests/unit/codex-connection-edit-6562.test.ts b/tests/unit/codex-connection-edit-6562.test.ts index 7b444a95cc..a1df77a5ac 100644 --- a/tests/unit/codex-connection-edit-6562.test.ts +++ b/tests/unit/codex-connection-edit-6562.test.ts @@ -46,7 +46,7 @@ const providerByIdRoute = await import("../../src/app/api/providers/[id]/route.t function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -56,7 +56,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createCodexConnection( diff --git a/tests/unit/codex-fingerprint-seed-persistence.test.ts b/tests/unit/codex-fingerprint-seed-persistence.test.ts index d65b7197b4..82b88b17b9 100644 --- a/tests/unit/codex-fingerprint-seed-persistence.test.ts +++ b/tests/unit/codex-fingerprint-seed-persistence.test.ts @@ -14,13 +14,13 @@ const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3} async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } beforeEach(resetStorage); after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createCodexOAuthConnection(providerSpecificData?: Record) { diff --git a/tests/unit/codex-gpt55-effort-routing.test.ts b/tests/unit/codex-gpt55-effort-routing.test.ts index 17b0abdb40..2d1aeba82e 100644 --- a/tests/unit/codex-gpt55-effort-routing.test.ts +++ b/tests/unit/codex-gpt55-effort-routing.test.ts @@ -41,7 +41,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Defect B: suffixed bare names infer codex, not openai ───────────────────── diff --git a/tests/unit/codex-gpt55-routing-5887.test.ts b/tests/unit/codex-gpt55-routing-5887.test.ts index 5e77fcdb4c..d710d919e0 100644 --- a/tests/unit/codex-gpt55-routing-5887.test.ts +++ b/tests/unit/codex-gpt55-routing-5887.test.ts @@ -31,7 +31,7 @@ let openaiConnectionId: number | string | undefined; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // (a) Codex active, OpenAI NOT active → bare gpt-5.5 must infer codex. diff --git a/tests/unit/codex-import-refresh-validation-7522.test.ts b/tests/unit/codex-import-refresh-validation-7522.test.ts index cb22a60748..58abfb11d5 100644 --- a/tests/unit/codex-import-refresh-validation-7522.test.ts +++ b/tests/unit/codex-import-refresh-validation-7522.test.ts @@ -31,7 +31,7 @@ test.before(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function jsonResponse(body: unknown, status = 200) { @@ -70,7 +70,10 @@ const BASE_RECORD = { test("import: rejects a record whose refresh_token is already invalidated upstream (#7522)", async () => { await withMockedFetch( (async () => - jsonResponse({ error: { code: "refresh_token_invalidated" } }, 401)) as unknown as typeof fetch, + jsonResponse( + { error: { code: "refresh_token_invalidated" } }, + 401 + )) as unknown as typeof fetch, async () => { const { status, body } = await postImport({ accounts: BASE_RECORD }); @@ -83,7 +86,11 @@ test("import: rejects a record whose refresh_token is already invalidated upstre const rows = await providersDb.getProviderConnections({ provider: "codex" }); const created = rows.find((r) => r.email === BASE_RECORD.email); - assert.equal(created, undefined, "no connection should be persisted for a dead refresh_token"); + assert.equal( + created, + undefined, + "no connection should be persisted for a dead refresh_token" + ); } ); }); @@ -160,7 +167,11 @@ test("import: a transient network error validating the refresh_token does not bl test("import: error responses never leak a stack trace", async () => { await withMockedFetch( - (async () => jsonResponse({ error: { code: "refresh_token_invalidated" } }, 401)) as unknown as typeof fetch, + (async () => + jsonResponse( + { error: { code: "refresh_token_invalidated" } }, + 401 + )) as unknown as typeof fetch, async () => { const { body } = await postImport({ accounts: { ...BASE_RECORD, email: "leak-check@example.com" }, diff --git a/tests/unit/codex-import-token-route.test.ts b/tests/unit/codex-import-token-route.test.ts index f9bbbc4ec2..cafc20c897 100644 --- a/tests/unit/codex-import-token-route.test.ts +++ b/tests/unit/codex-import-token-route.test.ts @@ -39,7 +39,7 @@ test.before(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function postImportToken(body: unknown) { diff --git a/tests/unit/codex-models-catalog-refresh.test.ts b/tests/unit/codex-models-catalog-refresh.test.ts index 9de940db09..87c3522c76 100644 --- a/tests/unit/codex-models-catalog-refresh.test.ts +++ b/tests/unit/codex-models-catalog-refresh.test.ts @@ -43,7 +43,7 @@ type CatalogResponse = { async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("codex client (originator: codex_exec) receives a top-level `models` array so the catalog refresh decodes", async () => { diff --git a/tests/unit/codex-oauth-refresh-persist-6352.test.ts b/tests/unit/codex-oauth-refresh-persist-6352.test.ts index 12f23cd67d..5473a242a8 100644 --- a/tests/unit/codex-oauth-refresh-persist-6352.test.ts +++ b/tests/unit/codex-oauth-refresh-persist-6352.test.ts @@ -51,7 +51,7 @@ const { OAUTH_ENDPOINTS } = await import("../../open-sse/config/constants.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -94,7 +94,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("checkAndRefreshToken reuses the stored Codex refresh_token, persists the new access_token, rotates the refresh_token, and clears stale auth-failure state (#6352)", async () => { diff --git a/tests/unit/codex-orphaned-tool-outputs-2928.test.ts b/tests/unit/codex-orphaned-tool-outputs-2928.test.ts index 1a96a1263b..23ab9c00aa 100644 --- a/tests/unit/codex-orphaned-tool-outputs-2928.test.ts +++ b/tests/unit/codex-orphaned-tool-outputs-2928.test.ts @@ -36,7 +36,7 @@ function toolOutputs(input: InputItem[]): InputItem[] { test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Codex strips function_call_output items without matching function calls", () => { diff --git a/tests/unit/codex-quota-selection-hydration.test.ts b/tests/unit/codex-quota-selection-hydration.test.ts index 124c863fcd..f3d36ec19b 100644 --- a/tests/unit/codex-quota-selection-hydration.test.ts +++ b/tests/unit/codex-quota-selection-hydration.test.ts @@ -21,7 +21,7 @@ function futureIso(ms = 60_000) { async function resetStorage() { core.resetDbInstance(); quotaCache.__clearForTests(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Codex selection ignores hydrated Spark-only exhaustion for normal Codex models", async () => { diff --git a/tests/unit/codex-reset-credits.test.ts b/tests/unit/codex-reset-credits.test.ts index e9466858d2..2a6ecccee7 100644 --- a/tests/unit/codex-reset-credits.test.ts +++ b/tests/unit/codex-reset-credits.test.ts @@ -17,7 +17,7 @@ type QuotaUsageRecord = Record; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("consumeCodexResetCredit fetches a credit id, posts it, then refreshes usage", async () => { diff --git a/tests/unit/codex-responses-passthrough-strip-3317.test.ts b/tests/unit/codex-responses-passthrough-strip-3317.test.ts index 9c755e6ff7..b925eb14d7 100644 --- a/tests/unit/codex-responses-passthrough-strip-3317.test.ts +++ b/tests/unit/codex-responses-passthrough-strip-3317.test.ts @@ -72,7 +72,7 @@ test.after(() => { /* ignore */ } try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ignore */ } diff --git a/tests/unit/codex-responses-ws-fingerprint.test.ts b/tests/unit/codex-responses-ws-fingerprint.test.ts index e65cdeefb2..77a56c1f12 100644 --- a/tests/unit/codex-responses-ws-fingerprint.test.ts +++ b/tests/unit/codex-responses-ws-fingerprint.test.ts @@ -15,14 +15,14 @@ const { POST } = await import("../../src/app/api/internal/codex-responses-ws/rou function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(resetDb); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Codex internal websocket bridge prepare preserves original OAuth identity in off mode", async () => { diff --git a/tests/unit/codex-same-account-transport-retry-9708.test.ts b/tests/unit/codex-same-account-transport-retry-9708.test.ts index e436df0080..cca34dd347 100644 --- a/tests/unit/codex-same-account-transport-retry-9708.test.ts +++ b/tests/unit/codex-same-account-transport-retry-9708.test.ts @@ -24,7 +24,7 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9708: 503 connection-reset and 507 buffer errors are retryable pre-output transport", () => { diff --git a/tests/unit/codex-session-affinity-reset-aware-5903.test.ts b/tests/unit/codex-session-affinity-reset-aware-5903.test.ts index 02f4ef6f1f..e3aed03da3 100644 --- a/tests/unit/codex-session-affinity-reset-aware-5903.test.ts +++ b/tests/unit/codex-session-affinity-reset-aware-5903.test.ts @@ -31,7 +31,7 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -56,7 +56,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("codex session affinity wins over a per-request reset-aware forcedConnectionId (#5903)", async () => { @@ -73,7 +73,11 @@ test("codex session affinity wins over a per-request reset-aware forcedConnectio sessionKey: "session-S", forcedConnectionId: connectionA.id, }); - assert.equal(request1?.connectionId, connectionA.id, "request 1 should pin to the scored winner A"); + assert.equal( + request1?.connectionId, + connectionA.id, + "request 1 should pin to the scored winner A" + ); assert.equal( affinityDb.getSessionAccountAffinity("session-S", "codex", 60_000)?.connectionId, connectionA.id, @@ -105,7 +109,11 @@ test("codex session affinity wins over a per-request reset-aware forcedConnectio sessionKey: "session-S2", forcedConnectionId: connectionB.id, }); - assert.equal(request3?.connectionId, connectionB.id, "a new session must honor the fresh re-scored pick"); + assert.equal( + request3?.connectionId, + connectionB.id, + "a new session must honor the fresh re-scored pick" + ); assert.equal( affinityDb.getSessionAccountAffinity("session-S2", "codex", 60_000)?.connectionId, connectionB.id, diff --git a/tests/unit/codex-settings-wire-api-default.test.ts b/tests/unit/codex-settings-wire-api-default.test.ts index d8dae1b1b7..7b7d5fd32d 100644 --- a/tests/unit/codex-settings-wire-api-default.test.ts +++ b/tests/unit/codex-settings-wire-api-default.test.ts @@ -44,7 +44,7 @@ const post = async (body: Record) => test.after(async () => { os.homedir = originalHome; - await fs.rm(TEST_HOME, { recursive: true, force: true }); + await fs.rm(TEST_HOME, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; if (originalWriteFlag === undefined) delete process.env.CLI_ALLOW_CONFIG_WRITES; @@ -78,7 +78,7 @@ test("POST resolves the Codex wire API before URL normalization and TOML generat for (const testCase of cases) { await t.test(testCase.name, async () => { - await fs.rm(TEST_HOME, { recursive: true, force: true }); + await fs.rm(TEST_HOME, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); const response = await post(testCase.body); assert.equal(response.status, 200); diff --git a/tests/unit/codex-stream-false.test.ts b/tests/unit/codex-stream-false.test.ts index 138272d8e7..7c111c7bf6 100644 --- a/tests/unit/codex-stream-false.test.ts +++ b/tests/unit/codex-stream-false.test.ts @@ -139,7 +139,7 @@ function buildResponsesNdjson(text = "Brasilia") { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -207,7 +207,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("CodexExecutor.transformRequest clones the request body before forcing stream=true", () => { diff --git a/tests/unit/codex-synced-bare-model-routing.test.ts b/tests/unit/codex-synced-bare-model-routing.test.ts index 765b5a1de3..685ce7f456 100644 --- a/tests/unit/codex-synced-bare-model-routing.test.ts +++ b/tests/unit/codex-synced-bare-model-routing.test.ts @@ -46,13 +46,13 @@ async function seedSyncedModel(provider: TestProvider, modelId: string, isActive test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("bare GPT-5.6 model routes through Codex when it is the only active provider", async () => { diff --git a/tests/unit/codex-ws-policy-enforcement-6564.test.ts b/tests/unit/codex-ws-policy-enforcement-6564.test.ts index 7801e27a9f..3cf85bc3e0 100644 --- a/tests/unit/codex-ws-policy-enforcement-6564.test.ts +++ b/tests/unit/codex-ws-policy-enforcement-6564.test.ts @@ -71,7 +71,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -95,7 +95,7 @@ test.after(async () => { apiKeysDb.resetApiKeyState(); costRules.resetCostData(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** Builds a bridge POST request for the internal codex-responses-ws route's "prepare" action. */ diff --git a/tests/unit/colocate-optionals.test.ts b/tests/unit/colocate-optionals.test.ts index 8250c46317..7c8370be33 100644 --- a/tests/unit/colocate-optionals.test.ts +++ b/tests/unit/colocate-optionals.test.ts @@ -53,7 +53,12 @@ function buildRoot(rootDir: string): void { }, { "dist/index.js": "export const llmlingua = true;\n" } ); - mkPkg(rootNm, "es-toolkit", { main: "index.js" }, { "index.js": "export const esToolkit = true;\n" }); + mkPkg( + rootNm, + "es-toolkit", + { main: "index.js" }, + { "index.js": "export const esToolkit = true;\n" } + ); mkPkg( rootNm, "js-tiktoken", @@ -71,12 +76,7 @@ test("computeDependencyClosure walks deps transitively and skips peers (transfor buildRoot(root); const closure = computeDependencyClosure(join(root, "node_modules")); - for (const expected of [ - "@atjsh/llmlingua-2", - "js-tiktoken", - "es-toolkit", - "base64-js", - ]) { + for (const expected of ["@atjsh/llmlingua-2", "js-tiktoken", "es-toolkit", "base64-js"]) { assert.ok(closure.includes(expected), `closure should include ${expected}`); } // The peer (declared via peerDependencies, NOT dependencies) must NOT be pulled in. @@ -85,7 +85,7 @@ test("computeDependencyClosure walks deps transitively and skips peers (transfor "closure must NOT include the transformers peer" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -104,12 +104,7 @@ test("colocateLlmlinguaOptionals copies the closure into dist and never clobbers } // Full closure landed in dist/node_modules. - for (const name of [ - "@atjsh/llmlingua-2", - "es-toolkit", - "js-tiktoken", - "base64-js", - ]) { + for (const name of ["@atjsh/llmlingua-2", "es-toolkit", "js-tiktoken", "base64-js"]) { assert.ok(existsSync(join(distNm, name)), `${name} should be co-located into dist`); } // The package payload came along (not just the manifest). @@ -121,7 +116,7 @@ test("colocateLlmlinguaOptionals copies the closure into dist and never clobbers ); assert.equal(distTransformers.version, "4.2.0", "dist transformers must remain 4.2.0"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -140,7 +135,7 @@ test("colocateLlmlinguaOptionals is idempotent (second run is a no-op)", () => { assert.equal(second.reason, "already co-located"); } } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -157,7 +152,7 @@ test("colocateLlmlinguaOptionals skips when SLM optionals are not installed", () assert.equal(result.reason, "SLM optionals not installed at root"); } } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -171,7 +166,7 @@ test("colocateLlmlinguaOptionals skips when there is no standalone dist bundle", assert.equal(result.reason, "no standalone dist/node_modules"); } } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -206,7 +201,7 @@ test("colocateLlmlinguaOptionals fills a Next-traced stub (package.json only, no "the real dist/index.js must be filled in, not left missing behind the stub" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/combo-account-allowlist-3266.test.ts b/tests/unit/combo-account-allowlist-3266.test.ts index 57411db268..eddde9809a 100644 --- a/tests/unit/combo-account-allowlist-3266.test.ts +++ b/tests/unit/combo-account-allowlist-3266.test.ts @@ -42,7 +42,7 @@ function okResponse(content: string) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -63,7 +63,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── 1. Schema parse ───────────────────────────────────────────────────────── diff --git a/tests/unit/combo-attempt-body-isolation-7847.test.ts b/tests/unit/combo-attempt-body-isolation-7847.test.ts index 9373c51e7c..36cedb67b1 100644 --- a/tests/unit/combo-attempt-body-isolation-7847.test.ts +++ b/tests/unit/combo-attempt-body-isolation-7847.test.ts @@ -97,7 +97,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/combo-auto-candidate-expansion.test.ts b/tests/unit/combo-auto-candidate-expansion.test.ts index 4cf4be0c01..8ae2747c4f 100644 --- a/tests/unit/combo-auto-candidate-expansion.test.ts +++ b/tests/unit/combo-auto-candidate-expansion.test.ts @@ -20,7 +20,7 @@ const providerModels = await import("../../open-sse/config/providerModels.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -28,7 +28,7 @@ test.beforeEach(() => resetStorage()); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/combo-auto-pool-visible-only.test.ts b/tests/unit/combo-auto-pool-visible-only.test.ts index e0748ea77b..002140163e 100644 --- a/tests/unit/combo-auto-pool-visible-only.test.ts +++ b/tests/unit/combo-auto-pool-visible-only.test.ts @@ -24,7 +24,7 @@ const combo = await import("../../open-sse/services/combo.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -32,7 +32,7 @@ test.beforeEach(() => resetStorage()); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); @@ -98,7 +98,9 @@ test("expandAutoComboCandidatePool excludes catalog-only models (openrouter/auto ); assert.ok( - expanded.some((t) => t.provider === "openrouter" && t.modelStr === "openrouter/liquid/lfm-2.5-2.6b:free"), + expanded.some( + (t) => t.provider === "openrouter" && t.modelStr === "openrouter/liquid/lfm-2.5-2.6b:free" + ), "a synced free model must be expanded into the pool" ); }); diff --git a/tests/unit/combo-bracket-names.test.ts b/tests/unit/combo-bracket-names.test.ts index 0f4d8af0de..96ebcb9d2a 100644 --- a/tests/unit/combo-bracket-names.test.ts +++ b/tests/unit/combo-bracket-names.test.ts @@ -14,7 +14,7 @@ const sseModelService = await import("../../src/sse/services/model.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -24,7 +24,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("combo schemas accept names with spaces and square brackets", () => { diff --git a/tests/unit/combo-builder-effort-variants-8072.test.ts b/tests/unit/combo-builder-effort-variants-8072.test.ts index 5a1ffe7eec..da92cbea65 100644 --- a/tests/unit/combo-builder-effort-variants-8072.test.ts +++ b/tests/unit/combo-builder-effort-variants-8072.test.ts @@ -34,7 +34,7 @@ const { getComboBuilderOptions } = await import("../../src/lib/combos/builderOpt test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8072 buildModelOptions: synced - effort variants appear in the Combo Builder picker and inherit the base model's metadata", async () => { diff --git a/tests/unit/combo-builder-model-source-5477.test.ts b/tests/unit/combo-builder-model-source-5477.test.ts index 230e4fe48d..3ca86da56f 100644 --- a/tests/unit/combo-builder-model-source-5477.test.ts +++ b/tests/unit/combo-builder-model-source-5477.test.ts @@ -22,7 +22,7 @@ const { getComboBuilderOptions } = await import("../../src/lib/combos/builderOpt test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5477 buildModelOptions classifies custom-model source (manual -> custom, api-sync -> imported)", async () => { diff --git a/tests/unit/combo-builder-opencode-prefix.test.ts b/tests/unit/combo-builder-opencode-prefix.test.ts index 8ce510e8be..24cfe8762d 100644 --- a/tests/unit/combo-builder-opencode-prefix.test.ts +++ b/tests/unit/combo-builder-opencode-prefix.test.ts @@ -28,7 +28,7 @@ const { parseModel } = await import("../../open-sse/services/model.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#2901 no-auth OpenCode combo models use the oc/ prefix (not opencode/)", async () => { diff --git a/tests/unit/combo-builder-options-route.test.ts b/tests/unit/combo-builder-options-route.test.ts index 8353b40de2..9f5181b8f6 100644 --- a/tests/unit/combo-builder-options-route.test.ts +++ b/tests/unit/combo-builder-options-route.test.ts @@ -16,7 +16,7 @@ const route = await import("../../src/app/api/combos/builder/options/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,7 +51,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("combo builder options route aggregates providers, connections, models and combo refs", async () => { diff --git a/tests/unit/combo-cache-invalidation.test.ts b/tests/unit/combo-cache-invalidation.test.ts index 5291c5c76a..ebff45d40a 100644 --- a/tests/unit/combo-cache-invalidation.test.ts +++ b/tests/unit/combo-cache-invalidation.test.ts @@ -36,7 +36,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -58,7 +58,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Mirror the cache-validity predicate used by the handler cache layers diff --git a/tests/unit/combo-context-generic-default-10734.test.ts b/tests/unit/combo-context-generic-default-10734.test.ts index 27749b9f9a..78d932d22e 100644 --- a/tests/unit/combo-context-generic-default-10734.test.ts +++ b/tests/unit/combo-context-generic-default-10734.test.ts @@ -19,7 +19,7 @@ const catalog = await import("../../src/app/api/v1/models/catalog.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10734: resolveTokenLimit marks the generic 128k catch-all as specific:false", () => { diff --git a/tests/unit/combo-context-length.test.ts b/tests/unit/combo-context-length.test.ts index c416b4d8be..fb900eaee3 100644 --- a/tests/unit/combo-context-length.test.ts +++ b/tests/unit/combo-context-length.test.ts @@ -17,7 +17,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -38,7 +38,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Zod Schema Validation (createComboSchema) ─── diff --git a/tests/unit/combo-context-overflow-compression-probe.test.ts b/tests/unit/combo-context-overflow-compression-probe.test.ts index aae7f3ab2e..c854339c69 100644 --- a/tests/unit/combo-context-overflow-compression-probe.test.ts +++ b/tests/unit/combo-context-overflow-compression-probe.test.ts @@ -43,7 +43,7 @@ test.after(() => { } else { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { diff --git a/tests/unit/combo-context-prefix-resolution.test.ts b/tests/unit/combo-context-prefix-resolution.test.ts index bd586f2efc..8a827bc6de 100644 --- a/tests/unit/combo-context-prefix-resolution.test.ts +++ b/tests/unit/combo-context-prefix-resolution.test.ts @@ -38,7 +38,7 @@ const { setModelContextOverride, removeModelContextOverride } = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("computeComboContextLength resolves a registry-known, prefixed member (glm/glm-5.2) to its real context window", () => { diff --git a/tests/unit/combo-context-relay.test.ts b/tests/unit/combo-context-relay.test.ts index 5e83b460c3..e984d7a696 100644 --- a/tests/unit/combo-context-relay.test.ts +++ b/tests/unit/combo-context-relay.test.ts @@ -78,7 +78,7 @@ function buildQuotaResponse(usedPercent, resetAfterSeconds = 3600) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -116,7 +116,7 @@ test.after(async () => { clearSessions(); globalThis.fetch = originalFetch; await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("handleComboChat context-relay routes to the first available model", async () => { diff --git a/tests/unit/combo-context-window-filter.test.ts b/tests/unit/combo-context-window-filter.test.ts index 442caf85e0..a78c3d5ba5 100644 --- a/tests/unit/combo-context-window-filter.test.ts +++ b/tests/unit/combo-context-window-filter.test.ts @@ -27,7 +27,7 @@ test.after(() => { } else { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { diff --git a/tests/unit/combo-description-5005.test.ts b/tests/unit/combo-description-5005.test.ts index c77a6a9185..172f121b6d 100644 --- a/tests/unit/combo-description-5005.test.ts +++ b/tests/unit/combo-description-5005.test.ts @@ -16,16 +16,15 @@ import path from "node:path"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-combo-desc-5005-")); process.env.DATA_DIR = TEST_DATA_DIR; -const { createComboSchema, updateComboSchema } = await import( - "../../src/shared/validation/schemas.ts" -); +const { createComboSchema, updateComboSchema } = + await import("../../src/shared/validation/schemas.ts"); const core = await import("../../src/lib/db/core.ts"); const combosDb = await import("../../src/lib/db/combos.ts"); async function resetStorage() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +35,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createComboSchema preserves description instead of stripping it", () => { diff --git a/tests/unit/combo-dispatch-prelude.test.ts b/tests/unit/combo-dispatch-prelude.test.ts index 87d35ef25d..68307b8da2 100644 --- a/tests/unit/combo-dispatch-prelude.test.ts +++ b/tests/unit/combo-dispatch-prelude.test.ts @@ -89,7 +89,7 @@ function setup(combo: ComboInput) { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; if (ORIGINAL_API_KEY_SECRET === undefined) delete process.env.API_KEY_SECRET; diff --git a/tests/unit/combo-empty-models.test.ts b/tests/unit/combo-empty-models.test.ts index 95f32813a3..77785f9cb5 100644 --- a/tests/unit/combo-empty-models.test.ts +++ b/tests/unit/combo-empty-models.test.ts @@ -15,7 +15,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("an update cannot remove every model from a combo", () => { diff --git a/tests/unit/combo-fallback-token-estimate-7847.test.ts b/tests/unit/combo-fallback-token-estimate-7847.test.ts index 1a8e57838c..b4d1aeb69a 100644 --- a/tests/unit/combo-fallback-token-estimate-7847.test.ts +++ b/tests/unit/combo-fallback-token-estimate-7847.test.ts @@ -22,7 +22,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/combo-forecast.test.ts b/tests/unit/combo-forecast.test.ts index 46bbc75c2b..2e7af7891f 100644 --- a/tests/unit/combo-forecast.test.ts +++ b/tests/unit/combo-forecast.test.ts @@ -23,7 +23,7 @@ const { normalizeComboStep } = await import("../../src/lib/combos/steps.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -85,7 +85,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/combo-health-dashboard.test.ts b/tests/unit/combo-health-dashboard.test.ts index 52449883bf..41edbf7f7d 100644 --- a/tests/unit/combo-health-dashboard.test.ts +++ b/tests/unit/combo-health-dashboard.test.ts @@ -26,7 +26,7 @@ const { normalizeComboStep } = await import("../../src/lib/combos/steps.ts"); async function resetStorage() { comboMetrics.resetAllComboMetrics(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -120,7 +120,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/combo-health-route.test.ts b/tests/unit/combo-health-route.test.ts index 9aae08757d..489ef8c534 100644 --- a/tests/unit/combo-health-route.test.ts +++ b/tests/unit/combo-health-route.test.ts @@ -18,7 +18,7 @@ const { normalizeComboStep } = await import("../../src/lib/combos/steps.ts"); async function resetStorage() { comboMetrics.resetAllComboMetrics(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -29,7 +29,7 @@ test.beforeEach(async () => { test.after(() => { comboMetrics.resetAllComboMetrics(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("combo health route exposes step-level target health for structured combos", async () => { diff --git a/tests/unit/combo-hidden-leaf-routing.test.ts b/tests/unit/combo-hidden-leaf-routing.test.ts index 3c340c5b20..87c590ec5b 100644 --- a/tests/unit/combo-hidden-leaf-routing.test.ts +++ b/tests/unit/combo-hidden-leaf-routing.test.ts @@ -21,13 +21,13 @@ function okResponse(): Response { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("handleComboChat never routes hidden leaves in priority, weighted, or round-robin combos", async () => { diff --git a/tests/unit/combo-id-resolution-4446.test.ts b/tests/unit/combo-id-resolution-4446.test.ts index 6b69a49f8f..e714dac404 100644 --- a/tests/unit/combo-id-resolution-4446.test.ts +++ b/tests/unit/combo-id-resolution-4446.test.ts @@ -21,7 +21,7 @@ const sseModelService = await import("../../src/sse/services/model.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4446 getComboForModel resolves a combo by a case-insensitive name (lowercased slug)", async () => { diff --git a/tests/unit/combo-lockout-quota-reset-6863.test.ts b/tests/unit/combo-lockout-quota-reset-6863.test.ts index 463cd361d2..35032f4907 100644 --- a/tests/unit/combo-lockout-quota-reset-6863.test.ts +++ b/tests/unit/combo-lockout-quota-reset-6863.test.ts @@ -30,7 +30,7 @@ test.after(() => { clearAllModelLockouts(); try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/combo-model-name-collision-8530.test.ts b/tests/unit/combo-model-name-collision-8530.test.ts index fcdf09a827..f9d8da17ab 100644 --- a/tests/unit/combo-model-name-collision-8530.test.ts +++ b/tests/unit/combo-model-name-collision-8530.test.ts @@ -35,7 +35,7 @@ interface ComboResponseBody { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -61,7 +61,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("POST /api/combos: name colliding with a real model id is created (#6940 pattern), with a warning", async () => { diff --git a/tests/unit/combo-patch-verb.test.ts b/tests/unit/combo-patch-verb.test.ts index c72d0e23d4..9f35123ad5 100644 --- a/tests/unit/combo-patch-verb.test.ts +++ b/tests/unit/combo-patch-verb.test.ts @@ -13,7 +13,7 @@ const comboRoute = await import("../../src/app/api/combos/[id]/route.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function patch(id: string, body: Record) { diff --git a/tests/unit/combo-prescreen.test.ts b/tests/unit/combo-prescreen.test.ts index 63d681b9c5..7d687227a6 100644 --- a/tests/unit/combo-prescreen.test.ts +++ b/tests/unit/combo-prescreen.test.ts @@ -14,7 +14,7 @@ const combosDb = await import("../../src/lib/db/combos.ts"); after(() => { dbCore.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/combo-priority-quota-exhaustion-cutoff-5923.test.ts b/tests/unit/combo-priority-quota-exhaustion-cutoff-5923.test.ts index 252c9cef3b..8cb5f018d8 100644 --- a/tests/unit/combo-priority-quota-exhaustion-cutoff-5923.test.ts +++ b/tests/unit/combo-priority-quota-exhaustion-cutoff-5923.test.ts @@ -33,7 +33,7 @@ const { getCircuitBreaker } = await import("../../src/shared/utils/circuitBreake test.after(() => { dbCore.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function makeLog() { diff --git a/tests/unit/combo-quota-exhaustion-only-fallback.test.ts b/tests/unit/combo-quota-exhaustion-only-fallback.test.ts index cbb4f70c11..0db3589e99 100644 --- a/tests/unit/combo-quota-exhaustion-only-fallback.test.ts +++ b/tests/unit/combo-quota-exhaustion-only-fallback.test.ts @@ -26,7 +26,7 @@ test.after(() => { resetDbInstance(); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function log() { diff --git a/tests/unit/combo-quota-share-cooldown-wait.test.ts b/tests/unit/combo-quota-share-cooldown-wait.test.ts index ba33def470..a803245320 100644 --- a/tests/unit/combo-quota-share-cooldown-wait.test.ts +++ b/tests/unit/combo-quota-share-cooldown-wait.test.ts @@ -94,7 +94,7 @@ function comboOf(strategy: string) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -107,7 +107,7 @@ test.after(async () => { clearAllModelLockouts(); try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } diff --git a/tests/unit/combo-quota-token-limit.test.ts b/tests/unit/combo-quota-token-limit.test.ts index 53ecdb91c1..e93f090606 100644 --- a/tests/unit/combo-quota-token-limit.test.ts +++ b/tests/unit/combo-quota-token-limit.test.ts @@ -23,7 +23,7 @@ test.after(() => { else process.env.DATA_DIR = ORIGINAL_DATA_DIR; if (ORIGINAL_QUOTA_ROUTING === undefined) delete process.env.OMNIROUTE_QUOTA_AWARE_ROUTING; else process.env.OMNIROUTE_QUOTA_AWARE_ROUTING = ORIGINAL_QUOTA_ROUTING; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("round-robin quota reservation keeps the connection token limit", async () => { diff --git a/tests/unit/combo-resource-404-health.test.ts b/tests/unit/combo-resource-404-health.test.ts index a7d318a8d3..fa5e71a15e 100644 --- a/tests/unit/combo-resource-404-health.test.ts +++ b/tests/unit/combo-resource-404-health.test.ts @@ -47,7 +47,7 @@ test.after(() => { clearAllModelLockouts(); clearCooldownState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("combo resource 404 never records model lockout or provider cooldown", async () => { diff --git a/tests/unit/combo-roundrobin-compat-fallback-6238.test.ts b/tests/unit/combo-roundrobin-compat-fallback-6238.test.ts index 8ab28e1085..0aa1a04799 100644 --- a/tests/unit/combo-roundrobin-compat-fallback-6238.test.ts +++ b/tests/unit/combo-roundrobin-compat-fallback-6238.test.ts @@ -80,7 +80,7 @@ test.after(() => { clearModelsDevCapabilities(); settingsDb.clearAllLKGP(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/combo-routes-composite-tiers.test.ts b/tests/unit/combo-routes-composite-tiers.test.ts index bb1cbc0f93..4d2ba5f656 100644 --- a/tests/unit/combo-routes-composite-tiers.test.ts +++ b/tests/unit/combo-routes-composite-tiers.test.ts @@ -14,7 +14,7 @@ const comboRoute = await import("../../src/app/api/combos/[id]/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -77,7 +77,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("POST /api/combos persists names with spaces and square brackets", async () => { @@ -271,7 +271,6 @@ test("PUT /api/combos preserves legacy string combo refs during normalization", assert.equal(stored.models[0].comboName, "child-ref"); }); - test("POST /api/combos returns a structured 400 for invariant violations", async () => { const response = await createRoute.POST( makeCreateRequest({ diff --git a/tests/unit/combo-routing-engine.test.ts b/tests/unit/combo-routing-engine.test.ts index aa78ceeaf6..41e4f43d35 100644 --- a/tests/unit/combo-routing-engine.test.ts +++ b/tests/unit/combo-routing-engine.test.ts @@ -128,7 +128,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: any) { lastError = error; diff --git a/tests/unit/combo-rr-diagnostics-11462.test.ts b/tests/unit/combo-rr-diagnostics-11462.test.ts index ade088e3ce..d9bd60f64a 100644 --- a/tests/unit/combo-rr-diagnostics-11462.test.ts +++ b/tests/unit/combo-rr-diagnostics-11462.test.ts @@ -12,9 +12,8 @@ const { handleComboChat } = await import("../../open-sse/services/combo.ts"); const core = await import("../../src/lib/db/core.ts"); const { resetAllComboMetrics } = await import("../../open-sse/services/comboMetrics.ts"); const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts"); -const { resetAll: resetAllSemaphores } = await import( - "../../open-sse/services/rateLimitSemaphore.ts" -); +const { resetAll: resetAllSemaphores } = + await import("../../open-sse/services/rateLimitSemaphore.ts"); function createLog() { return { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} }; @@ -36,7 +35,7 @@ test.after(() => { resetAllCircuitBreakers(); resetAllSemaphores(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/combo-rr-fallback-advance-948.test.ts b/tests/unit/combo-rr-fallback-advance-948.test.ts index 3ff204c8db..2bcb462021 100644 --- a/tests/unit/combo-rr-fallback-advance-948.test.ts +++ b/tests/unit/combo-rr-fallback-advance-948.test.ts @@ -39,9 +39,30 @@ function rrCombo(name: string) { // per-conversation pin; stickyLimit defaults to 1 (true round-robin). config: { maxRetries: 0, disableSessionStickiness: true }, models: [ - { kind: "model", provider: "codex", providerId: "codex", model: "m-a", connectionId: "conn-A", id: `${name}-0` }, - { kind: "model", provider: "codex", providerId: "codex", model: "m-b", connectionId: "conn-B", id: `${name}-1` }, - { kind: "model", provider: "glm-cn", providerId: "glm-cn", model: "m-c", connectionId: "conn-C", id: `${name}-2` }, + { + kind: "model", + provider: "codex", + providerId: "codex", + model: "m-a", + connectionId: "conn-A", + id: `${name}-0`, + }, + { + kind: "model", + provider: "codex", + providerId: "codex", + model: "m-b", + connectionId: "conn-B", + id: `${name}-1`, + }, + { + kind: "model", + provider: "glm-cn", + providerId: "glm-cn", + model: "m-c", + connectionId: "conn-C", + id: `${name}-2`, + }, ], }; } @@ -89,7 +110,7 @@ test.after(() => { } if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#948: two consecutive requests do not reuse the fallback-served model", async () => { diff --git a/tests/unit/combo-rr-session-stickiness-3825.test.ts b/tests/unit/combo-rr-session-stickiness-3825.test.ts index 9ef5ed2d2c..c3bcb38f08 100644 --- a/tests/unit/combo-rr-session-stickiness-3825.test.ts +++ b/tests/unit/combo-rr-session-stickiness-3825.test.ts @@ -39,14 +39,38 @@ function rrCombo(name: string) { strategy: "round-robin", config: { maxRetries: 0 }, models: [ - { kind: "model", provider: "codex", providerId: "codex", model: "m-a", connectionId: "conn-A", id: `${name}-0` }, - { kind: "model", provider: "codex", providerId: "codex", model: "m-b", connectionId: "conn-B", id: `${name}-1` }, - { kind: "model", provider: "glm-cn", providerId: "glm-cn", model: "m-c", connectionId: "conn-C", id: `${name}-2` }, + { + kind: "model", + provider: "codex", + providerId: "codex", + model: "m-a", + connectionId: "conn-A", + id: `${name}-0`, + }, + { + kind: "model", + provider: "codex", + providerId: "codex", + model: "m-b", + connectionId: "conn-B", + id: `${name}-1`, + }, + { + kind: "model", + provider: "glm-cn", + providerId: "glm-cn", + model: "m-c", + connectionId: "conn-C", + id: `${name}-2`, + }, ], }; } -async function dispatchConnection(combo: Record, firstMessage: string): Promise { +async function dispatchConnection( + combo: Record, + firstMessage: string +): Promise { let conn = "?"; await handleComboChat({ body: { model: combo.name, messages: [{ role: "user", content: firstMessage }], stream: false }, @@ -79,7 +103,7 @@ test.beforeEach(() => { test.after(() => { stick.__setStickinessHeadroomFetcherForTests(null); dbCore.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); @@ -104,7 +128,10 @@ test("round-robin: DISTINCT conversations still spread across connections on tur const combo = rrCombo("rr-spread"); const hist: Record = {}; for (let i = 0; i < 6; i++) { - const conn = await dispatchConnection(combo, `conversation number ${i} — distinct first message`); + const conn = await dispatchConnection( + combo, + `conversation number ${i} — distinct first message` + ); hist[conn] = (hist[conn] || 0) + 1; } // Round-robin distribution must be preserved across conversations: more than one diff --git a/tests/unit/combo-runtime-unit-concurrency.test.ts b/tests/unit/combo-runtime-unit-concurrency.test.ts index 8ccebe4603..ac2695c4a1 100644 --- a/tests/unit/combo-runtime-unit-concurrency.test.ts +++ b/tests/unit/combo-runtime-unit-concurrency.test.ts @@ -63,7 +63,7 @@ test.after(() => { resetDbInstance(); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("isRuntimeUnitAtConcurrencyCap returns true for a model unit at cap", async () => { diff --git a/tests/unit/combo-scope-proxy-dead-7149.test.ts b/tests/unit/combo-scope-proxy-dead-7149.test.ts index 8d301763e9..06e4592a6f 100644 --- a/tests/unit/combo-scope-proxy-dead-7149.test.ts +++ b/tests/unit/combo-scope-proxy-dead-7149.test.ts @@ -22,13 +22,13 @@ type ProxyResolutionLike = { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7149: a proxy assigned to a Combo via the dashboard (registry scope='combo') is honored when resolving the proxy for a request routed through that combo", async () => { diff --git a/tests/unit/combo-scoring-inspector.test.ts b/tests/unit/combo-scoring-inspector.test.ts index 12062cbbe5..a8d4f4c9a2 100644 --- a/tests/unit/combo-scoring-inspector.test.ts +++ b/tests/unit/combo-scoring-inspector.test.ts @@ -36,7 +36,7 @@ async function resetStorage() { clearAllModelLockouts(); resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -145,7 +145,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/combo-selected-connection-success.test.ts b/tests/unit/combo-selected-connection-success.test.ts index 2e986639c7..fc4a32a431 100644 --- a/tests/unit/combo-selected-connection-success.test.ts +++ b/tests/unit/combo-selected-connection-success.test.ts @@ -47,7 +47,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: any) { lastError = error; diff --git a/tests/unit/combo-sessionless-pin-3825.test.ts b/tests/unit/combo-sessionless-pin-3825.test.ts index d8bcd2207f..e71e90c16c 100644 --- a/tests/unit/combo-sessionless-pin-3825.test.ts +++ b/tests/unit/combo-sessionless-pin-3825.test.ts @@ -56,7 +56,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: any) { lastError = error; diff --git a/tests/unit/combo-silent-stop-gaps.test.ts b/tests/unit/combo-silent-stop-gaps.test.ts index 3b101a20c0..5ace242f14 100644 --- a/tests/unit/combo-silent-stop-gaps.test.ts +++ b/tests/unit/combo-silent-stop-gaps.test.ts @@ -90,7 +90,7 @@ test.after(async () => { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } diff --git a/tests/unit/combo-speed-telemetry-6875.test.ts b/tests/unit/combo-speed-telemetry-6875.test.ts index 6bef6edd58..83ad13bf67 100644 --- a/tests/unit/combo-speed-telemetry-6875.test.ts +++ b/tests/unit/combo-speed-telemetry-6875.test.ts @@ -36,7 +36,7 @@ const core = await import("../../src/lib/db/core.ts"); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -218,9 +218,7 @@ test("buildAutoCandidates: candidate carries avgTtftMs/avgE2ELatencyMs/avgTokens // slipped past the positive() guard). assert.ok(typeof candidate!.avgTtftMs === "number" && candidate!.avgTtftMs > 0); assert.ok(typeof candidate!.avgE2ELatencyMs === "number" && candidate!.avgE2ELatencyMs > 0); - assert.ok( - typeof candidate!.avgTokensPerSecond === "number" && candidate!.avgTokensPerSecond > 0 - ); + assert.ok(typeof candidate!.avgTokensPerSecond === "number" && candidate!.avgTokensPerSecond > 0); }); test("buildAutoCandidates: a provider/model with no historical signal omits the speed-telemetry fields", async () => { diff --git a/tests/unit/combo-stickiness-responses-input-7270.test.ts b/tests/unit/combo-stickiness-responses-input-7270.test.ts index 125b551b5b..4b68ab8356 100644 --- a/tests/unit/combo-stickiness-responses-input-7270.test.ts +++ b/tests/unit/combo-stickiness-responses-input-7270.test.ts @@ -39,9 +39,30 @@ function rrCombo(name: string) { strategy: "round-robin", config: { maxRetries: 0 }, models: [ - { kind: "model", provider: "codex", providerId: "codex", model: "m-a", connectionId: "conn-A", id: `${name}-0` }, - { kind: "model", provider: "codex", providerId: "codex", model: "m-b", connectionId: "conn-B", id: `${name}-1` }, - { kind: "model", provider: "glm-cn", providerId: "glm-cn", model: "m-c", connectionId: "conn-C", id: `${name}-2` }, + { + kind: "model", + provider: "codex", + providerId: "codex", + model: "m-a", + connectionId: "conn-A", + id: `${name}-0`, + }, + { + kind: "model", + provider: "codex", + providerId: "codex", + model: "m-b", + connectionId: "conn-B", + id: `${name}-1`, + }, + { + kind: "model", + provider: "glm-cn", + providerId: "glm-cn", + model: "m-c", + connectionId: "conn-C", + id: `${name}-2`, + }, ], }; } @@ -92,7 +113,7 @@ test.beforeEach(() => { test.after(() => { stick.__setStickinessHeadroomFetcherForTests(null); dbCore.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/combo-strategies.test.ts b/tests/unit/combo-strategies.test.ts index 127a20ab80..dd0c7be367 100644 --- a/tests/unit/combo-strategies.test.ts +++ b/tests/unit/combo-strategies.test.ts @@ -24,7 +24,7 @@ const { saveModelsDevCapabilities } = await import("../../src/lib/modelsDevSync. after(() => { dbCore.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/combo-strategy-fallbacks.test.ts b/tests/unit/combo-strategy-fallbacks.test.ts index 88792e64cc..1cd34ef7b6 100644 --- a/tests/unit/combo-strategy-fallbacks.test.ts +++ b/tests/unit/combo-strategy-fallbacks.test.ts @@ -55,7 +55,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: any) { lastError = error; diff --git a/tests/unit/combo-strict-random-distribution-3959.test.ts b/tests/unit/combo-strict-random-distribution-3959.test.ts index 5209b6c49c..d4ac6590f0 100644 --- a/tests/unit/combo-strict-random-distribution-3959.test.ts +++ b/tests/unit/combo-strict-random-distribution-3959.test.ts @@ -24,9 +24,8 @@ const { handleComboChat } = await import("../../open-sse/services/combo.ts"); const core = await import("../../src/lib/db/core.ts"); const { resetAllComboMetrics } = await import("../../open-sse/services/comboMetrics.ts"); const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts"); -const { resetAll: resetAllSemaphores } = await import( - "../../open-sse/services/rateLimitSemaphore.ts" -); +const { resetAll: resetAllSemaphores } = + await import("../../open-sse/services/rateLimitSemaphore.ts"); const { _resetAllDecks } = await import("../../src/shared/utils/shuffleDeck.ts"); function createLog() { @@ -61,7 +60,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3959 strict-random spreads the fallback across healthy peers, not a fixed model", async () => { diff --git a/tests/unit/combo-system-prompt-templates-5501.test.ts b/tests/unit/combo-system-prompt-templates-5501.test.ts index e31e14fde3..06ff50fafd 100644 --- a/tests/unit/combo-system-prompt-templates-5501.test.ts +++ b/tests/unit/combo-system-prompt-templates-5501.test.ts @@ -66,14 +66,20 @@ function bodyWithSystem(content: string) { return { model: "openai/gpt-4o-mini", max_tokens: 100, - messages: [{ role: "system", content }, { role: "user", content: "hi" }], + messages: [ + { role: "system", content }, + { role: "user", content: "hi" }, + ], }; } test("messages format: expands all placeholders in messages[0] system content", () => { const body = { messages: [ - { role: "system", content: "M={{MODEL_ID}} P={{PROVIDER_ID}} A={{ACCOUNT}} F={{FINGERPRINT}}" }, + { + role: "system", + content: "M={{MODEL_ID}} P={{PROVIDER_ID}} A={{ACCOUNT}} F={{FINGERPRINT}}", + }, { role: "user", content: "hi" }, ], }; @@ -113,7 +119,10 @@ test("empty value expands to empty string", () => { test("no placeholders: body unchanged (deep equal)", () => { const body = { - messages: [{ role: "system", content: "plain" }, { role: "user", content: "hi" }], + messages: [ + { role: "system", content: "plain" }, + { role: "user", content: "hi" }, + ], }; const out = expandComboSystemPromptTemplates(body, CTX); assert.deepEqual(out, body); @@ -151,7 +160,11 @@ test("resolveTargetFingerprint: non-fp provider returns null", () => { test("resolveTargetFingerprint: pinned fingerprint wins", () => { assert.equal( - resolveTargetFingerprint({ provider: "opencode", pinnedFingerprint: "pin1", executionKey: "k@fp:abc" }), + resolveTargetFingerprint({ + provider: "opencode", + pinnedFingerprint: "pin1", + executionKey: "k@fp:abc", + }), "pin1" ); }); @@ -176,7 +189,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); @@ -267,4 +280,4 @@ test("round-robin gate: without combo system_message, client system content stay allCombos: null, }); assert.deepEqual(seen, ["keep {{MODEL_ID}} literal"]); -}); \ No newline at end of file +}); diff --git a/tests/unit/combo-target-resolution-split.test.ts b/tests/unit/combo-target-resolution-split.test.ts index 92d95f570a..9f80ff17fd 100644 --- a/tests/unit/combo-target-resolution-split.test.ts +++ b/tests/unit/combo-target-resolution-split.test.ts @@ -30,7 +30,7 @@ test.after(() => { } else { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { diff --git a/tests/unit/combo-test-route.test.ts b/tests/unit/combo-test-route.test.ts index 022732e02c..b70f11fd94 100644 --- a/tests/unit/combo-test-route.test.ts +++ b/tests/unit/combo-test-route.test.ts @@ -19,7 +19,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -55,7 +55,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("combo test route validates request payloads and combo existence", async () => { diff --git a/tests/unit/combo-vision-aware-routing.test.ts b/tests/unit/combo-vision-aware-routing.test.ts index 8d5c186c3f..d77da16bb2 100644 --- a/tests/unit/combo-vision-aware-routing.test.ts +++ b/tests/unit/combo-vision-aware-routing.test.ts @@ -42,7 +42,7 @@ const { deriveRequestCompatibilityRequirements, hasHardCapabilityFailure } = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --- Part A: capability resolution ----------------------------------------- diff --git a/tests/unit/combo/combo-failure-tracker-session-isolation.test.ts b/tests/unit/combo/combo-failure-tracker-session-isolation.test.ts index 7db23c6ce5..5db4619676 100644 --- a/tests/unit/combo/combo-failure-tracker-session-isolation.test.ts +++ b/tests/unit/combo/combo-failure-tracker-session-isolation.test.ts @@ -32,7 +32,7 @@ const failureTracker = await import("../../../open-sse/services/combo/failureTra test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("recordComboFailure clears only the failing session's pin, leaving other sessions on the same combo untouched", () => { diff --git a/tests/unit/combo/connection-aware-expansion.test.ts b/tests/unit/combo/connection-aware-expansion.test.ts index 6dbd2a3f4a..1c4a47bfb3 100644 --- a/tests/unit/combo/connection-aware-expansion.test.ts +++ b/tests/unit/combo/connection-aware-expansion.test.ts @@ -55,7 +55,7 @@ function makeTarget(overrides: Record = {}) { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Gate: strategy + config resolution diff --git a/tests/unit/combo/image-combo.test.ts b/tests/unit/combo/image-combo.test.ts index d122dace10..d455875b96 100644 --- a/tests/unit/combo/image-combo.test.ts +++ b/tests/unit/combo/image-combo.test.ts @@ -62,7 +62,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: unknown) { lastError = error; @@ -220,7 +220,10 @@ test("non-combo bare model names pass through model resolution unchanged", async assert.equal(response.status, 400); const body = await response.json(); const bodyStr = JSON.stringify(body); - assert.ok(bodyStr.includes("not found") || bodyStr.includes("not a valid"), "Combo not found error"); + assert.ok( + bodyStr.includes("not found") || bodyStr.includes("not a valid"), + "Combo not found error" + ); }); test("provider/model format (with slash) is not treated as a combo name", async () => { @@ -279,4 +282,4 @@ test("all error responses from executeImageCombo sanitize stack traces", async ( `Scenario "${scenario.name}" does not leak stack traces` ); } -}); \ No newline at end of file +}); diff --git a/tests/unit/combo/reset-window-strategy-9330.test.ts b/tests/unit/combo/reset-window-strategy-9330.test.ts index 30bfcd43d0..6485056564 100644 --- a/tests/unit/combo/reset-window-strategy-9330.test.ts +++ b/tests/unit/combo/reset-window-strategy-9330.test.ts @@ -42,7 +42,7 @@ const { registerQuotaFetcher } = await import("../../../open-sse/services/quotaP after(() => { dbCore.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/combo/speech-combo.test.ts b/tests/unit/combo/speech-combo.test.ts index 4bd415d830..8972990925 100644 --- a/tests/unit/combo/speech-combo.test.ts +++ b/tests/unit/combo/speech-combo.test.ts @@ -27,7 +27,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: unknown) { lastError = error; diff --git a/tests/unit/combo/strict-context-failopen-8786.test.ts b/tests/unit/combo/strict-context-failopen-8786.test.ts index 68a1e8c75c..29fdb48cc3 100644 --- a/tests/unit/combo/strict-context-failopen-8786.test.ts +++ b/tests/unit/combo/strict-context-failopen-8786.test.ts @@ -22,13 +22,12 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); const { getModelContextLimit } = await import("../../../src/lib/modelCapabilities.ts"); -const { applyContextRequirements } = await import( - "../../../open-sse/services/combo/contextRequirements.ts" -); +const { applyContextRequirements } = + await import("../../../open-sse/services/combo/contextRequirements.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function target(provider: string, modelStr: string) { diff --git a/tests/unit/combo/video-combo.test.ts b/tests/unit/combo/video-combo.test.ts index d429ada930..bb280b161f 100644 --- a/tests/unit/combo/video-combo.test.ts +++ b/tests/unit/combo/video-combo.test.ts @@ -59,7 +59,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: unknown) { lastError = error; diff --git a/tests/unit/combos-duplicate-resolution-audit.test.ts b/tests/unit/combos-duplicate-resolution-audit.test.ts index ea304e8a85..78d7bf21c6 100644 --- a/tests/unit/combos-duplicate-resolution-audit.test.ts +++ b/tests/unit/combos-duplicate-resolution-audit.test.ts @@ -22,7 +22,7 @@ const { resolveBuiltinAutoSpec } = test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/combos-duplicate-route.test.ts b/tests/unit/combos-duplicate-route.test.ts index 447c26583b..5e957d8a9e 100644 --- a/tests/unit/combos-duplicate-route.test.ts +++ b/tests/unit/combos-duplicate-route.test.ts @@ -38,7 +38,7 @@ function makePostRequest(url: string, body: unknown, apiKey?: string): Request { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/combos-quota-protected.test.ts b/tests/unit/combos-quota-protected.test.ts index cf2c4ad6ce..63de82ce00 100644 --- a/tests/unit/combos-quota-protected.test.ts +++ b/tests/unit/combos-quota-protected.test.ts @@ -13,7 +13,7 @@ const comboRoute = await import("../../src/app/api/combos/[id]/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ---- quota-protected combos ---- diff --git a/tests/unit/command-code-auth-assist.test.ts b/tests/unit/command-code-auth-assist.test.ts index f8ca2c8a66..0972d8a981 100644 --- a/tests/unit/command-code-auth-assist.test.ts +++ b/tests/unit/command-code-auth-assist.test.ts @@ -19,7 +19,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Command Code auth assist start/callback/status/apply keeps state hash and key private", async () => { diff --git a/tests/unit/command-code-executor.test.ts b/tests/unit/command-code-executor.test.ts index 247aab2dea..01ee533af3 100644 --- a/tests/unit/command-code-executor.test.ts +++ b/tests/unit/command-code-executor.test.ts @@ -72,7 +72,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Command Code provider catalog has pinned models and alias lookup", () => { @@ -232,7 +232,9 @@ test("Command Code executor passes the upstream OpenAI SSE stream through untouc }); }; - const { response } = await (await getExecutor("command-code")).execute({ + const { response } = await ( + await getExecutor("command-code") + ).execute({ model: "gpt-5.4", stream: true, credentials: { apiKey: "cc_test_key" }, @@ -268,7 +270,9 @@ test("Command Code executor passes the upstream OpenAI JSON through untouched (n }); }; - const { response } = await (await getExecutor("command-code")).execute({ + const { response } = await ( + await getExecutor("command-code") + ).execute({ model: "gpt-5.4-mini", stream: false, credentials: { apiKey: "cc_test_key" }, @@ -280,8 +284,11 @@ test("Command Code executor passes the upstream OpenAI JSON through untouched (n }); test("Command Code executor surfaces upstream errors", async () => { - globalThis.fetch = async () => new Response("bad key", { status: 401, statusText: "Unauthorized" }); - const upstreamFailure = await (await getExecutor("command-code")).execute({ + globalThis.fetch = async () => + new Response("bad key", { status: 401, statusText: "Unauthorized" }); + const upstreamFailure = await ( + await getExecutor("command-code") + ).execute({ model: "gpt-5.4-mini", stream: false, credentials: { apiKey: "cc_test_key" }, @@ -352,7 +359,9 @@ test("Command Code stream preserves the upstream OpenAI usage chunk (passthrough globalThis.fetch = async () => new Response(sse, { status: 200, headers: { "Content-Type": "text/event-stream" } }); - const { response } = await (await getExecutor("command-code")).execute({ + const { response } = await ( + await getExecutor("command-code") + ).execute({ model: "gpt-5.4-mini", stream: true, credentials: { apiKey: "cc_test_key" }, @@ -409,7 +418,9 @@ test("Command Code executor falls back to /alpha/generate on 403 (e.g. Go plan w return new Response("Not found", { status: 404 }); }; - const { response, url, headers } = await (await getExecutor("command-code")).execute({ + const { response, url, headers } = await ( + await getExecutor("command-code") + ).execute({ model: "deepseek/deepseek-v4-flash", stream: true, credentials: { apiKey: "cc_go_plan_key" }, @@ -456,7 +467,9 @@ test("Command Code executor falls back to /alpha/generate on 403 (Go plan) for n return new Response("Not found", { status: 404 }); }; - const { response } = await (await getExecutor("command-code")).execute({ + const { response } = await ( + await getExecutor("command-code") + ).execute({ model: "gpt-5.4", stream: false, credentials: { apiKey: "cc_go_plan_key" }, @@ -484,7 +497,9 @@ test("Command Code executor surfaces fallback error when both /provider/v1 and / return new Response("error", { status: 500 }); }; - const result = await (await getExecutor("command-code")).execute({ + const result = await ( + await getExecutor("command-code") + ).execute({ model: "gpt-5.4", stream: false, credentials: { apiKey: "cc_key" }, diff --git a/tests/unit/command-code-user-array-5166.test.ts b/tests/unit/command-code-user-array-5166.test.ts index cb4cd5f682..fb6838867c 100644 --- a/tests/unit/command-code-user-array-5166.test.ts +++ b/tests/unit/command-code-user-array-5166.test.ts @@ -30,7 +30,7 @@ function okResponse() { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.afterEach(() => { diff --git a/tests/unit/command-code-vision.test.ts b/tests/unit/command-code-vision.test.ts index 5af6176a49..bf55bf0678 100644 --- a/tests/unit/command-code-vision.test.ts +++ b/tests/unit/command-code-vision.test.ts @@ -30,7 +30,7 @@ function okResponse() { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.afterEach(() => { diff --git a/tests/unit/compliance-audit-route.test.ts b/tests/unit/compliance-audit-route.test.ts index 51e4fc9c09..4004ddd25b 100644 --- a/tests/unit/compliance-audit-route.test.ts +++ b/tests/unit/compliance-audit-route.test.ts @@ -13,7 +13,7 @@ const auditRoute = await import("../../src/app/api/compliance/audit-log/route.ts function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -23,7 +23,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("compliance audit route keeps array payloads and exposes total count with structured filters", async () => { diff --git a/tests/unit/compliance-index.test.ts b/tests/unit/compliance-index.test.ts index f99a5a4b26..7d94572487 100644 --- a/tests/unit/compliance-index.test.ts +++ b/tests/unit/compliance-index.test.ts @@ -15,7 +15,7 @@ const compliance = await import("../../src/lib/compliance/index.ts"); function resetDb() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -26,7 +26,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("compliance audit log initialization, writes and filtered reads work end to end", () => { diff --git a/tests/unit/compression-settings-cache.test.ts b/tests/unit/compression-settings-cache.test.ts index 729e4c8a25..00b50ce90f 100644 --- a/tests/unit/compression-settings-cache.test.ts +++ b/tests/unit/compression-settings-cache.test.ts @@ -24,7 +24,7 @@ function cleanup() { delete process.env.DATA_DIR; } try { - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} } @@ -81,11 +81,26 @@ test("getCompressionSettings returned config has expected shape", async () => { assert.ok(typeof config.defaultMode === "string", "defaultMode should be string"); assert.ok(typeof config.autoTriggerTokens === "number", "autoTriggerTokens should be number"); assert.ok(typeof config.cacheMinutes === "number", "cacheMinutes should be number"); - assert.ok(typeof config.preserveSystemPrompt === "boolean", "preserveSystemPrompt should be boolean"); - assert.ok(config.cavemanConfig && typeof config.cavemanConfig === "object", "cavemanConfig should be object"); - assert.ok(config.rtkConfig && typeof config.rtkConfig === "object", "rtkConfig should be object"); - assert.ok(config.languageConfig && typeof config.languageConfig === "object", "languageConfig should be object"); - assert.ok(config.aggressive && typeof config.aggressive === "object", "aggressive should be object"); + assert.ok( + typeof config.preserveSystemPrompt === "boolean", + "preserveSystemPrompt should be boolean" + ); + assert.ok( + config.cavemanConfig && typeof config.cavemanConfig === "object", + "cavemanConfig should be object" + ); + assert.ok( + config.rtkConfig && typeof config.rtkConfig === "object", + "rtkConfig should be object" + ); + assert.ok( + config.languageConfig && typeof config.languageConfig === "object", + "languageConfig should be object" + ); + assert.ok( + config.aggressive && typeof config.aggressive === "object", + "aggressive should be object" + ); assert.ok(config.ultra && typeof config.ultra === "object", "ultra should be object"); } finally { cleanup(); diff --git a/tests/unit/compression-tokens.test.ts b/tests/unit/compression-tokens.test.ts index a7a5a422b8..743892b40f 100644 --- a/tests/unit/compression-tokens.test.ts +++ b/tests/unit/compression-tokens.test.ts @@ -68,31 +68,19 @@ test("tokensCompressed round-trips through saveCallLog → getCallLogs", async ( limit: 10, }); - const logNull = logs.find( - (l: { id: string }) => l.id === "log-null" - ); - const logComp = logs.find( - (l: { id: string }) => l.id === "log-350" - ); + const logNull = logs.find((l: { id: string }) => l.id === "log-null"); + const logComp = logs.find((l: { id: string }) => l.id === "log-350"); // null when no compression - assert.equal( - logNull.tokens?.compressed, - null, - "uncompressed log should have null compressed" - ); + assert.equal(logNull.tokens?.compressed, null, "uncompressed log should have null compressed"); // Positive value when compressed - assert.equal( - logComp.tokens?.compressed, - 350, - "compressed log should store exact token delta" - ); + assert.equal(logComp.tokens?.compressed, 350, "compressed log should store exact token delta"); // Input tokens unaffected assert.equal(logComp.tokens?.in, 1000); assert.equal(logComp.tokens?.out, 500); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/compression/active-combo-integration.test.ts b/tests/unit/compression/active-combo-integration.test.ts index 09e1c641cd..4aa57c2edd 100644 --- a/tests/unit/compression/active-combo-integration.test.ts +++ b/tests/unit/compression/active-combo-integration.test.ts @@ -11,12 +11,14 @@ process.env.DATA_DIR = TEST_DATA_DIR; const { getDbInstance, resetDbInstance } = await import("../../../src/lib/db/core.ts"); const combosDb = await import("../../../src/lib/db/compressionCombos.ts"); const { updateCompressionSettings } = await import("../../../src/lib/db/compression.ts"); -const { selectCompressionPlan } = await import("../../../open-sse/services/compression/strategySelector.ts"); -const { DEFAULT_COMPRESSION_CONFIG } = await import("../../../open-sse/services/compression/types.ts"); +const { selectCompressionPlan } = + await import("../../../open-sse/services/compression/strategySelector.ts"); +const { DEFAULT_COMPRESSION_CONFIG } = + await import("../../../open-sse/services/compression/types.ts"); after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL; }); @@ -31,7 +33,9 @@ test("an active named combo's pipeline is what selectCompressionPlan resolves, f await updateCompressionSettings({ enabled: true, activeComboId: created.id }); // Mirror chatCore's load: build the combos map from the DB. - const combos = Object.fromEntries(combosDb.listCompressionCombos().map((c) => [c.id, c.pipeline])); + const combos = Object.fromEntries( + combosDb.listCompressionCombos().map((c) => [c.id, c.pipeline]) + ); const config = { ...DEFAULT_COMPRESSION_CONFIG, enabled: true, activeComboId: created.id }; const plan = selectCompressionPlan(config, null, 5000, undefined, undefined, combos); assert.equal(plan.mode, "stacked"); diff --git a/tests/unit/compression/adaptive-context-budget-config.test.ts b/tests/unit/compression/adaptive-context-budget-config.test.ts index 4dd4acb68c..7f92117d7a 100644 --- a/tests/unit/compression/adaptive-context-budget-config.test.ts +++ b/tests/unit/compression/adaptive-context-budget-config.test.ts @@ -19,19 +19,16 @@ const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); -const { getCompressionSettings, updateCompressionSettings } = await import( - "../../../src/lib/db/compression.ts" -); -const { compressionSettingsUpdateSchema } = await import( - "../../../src/shared/validation/compressionConfigSchemas.ts" -); -const { DEFAULT_CONTEXT_BUDGET } = await import( - "../../../open-sse/services/compression/adaptiveCompression/types.ts" -); +const { getCompressionSettings, updateCompressionSettings } = + await import("../../../src/lib/db/compression.ts"); +const { compressionSettingsUpdateSchema } = + await import("../../../src/shared/validation/compressionConfigSchemas.ts"); +const { DEFAULT_CONTEXT_BUDGET } = + await import("../../../open-sse/services/compression/adaptiveCompression/types.ts"); beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -41,7 +38,7 @@ afterEach(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { @@ -71,7 +68,12 @@ describe("bug #7005: adaptive context-budget dial is configurable", () => { it("updateCompressionSettings() persists a partial contextBudget merge", async () => { await updateCompressionSettings({ - contextBudget: { ...DEFAULT_CONTEXT_BUDGET, mode: "floor", policy: "absolute", absoluteBudget: 8000 }, + contextBudget: { + ...DEFAULT_CONTEXT_BUDGET, + mode: "floor", + policy: "absolute", + absoluteBudget: 8000, + }, }); const settings = await getCompressionSettings(); assert.equal(settings.contextBudget?.mode, "floor"); diff --git a/tests/unit/compression/caveman-db.test.ts b/tests/unit/compression/caveman-db.test.ts index b1cd5f8592..2257c9abb9 100644 --- a/tests/unit/compression/caveman-db.test.ts +++ b/tests/unit/compression/caveman-db.test.ts @@ -16,7 +16,7 @@ const { getCompressionSettings, updateCompressionSettings } = describe("compression DB module", () => { beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -26,7 +26,7 @@ describe("compression DB module", () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/compression/compareRoute.test.ts b/tests/unit/compression/compareRoute.test.ts index c3d75f7b0e..ae6a268053 100644 --- a/tests/unit/compression/compareRoute.test.ts +++ b/tests/unit/compression/compareRoute.test.ts @@ -11,18 +11,27 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/compare/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/compare", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("ranks a high-savings engine above a no-op for repetitive tool output", async () => { - const text = ["$ npm install", + const text = [ + "$ npm install", "npm warn deprecated glob@7.2.3: no longer supported", "npm warn deprecated glob@7.2.3: no longer supported", "npm warn deprecated glob@7.2.3: no longer supported", - "added 1234 packages"].join("\n"); - const res = await route.POST(makeReq({ messages: [{ role: "user", content: text }], engineIds: ["rtk", "lite"] })); + "added 1234 packages", + ].join("\n"); + const res = await route.POST( + makeReq({ messages: [{ role: "user", content: text }], engineIds: ["rtk", "lite"] }) + ); assert.equal(res.status, 200); const body = await res.json(); assert.ok(Array.isArray(body.rows) && body.rows.length === 2); diff --git a/tests/unit/compression/compression-combos-db.test.ts b/tests/unit/compression/compression-combos-db.test.ts index 0b58800334..14cd61be95 100644 --- a/tests/unit/compression/compression-combos-db.test.ts +++ b/tests/unit/compression/compression-combos-db.test.ts @@ -13,7 +13,7 @@ const combosDb = await import("../../../src/lib/db/compressionCombos.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -23,7 +23,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/compression/compression-engines-map-migration.test.ts b/tests/unit/compression/compression-engines-map-migration.test.ts index d315c737e5..d7ed99624b 100644 --- a/tests/unit/compression/compression-engines-map-migration.test.ts +++ b/tests/unit/compression/compression-engines-map-migration.test.ts @@ -9,19 +9,18 @@ const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; const { getDbInstance, resetDbInstance } = await import("../../../src/lib/db/core.ts"); -const { getCompressionSettings, updateCompressionSettings } = await import( - "../../../src/lib/db/compression.ts" -); +const { getCompressionSettings, updateCompressionSettings } = + await import("../../../src/lib/db/compression.ts"); function freshDir() { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/compression/compression-preview-auth.test.ts b/tests/unit/compression/compression-preview-auth.test.ts index b5bfb1332e..0e6ebc5553 100644 --- a/tests/unit/compression/compression-preview-auth.test.ts +++ b/tests/unit/compression/compression-preview-auth.test.ts @@ -24,7 +24,7 @@ type ErrorResponseBody = { async function resetAuthRequiredStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -44,7 +44,7 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("compression preview requires management auth before reading preview input", async () => { diff --git a/tests/unit/compression/compressionAnalytics.test.ts b/tests/unit/compression/compressionAnalytics.test.ts index eaef7898df..7402059c82 100644 --- a/tests/unit/compression/compressionAnalytics.test.ts +++ b/tests/unit/compression/compressionAnalytics.test.ts @@ -42,7 +42,7 @@ describe("compressionAnalytics", () => { after(() => { core.closeDbInstance(); - rmSync(tmpDir, { recursive: true, force: true }); + rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("empty table returns zeroed summary", () => { diff --git a/tests/unit/compression/db.test.ts b/tests/unit/compression/db.test.ts index 1861e71dcf..957cdbf899 100644 --- a/tests/unit/compression/db.test.ts +++ b/tests/unit/compression/db.test.ts @@ -14,7 +14,7 @@ const { getCompressionSettings, updateCompressionSettings } = beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -24,7 +24,7 @@ afterEach(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/compression/headroom-minrows-persist-8056.test.ts b/tests/unit/compression/headroom-minrows-persist-8056.test.ts index de52eb5b11..717af14673 100644 --- a/tests/unit/compression/headroom-minrows-persist-8056.test.ts +++ b/tests/unit/compression/headroom-minrows-persist-8056.test.ts @@ -32,7 +32,7 @@ const { getCompressionSettings, updateCompressionSettings } = beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -42,7 +42,7 @@ afterEach(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/compression/llmlingua-model-store.test.ts b/tests/unit/compression/llmlingua-model-store.test.ts index 0459432b5b..18f820a573 100644 --- a/tests/unit/compression/llmlingua-model-store.test.ts +++ b/tests/unit/compression/llmlingua-model-store.test.ts @@ -87,7 +87,7 @@ describe("getLlmlinguaModelCacheDir", () => { } if (tmpDir) { try { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ignore cleanup errors */ } diff --git a/tests/unit/compression/llmlingua-worker-resolution.test.ts b/tests/unit/compression/llmlingua-worker-resolution.test.ts index cd7df8e9ac..356ef718fd 100644 --- a/tests/unit/compression/llmlingua-worker-resolution.test.ts +++ b/tests/unit/compression/llmlingua-worker-resolution.test.ts @@ -67,7 +67,7 @@ test("firstAncestorWith walks up from anchors to find a marker", () => { assert.equal(found, path.join(tmp, "dist"), "must find the dist root by walking up"); assert.equal(firstAncestorWith([anchor], path.join("node_modules", "nope")), null); } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/compression/mcp-accessibility-config.test.ts b/tests/unit/compression/mcp-accessibility-config.test.ts index 96431eddfb..da14e4d30d 100644 --- a/tests/unit/compression/mcp-accessibility-config.test.ts +++ b/tests/unit/compression/mcp-accessibility-config.test.ts @@ -24,7 +24,7 @@ const route = await import("../../../src/app/api/settings/compression/mcp-access function resetDir() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ describe("mcpAccessibility config reachability", () => { afterEach(() => core.resetDbInstance()); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/compression/omniglyph-profile-config.test.ts b/tests/unit/compression/omniglyph-profile-config.test.ts index d24f361bae..4d16e4d314 100644 --- a/tests/unit/compression/omniglyph-profile-config.test.ts +++ b/tests/unit/compression/omniglyph-profile-config.test.ts @@ -21,13 +21,12 @@ const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); -const { getCompressionSettings, updateCompressionSettings } = await import( - "../../../src/lib/db/compression.ts" -); +const { getCompressionSettings, updateCompressionSettings } = + await import("../../../src/lib/db/compression.ts"); beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -37,7 +36,7 @@ afterEach(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/compression/omniglyph-registries.test.ts b/tests/unit/compression/omniglyph-registries.test.ts index 895f1c54e2..5737c3c6fc 100644 --- a/tests/unit/compression/omniglyph-registries.test.ts +++ b/tests/unit/compression/omniglyph-registries.test.ts @@ -25,13 +25,13 @@ const { compressionConfigureInput } = await import("../../../open-sse/mcp-server beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/compression/preserve-system-prompt-mode-db.test.ts b/tests/unit/compression/preserve-system-prompt-mode-db.test.ts index ab3ae491f7..662524cbfc 100644 --- a/tests/unit/compression/preserve-system-prompt-mode-db.test.ts +++ b/tests/unit/compression/preserve-system-prompt-mode-db.test.ts @@ -38,7 +38,7 @@ test.after(async () => { /* core never loaded */ } try { - fs.rmSync(TEMP_DIR, { recursive: true, force: true }); + fs.rmSync(TEMP_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best-effort */ } @@ -59,9 +59,8 @@ test("legacy preserveSystemPrompt=false (no mode row) derives whenNoCache", asyn ); // End-to-end: without a cacheable prefix, a legacy-off install must still compress the prompt. - const { resolveCacheAwareConfig } = await import( - "../../../open-sse/services/compression/cacheAwareConfig.ts" - ); + const { resolveCacheAwareConfig } = + await import("../../../open-sse/services/compression/cacheAwareConfig.ts"); assert.equal( resolveCacheAwareConfig(cfg).preserveSystemPrompt, false, diff --git a/tests/unit/compression/preview-fallback-reasons-6461.test.ts b/tests/unit/compression/preview-fallback-reasons-6461.test.ts index 4de93f128f..4b15d63e6c 100644 --- a/tests/unit/compression/preview-fallback-reasons-6461.test.ts +++ b/tests/unit/compression/preview-fallback-reasons-6461.test.ts @@ -29,7 +29,7 @@ function makeReq(body: unknown) { test.beforeEach(() => core.resetDbInstance()); test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6461 preview exposes fallbackReasons and mirrors it into skippedReasons", async () => { diff --git a/tests/unit/compression/preview-outer-engine-token-reconcile-6488.test.ts b/tests/unit/compression/preview-outer-engine-token-reconcile-6488.test.ts index 0d7d01da9b..2096bff502 100644 --- a/tests/unit/compression/preview-outer-engine-token-reconcile-6488.test.ts +++ b/tests/unit/compression/preview-outer-engine-token-reconcile-6488.test.ts @@ -22,7 +22,7 @@ function makeReq(body: unknown) { test.beforeEach(() => core.resetDbInstance()); test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression for #6488: outer originalTokens/compressedTokens (real tiktoken counter over diff --git a/tests/unit/compression/previewRouteBreakdown.test.ts b/tests/unit/compression/previewRouteBreakdown.test.ts index a4053bd73c..10de10f393 100644 --- a/tests/unit/compression/previewRouteBreakdown.test.ts +++ b/tests/unit/compression/previewRouteBreakdown.test.ts @@ -11,16 +11,23 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/preview/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/preview", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("response carries a non-empty engineBreakdown for a single engine", async () => { - const res = await route.POST(makeReq({ - messages: [{ role: "user", content: "$ git status\nOn branch main\nnothing to commit" }], - engineId: "rtk", - })); + const res = await route.POST( + makeReq({ + messages: [{ role: "user", content: "$ git status\nOn branch main\nnothing to commit" }], + engineId: "rtk", + }) + ); assert.equal(res.status, 200); const body = await res.json(); assert.ok(Array.isArray(body.engineBreakdown)); diff --git a/tests/unit/compression/previewRouteFidelity.test.ts b/tests/unit/compression/previewRouteFidelity.test.ts index b87f70b6b4..8cc54f1f9f 100644 --- a/tests/unit/compression/previewRouteFidelity.test.ts +++ b/tests/unit/compression/previewRouteFidelity.test.ts @@ -11,26 +11,37 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/preview/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/preview", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("fidelityGate flag is accepted (200) and preview still works", async () => { - const res = await route.POST(makeReq({ - messages: [{ role: "user", content: "$ git status\nOn branch main" }], - engineId: "rtk", fidelityGate: { enabled: true }, - })); + const res = await route.POST( + makeReq({ + messages: [{ role: "user", content: "$ git status\nOn branch main" }], + engineId: "rtk", + fidelityGate: { enabled: true }, + }) + ); assert.equal(res.status, 200); const body = await res.json(); assert.ok(Array.isArray(body.engineBreakdown)); }); test("malformed fidelityGate is rejected (proves the field is in the schema, not stripped)", async () => { - const res = await route.POST(makeReq({ - messages: [{ role: "user", content: "x" }], - engineId: "rtk", fidelityGate: { enabled: "yes" }, // wrong type - })); + const res = await route.POST( + makeReq({ + messages: [{ role: "user", content: "x" }], + engineId: "rtk", + fidelityGate: { enabled: "yes" }, // wrong type + }) + ); assert.equal(res.status, 400); }); diff --git a/tests/unit/compression/previewRouteFuzzy.test.ts b/tests/unit/compression/previewRouteFuzzy.test.ts index 3b4b31159c..f08d2c99ba 100644 --- a/tests/unit/compression/previewRouteFuzzy.test.ts +++ b/tests/unit/compression/previewRouteFuzzy.test.ts @@ -11,28 +11,42 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/preview/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/preview", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); const A = "alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu nu xi omicron pi rho"; test("fuzzyDedup flag drives the session-dedup lane to produce a CCR marker", async () => { - const res = await route.POST(makeReq({ - messages: [{ role: "user", content: A }, { role: "user", content: A + " sigma" }], - engineId: "session-dedup", - fuzzyDedup: { enabled: true }, - })); + const res = await route.POST( + makeReq({ + messages: [ + { role: "user", content: A }, + { role: "user", content: A + " sigma" }, + ], + engineId: "session-dedup", + fuzzyDedup: { enabled: true }, + }) + ); assert.equal(res.status, 200); const body = await res.json(); assert.match(body.compressed, /\[CCR retrieve hash=[0-9a-f]{24}/); }); test("malformed fuzzyDedup is rejected (field is in the schema, not stripped)", async () => { - const res = await route.POST(makeReq({ - messages: [{ role: "user", content: "x" }], engineId: "session-dedup", fuzzyDedup: { enabled: "yes" }, - })); + const res = await route.POST( + makeReq({ + messages: [{ role: "user", content: "x" }], + engineId: "session-dedup", + fuzzyDedup: { enabled: "yes" }, + }) + ); assert.equal(res.status, 400); }); diff --git a/tests/unit/compression/previewRouteIonizer.test.ts b/tests/unit/compression/previewRouteIonizer.test.ts index eebcb0989d..81e370275b 100644 --- a/tests/unit/compression/previewRouteIonizer.test.ts +++ b/tests/unit/compression/previewRouteIonizer.test.ts @@ -12,16 +12,26 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/preview/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/preview", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("the ionizer lane samples an oversized JSON array into a CCR marker", async () => { const big = JSON.stringify(Array.from({ length: 400 }, (_, i) => ({ i, v: `r${i}` }))); - const res = await route.POST(makeReq({ messages: [{ role: "user", content: big }], engineId: "ionizer" })); + const res = await route.POST( + makeReq({ messages: [{ role: "user", content: big }], engineId: "ionizer" }) + ); assert.equal(res.status, 200); const body = await res.json(); - assert.match(body.compressed, /\[ionizer: kept \d+\/400 rows; full → CCR retrieve hash=[0-9a-f]{24}/); + assert.match( + body.compressed, + /\[ionizer: kept \d+\/400 rows; full → CCR retrieve hash=[0-9a-f]{24}/ + ); }); diff --git a/tests/unit/compression/previewRoutePipeline.test.ts b/tests/unit/compression/previewRoutePipeline.test.ts index b90ddfcc73..e3f0f1bde7 100644 --- a/tests/unit/compression/previewRoutePipeline.test.ts +++ b/tests/unit/compression/previewRoutePipeline.test.ts @@ -11,14 +11,22 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/preview/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/preview", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("pipeline runs the engines in the GIVEN order (reversed vs default rtk→caveman)", async () => { - const text = "$ pytest\ntests/a.py ....\nbasically what I mean is that you should loop through them one by one"; - const res = await route.POST(makeReq({ messages: [{ role: "user", content: text }], pipeline: ["caveman", "rtk"] })); + const text = + "$ pytest\ntests/a.py ....\nbasically what I mean is that you should loop through them one by one"; + const res = await route.POST( + makeReq({ messages: [{ role: "user", content: text }], pipeline: ["caveman", "rtk"] }) + ); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.mode, "stacked"); @@ -28,14 +36,18 @@ test("pipeline runs the engines in the GIVEN order (reversed vs default rtk→ca }); test("pipeline accepts the 4 schema-restricted engines and does NOT fall back to the default rtk/caveman", async () => { - const res = await route.POST(makeReq({ - messages: [{ role: "user", content: "x".repeat(80) }], - pipeline: ["session-dedup", "headroom"], - })); + const res = await route.POST( + makeReq({ + messages: [{ role: "user", content: "x".repeat(80) }], + pipeline: ["session-dedup", "headroom"], + }) + ); assert.equal(res.status, 200); // would be 400 if it went through the strict config schema const body = await res.json(); // Discriminating: if `pipeline` were stripped, this would be the default rtk→caveman cascade. assert.ok( - body.engineBreakdown.every((e: { engine: string }) => e.engine !== "rtk" && e.engine !== "caveman") + body.engineBreakdown.every( + (e: { engine: string }) => e.engine !== "rtk" && e.engine !== "caveman" + ) ); }); diff --git a/tests/unit/compression/previewRouteTokens.test.ts b/tests/unit/compression/previewRouteTokens.test.ts index b0b36d313b..2f639da84f 100644 --- a/tests/unit/compression/previewRouteTokens.test.ts +++ b/tests/unit/compression/previewRouteTokens.test.ts @@ -15,15 +15,22 @@ const { countTextTokens } = await import("../../../src/shared/utils/tiktokenCoun function makeReq(body: unknown) { return new Request("http://localhost/api/compression/preview", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("originalTokens equals countTextTokens, not the *1.33 estimate", async () => { const text = "the quick brown fox jumps over the lazy dog repeatedly and often"; - const res = await route.POST(makeReq({ messages: [{ role: "user", content: text }], mode: "off" })); + const res = await route.POST( + makeReq({ messages: [{ role: "user", content: text }], mode: "off" }) + ); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.originalTokens, countTextTokens(body.original)); diff --git a/tests/unit/compression/previewRouteToon.test.ts b/tests/unit/compression/previewRouteToon.test.ts index f10d9dcbd9..d912e77b08 100644 --- a/tests/unit/compression/previewRouteToon.test.ts +++ b/tests/unit/compression/previewRouteToon.test.ts @@ -20,7 +20,7 @@ function makeReq(body: unknown) { test.beforeEach(() => core.resetDbInstance()); test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("headroom engine carries encoderComparison with one array and a valid winner", async () => { diff --git a/tests/unit/compression/retrieveRoute.test.ts b/tests/unit/compression/retrieveRoute.test.ts index cbff7a447c..14f342086e 100644 --- a/tests/unit/compression/retrieveRoute.test.ts +++ b/tests/unit/compression/retrieveRoute.test.ts @@ -11,11 +11,16 @@ const core = await import("../../../src/lib/db/core.ts"); const route = await import("../../../src/app/api/compression/retrieve/route.ts"); function makeReq(body: unknown) { return new Request("http://localhost/api/compression/retrieve", { - method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), }); } test.beforeEach(() => core.resetDbInstance()); -test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); +test.after(() => { + core.resetDbInstance(); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); test("400 when hash is missing", async () => { const res = await route.POST(makeReq({})); assert.equal(res.status, 400); diff --git a/tests/unit/compression/retrieveRouteRanged.test.ts b/tests/unit/compression/retrieveRouteRanged.test.ts index a1dd2a941e..3f002e1872 100644 --- a/tests/unit/compression/retrieveRouteRanged.test.ts +++ b/tests/unit/compression/retrieveRouteRanged.test.ts @@ -24,7 +24,7 @@ test.beforeEach(() => { }); test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("mode:head n:2 returns first 2 lines", async () => { diff --git a/tests/unit/compression/rtk-command-samples.test.ts b/tests/unit/compression/rtk-command-samples.test.ts index b352e38647..81fbfbd5eb 100644 --- a/tests/unit/compression/rtk-command-samples.test.ts +++ b/tests/unit/compression/rtk-command-samples.test.ts @@ -35,7 +35,7 @@ beforeEach(() => { afterEach(() => { if (prevDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = prevDataDir; - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("maybePersistRtkRawOutput — command sidecar", () => { diff --git a/tests/unit/compression/rtk-grouping-config.test.ts b/tests/unit/compression/rtk-grouping-config.test.ts index 6a65b1b6e3..8426af9e19 100644 --- a/tests/unit/compression/rtk-grouping-config.test.ts +++ b/tests/unit/compression/rtk-grouping-config.test.ts @@ -16,14 +16,13 @@ const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); -const { getCompressionSettings, updateCompressionSettings } = await import( - "../../../src/lib/db/compression.ts" -); +const { getCompressionSettings, updateCompressionSettings } = + await import("../../../src/lib/db/compression.ts"); describe("RTK grouping config persistence (R5)", () => { beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -33,7 +32,7 @@ describe("RTK grouping config persistence (R5)", () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/compression/rtk-mcp-tools.test.ts b/tests/unit/compression/rtk-mcp-tools.test.ts index aefba54d0b..b79af21907 100644 --- a/tests/unit/compression/rtk-mcp-tools.test.ts +++ b/tests/unit/compression/rtk-mcp-tools.test.ts @@ -10,12 +10,10 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omni-rtk-mcp-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); -const { handleRtkDiscover, handleRtkLearn } = await import( - "../../../open-sse/mcp-server/tools/compressionTools.ts" -); -const { maybePersistRtkRawOutput } = await import( - "../../../open-sse/services/compression/engines/rtk/rawOutput.ts" -); +const { handleRtkDiscover, handleRtkLearn } = + await import("../../../open-sse/mcp-server/tools/compressionTools.ts"); +const { maybePersistRtkRawOutput } = + await import("../../../open-sse/services/compression/engines/rtk/rawOutput.ts"); const { getRecentAuditEntries } = await import("../../../open-sse/mcp-server/audit.ts"); const NOISE = [ @@ -42,14 +40,14 @@ function seedSamples() { beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); // run migrations → mcp_tool_audit table exists }); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("RTK MCP tools (T07)", () => { @@ -66,7 +64,10 @@ describe("RTK MCP tools (T07)", () => { const result = await handleRtkLearn({ command: "gradle build", limit: 100 }); assert.equal(result.command, "gradle build"); assert.ok(result.sampleCount >= 1, "expected at least one matching sample"); - assert.ok(result.filter && typeof result.filter === "object", "expected a suggested filter draft"); + assert.ok( + result.filter && typeof result.filter === "object", + "expected a suggested filter draft" + ); }); it("returns an empty/baseline result with no samples (no throw)", async () => { diff --git a/tests/unit/compression/rtk-raw-output-route.test.ts b/tests/unit/compression/rtk-raw-output-route.test.ts index 0ab56c1928..7eca439114 100644 --- a/tests/unit/compression/rtk-raw-output-route.test.ts +++ b/tests/unit/compression/rtk-raw-output-route.test.ts @@ -23,7 +23,7 @@ type ErrorResponseBody = { async function resetAuthRequiredStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: true, @@ -43,7 +43,7 @@ test.after(() => { if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("RTK raw-output route requires management auth before reading retained output", async () => { diff --git a/tests/unit/compression/rtk-renderers-config.test.ts b/tests/unit/compression/rtk-renderers-config.test.ts index 2be878169d..86812f8241 100644 --- a/tests/unit/compression/rtk-renderers-config.test.ts +++ b/tests/unit/compression/rtk-renderers-config.test.ts @@ -22,7 +22,7 @@ describe("RTK renderer config persistence", () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/compression/rtk-strip-comments.test.ts b/tests/unit/compression/rtk-strip-comments.test.ts index f9b70963ab..39d31a7662 100644 --- a/tests/unit/compression/rtk-strip-comments.test.ts +++ b/tests/unit/compression/rtk-strip-comments.test.ts @@ -4,10 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { - applyRtkCompression, - stripCode, -} from "../../../open-sse/services/compression/index.ts"; +import { applyRtkCompression, stripCode } from "../../../open-sse/services/compression/index.ts"; import { rtkConfigSchema } from "../../../src/shared/validation/compressionConfigSchemas.ts"; import { DEFAULT_RTK_CONFIG } from "../../../open-sse/services/compression/types.ts"; @@ -22,9 +19,8 @@ const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../../src/lib/db/core.ts"); -const { getCompressionSettings, updateCompressionSettings } = await import( - "../../../src/lib/db/compression.ts" -); +const { getCompressionSettings, updateCompressionSettings } = + await import("../../../src/lib/db/compression.ts"); describe("RTK strip-code-comments — stripCode behavior", () => { it("removes line/block comments but keeps JSDoc when preserveDocstrings is on", () => { @@ -99,7 +95,7 @@ describe("RTK strip-code-comments — runtime reachability", () => { describe("RTK strip-code-comments — config persistence", () => { beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -109,7 +105,7 @@ describe("RTK strip-code-comments — config persistence", () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/conductor-a2a-post.test.ts b/tests/unit/conductor-a2a-post.test.ts index 7cbae0e4d6..801da19606 100644 --- a/tests/unit/conductor-a2a-post.test.ts +++ b/tests/unit/conductor-a2a-post.test.ts @@ -32,12 +32,18 @@ function delegationRequest(body: unknown, bearer?: string) { const VALID_BODY = { skill: "conductor-cli-claude", messages: [{ role: "user", content: "adicione um README com a seção Sobre" }], - metadata: { conductor: { repo: { url: "https://git.x/repo", base_ref: "dev" }, mode: "solo", model: "cc/claude-sonnet-5" } }, + metadata: { + conductor: { + repo: { url: "https://git.x/repo", base_ref: "dev" }, + mode: "solo", + model: "cc/claude-sonnet-5", + }, + }, }; test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.CONDUCTOR_HUB_URL; delete process.env.OMNIROUTE_API_KEY; @@ -45,7 +51,7 @@ test.beforeEach(() => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.CONDUCTOR_HUB_URL; delete process.env.OMNIROUTE_API_KEY; while (servers.length > 0) { @@ -91,7 +97,11 @@ test("delegação válida → 201 com o task_id do hub; requirements derivados d const out = await res.json(); assert.equal(out.conductor_task_id, "t_delegada"); assert.equal(out.state, "submitted"); - const sent = bodies[0] as { repo: { url: string; base_ref: string }; spec: { prompt: string }; requirements: { cli: string; model: string } }; + const sent = bodies[0] as { + repo: { url: string; base_ref: string }; + spec: { prompt: string }; + requirements: { cli: string; model: string }; + }; assert.equal(sent.repo.url, "https://git.x/repo"); assert.equal(sent.repo.base_ref, "dev"); assert.equal(sent.spec.prompt, "adicione um README com a seção Sobre"); diff --git a/tests/unit/conductor-ask-route.test.ts b/tests/unit/conductor-ask-route.test.ts index 9edfffbc8d..3fdadccde8 100644 --- a/tests/unit/conductor-ask-route.test.ts +++ b/tests/unit/conductor-ask-route.test.ts @@ -15,14 +15,14 @@ const servers: Server[] = []; test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.CONDUCTOR_SPOKESPERSON_URL; }); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.CONDUCTOR_SPOKESPERSON_URL; while (servers.length > 0) { const s = servers.pop(); @@ -31,7 +31,10 @@ test.after(async () => { }); test("fonte: auth antes do proxy; token nunca manuseado na rota", () => { - const src = fs.readFileSync(path.join(process.cwd(), "src/app/api/conductor/ask/route.ts"), "utf8"); + const src = fs.readFileSync( + path.join(process.cwd(), "src/app/api/conductor/ask/route.ts"), + "utf8" + ); const authAt = src.indexOf("requireManagementAuth("); assert.ok(authAt > 0); assert.match(src, /if \(authError\) return authError;/); diff --git a/tests/unit/conductor-fleet-route.test.ts b/tests/unit/conductor-fleet-route.test.ts index 4fb4b88a2b..adddca7297 100644 --- a/tests/unit/conductor-fleet-route.test.ts +++ b/tests/unit/conductor-fleet-route.test.ts @@ -19,7 +19,9 @@ function fakeHub(routes: Record): Pro const server = createServer((req, res) => { const hit = Object.entries(routes).find(([p]) => (req.url ?? "").startsWith(p)); res.writeHead(hit ? hit[1].status : 404, { "content-type": "application/json" }); - res.end(JSON.stringify(hit ? hit[1].body : { error: "hub: segredo interno que NÃO pode vazar" })); + res.end( + JSON.stringify(hit ? hit[1].body : { error: "hub: segredo interno que NÃO pode vazar" }) + ); }); servers.push(server); return new Promise((resolve) => { @@ -32,7 +34,7 @@ function fakeHub(routes: Record): Pro test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.CONDUCTOR_HUB_URL; delete process.env.CONDUCTOR_HUB_TOKEN; @@ -40,7 +42,7 @@ test.beforeEach(() => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.CONDUCTOR_HUB_URL; while (servers.length > 0) { const s = servers.pop(); @@ -52,11 +54,26 @@ test("GET /api/conductor/fleet devolve snapshot whitelisted; sem hub → degrada process.env.CONDUCTOR_HUB_URL = await fakeHub({ "/v1/runners": { status: 200, - body: [{ id: "r_1", token: "VAZOU?", online: true, capabilities: { name: "devbox", clis: [{ profile: "claude" }] } }], + body: [ + { + id: "r_1", + token: "VAZOU?", + online: true, + capabilities: { name: "devbox", clis: [{ profile: "claude" }] }, + }, + ], }, "/v1/tasks": { status: 200, - body: [{ id: "t_1", status: "working", mode: "solo", repo: { url: "https://x/r" }, assigned_runner: "r_1" }], + body: [ + { + id: "t_1", + status: "working", + mode: "solo", + repo: { url: "https://x/r" }, + assigned_runner: "r_1", + }, + ], }, }); process.env.CONDUCTOR_HUB_TOKEN = "tok"; @@ -86,7 +103,10 @@ test("GET /api/conductor/tasks/[id] → 404 sanitizado quando o hub não conhece test("POST cancel repassa recusa do hub com status, sem corpo upstream", async () => { process.env.CONDUCTOR_HUB_URL = await fakeHub({ - "/v1/tasks/t_done/cancel": { status: 409, body: { error: "segredo interno que NÃO pode vazar" } }, + "/v1/tasks/t_done/cancel": { + status: 409, + body: { error: "segredo interno que NÃO pode vazar" }, + }, "/v1/tasks/t_ok/cancel": { status: 200, body: { ok: true } }, }); const denied = await cancelRoute.POST(new Request("http://localhost/x", { method: "POST" }), { diff --git a/tests/unit/config-audit-persistence.test.ts b/tests/unit/config-audit-persistence.test.ts index 4bad88bc5d..12e5a1120b 100644 --- a/tests/unit/config-audit-persistence.test.ts +++ b/tests/unit/config-audit-persistence.test.ts @@ -16,7 +16,7 @@ type CountRow = { c: number }; function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -59,11 +59,22 @@ test.after(() => { test("recordChange persists to SQLite, not memory", () => { const db = core.getDbInstance(); const tableRow = db - .prepare("SELECT count(*) as c FROM sqlite_master WHERE type='table' AND name='config_audit_log'") + .prepare( + "SELECT count(*) as c FROM sqlite_master WHERE type='table' AND name='config_audit_log'" + ) .get() as CountRow; assert.equal(tableRow.c, 1); - const e = audit.recordChange("update", "provider", "p1", "My Provider", { a: 1 }, { a: 2 }, "api", null); + const e = audit.recordChange( + "update", + "provider", + "p1", + "My Provider", + { a: 1 }, + { a: 2 }, + "api", + null + ); assert.equal(countRows(), 1); const { entries, total } = audit.getAuditLog({ target: "provider" }); @@ -74,7 +85,15 @@ test("recordChange persists to SQLite, not memory", () => { test("pagination + filters read from SQLite", () => { audit.recordChange("create", "combo", "c1", "C1", null, { models: ["m1"] }, "dashboard"); - audit.recordChange("update", "combo", "c1", "C1", { models: ["m1"] }, { models: ["m1", "m2"] }, "api"); + audit.recordChange( + "update", + "combo", + "c1", + "C1", + { models: ["m1"] }, + { models: ["m1", "m2"] }, + "api" + ); const { entries, total } = audit.getAuditLog({ target: "combo", limit: 1, offset: 0 }); assert.equal(total, 2); diff --git a/tests/unit/config-expiry-time-bomb.test.ts b/tests/unit/config-expiry-time-bomb.test.ts index 7740e09e5c..dbb837f2ab 100644 --- a/tests/unit/config-expiry-time-bomb.test.ts +++ b/tests/unit/config-expiry-time-bomb.test.ts @@ -92,7 +92,7 @@ test("scanConfigExpiry: walks a config tree, skips node_modules and invalid JSON const found = scanConfigExpiry(dir).map((f) => `${f.file}:${f.keyPath}`); assert.deepEqual(found, ["a.json:validUntil", "sub/b.json:deep.expiresAt"]); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/config-hot-reload.test.ts b/tests/unit/config-hot-reload.test.ts index fabd87a500..195421ede1 100644 --- a/tests/unit/config-hot-reload.test.ts +++ b/tests/unit/config-hot-reload.test.ts @@ -45,7 +45,7 @@ async function resetStorage() { }); invalidateCacheControlSettingsCache(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/console-interceptor-message-fidelity.test.ts b/tests/unit/console-interceptor-message-fidelity.test.ts index ab1cd6f90e..e3c8e2d2de 100644 --- a/tests/unit/console-interceptor-message-fidelity.test.ts +++ b/tests/unit/console-interceptor-message-fidelity.test.ts @@ -64,7 +64,7 @@ test("the interceptor keeps the component and substitutes printf formats", () => assert.equal(plain, 'plain message {"a":1}'); } finally { __consoleInterceptorInternals.reset(); - fs.rmSync(LOG_DIR, { recursive: true, force: true }); + fs.rmSync(LOG_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -90,6 +90,6 @@ test("a first argument that coincidentally contains a printf token does not swal assert.ok(entry.includes(err.stack || ""), "Error stack was dropped"); } finally { __consoleInterceptorInternals.reset(); - fs.rmSync(LOG_DIR, { recursive: true, force: true }); + fs.rmSync(LOG_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/context-handoff.test.ts b/tests/unit/context-handoff.test.ts index a19b8734a8..8bbd7fac83 100644 --- a/tests/unit/context-handoff.test.ts +++ b/tests/unit/context-handoff.test.ts @@ -13,7 +13,7 @@ const contextHandoff = await import("../../open-sse/services/contextHandoff.ts") async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("buildHandoffSystemMessage and injectHandoffIntoBody preserve existing history", () => { diff --git a/tests/unit/context-manager.test.ts b/tests/unit/context-manager.test.ts index de95d5b6f2..17df8f9a25 100644 --- a/tests/unit/context-manager.test.ts +++ b/tests/unit/context-manager.test.ts @@ -16,7 +16,7 @@ test.after(() => { core.resetDbInstance(); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── estimateTokens ───────────────────────────────────────────────────────── diff --git a/tests/unit/context-window-reconcile-persisted-overrides.test.ts b/tests/unit/context-window-reconcile-persisted-overrides.test.ts index 13285d398f..eeaf2e610c 100644 --- a/tests/unit/context-window-reconcile-persisted-overrides.test.ts +++ b/tests/unit/context-window-reconcile-persisted-overrides.test.ts @@ -16,13 +16,13 @@ const { runContextWindowReconcile } = await import("../../src/lib/contextWindowR test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("runContextWindowReconcile retains an auto override across repeated synced discovery", async () => { diff --git a/tests/unit/conversationTurnContent.test.ts b/tests/unit/conversationTurnContent.test.ts index adccdf3a8c..8f941a0618 100644 --- a/tests/unit/conversationTurnContent.test.ts +++ b/tests/unit/conversationTurnContent.test.ts @@ -19,7 +19,7 @@ const { resolveTurnDisplayContent } = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function insertCallLog(row: { id: string; correlationId: string; artifactRelPath: string | null }) { diff --git a/tests/unit/conversations-active-call-log-id.test.ts b/tests/unit/conversations-active-call-log-id.test.ts index 9e8473f582..843efe022b 100644 --- a/tests/unit/conversations-active-call-log-id.test.ts +++ b/tests/unit/conversations-active-call-log-id.test.ts @@ -28,7 +28,7 @@ const route = await import("../../src/app/api/conversations/route.ts"); test.after(() => { core.resetDbInstance(); usageHistory.clearPendingRequests(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { diff --git a/tests/unit/cooldown-epoch-string-3954.test.ts b/tests/unit/cooldown-epoch-string-3954.test.ts index ddc3af23c7..7d8a19d27c 100644 --- a/tests/unit/cooldown-epoch-string-3954.test.ts +++ b/tests/unit/cooldown-epoch-string-3954.test.ts @@ -24,13 +24,12 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); -const { isAccountUnavailable, getEarliestRateLimitedUntil, filterAvailableAccounts } = await import( - "../../open-sse/services/accountFallback.ts" -); +const { isAccountUnavailable, getEarliestRateLimitedUntil, filterAvailableAccounts } = + await import("../../open-sse/services/accountFallback.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const HOUR = 3_600_000; diff --git a/tests/unit/correctness/goldenSnapshot.test.ts b/tests/unit/correctness/goldenSnapshot.test.ts index d7f804cea5..bc341cfe10 100644 --- a/tests/unit/correctness/goldenSnapshot.test.ts +++ b/tests/unit/correctness/goldenSnapshot.test.ts @@ -23,7 +23,7 @@ test("goldenSnapshot writes on first run then matches", (t) => { assert.throws(() => goldenSnapshot("selftest/sample", { a: 1, b: 3 }, tmpDir)); // Cleanup - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("goldenSnapshot first-run (no UPDATE_GOLDEN) writes and passes", () => { @@ -36,6 +36,6 @@ test("goldenSnapshot first-run (no UPDATE_GOLDEN) writes and passes", () => { // File exists: different value should throw assert.throws(() => goldenSnapshot("test/value", { x: 99 }, td)); } finally { - fs.rmSync(td, { recursive: true, force: true }); + fs.rmSync(td, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cursor-agent-availability-route-authenticated.test.ts b/tests/unit/cursor-agent-availability-route-authenticated.test.ts index 1959910495..3472e5b15b 100644 --- a/tests/unit/cursor-agent-availability-route-authenticated.test.ts +++ b/tests/unit/cursor-agent-availability-route-authenticated.test.ts @@ -22,7 +22,7 @@ const { GET } = await import("../../src/app/api/providers/cursor/agent-availabil test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const FAKE_CURSOR_AGENT_SCRIPT = `#!/usr/bin/env node @@ -46,7 +46,7 @@ test.after(() => { process.env.HOME = originalHome; if (originalUserProfile !== undefined) process.env.USERPROFILE = originalUserProfile; else delete process.env.USERPROFILE; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("returns {cursorAgentAvailable: true} and ONLY that field when cursor-agent is authenticated", async () => { diff --git a/tests/unit/cursor-agent-availability-route.test.ts b/tests/unit/cursor-agent-availability-route.test.ts index c395a228d9..6b9a5685f2 100644 --- a/tests/unit/cursor-agent-availability-route.test.ts +++ b/tests/unit/cursor-agent-availability-route.test.ts @@ -50,7 +50,7 @@ if (args[0] === "status") { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function writeFakeCursorAgentBinary(destPath: string): void { @@ -72,7 +72,7 @@ test.after(() => { if (originalUserProfile !== undefined) process.env.USERPROFILE = originalUserProfile; else delete process.env.USERPROFILE; delete process.env.FAKE_CURSOR_AGENT_STATUS_MODE; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("returns {cursorAgentAvailable: false} and ONLY that field when cursor-agent is unauthenticated", async () => { diff --git a/tests/unit/cursor-agent-cli-version.test.ts b/tests/unit/cursor-agent-cli-version.test.ts index abd4031756..4ec68f69e4 100644 --- a/tests/unit/cursor-agent-cli-version.test.ts +++ b/tests/unit/cursor-agent-cli-version.test.ts @@ -59,7 +59,7 @@ test("newestVersionInDir picks lexicographically newest matching child", () => { fs.mkdirSync(path.join(tmp, "3.9.0")); assert.equal(newestVersionInDir(tmp), "2026.07.08-0c04a8a"); } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -79,7 +79,7 @@ test("detectCursorAgentCliVersionFromFs uses shim realpath under versions/", assert.equal(detectCursorAgentCliVersionFromFs(home), id); }); } finally { - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -93,8 +93,8 @@ test("detectCursorAgentCliVersionFromFs uses CURSOR_DATA_DIR versions when no sh assert.equal(detectCursorAgentCliVersionFromFs(home), id); }); } finally { - fs.rmSync(home, { recursive: true, force: true }); - fs.rmSync(data, { recursive: true, force: true }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(data, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -123,7 +123,7 @@ test("getCursorAgentCliVersion ignores invalid env and uses pin when FS empty", ); } finally { resetCursorAgentCliVersionCache(); - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -160,8 +160,8 @@ test("getCursorAgentCliVersion reads CURSOR_DATA_DIR via isolated HOME", () => { ); } finally { resetCursorAgentCliVersionCache(); - fs.rmSync(home, { recursive: true, force: true }); - fs.rmSync(data, { recursive: true, force: true }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(data, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -209,8 +209,8 @@ test("disk cache hit serves immediately without blocking on network", async () = ); } finally { resetCursorAgentCliVersionTestHooks(); - fs.rmSync(cacheDir, { recursive: true, force: true }); - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(cacheDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -235,7 +235,7 @@ test("refreshCursorAgentCliVersionFromInstaller writes disk cache from HTML", as assert.equal(onDisk.version, scrapedId); } finally { resetCursorAgentCliVersionTestHooks(); - fs.rmSync(cacheDir, { recursive: true, force: true }); + fs.rmSync(cacheDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -264,7 +264,7 @@ test("invalid installer HTML falls through to pin", async () => { assert.equal(id, null); } finally { resetCursorAgentCliVersionTestHooks(); - fs.rmSync(cacheDir, { recursive: true, force: true }); - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(cacheDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/cursor-agent-models.test.ts b/tests/unit/cursor-agent-models.test.ts index 7b03ff9518..1d72c79834 100644 --- a/tests/unit/cursor-agent-models.test.ts +++ b/tests/unit/cursor-agent-models.test.ts @@ -123,7 +123,7 @@ describe("resolveCursorAgentBinary", () => { if (ORIGINAL_USERPROFILE !== undefined) process.env.USERPROFILE = ORIGINAL_USERPROFILE; else delete process.env.USERPROFILE; process.env.PATH = ORIGINAL_PATH; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("finds the HOME-relative fixed candidate (~/.local/bin/cursor-agent) with allowPathFallback:false", () => { @@ -152,7 +152,7 @@ describe("resolveCursorAgentBinary", () => { assert.equal(resolveCursorAgentBinary({ allowPathFallback: false }), fixedBinary); assert.equal(resolveCursorAgentBinary({ allowPathFallback: true }), fixedBinary); } finally { - fs.rmSync(pathDir, { recursive: true, force: true }); + fs.rmSync(pathDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -175,7 +175,7 @@ describe("resolveCursorAgentBinary", () => { assert.equal(resolveCursorAgentBinary({ allowPathFallback: true }), pathOnlyBinary); assert.equal(resolveCursorAgentBinary(), pathOnlyBinary); } finally { - fs.rmSync(pathDir, { recursive: true, force: true }); + fs.rmSync(pathDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -198,7 +198,7 @@ describe("resolveCursorAgentBinary", () => { try { assert.equal(resolveCursorAgentBinary({ allowPathFallback: false }), null); } finally { - fs.rmSync(pathDir, { recursive: true, force: true }); + fs.rmSync(pathDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); @@ -261,7 +261,7 @@ if (selfExitMs) { afterEach(() => { delete process.env.FAKE_BIN_SELF_EXIT_MS; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("sends SIGKILL after the follow-up window when the process ignores SIGTERM", async () => { diff --git a/tests/unit/cursor-renewal.test.ts b/tests/unit/cursor-renewal.test.ts index fcb480bca1..242570b8ea 100644 --- a/tests/unit/cursor-renewal.test.ts +++ b/tests/unit/cursor-renewal.test.ts @@ -120,7 +120,7 @@ describe("runCursorAgentNudge", () => { afterEach(() => { clearFakeCursorAgentEnv(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it('invokes the binary with exactly ["--list-models"] and never "login"', async () => { @@ -180,7 +180,7 @@ describe("checkCursorAgentAvailability", () => { if (ORIGINAL_USERPROFILE !== undefined) process.env.USERPROFILE = ORIGINAL_USERPROFILE; else delete process.env.USERPROFILE; clearFakeCursorAgentEnv(); - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("reports available:true when the resolved binary is authenticated", async () => { @@ -298,7 +298,7 @@ describe("getCachedCursorAgentAvailability (Task 5 Step 1 — 5-minute TTL wrapp if (ORIGINAL_USERPROFILE !== undefined) process.env.USERPROFILE = ORIGINAL_USERPROFILE; else delete process.env.USERPROFILE; clearFakeCursorAgentEnv(); - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // A single test, one continuous mocked timeline: getCachedCursorAgentAvailability()'s @@ -364,7 +364,7 @@ describe("renewCursorConnection", () => { if (ORIGINAL_USERPROFILE !== undefined) process.env.USERPROFILE = ORIGINAL_USERPROFILE; else delete process.env.USERPROFILE; clearFakeCursorAgentEnv(); - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function writeIdeToken(accessToken: string, machineId?: string): Promise { diff --git a/tests/unit/cursor-token-extractor.test.ts b/tests/unit/cursor-token-extractor.test.ts index 986d8dd0ad..70b60dc95c 100644 --- a/tests/unit/cursor-token-extractor.test.ts +++ b/tests/unit/cursor-token-extractor.test.ts @@ -236,7 +236,7 @@ describe("tryAgentAuth", () => { } else { delete process.env.USERPROFILE; } - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("finds a token in the primary auth.json candidate", async () => { @@ -336,7 +336,7 @@ describe("tryIdeAuth", () => { delete process.env.USERPROFILE; } if (tmpHome) { - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); tmpHome = undefined; } }); diff --git a/tests/unit/cursor-version-detector.test.mjs b/tests/unit/cursor-version-detector.test.mjs index 6fef869a9b..fc70e70555 100644 --- a/tests/unit/cursor-version-detector.test.mjs +++ b/tests/unit/cursor-version-detector.test.mjs @@ -45,7 +45,7 @@ test("getCursorVersion reads version from state.vscdb", () => { } finally { if (origEnv === undefined) delete process.env.CURSOR_STATE_DB_PATH; else process.env.CURSOR_STATE_DB_PATH = origEnv; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -74,7 +74,7 @@ test("getCursorVersion returns fallback when DB has no version key", () => { } finally { if (origEnv === undefined) delete process.env.CURSOR_STATE_DB_PATH; else process.env.CURSOR_STATE_DB_PATH = origEnv; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -100,7 +100,7 @@ test("getCursorVersion caches the result across calls", () => { } finally { if (origEnv === undefined) delete process.env.CURSOR_STATE_DB_PATH; else process.env.CURSOR_STATE_DB_PATH = origEnv; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -126,6 +126,6 @@ test("resetCursorVersionCache forces re-read from DB", () => { } finally { if (origEnv === undefined) delete process.env.CURSOR_STATE_DB_PATH; else process.env.CURSOR_STATE_DB_PATH = origEnv; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/custom-headers-provider-nodes.test.ts b/tests/unit/custom-headers-provider-nodes.test.ts index 17646b37f9..651ff02ff1 100644 --- a/tests/unit/custom-headers-provider-nodes.test.ts +++ b/tests/unit/custom-headers-provider-nodes.test.ts @@ -18,7 +18,7 @@ const { DefaultExecutor } = await import("../../open-sse/executors/default.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createProviderNodeSchema accepts valid customHeaders as record of strings", () => { diff --git a/tests/unit/custom-model-target-format.test.ts b/tests/unit/custom-model-target-format.test.ts index 062a97566d..6382e367b2 100644 --- a/tests/unit/custom-model-target-format.test.ts +++ b/tests/unit/custom-model-target-format.test.ts @@ -38,7 +38,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#2905 addCustomModel persists targetFormat", async () => { diff --git a/tests/unit/dashscope-text-models-discovery.test.ts b/tests/unit/dashscope-text-models-discovery.test.ts index 5e62ce7613..bef519cc29 100644 --- a/tests/unit/dashscope-text-models-discovery.test.ts +++ b/tests/unit/dashscope-text-models-discovery.test.ts @@ -73,7 +73,7 @@ const MIXED_DASHSCOPE_MODELS = [ async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -139,7 +139,7 @@ async function assertTextOnlyDiscovery({ test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Qwen Cloud syncs only text models from the selected Beijing region", async () => { diff --git a/tests/unit/data-dir-writable-fallback.test.ts b/tests/unit/data-dir-writable-fallback.test.ts index 70421108f5..57cbf1def8 100644 --- a/tests/unit/data-dir-writable-fallback.test.ts +++ b/tests/unit/data-dir-writable-fallback.test.ts @@ -15,9 +15,7 @@ import { const IS_ROOT = typeof process.getuid === "function" && process.getuid() === 0; const IS_WINDOWS = process.platform === "win32"; -async function withTempEnv( - fn: (paths: { root: string; home: string }) => void | Promise -) { +async function withTempEnv(fn: (paths: { root: string; home: string }) => void | Promise) { const originalEnv = { ...process.env }; const root = fs.mkdtempSync(path.join(os.tmpdir(), "omni-datadir-")); const home = path.join(root, "home"); @@ -44,7 +42,7 @@ async function withTempEnv( } catch { // ignore } - fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } @@ -60,26 +58,30 @@ test("resolveWritableDataDir returns the configured DATA_DIR when it is writable }); }); -test("resolveWritableDataDir falls back to the default dir when DATA_DIR is not writable (EACCES/EPERM)", { skip: IS_ROOT || IS_WINDOWS }, async () => { - await withTempEnv(({ root, home }) => { - // A read-only parent makes mkdir of the child fail with EACCES/EPERM. - const lockedParent = path.join(root, "locked"); - fs.mkdirSync(lockedParent, { recursive: true }); - fs.chmodSync(lockedParent, 0o555); +test( + "resolveWritableDataDir falls back to the default dir when DATA_DIR is not writable (EACCES/EPERM)", + { skip: IS_ROOT || IS_WINDOWS }, + async () => { + await withTempEnv(({ root, home }) => { + // A read-only parent makes mkdir of the child fail with EACCES/EPERM. + const lockedParent = path.join(root, "locked"); + fs.mkdirSync(lockedParent, { recursive: true }); + fs.chmodSync(lockedParent, 0o555); - const configured = path.join(lockedParent, "data"); - process.env.DATA_DIR = configured; + const configured = path.join(lockedParent, "data"); + process.env.DATA_DIR = configured; - const resolved = resolveWritableDataDir(); - const expectedFallback = getDefaultDataDir(); + const resolved = resolveWritableDataDir(); + const expectedFallback = getDefaultDataDir(); - // It must NOT return the unwritable configured dir... - assert.notEqual(resolved, path.resolve(configured)); - // ...and instead fall back to the default user dir (~/.omniroute under HOME). - assert.equal(resolved, expectedFallback); - assert.ok(resolved.startsWith(path.resolve(home))); - }); -}); + // It must NOT return the unwritable configured dir... + assert.notEqual(resolved, path.resolve(configured)); + // ...and instead fall back to the default user dir (~/.omniroute under HOME). + assert.equal(resolved, expectedFallback); + assert.ok(resolved.startsWith(path.resolve(home))); + }); + } +); test("resolveWritableDataDir returns the default dir (no probe) when DATA_DIR is unset", async () => { await withTempEnv(() => { @@ -105,9 +107,12 @@ test("resolveWritableDataDir rethrows non-permission errors", { skip: IS_WINDOWS const configured = path.join(fileParent, "data"); process.env.DATA_DIR = configured; - assert.throws(() => resolveWritableDataDir(), (err: NodeJS.ErrnoException) => { - return err.code !== "EACCES" && err.code !== "EPERM"; - }); + assert.throws( + () => resolveWritableDataDir(), + (err: NodeJS.ErrnoException) => { + return err.code !== "EACCES" && err.code !== "EPERM"; + } + ); }); }); diff --git a/tests/unit/database-settings-maintenance.test.ts b/tests/unit/database-settings-maintenance.test.ts index a6c3d69e83..d5923d621f 100644 --- a/tests/unit/database-settings-maintenance.test.ts +++ b/tests/unit/database-settings-maintenance.test.ts @@ -30,7 +30,7 @@ type UsageSummaryRow = { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/datadir-test-context-guard-10428.test.ts b/tests/unit/datadir-test-context-guard-10428.test.ts index e957a490fa..93fad86c73 100644 --- a/tests/unit/datadir-test-context-guard-10428.test.ts +++ b/tests/unit/datadir-test-context-guard-10428.test.ts @@ -40,19 +40,19 @@ function withEnv(overrides: Record, run: () => void) } test("G1: a test context with no DATA_DIR never resolves to the operator's real data dir", () => { - withEnv({ DATA_DIR: undefined, NODE_ENV: "test", OMNIROUTE_ALLOW_DEFAULT_DATA_DIR: undefined }, () => { - const resolved = resolveWritableDataDir(); - assert.notEqual( - resolved, - getDefaultDataDir(), - "a test run must never be handed the operator's real DATA_DIR" - ); - assert.ok( - resolved.startsWith(os.tmpdir()), - `expected a throwaway temp dir, got ${resolved}` - ); - assert.ok(fs.existsSync(resolved), "the redirected dir must exist and be usable"); - }); + withEnv( + { DATA_DIR: undefined, NODE_ENV: "test", OMNIROUTE_ALLOW_DEFAULT_DATA_DIR: undefined }, + () => { + const resolved = resolveWritableDataDir(); + assert.notEqual( + resolved, + getDefaultDataDir(), + "a test run must never be handed the operator's real DATA_DIR" + ); + assert.ok(resolved.startsWith(os.tmpdir()), `expected a throwaway temp dir, got ${resolved}`); + assert.ok(fs.existsSync(resolved), "the redirected dir must exist and be usable"); + } + ); }); test("G2: an explicit DATA_DIR still wins inside a test context", () => { @@ -60,20 +60,17 @@ test("G2: an explicit DATA_DIR still wins inside a test context", () => { withEnv({ DATA_DIR: explicit, NODE_ENV: "test" }, () => { assert.equal(resolveWritableDataDir(), explicit); }); - fs.rmSync(explicit, { recursive: true, force: true }); + fs.rmSync(explicit, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("G3: the escape hatch restores the old behavior for deliberate runs", () => { - withEnv( - { DATA_DIR: undefined, NODE_ENV: "test", OMNIROUTE_ALLOW_DEFAULT_DATA_DIR: "1" }, - () => { - assert.equal( - resolveWritableDataDir(), - getDefaultDataDir(), - "an explicit opt-in must still reach the real dir, so the intent is recorded" - ); - } - ); + withEnv({ DATA_DIR: undefined, NODE_ENV: "test", OMNIROUTE_ALLOW_DEFAULT_DATA_DIR: "1" }, () => { + assert.equal( + resolveWritableDataDir(), + getDefaultDataDir(), + "an explicit opt-in must still reach the real dir, so the intent is recorded" + ); + }); }); test("G4: a normal server run (no test markers) is untouched", () => { diff --git a/tests/unit/db-adapters/driverFactory.test.ts b/tests/unit/db-adapters/driverFactory.test.ts index b73ea87a6f..e4383ea955 100644 --- a/tests/unit/db-adapters/driverFactory.test.ts +++ b/tests/unit/db-adapters/driverFactory.test.ts @@ -7,7 +7,6 @@ import { createRequire } from "node:module"; import type * as NodePath from "node:path"; import { runtimeRequire } from "../../../src/lib/db/adapters/runtimeRequire.ts"; - const { createSyncDriverFactory, createBetterSqliteProbe, @@ -33,11 +32,10 @@ function forceNodeSqlite() { function createTempDatabasePath(t: TestContext) { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-node-sqlite-")); const databasePath = path.join(dir, "database.sqlite"); - t.after(() => fs.rmSync(dir, { recursive: true, force: true })); + t.after(() => fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })); return databasePath; } - describe("driverFactory", () => { test("runtimeRequire loads Node built-ins outside webpack", () => { const nodePath = runtimeRequire("node:path") as typeof NodePath; diff --git a/tests/unit/db-agent-bridge-bypass.test.ts b/tests/unit/db-agent-bridge-bypass.test.ts index a45e8f8831..b85cee532a 100644 --- a/tests/unit/db-agent-bridge-bypass.test.ts +++ b/tests/unit/db-agent-bridge-bypass.test.ts @@ -4,9 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-db-agent-bridge-bypass-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-db-agent-bridge-bypass-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -18,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -39,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const DEFAULT_PATTERNS = [ diff --git a/tests/unit/db-agent-bridge-mappings.test.ts b/tests/unit/db-agent-bridge-mappings.test.ts index 5c03d24fa4..83ec3baf1c 100644 --- a/tests/unit/db-agent-bridge-mappings.test.ts +++ b/tests/unit/db-agent-bridge-mappings.test.ts @@ -4,9 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-db-agent-bridge-mappings-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-db-agent-bridge-mappings-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -18,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -39,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getMappingsForAgent returns empty array when no mappings exist", () => { diff --git a/tests/unit/db-agent-bridge-state.test.ts b/tests/unit/db-agent-bridge-state.test.ts index 919c17646b..ec2d262e44 100644 --- a/tests/unit/db-agent-bridge-state.test.ts +++ b/tests/unit/db-agent-bridge-state.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration is idempotent — running getDbInstance twice does not throw", () => { diff --git a/tests/unit/db-apiKeys-crud.test.ts b/tests/unit/db-apiKeys-crud.test.ts index c7dc35e15a..f1c4bfcbd8 100644 --- a/tests/unit/db-apiKeys-crud.test.ts +++ b/tests/unit/db-apiKeys-crud.test.ts @@ -31,7 +31,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { @@ -65,10 +65,9 @@ test("createApiKey with scopes stores them", async () => { test("createApiKey rejects empty machineId", async () => { await resetStorage(); - await assert.rejects( - () => apiKeys.createApiKey("Bad Key", ""), - { message: /machineId is required/i } - ); + await assert.rejects(() => apiKeys.createApiKey("Bad Key", ""), { + message: /machineId is required/i, + }); }); // ──────────────── getApiKeys ──────────────── @@ -375,7 +374,10 @@ test("updateApiKeyPermissions clears accessSchedule with null", async () => { test("updateApiKeyPermissions sets rateLimits", async () => { await resetStorage(); const created = await apiKeys.createApiKey("Rate Limited", "ma-026"); - const limits = [{ limit: 100, window: 60 }, { limit: 1000, window: 3600 }]; + const limits = [ + { limit: 100, window: 60 }, + { limit: 1000, window: 3600 }, + ]; await apiKeys.updateApiKeyPermissions(created.id, { rateLimits: limits }); const loaded = await apiKeys.getApiKeyById(created.id); assert.deepEqual(loaded!.rateLimits, limits); diff --git a/tests/unit/db-backup-autobackup-setting-5871.test.ts b/tests/unit/db-backup-autobackup-setting-5871.test.ts index e9ed86365c..bb8704076c 100644 --- a/tests/unit/db-backup-autobackup-setting-5871.test.ts +++ b/tests/unit/db-backup-autobackup-setting-5871.test.ts @@ -29,7 +29,7 @@ const databaseSettings = await import("../../src/lib/db/databaseSettings.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -40,7 +40,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("fresh install (seeded default autoBackupEnabled=false) → auto backups disabled", () => { diff --git a/tests/unit/db-backup-extended.test.ts b/tests/unit/db-backup-extended.test.ts index d4f9f26463..4ed9a08064 100644 --- a/tests/unit/db-backup-extended.test.ts +++ b/tests/unit/db-backup-extended.test.ts @@ -21,12 +21,12 @@ async function resetStorage() { const targetPath = path.join(TEST_DATA_DIR, entry); const stat = fs.lstatSync(targetPath); if (stat.isDirectory()) { - fs.rmSync(targetPath, { recursive: true, force: true }); + fs.rmSync(targetPath, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } else { await backupDb.unlinkFileWithRetry(targetPath, { maxAttempts: 20, baseDelayMs: 25 }); } } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -78,7 +78,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("backupDbFile creates manual backups and listDbBackups returns metadata", async () => { @@ -98,7 +98,7 @@ test("backupDbFile creates manual backups and listDbBackups returns metadata", a }); test("listDbBackups returns an empty list when the backup directory is missing", async () => { - fs.rmSync(core.DB_BACKUPS_DIR, { recursive: true, force: true }); + fs.rmSync(core.DB_BACKUPS_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); const backups = await backupDb.listDbBackups(); assert.deepEqual(backups, []); }); diff --git a/tests/unit/db-backups-skills-3500.test.ts b/tests/unit/db-backups-skills-3500.test.ts index a2f0118ab2..bf0c0d50cf 100644 --- a/tests/unit/db-backups-skills-3500.test.ts +++ b/tests/unit/db-backups-skills-3500.test.ts @@ -161,9 +161,7 @@ test("exportAllSummaryRows — returns provider_connections rows (no credentials const { providers } = backupMod.exportAllSummaryRows(); - const found = (providers as Array<{ id: string; provider: string }>).find( - (p) => p.id === connId - ); + const found = (providers as Array<{ id: string; provider: string }>).find((p) => p.id === connId); assert.ok(found, "providers must include seeded row"); assert.equal(found?.provider, "openai"); // Sensitive credential columns must NOT be exported — the query only selects @@ -229,7 +227,7 @@ test.after(() => { /* best effort */ } try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } diff --git a/tests/unit/db-call-log-stats-3500.test.ts b/tests/unit/db-call-log-stats-3500.test.ts index 5216132d8b..b4d7b48ae0 100644 --- a/tests/unit/db-call-log-stats-3500.test.ts +++ b/tests/unit/db-call-log-stats-3500.test.ts @@ -85,7 +85,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -97,12 +97,16 @@ test("#3500 getProviderMetrics — aggregates totals and latency per provider", // provider_connections row — seed openai/anthropic connections so their // call_logs rows are not filtered out as ghost/deleted providers. const db0 = core.getDbInstance(); - db0.prepare( - `INSERT INTO provider_connections (id, provider, created_at, updated_at) VALUES (?, ?, ?, ?)` - ).run("conn-3500-openai", "openai", new Date().toISOString(), new Date().toISOString()); - db0.prepare( - `INSERT INTO provider_connections (id, provider, created_at, updated_at) VALUES (?, ?, ?, ?)` - ).run("conn-3500-anthropic", "anthropic", new Date().toISOString(), new Date().toISOString()); + db0 + .prepare( + `INSERT INTO provider_connections (id, provider, created_at, updated_at) VALUES (?, ?, ?, ?)` + ) + .run("conn-3500-openai", "openai", new Date().toISOString(), new Date().toISOString()); + db0 + .prepare( + `INSERT INTO provider_connections (id, provider, created_at, updated_at) VALUES (?, ?, ?, ?)` + ) + .run("conn-3500-anthropic", "anthropic", new Date().toISOString(), new Date().toISOString()); // Two openai rows: one success, one error with error_summary const ts1 = "2025-06-01T10:00:00.000Z"; @@ -121,11 +125,14 @@ test("#3500 getProviderMetrics — aggregates totals and latency per provider", // Provider '-' should be excluded insertCallLog({ provider: "-", status: 200 }); // Provider null should be excluded (insert directly to avoid type issue) - core.getDbInstance().prepare( - `INSERT INTO call_logs (id, timestamp, method, path, status, model, provider, duration, + core + .getDbInstance() + .prepare( + `INSERT INTO call_logs (id, timestamp, method, path, status, model, provider, duration, tokens_in, tokens_out, cache_source, detail_state, has_request_body, has_response_body, has_pipeline_details) VALUES (?, ?, 'POST', '/v1/test', 200, 'x', NULL, 100, 0, 0, 'upstream', 'none', 0, 0, 0)` - ).run(`log-3500-null-${++_idSeq}`, new Date().toISOString()); + ) + .run(`log-3500-null-${++_idSeq}`, new Date().toISOString()); const rows = mod.getProviderMetrics(); @@ -213,12 +220,36 @@ test("#3500 getSearchAggregateStats — correct totals, today, errors, avg, cach // Rows inserted after todayStart qualify as "today" const nowIso = new Date().toISOString(); // duration=0 → excluded from avg_duration; duration=3 → cached (>0 && <5) - insertCallLog({ provider: "brave", status: 200, duration: 100, request_type: "search", timestamp: nowIso }); - insertCallLog({ provider: "brave", status: 200, duration: 3, request_type: "search", timestamp: nowIso }); - insertCallLog({ provider: "brave", status: 500, duration: 80, request_type: "search", timestamp: nowIso }); + insertCallLog({ + provider: "brave", + status: 200, + duration: 100, + request_type: "search", + timestamp: nowIso, + }); + insertCallLog({ + provider: "brave", + status: 200, + duration: 3, + request_type: "search", + timestamp: nowIso, + }); + insertCallLog({ + provider: "brave", + status: 500, + duration: 80, + request_type: "search", + timestamp: nowIso, + }); // Old row (yesterday) — not in today count const yesterday = new Date(Date.now() - 86_400_000).toISOString(); - insertCallLog({ provider: "brave", status: 200, duration: 200, request_type: "search", timestamp: yesterday }); + insertCallLog({ + provider: "brave", + status: 200, + duration: 200, + request_type: "search", + timestamp: yesterday, + }); const result = mod.getSearchAggregateStats(todayIso); @@ -297,9 +328,7 @@ test("getProviderUsageSince — only counts rows inside the window", () => { insertCallLog({ provider: "usage-window", status: 200, timestamp: OUT_OF_WINDOW }); insertCallLog({ provider: "usage-window", status: 500, timestamp: OUT_OF_WINDOW }); - const row = mod - .getProviderUsageSince(USAGE_CUTOFF) - .find((r) => r.provider === "usage-window"); + const row = mod.getProviderUsageSince(USAGE_CUTOFF).find((r) => r.provider === "usage-window"); assert.ok(row, "provider must be present"); assert.equal(row.requests, 2, "rows before the cutoff must not be counted"); assert.equal(row.successes, 2); @@ -314,9 +343,7 @@ test("getProviderUsageSince — 2xx/3xx count as success, 4xx/5xx do not", () => insertCallLog({ provider: "usage-status", status, timestamp: IN_WINDOW }); } - const row = mod - .getProviderUsageSince(USAGE_CUTOFF) - .find((r) => r.provider === "usage-status"); + const row = mod.getProviderUsageSince(USAGE_CUTOFF).find((r) => r.provider === "usage-status"); assert.ok(row); assert.equal(row.requests, 8); assert.equal(row.successes, 4, "same success rule as getProviderMetrics"); @@ -349,9 +376,7 @@ test("getProviderUsageSince — latency and lastRequestAt are bounded by the win timestamp: OUT_OF_WINDOW, }); - const row = mod - .getProviderUsageSince(USAGE_CUTOFF) - .find((r) => r.provider === "usage-latency"); + const row = mod.getProviderUsageSince(USAGE_CUTOFF).find((r) => r.provider === "usage-latency"); assert.ok(row); assert.equal(row.avgLatencyMs, 100, "the out-of-window 900ms row must not weigh in"); assert.equal(row.lastRequestAt, IN_WINDOW); @@ -362,6 +387,12 @@ test("getProviderUsageSince — providers '-' and NULL are excluded", () => { insertCallLog({ provider: "-", status: 200, timestamp: IN_WINDOW }); const rows = mod.getProviderUsageSince(USAGE_CUTOFF); - assert.equal(rows.find((r) => r.provider === "-"), undefined); - assert.equal(rows.find((r) => r.provider === null), undefined); + assert.equal( + rows.find((r) => r.provider === "-"), + undefined + ); + assert.equal( + rows.find((r) => r.provider === null), + undefined + ); }); diff --git a/tests/unit/db-ccr-migration-renumber-134.test.ts b/tests/unit/db-ccr-migration-renumber-134.test.ts index 2be3b40c98..edbdd23f6e 100644 --- a/tests/unit/db-ccr-migration-renumber-134.test.ts +++ b/tests/unit/db-ccr-migration-renumber-134.test.ts @@ -49,7 +49,7 @@ function createLegacyDb(appliedName: string) { } test.after(() => { - fs.rmSync(migrationsDir, { recursive: true, force: true }); + fs.rmSync(migrationsDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalMigrationsDir === undefined) delete process.env.OMNIROUTE_MIGRATIONS_DIR; else process.env.OMNIROUTE_MIGRATIONS_DIR = originalMigrationsDir; }); diff --git a/tests/unit/db-cleanup-xp-audit-log.test.ts b/tests/unit/db-cleanup-xp-audit-log.test.ts index 630acaf17c..7fe7047845 100644 --- a/tests/unit/db-cleanup-xp-audit-log.test.ts +++ b/tests/unit/db-cleanup-xp-audit-log.test.ts @@ -19,7 +19,7 @@ type CountRow = { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/db-combos-crud.test.ts b/tests/unit/db-combos-crud.test.ts index 986ab7d76e..f610197b44 100644 --- a/tests/unit/db-combos-crud.test.ts +++ b/tests/unit/db-combos-crud.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createCombo stores default strategy and supports lookup by id and name", async () => { diff --git a/tests/unit/db-command-code-auth.test.ts b/tests/unit/db-command-code-auth.test.ts index 266aa7c333..6b67dd28fd 100644 --- a/tests/unit/db-command-code-auth.test.ts +++ b/tests/unit/db-command-code-auth.test.ts @@ -12,7 +12,7 @@ const commandCodeAuthDb = await import("../../src/lib/db/commandCodeAuth.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("status lookup expires stale pending command-code auth sessions", () => { diff --git a/tests/unit/db-core-extended.test.ts b/tests/unit/db-core-extended.test.ts index b38b567d06..95516bcfe7 100644 --- a/tests/unit/db-core-extended.test.ts +++ b/tests/unit/db-core-extended.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { diff --git a/tests/unit/db-core-init.test.ts b/tests/unit/db-core-init.test.ts index e93736e2af..5210562725 100644 --- a/tests/unit/db-core-init.test.ts +++ b/tests/unit/db-core-init.test.ts @@ -50,7 +50,7 @@ function makeTempDir(prefix) { } function removePath(targetPath) { - fs.rmSync(targetPath, { recursive: true, force: true }); + fs.rmSync(targetPath, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } async function importFresh(modulePath) { @@ -540,35 +540,39 @@ test("build phase returns the no-op stub without creating sqlite files", serial, } }); -test("invalid DATA_DIR (a file where a dir is expected) surfaces as a startup failure", serial, async () => { - const sandboxDir = makeTempDir("omniroute-db-bad-path-"); - const fileAsDir = path.join(sandboxDir, "not-a-directory"); - fs.writeFileSync(fileAsDir, "blocked"); +test( + "invalid DATA_DIR (a file where a dir is expected) surfaces as a startup failure", + serial, + async () => { + const sandboxDir = makeTempDir("omniroute-db-bad-path-"); + const fileAsDir = path.join(sandboxDir, "not-a-directory"); + fs.writeFileSync(fileAsDir, "blocked"); - try { - // Since #4767, db/core.ts resolves a writable data dir at module load via - // resolveWritableDataDir() → mkdirSync(recursive). Pointing DATA_DIR at a - // regular file is a non-permission misconfiguration (EEXIST/ENOTDIR), which - // resolveWritableDataDir rethrows by design (only EACCES/EPERM fall back), so - // the failure now surfaces at import time, not lazily from getDbInstance(). - let caught: unknown; - await withEnv({ DATA_DIR: fileAsDir }, () => importFresh("src/lib/db/core.ts")).then( - () => { - throw new Error("expected importing db/core with an invalid DATA_DIR to reject"); - }, - (err) => { - caught = err; - } - ); - assert.ok(caught instanceof Error, "an invalid DATA_DIR must surface as a thrown Error"); - assert.match( - String((caught as Error).message), - /unable to open database file|ENOTDIR|EEXIST|not a directory|file already exists/i - ); - } finally { - removePath(sandboxDir); + try { + // Since #4767, db/core.ts resolves a writable data dir at module load via + // resolveWritableDataDir() → mkdirSync(recursive). Pointing DATA_DIR at a + // regular file is a non-permission misconfiguration (EEXIST/ENOTDIR), which + // resolveWritableDataDir rethrows by design (only EACCES/EPERM fall back), so + // the failure now surfaces at import time, not lazily from getDbInstance(). + let caught: unknown; + await withEnv({ DATA_DIR: fileAsDir }, () => importFresh("src/lib/db/core.ts")).then( + () => { + throw new Error("expected importing db/core with an invalid DATA_DIR to reject"); + }, + (err) => { + caught = err; + } + ); + assert.ok(caught instanceof Error, "an invalid DATA_DIR must surface as a thrown Error"); + assert.match( + String((caught as Error).message), + /unable to open database file|ENOTDIR|EEXIST|not a directory|file already exists/i + ); + } finally { + removePath(sandboxDir); + } } -}); +); test( "legacy empty schema databases are renamed before a fresh sqlite database is created", diff --git a/tests/unit/db-core-migration.test.ts b/tests/unit/db-core-migration.test.ts index 8069214877..61545c072c 100644 --- a/tests/unit/db-core-migration.test.ts +++ b/tests/unit/db-core-migration.test.ts @@ -13,7 +13,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Test 1: migrateFromJson handles empty db.json and renames it", () => { diff --git a/tests/unit/db-core.test.ts b/tests/unit/db-core.test.ts index b198a780a7..5d7027dcb3 100644 --- a/tests/unit/db-core.test.ts +++ b/tests/unit/db-core.test.ts @@ -12,7 +12,7 @@ function makeTempDir(prefix: string): string { } function removePath(targetPath: string) { - fs.rmSync(targetPath, { recursive: true, force: true }); + fs.rmSync(targetPath, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } const originalEnv = { diff --git a/tests/unit/db-detailed-logs.test.ts b/tests/unit/db-detailed-logs.test.ts index 4469c7baf7..0eef9b566b 100644 --- a/tests/unit/db-detailed-logs.test.ts +++ b/tests/unit/db-detailed-logs.test.ts @@ -29,7 +29,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_PII_ENABLED === undefined) { delete process.env.PII_RESPONSE_SANITIZATION; diff --git a/tests/unit/db-domainState-crud.test.ts b/tests/unit/db-domainState-crud.test.ts index c02be9060c..eecc41142a 100644 --- a/tests/unit/db-domainState-crud.test.ts +++ b/tests/unit/db-domainState-crud.test.ts @@ -15,7 +15,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { @@ -166,7 +166,15 @@ test("saveBudgetResetLog and loadBudgetResetLogs", async () => { test("deleteBudget removes budget and reset logs", async () => { await resetStorage(); ds.saveBudget("del-key", { dailyLimitUsd: 10 }); - ds.saveBudgetResetLog({ apiKeyId: "del-key", resetInterval: "daily", previousSpend: 3, resetAt: 1, nextResetAt: 2, periodStart: 0, periodEnd: 1 }); + ds.saveBudgetResetLog({ + apiKeyId: "del-key", + resetInterval: "daily", + previousSpend: 3, + resetAt: 1, + nextResetAt: 2, + periodStart: 0, + periodEnd: 1, + }); ds.deleteBudget("del-key"); assert.equal(ds.loadBudget("del-key"), null); assert.deepEqual(ds.loadBudgetResetLogs("del-key"), []); diff --git a/tests/unit/db-fresh-setup-9934.test.ts b/tests/unit/db-fresh-setup-9934.test.ts index 6faafa3f8a..2330eedb6e 100644 --- a/tests/unit/db-fresh-setup-9934.test.ts +++ b/tests/unit/db-fresh-setup-9934.test.ts @@ -132,9 +132,9 @@ test( }, "first serve must not abort on a fresh setup DB that only has the 001 seed (#9934)"); // Prove the fresh DB actually got migrated past 001 to the latest version. - const maxRow = db.prepare( - "SELECT MAX(CAST(version AS INTEGER)) AS maxV FROM _omniroute_migrations" - ).get(); + const maxRow = db + .prepare("SELECT MAX(CAST(version AS INTEGER)) AS maxV FROM _omniroute_migrations") + .get(); assert.ok( (maxRow?.maxV ?? 0) > 1, `expected migrations beyond 001 to run, got max=${maxRow?.maxV}` @@ -142,7 +142,7 @@ test( } finally { if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); diff --git a/tests/unit/db-gamification-federation-3500.test.ts b/tests/unit/db-gamification-federation-3500.test.ts index 5fd1876fec..f36e5daee2 100644 --- a/tests/unit/db-gamification-federation-3500.test.ts +++ b/tests/unit/db-gamification-federation-3500.test.ts @@ -28,11 +28,23 @@ function seedServers() { db.prepare( `INSERT OR REPLACE INTO community_servers (id, name, url, api_key_hash, status) VALUES (?, ?, ?, ?, ?)` - ).run("srv-connected", "Connected Server", "https://connected.example", "hash-connected", "connected"); + ).run( + "srv-connected", + "Connected Server", + "https://connected.example", + "hash-connected", + "connected" + ); db.prepare( `INSERT OR REPLACE INTO community_servers (id, name, url, api_key_hash, status) VALUES (?, ?, ?, ?, ?)` - ).run("srv-disconnected", "Disconnected Server", "https://disconnected.example", "hash-disconnected", "disconnected"); + ).run( + "srv-disconnected", + "Disconnected Server", + "https://disconnected.example", + "hash-disconnected", + "disconnected" + ); } test.after(async () => { @@ -42,7 +54,12 @@ test.after(async () => { const tryRm = (attempts: number) => { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } resolve(); } catch (err: any) { @@ -73,9 +90,5 @@ test("getConnectedServerByKeyHash returns undefined for an unknown hash", () => test("getConnectedServerByKeyHash returns undefined for a disconnected server (status filter)", () => { seedServers(); const result = gamifDb.getConnectedServerByKeyHash("hash-disconnected"); - assert.equal( - result, - undefined, - "should not return a server whose status is not 'connected'" - ); + assert.equal(result, undefined, "should not return a server whose status is not 'connected'"); }); diff --git a/tests/unit/db-health-check.test.ts b/tests/unit/db-health-check.test.ts index 52f0f0a7a6..4486b7fc60 100644 --- a/tests/unit/db-health-check.test.ts +++ b/tests/unit/db-health-check.test.ts @@ -16,7 +16,7 @@ const healthCheckDb = await import("../../src/lib/db/healthCheck.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -27,7 +27,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function insertBrokenRows(db) { diff --git a/tests/unit/db-health-driver.test.ts b/tests/unit/db-health-driver.test.ts index efbc6b08f6..ef8a652eda 100644 --- a/tests/unit/db-health-driver.test.ts +++ b/tests/unit/db-health-driver.test.ts @@ -14,7 +14,7 @@ const driverFactory = await import("../../src/lib/db/adapters/driverFactory.ts") test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── describeDbDriver: pure decision ─────────────────── diff --git a/tests/unit/db-health-route.test.ts b/tests/unit/db-health-route.test.ts index 8b36871b88..415fffc9cb 100644 --- a/tests/unit/db-health-route.test.ts +++ b/tests/unit/db-health-route.test.ts @@ -19,7 +19,7 @@ const TEST_INITIAL_PASSWORD = "db-health-route-password"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); process.env.JWT_SECRET = TEST_JWT_SECRET; process.env.INITIAL_PASSWORD = TEST_INITIAL_PASSWORD; @@ -58,7 +58,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_JWT_SECRET === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = ORIGINAL_JWT_SECRET; if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/db-inspector-custom-hosts.test.ts b/tests/unit/db-inspector-custom-hosts.test.ts index 39ad298ae8..4496f2d51b 100644 --- a/tests/unit/db-inspector-custom-hosts.test.ts +++ b/tests/unit/db-inspector-custom-hosts.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -39,7 +39,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("listCustomHosts returns empty array initially", () => { diff --git a/tests/unit/db-inspector-sessions.test.ts b/tests/unit/db-inspector-sessions.test.ts index 801309d7d1..164e82223e 100644 --- a/tests/unit/db-inspector-sessions.test.ts +++ b/tests/unit/db-inspector-sessions.test.ts @@ -4,9 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-db-inspector-sessions-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-db-inspector-sessions-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -18,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -39,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createSession returns a uuid and started_at timestamp", () => { diff --git a/tests/unit/db-install-upgrade-schema-parity.test.ts b/tests/unit/db-install-upgrade-schema-parity.test.ts index 9ce6c408c4..6ed39eee5e 100644 --- a/tests/unit/db-install-upgrade-schema-parity.test.ts +++ b/tests/unit/db-install-upgrade-schema-parity.test.ts @@ -49,7 +49,7 @@ test.after(() => { } catch { /* best effort */ } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function migrationFiles(): Array<{ version: string; name: string }> { diff --git a/tests/unit/db-job-registry-migration-renumber-139.test.ts b/tests/unit/db-job-registry-migration-renumber-139.test.ts index 11f430dc0f..09788ae2cc 100644 --- a/tests/unit/db-job-registry-migration-renumber-139.test.ts +++ b/tests/unit/db-job-registry-migration-renumber-139.test.ts @@ -35,7 +35,7 @@ fs.writeFileSync( const { runMigrations } = await import("../../src/lib/db/migrationRunner.ts"); test.after(() => { - fs.rmSync(migrationsDir, { recursive: true, force: true }); + fs.rmSync(migrationsDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalMigrationsDir === undefined) delete process.env.OMNIROUTE_MIGRATIONS_DIR; else process.env.OMNIROUTE_MIGRATIONS_DIR = originalMigrationsDir; }); diff --git a/tests/unit/db-logs-cache-3500.test.ts b/tests/unit/db-logs-cache-3500.test.ts index 914a3f9a6b..b4e020f9a2 100644 --- a/tests/unit/db-logs-cache-3500.test.ts +++ b/tests/unit/db-logs-cache-3500.test.ts @@ -69,7 +69,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // =========================================================================== diff --git a/tests/unit/db-migration-runner-extra-dirs.test.ts b/tests/unit/db-migration-runner-extra-dirs.test.ts index 845b06366c..494122e7a7 100644 --- a/tests/unit/db-migration-runner-extra-dirs.test.ts +++ b/tests/unit/db-migration-runner-extra-dirs.test.ts @@ -85,7 +85,7 @@ const { runMigrations } = await import("../../src/lib/db/migrationRunner.ts"); process.on("exit", () => { for (const dir of tempDirs) { try { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ignore */ } @@ -258,7 +258,7 @@ test("diretório core ausente não impede as migrations dos extras", async () => name: f, body: fs.readFileSync(path.join(CORE_DIR, f), "utf-8"), })); - fs.rmSync(CORE_DIR, { recursive: true, force: true }); + fs.rmSync(CORE_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); try { const r = runWithExtras(`ee=${eeDir}`); assert.ok(r.tables.includes("ee_solo"), `tabelas: ${r.tables.join(", ")}`); diff --git a/tests/unit/db-model-aliases-cascade.test.ts b/tests/unit/db-model-aliases-cascade.test.ts index 2d1a76ce30..e75f2fc144 100644 --- a/tests/unit/db-model-aliases-cascade.test.ts +++ b/tests/unit/db-model-aliases-cascade.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("deleteModelAliasesForProvider removes only the target provider's aliases", async () => { diff --git a/tests/unit/db-model-context-overrides.test.ts b/tests/unit/db-model-context-overrides.test.ts index 5584ac3bc9..e13a791b26 100644 --- a/tests/unit/db-model-context-overrides.test.ts +++ b/tests/unit/db-model-context-overrides.test.ts @@ -14,7 +14,7 @@ const mco = await import("../../src/lib/db/modelContextOverrides.ts"); function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(moduleDataDir, { recursive: true }); } @@ -26,7 +26,7 @@ beforeEach(() => { after(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("modelContextOverrides", () => { @@ -47,7 +47,10 @@ describe("modelContextOverrides", () => { it("upserts on the same (provider, model) key and records the source", () => { mco.setModelContextOverride("anthropic", "claude-sonnet-4-5", 200000, "auto:discovery"); - assert.equal(mco.getModelContextOverrideRecord("anthropic", "claude-sonnet-4-5")?.source, "auto:discovery"); + assert.equal( + mco.getModelContextOverrideRecord("anthropic", "claude-sonnet-4-5")?.source, + "auto:discovery" + ); // Re-set as manual overwrites the same row. mco.setModelContextOverride("anthropic", "claude-sonnet-4-5", 1000000, "manual"); const rec = mco.getModelContextOverrideRecord("anthropic", "claude-sonnet-4-5"); @@ -82,9 +85,9 @@ describe("modelContextOverrides", () => { mco.setModelContextOverride("anthropic", "claude-sonnet-4-5", 200000, "auto:discovery"); const all = mco.listModelContextOverrides(); assert.equal(all.length, 2); - assert.deepEqual( - all.map((o) => `${o.provider}/${o.modelId}`).sort(), - ["anthropic/claude-sonnet-4-5", "openai/gpt-5"] - ); + assert.deepEqual(all.map((o) => `${o.provider}/${o.modelId}`).sort(), [ + "anthropic/claude-sonnet-4-5", + "openai/gpt-5", + ]); }); }); diff --git a/tests/unit/db-models-crud.test.ts b/tests/unit/db-models-crud.test.ts index bd21ad6aca..31c0d30253 100644 --- a/tests/unit/db-models-crud.test.ts +++ b/tests/unit/db-models-crud.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("model aliases can be created, listed and deleted", async () => { diff --git a/tests/unit/db-models-extended.test.ts b/tests/unit/db-models-extended.test.ts index 201d9d88a3..8971da4e2a 100644 --- a/tests/unit/db-models-extended.test.ts +++ b/tests/unit/db-models-extended.test.ts @@ -25,7 +25,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { diff --git a/tests/unit/db-playground-presets.test.ts b/tests/unit/db-playground-presets.test.ts index f3907481e8..77b8497466 100644 --- a/tests/unit/db-playground-presets.test.ts +++ b/tests/unit/db-playground-presets.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -39,7 +39,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Migration idempotency ─────────────────────────────────────────────────── diff --git a/tests/unit/db-pre-migration-backup-retention-10421.test.ts b/tests/unit/db-pre-migration-backup-retention-10421.test.ts index bc99aa39fb..798bb3cb66 100644 --- a/tests/unit/db-pre-migration-backup-retention-10421.test.ts +++ b/tests/unit/db-pre-migration-backup-retention-10421.test.ts @@ -211,7 +211,7 @@ test( ); } finally { db.close(); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); @@ -263,6 +263,6 @@ test("#10421 the newest pre-migration backup survives pruning", serial, async () assert.equal(fresh.length, 1, `expected the run's own backup to survive, got ${fresh.length}`); } finally { db.close(); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/db-provider-cookie-dedup-3368.test.ts b/tests/unit/db-provider-cookie-dedup-3368.test.ts index 9d5916a4ff..f62278b317 100644 --- a/tests/unit/db-provider-cookie-dedup-3368.test.ts +++ b/tests/unit/db-provider-cookie-dedup-3368.test.ts @@ -19,7 +19,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -40,7 +40,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3368 cookie dedup: re-importing the same cookie under a different name updates, not duplicates", async () => { diff --git a/tests/unit/db-provider-daily-usage-4009.test.ts b/tests/unit/db-provider-daily-usage-4009.test.ts index 9c19f747a3..3dcf30c2f5 100644 --- a/tests/unit/db-provider-daily-usage-4009.test.ts +++ b/tests/unit/db-provider-daily-usage-4009.test.ts @@ -59,7 +59,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4009 getProviderDailyUsageRows is exported as a function", () => { diff --git a/tests/unit/db-provider-limits.test.ts b/tests/unit/db-provider-limits.test.ts index e5104e5e08..40c6804ad8 100644 --- a/tests/unit/db-provider-limits.test.ts +++ b/tests/unit/db-provider-limits.test.ts @@ -12,7 +12,7 @@ const providerLimitsDb = await import("../../src/lib/db/providerLimits.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("providerLimits cache returns empty defaults before any writes", () => { diff --git a/tests/unit/db-provider-plans.test.ts b/tests/unit/db-provider-plans.test.ts index ab9c25edae..a9a35c285d 100644 --- a/tests/unit/db-provider-plans.test.ts +++ b/tests/unit/db-provider-plans.test.ts @@ -26,7 +26,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -46,7 +46,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -54,12 +54,7 @@ test.after(async () => { // --------------------------------------------------------------------------- test("upsertPlan creates a plan row", () => { - plansDb.upsertPlan( - "conn-1", - "codex", - [{ unit: "percent", window: "5h", limit: 100 }], - "auto" - ); + plansDb.upsertPlan("conn-1", "codex", [{ unit: "percent", window: "5h", limit: 100 }], "auto"); const all = plansDb.listPlans(); assert.equal(all.length, 1); @@ -204,7 +199,12 @@ test("upserting one plan does not affect other connection plans", () => { ); // Update conn-x - plansDb.upsertPlan("conn-x", "openai", [{ unit: "usd", window: "monthly", limit: 100 }], "manual"); + plansDb.upsertPlan( + "conn-x", + "openai", + [{ unit: "usd", window: "monthly", limit: 100 }], + "manual" + ); const planY = plansDb.getPlan("conn-y"); assert.ok(planY, "conn-y should still exist"); diff --git a/tests/unit/db-provider-stats.test.ts b/tests/unit/db-provider-stats.test.ts index 398351084a..0d4f5c09d7 100644 --- a/tests/unit/db-provider-stats.test.ts +++ b/tests/unit/db-provider-stats.test.ts @@ -72,7 +72,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3175 getProviderCallStats aggregates totals, success and latency per provider", () => { diff --git a/tests/unit/db-providers-access-token-1290.test.ts b/tests/unit/db-providers-access-token-1290.test.ts index 85d94ec50f..45c1600e4d 100644 --- a/tests/unit/db-providers-access-token-1290.test.ts +++ b/tests/unit/db-providers-access-token-1290.test.ts @@ -20,7 +20,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createProviderConnection: authType access_token never dedups — same email creates a new row each time", async () => { diff --git a/tests/unit/db-providers-cross-idp-dedup-2244.test.ts b/tests/unit/db-providers-cross-idp-dedup-2244.test.ts index fd74044cc4..47c05102a2 100644 --- a/tests/unit/db-providers-cross-idp-dedup-2244.test.ts +++ b/tests/unit/db-providers-cross-idp-dedup-2244.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -45,7 +45,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#2244 cross-IdP dedup: same email + same username updates the existing connection", async () => { @@ -92,7 +92,9 @@ test("#2244 cross-IdP dedup: same email + DIFFERENT username creates a separate "two different IdP identities sharing an email must NOT be collapsed into one connection" ); const usernames = conns - .map((c) => (c as { providerSpecificData?: { username?: string } }).providerSpecificData?.username) + .map( + (c) => (c as { providerSpecificData?: { username?: string } }).providerSpecificData?.username + ) .sort(); assert.deepEqual(usernames, ["alice-google", "alice-huggingface"]); }); diff --git a/tests/unit/db-providers-crud.test.ts b/tests/unit/db-providers-crud.test.ts index a731780597..eb545bbfce 100644 --- a/tests/unit/db-providers-crud.test.ts +++ b/tests/unit/db-providers-crud.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createProviderConnection assigns provider-scoped priorities and supports filtered reads", async () => { @@ -418,11 +418,12 @@ test("getProviderConnections supports authType filter and column projection", as assert.equal(activeOAuth.length, 1); // Column projection: only requested columns returned - const projected = await providersDb.getProviderConnections({ authType: "oauth" }, undefined, undefined, [ - "id", - "provider", - "name", - ]); + const projected = await providersDb.getProviderConnections( + { authType: "oauth" }, + undefined, + undefined, + ["id", "provider", "name"] + ); assert.equal(projected.length, 1); const keys = Object.keys(projected[0]); // id, provider, name each appear in camelCase @@ -456,7 +457,11 @@ test("getProviderConnections rejects column names outside the real provider_conn // A mix of valid + invalid columns must still reject (fail-closed, not a // silent partial projection). await assert.rejects( - () => providersDb.getProviderConnections({}, undefined, undefined, ["id", "provider; DROP TABLE provider_connections; --"]), + () => + providersDb.getProviderConnections({}, undefined, undefined, [ + "id", + "provider; DROP TABLE provider_connections; --", + ]), /invalid column/i ); @@ -472,10 +477,12 @@ test("getProviderConnections rejects column names outside the real provider_conn isActive: true, group: "team-a", }); - const withGroup = await providersDb.getProviderConnections({ authType: "oauth" }, undefined, undefined, [ - "id", - "group", - ]); + const withGroup = await providersDb.getProviderConnections( + { authType: "oauth" }, + undefined, + undefined, + ["id", "group"] + ); assert.equal(withGroup.length, 1); assert.equal(withGroup[0].group, "team-a"); }); diff --git a/tests/unit/db-proxies-crud.test.ts b/tests/unit/db-proxies-crud.test.ts index 1cd35d35c9..4a69ebc718 100644 --- a/tests/unit/db-proxies-crud.test.ts +++ b/tests/unit/db-proxies-crud.test.ts @@ -17,7 +17,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -38,7 +38,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("proxy CRUD redacts secrets by default and preserves stored credentials when omitted", async () => { diff --git a/tests/unit/db-quota-consumption.test.ts b/tests/unit/db-quota-consumption.test.ts index 3a166291f4..b3daccbfde 100644 --- a/tests/unit/db-quota-consumption.test.ts +++ b/tests/unit/db-quota-consumption.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -128,7 +128,7 @@ test("getPair returns curr and prev buckets", () => { const now = Date.now(); consumptionDb.incrementBucket(key, dim, 100, 70, now); // current bucket - consumptionDb.incrementBucket(key, dim, 99, 30, now); // previous bucket + consumptionDb.incrementBucket(key, dim, 99, 30, now); // previous bucket const { curr, prev } = consumptionDb.getPair(key, dim, 100); assert.equal(curr, 70); @@ -157,8 +157,8 @@ test("gcOlderThan deletes only rows with updated_at strictly less than threshold // Insert 3 rows with different timestamps consumptionDb.incrementBucket("key-gc1", "pool-gc:tokens:daily", 1, 1, now - 100); // older → deleted - consumptionDb.incrementBucket("key-gc2", "pool-gc:tokens:daily", 2, 1, now - 1); // older → deleted - consumptionDb.incrementBucket("key-gc3", "pool-gc:tokens:daily", 3, 1, now); // at threshold → kept + consumptionDb.incrementBucket("key-gc2", "pool-gc:tokens:daily", 2, 1, now - 1); // older → deleted + consumptionDb.incrementBucket("key-gc3", "pool-gc:tokens:daily", 3, 1, now); // at threshold → kept consumptionDb.incrementBucket("key-gc4", "pool-gc:tokens:daily", 4, 1, now + 100); // newer → kept const deleted = consumptionDb.gcOlderThan(threshold); diff --git a/tests/unit/db-quota-migrations-idempotency.test.ts b/tests/unit/db-quota-migrations-idempotency.test.ts index 969335fc2f..d10fba4d93 100644 --- a/tests/unit/db-quota-migrations-idempotency.test.ts +++ b/tests/unit/db-quota-migrations-idempotency.test.ts @@ -24,7 +24,9 @@ const core = await import("../../src/lib/db/core.ts"); function getDb() { return core.getDbInstance() as unknown as { - prepare: (sql: string) => { + prepare: ( + sql: string + ) => { all: (...params: unknown[]) => TRow[]; get: (...params: unknown[]) => TRow | undefined; run: (...params: unknown[]) => { changes: number }; @@ -35,9 +37,7 @@ function getDb() { function listSqliteMaster(type: "table" | "index"): string[] { const db = getDb(); const rows = db - .prepare<{ name: string }>( - `SELECT name FROM sqlite_master WHERE type = ? ORDER BY name` - ) + .prepare<{ name: string }>(`SELECT name FROM sqlite_master WHERE type = ? ORDER BY name`) .all(type); return rows.map((r) => r.name); } @@ -53,7 +53,7 @@ const EXPECTED_INDEXES = [ test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migrations 073-075 create all expected tables and indexes on first init", () => { @@ -64,7 +64,10 @@ test("migrations 073-075 create all expected tables and indexes on first init", const indexes = listSqliteMaster("index"); for (const table of EXPECTED_TABLES) { - assert.ok(tables.includes(table), `Expected table '${table}' to exist. Found: ${tables.join(", ")}`); + assert.ok( + tables.includes(table), + `Expected table '${table}' to exist. Found: ${tables.join(", ")}` + ); } for (const idx of EXPECTED_INDEXES) { diff --git a/tests/unit/db-quota-pools.test.ts b/tests/unit/db-quota-pools.test.ts index ecf04494a1..c73fbf9ad4 100644 --- a/tests/unit/db-quota-pools.test.ts +++ b/tests/unit/db-quota-pools.test.ts @@ -27,7 +27,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/unit/db-quota-snapshots.test.ts b/tests/unit/db-quota-snapshots.test.ts index cce181254a..9a13864980 100644 --- a/tests/unit/db-quota-snapshots.test.ts +++ b/tests/unit/db-quota-snapshots.test.ts @@ -12,7 +12,7 @@ const quotaSnapshotsDb = await import("../../src/lib/db/quotaSnapshots.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("quotaSnapshots save and query rows with provider and connection filters", () => { diff --git a/tests/unit/db-read-cache.test.ts b/tests/unit/db-read-cache.test.ts index 55181dba2e..f1e58b2990 100644 --- a/tests/unit/db-read-cache.test.ts +++ b/tests/unit/db-read-cache.test.ts @@ -23,7 +23,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getCachedSettings returns cached data until TTL expires or cache is invalidated", async () => { diff --git a/tests/unit/db-recovery.test.ts b/tests/unit/db-recovery.test.ts index 0eaa3156d9..5a2aad049f 100644 --- a/tests/unit/db-recovery.test.ts +++ b/tests/unit/db-recovery.test.ts @@ -12,7 +12,7 @@ async function withRecoveryEnv(fn: (dataDir: string) => Promise) { try { await fn(dataDir); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; } diff --git a/tests/unit/db-registered-keys.test.ts b/tests/unit/db-registered-keys.test.ts index 6173cc08d4..4dee75800b 100644 --- a/tests/unit/db-registered-keys.test.ts +++ b/tests/unit/db-registered-keys.test.ts @@ -12,7 +12,7 @@ const registeredKeysDb = await import("../../src/lib/db/registeredKeys.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("registered keys issue, validate, consume budget and revoke correctly", () => { diff --git a/tests/unit/db-registeredKeys-crud.test.ts b/tests/unit/db-registeredKeys-crud.test.ts index 8475517982..7ef8c0a192 100644 --- a/tests/unit/db-registeredKeys-crud.test.ts +++ b/tests/unit/db-registeredKeys-crud.test.ts @@ -15,7 +15,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { diff --git a/tests/unit/db-reset-module-state.test.ts b/tests/unit/db-reset-module-state.test.ts index f4fdd63a12..2ab944dac0 100644 --- a/tests/unit/db-reset-module-state.test.ts +++ b/tests/unit/db-reset-module-state.test.ts @@ -22,7 +22,7 @@ const { isValidApiKey } = await import("../../src/sse/services/auth.ts"); async function recreateDataDirFromScratch(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // Primeiro acesso recria o DB do zero (migrations + colunas-fallback). await settingsDb.updateSettings({ requireLogin: true, setupComplete: true }); @@ -40,7 +40,7 @@ test("api-key validation survives a second resetDbInstance with a recreated DB ( test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/db-secrets.test.ts b/tests/unit/db-secrets.test.ts index 0d085c2176..033491b275 100644 --- a/tests/unit/db-secrets.test.ts +++ b/tests/unit/db-secrets.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getPersistedSecret returns null for missing keys", () => { diff --git a/tests/unit/db-settings-crud.test.ts b/tests/unit/db-settings-crud.test.ts index bc5d06aa4e..2b53e043ae 100644 --- a/tests/unit/db-settings-crud.test.ts +++ b/tests/unit/db-settings-crud.test.ts @@ -21,7 +21,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -43,7 +43,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) { delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/db-settings-debug-mode-default-10312.test.ts b/tests/unit/db-settings-debug-mode-default-10312.test.ts index 327b4ce74d..e4a22b6417 100644 --- a/tests/unit/db-settings-debug-mode-default-10312.test.ts +++ b/tests/unit/db-settings-debug-mode-default-10312.test.ts @@ -21,7 +21,7 @@ async function resetStorage() { delete (globalThis as { __omnirouteDb?: unknown }).__omnirouteDb; core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); diff --git a/tests/unit/db-settings-extended.test.ts b/tests/unit/db-settings-extended.test.ts index 6bb476a573..cf36810871 100644 --- a/tests/unit/db-settings-extended.test.ts +++ b/tests/unit/db-settings-extended.test.ts @@ -25,7 +25,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch { diff --git a/tests/unit/db-sqljs-atomic-persist.test.ts b/tests/unit/db-sqljs-atomic-persist.test.ts index bb61f2a5c3..de2b9f607c 100644 --- a/tests/unit/db-sqljs-atomic-persist.test.ts +++ b/tests/unit/db-sqljs-atomic-persist.test.ts @@ -96,7 +96,7 @@ test( } finally { if (readerFd !== null) fs.closeSync(readerFd); if (adapter?.open) adapter.close(); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); @@ -111,6 +111,6 @@ test("sql.js persist() is a no-op for :memory: databases (no temp file, no throw assert.deepEqual(fs.readdirSync(dataDir), [], "an in-memory database wrote to disk"); } finally { if (adapter?.open) adapter.close(); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/db-sqljs-close-poison-7494.test.ts b/tests/unit/db-sqljs-close-poison-7494.test.ts index cd819c8785..1da7b006ae 100644 --- a/tests/unit/db-sqljs-close-poison-7494.test.ts +++ b/tests/unit/db-sqljs-close-poison-7494.test.ts @@ -22,9 +22,8 @@ test( const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-7494-mech-")); const sqliteFile = path.join(dataDir, "storage.sqlite"); try { - const { preInitSqlJs, getSqlJsAdapter } = await import( - "../../src/lib/db/adapters/driverFactory" - ); + const { preInitSqlJs, getSqlJsAdapter } = + await import("../../src/lib/db/adapters/driverFactory"); const boot = await preInitSqlJs(sqliteFile); boot.exec("CREATE TABLE t (id INTEGER)"); @@ -32,9 +31,7 @@ test( const probe = getSqlJsAdapter(sqliteFile); probe! - .prepare( - "SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'" - ) + .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'") .get(); probe!.close(); @@ -46,7 +43,7 @@ test( "sanity: confirms the underlying sql.js singleton mechanism this bug exploits" ); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); @@ -59,9 +56,8 @@ test( const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-7494-guard-")); const sqliteFile = path.join(dataDir, "storage.sqlite"); try { - const { preInitSqlJs, getSqlJsAdapter } = await import( - "../../src/lib/db/adapters/driverFactory" - ); + const { preInitSqlJs, getSqlJsAdapter } = + await import("../../src/lib/db/adapters/driverFactory"); const { closeProbeIfSafe } = await import("../../src/lib/db/core"); const boot = await preInitSqlJs(sqliteFile); @@ -72,9 +68,7 @@ test( // the guarded helper instead of a raw .close() call. const probe = getSqlJsAdapter(sqliteFile); probe! - .prepare( - "SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'" - ) + .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'") .get(); closeProbeIfSafe(probe); @@ -94,7 +88,7 @@ test( // already-deleted path in the background. await new Promise((resolve) => setTimeout(resolve, 200)); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); @@ -117,7 +111,7 @@ test( assert.equal(probe!.open, false, "closeProbeIfSafe() must still close non-sql.js adapters"); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); diff --git a/tests/unit/db-sqljs-preinit-ordering-gap-7288.test.ts b/tests/unit/db-sqljs-preinit-ordering-gap-7288.test.ts index c68cebea3d..912702df13 100644 --- a/tests/unit/db-sqljs-preinit-ordering-gap-7288.test.ts +++ b/tests/unit/db-sqljs-preinit-ordering-gap-7288.test.ts @@ -61,7 +61,7 @@ test.after(() => { } if (prevDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = prevDataDir; - if (dataDir) fs.rmSync(dataDir, { recursive: true, force: true }); + if (dataDir) fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("src/lib/db/core.ts has no top-level await (breaks esbuild's CJS require() bundling — #7288 hotfix)", () => { @@ -183,9 +183,8 @@ test( const dir2 = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-7288-happy-")); const file2 = path.join(dir2, "storage.sqlite"); try { - const { tryOpenSync, getSqlJsAdapter } = await import( - "../../src/lib/db/adapters/driverFactory" - ); + const { tryOpenSync, getSqlJsAdapter } = + await import("../../src/lib/db/adapters/driverFactory"); const { default: Database } = await import("better-sqlite3"); const seed = new Database(file2); seed.exec("CREATE TABLE t (id INTEGER)"); @@ -204,7 +203,7 @@ test( "otherwise every boot would pay the WASM-load cost even on the happy path" ); } finally { - fs.rmSync(dir2, { recursive: true, force: true }); + fs.rmSync(dir2, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); diff --git a/tests/unit/db-synced-model-catalog-invalidation-8728.test.ts b/tests/unit/db-synced-model-catalog-invalidation-8728.test.ts index 7145857980..38940659e7 100644 --- a/tests/unit/db-synced-model-catalog-invalidation-8728.test.ts +++ b/tests/unit/db-synced-model-catalog-invalidation-8728.test.ts @@ -14,7 +14,7 @@ const readCache = await import("../../src/lib/db/readCache.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -45,7 +45,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("replace invalidates only for canonical persisted changes", async () => { diff --git a/tests/unit/db-upstreamProxy.test.ts b/tests/unit/db-upstreamProxy.test.ts index 7948e62eff..3b2b664478 100644 --- a/tests/unit/db-upstreamProxy.test.ts +++ b/tests/unit/db-upstreamProxy.test.ts @@ -53,12 +53,13 @@ afterEach(() => { }); after(() => { - if (fs.existsSync(fileTmpDir)) fs.rmSync(fileTmpDir, { recursive: true, force: true }); + if (fs.existsSync(fileTmpDir)) + fs.rmSync(fileTmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function resetModuleStorage() { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(moduleDataDir, { recursive: true }); } @@ -367,7 +368,7 @@ describe("db/upstreamProxy (module coverage)", () => { after(async () => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("validates proxy URLs and blocks unsupported or private destinations", async () => { diff --git a/tests/unit/db-usage-analytics-3500.test.ts b/tests/unit/db-usage-analytics-3500.test.ts index e9d49c4326..4bf2c7b409 100644 --- a/tests/unit/db-usage-analytics-3500.test.ts +++ b/tests/unit/db-usage-analytics-3500.test.ts @@ -89,7 +89,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/unit/db-versionManager.test.ts b/tests/unit/db-versionManager.test.ts index 34ff05a3a2..2020fc8e7f 100644 --- a/tests/unit/db-versionManager.test.ts +++ b/tests/unit/db-versionManager.test.ts @@ -64,12 +64,13 @@ afterEach(() => { }); after(() => { - if (fs.existsSync(fileTmpDir)) fs.rmSync(fileTmpDir, { recursive: true, force: true }); + if (fs.existsSync(fileTmpDir)) + fs.rmSync(fileTmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function resetModuleStorage() { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(moduleDataDir, { recursive: true }); } @@ -395,7 +396,7 @@ describe("db/versionManager (module coverage)", () => { after(async () => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("round-trips inserts, updates and status listings through the production module", async () => { diff --git a/tests/unit/db-webhooks.test.ts b/tests/unit/db-webhooks.test.ts index 78e83b0fc7..5e8ace2df7 100644 --- a/tests/unit/db-webhooks.test.ts +++ b/tests/unit/db-webhooks.test.ts @@ -12,7 +12,7 @@ const webhooksDb = await import("../../src/lib/db/webhooks.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("webhooks create, update, query enabled hooks and delete records", () => { diff --git a/tests/unit/db/api-keys.test.ts b/tests/unit/db/api-keys.test.ts index 3c01698b56..56f6145981 100644 --- a/tests/unit/db/api-keys.test.ts +++ b/tests/unit/db/api-keys.test.ts @@ -27,7 +27,7 @@ const MACHINE_ID = "machine1234567890"; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ───────────────────────────────────────────────────────────────────────────── diff --git a/tests/unit/db/connectionRuntimeState.test.ts b/tests/unit/db/connectionRuntimeState.test.ts index 1a90d0527a..897e0a0b2c 100644 --- a/tests/unit/db/connectionRuntimeState.test.ts +++ b/tests/unit/db/connectionRuntimeState.test.ts @@ -28,7 +28,7 @@ const crs = await import("../../../src/lib/db/connectionRuntimeState.ts"); async function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("get: returns null for unknown connection", async () => { diff --git a/tests/unit/db/context-editing-telemetry-record.test.ts b/tests/unit/db/context-editing-telemetry-record.test.ts index 1b5c9ad3eb..8242818b6b 100644 --- a/tests/unit/db/context-editing-telemetry-record.test.ts +++ b/tests/unit/db/context-editing-telemetry-record.test.ts @@ -29,7 +29,7 @@ const { function resetDb(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/db/default-combo-toggle.test.ts b/tests/unit/db/default-combo-toggle.test.ts index 62434b9cd6..8e49b23b72 100644 --- a/tests/unit/db/default-combo-toggle.test.ts +++ b/tests/unit/db/default-combo-toggle.test.ts @@ -27,7 +27,7 @@ const { getDefaultCompressionCombo, setEngineInDefaultCombo, getCompressionCombo function resetDb(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/db/discovery-results.test.ts b/tests/unit/db/discovery-results.test.ts index afc4106ee6..6ad482c0e9 100644 --- a/tests/unit/db/discovery-results.test.ts +++ b/tests/unit/db/discovery-results.test.ts @@ -21,7 +21,8 @@ before(async () => { after(() => { core.resetDbInstance(); - if (tmpDataDir) rmSync(tmpDataDir, { recursive: true, force: true }); + if (tmpDataDir) + rmSync(tmpDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("discoveryResults DB module", () => { diff --git a/tests/unit/db/jobRegistryDb.test.ts b/tests/unit/db/jobRegistryDb.test.ts index 08aa22a9c7..c701f08a75 100644 --- a/tests/unit/db/jobRegistryDb.test.ts +++ b/tests/unit/db/jobRegistryDb.test.ts @@ -28,7 +28,7 @@ const db = await import("../../../src/lib/db/jobRegistryDb.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("seed: migration registers 3 built-in jobs", () => { diff --git a/tests/unit/db/migration-071.test.ts b/tests/unit/db/migration-071.test.ts index 1522e37abc..6df839940b 100644 --- a/tests/unit/db/migration-071.test.ts +++ b/tests/unit/db/migration-071.test.ts @@ -25,7 +25,7 @@ const versionManager = await import("../../../src/lib/db/versionManager.ts"); async function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 071 — adds 3 new columns to version_manager", async () => { diff --git a/tests/unit/db/migration-163.test.ts b/tests/unit/db/migration-163.test.ts index dcad8bd959..ea1b6f7f39 100644 --- a/tests/unit/db/migration-163.test.ts +++ b/tests/unit/db/migration-163.test.ts @@ -24,7 +24,7 @@ const radarDb = await import("../../../src/lib/db/radar.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 163 — radar_feed_cache carries generated_at exactly once", () => { diff --git a/tests/unit/db/omp.test.ts b/tests/unit/db/omp.test.ts index d06e014b90..ae5c13329f 100644 --- a/tests/unit/db/omp.test.ts +++ b/tests/unit/db/omp.test.ts @@ -25,11 +25,8 @@ import os from "node:os"; import path from "node:path"; import Database from "better-sqlite3"; -const { - getOmpCredentials, - saveOmpCredentials, - deleteOmpCredentials, -} = await import("../../../src/lib/db/omp.ts"); +const { getOmpCredentials, saveOmpCredentials, deleteOmpCredentials } = + await import("../../../src/lib/db/omp.ts"); const PROVIDER_ID = "omniroute"; @@ -67,7 +64,7 @@ beforeEach(() => { afterEach(() => { process.env.HOME = origHome; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("db/omp.ts — getOmpCredentials", () => { diff --git a/tests/unit/db/per-engine-analytics.test.ts b/tests/unit/db/per-engine-analytics.test.ts index 018e14e1f2..58af68687e 100644 --- a/tests/unit/db/per-engine-analytics.test.ts +++ b/tests/unit/db/per-engine-analytics.test.ts @@ -27,7 +27,7 @@ const { insertCompressionAnalyticsRow, getPerEngineAnalytics } = function resetDb(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/db/per-engine-breakdown-analytics.test.ts b/tests/unit/db/per-engine-breakdown-analytics.test.ts index e5fec7147e..107d4768d0 100644 --- a/tests/unit/db/per-engine-breakdown-analytics.test.ts +++ b/tests/unit/db/per-engine-breakdown-analytics.test.ts @@ -27,7 +27,7 @@ const { insertCompressionAnalyticsRow, insertCompressionEngineBreakdown, getPerE function resetDb(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/db/quota-pools.test.ts b/tests/unit/db/quota-pools.test.ts index d818840740..5245e3910f 100644 --- a/tests/unit/db/quota-pools.test.ts +++ b/tests/unit/db/quota-pools.test.ts @@ -21,7 +21,7 @@ const { getDbInstance } = await import("../../../src/lib/db/core.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ───────────────────────────────────────────────────────────────────────────── diff --git a/tests/unit/db/repositories/sqliteComboRepositories.test.ts b/tests/unit/db/repositories/sqliteComboRepositories.test.ts index a9d9181234..94c41620e1 100644 --- a/tests/unit/db/repositories/sqliteComboRepositories.test.ts +++ b/tests/unit/db/repositories/sqliteComboRepositories.test.ts @@ -18,7 +18,7 @@ const combosDb = await import("../../../../src/lib/db/combos.ts"); async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,5 +42,5 @@ test("legacy combo count facade remains synchronous", async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/db/serviceModels.test.ts b/tests/unit/db/serviceModels.test.ts index 0e36f2164a..4d745d97fb 100644 --- a/tests/unit/db/serviceModels.test.ts +++ b/tests/unit/db/serviceModels.test.ts @@ -21,7 +21,7 @@ const { getServiceModels, saveServiceModels, markAllUnavailable } = function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getServiceModels — returns [] when no row exists", () => { diff --git a/tests/unit/db/vacuum-scheduler.test.ts b/tests/unit/db/vacuum-scheduler.test.ts index 0f979c2495..43fb6e9bb0 100644 --- a/tests/unit/db/vacuum-scheduler.test.ts +++ b/tests/unit/db/vacuum-scheduler.test.ts @@ -54,7 +54,7 @@ test.beforeEach(() => { test.after(() => { scheduler.__resetForTests(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/db/weak-rng-fixes.test.ts b/tests/unit/db/weak-rng-fixes.test.ts index 3d23d5d20c..9f50fe15a4 100644 --- a/tests/unit/db/weak-rng-fixes.test.ts +++ b/tests/unit/db/weak-rng-fixes.test.ts @@ -9,7 +9,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/deepseek-thinking-efforts.test.ts b/tests/unit/deepseek-thinking-efforts.test.ts index a47dc88c76..899402eab8 100644 --- a/tests/unit/deepseek-thinking-efforts.test.ts +++ b/tests/unit/deepseek-thinking-efforts.test.ts @@ -19,14 +19,14 @@ const { sanitizeReasoningEffortForProvider } = await import("../../open-sse/exec test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("DeepSeek registries declare none/low/high/max on both V4 models", () => { diff --git a/tests/unit/delete-provider-connection-clears-combo-pins-8887.test.ts b/tests/unit/delete-provider-connection-clears-combo-pins-8887.test.ts index b38a81c8d0..f97fb9115c 100644 --- a/tests/unit/delete-provider-connection-clears-combo-pins-8887.test.ts +++ b/tests/unit/delete-provider-connection-clears-combo-pins-8887.test.ts @@ -22,6 +22,9 @@ async function resetStorage(): Promise { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, + + maxRetries: 5, + retryDelay: 100, }); break; } catch (error: unknown) { @@ -84,6 +87,9 @@ test.after(() => { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, + + maxRetries: 5, + retryDelay: 100, }); }); diff --git a/tests/unit/delete-provider-connection-invalidates-lkgp-8887.test.ts b/tests/unit/delete-provider-connection-invalidates-lkgp-8887.test.ts index 83226544fe..04d4f52434 100644 --- a/tests/unit/delete-provider-connection-invalidates-lkgp-8887.test.ts +++ b/tests/unit/delete-provider-connection-invalidates-lkgp-8887.test.ts @@ -22,7 +22,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); break; } catch (error: unknown) { const code = @@ -60,7 +60,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8887: single delete removes only the matching LKGP pin", async () => { diff --git a/tests/unit/delete-provider-connection-purges-key-health-7740.test.ts b/tests/unit/delete-provider-connection-purges-key-health-7740.test.ts index 0d9cc7bc3a..f508cb51a4 100644 --- a/tests/unit/delete-provider-connection-purges-key-health-7740.test.ts +++ b/tests/unit/delete-provider-connection-purges-key-health-7740.test.ts @@ -16,7 +16,8 @@ async function resetStorage() { core.resetDbInstance(); for (let attempt = 0; attempt < 10; attempt++) { try { - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); break; } catch (error: unknown) { const code = (error as { code?: string } | undefined)?.code; @@ -33,7 +34,7 @@ test.beforeEach(async () => { }); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7740: orphaned provider connection (id removed from catalog) keeps surfacing apiKeyHealth and 404s on click, but deleting purges in-memory key-health", async () => { diff --git a/tests/unit/devin-bridge-network-guard.test.ts b/tests/unit/devin-bridge-network-guard.test.ts index 2114311637..cd974f6a3d 100644 --- a/tests/unit/devin-bridge-network-guard.test.ts +++ b/tests/unit/devin-bridge-network-guard.test.ts @@ -125,7 +125,7 @@ test("HTTP proxy overwrites Host and strips proxy and hop-by-hop credentials", a } finally { await close(proxy); await close(upstream); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -163,7 +163,7 @@ test("CONNECT rejects mismatched SNI before opening an upstream socket", async ( assert.match(fs.readFileSync(logPath, "utf8"), /"reason":"sni_mismatch"/); } finally { await close(proxy); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -212,6 +212,6 @@ test("CONNECT forwards only after matching SNI is validated", async () => { } finally { await close(proxy); await close(upstream); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/dgrid-provider.test.ts b/tests/unit/dgrid-provider.test.ts index 4542afad33..77fc9c77c3 100644 --- a/tests/unit/dgrid-provider.test.ts +++ b/tests/unit/dgrid-provider.test.ts @@ -71,13 +71,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { diff --git a/tests/unit/dns-config-generic.test.ts b/tests/unit/dns-config-generic.test.ts index a9441895ae..5f1d85921e 100644 --- a/tests/unit/dns-config-generic.test.ts +++ b/tests/unit/dns-config-generic.test.ts @@ -272,7 +272,7 @@ test("addDNSEntries: generates both IPv4 and IPv6 lines per host", () => { // --------------------------------------------------------------------------- test.after(() => { try { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best effort } diff --git a/tests/unit/docker-llmlingua-optionals-9166.test.ts b/tests/unit/docker-llmlingua-optionals-9166.test.ts index ac57d0d362..1765cbd413 100644 --- a/tests/unit/docker-llmlingua-optionals-9166.test.ts +++ b/tests/unit/docker-llmlingua-optionals-9166.test.ts @@ -1,13 +1,6 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { - existsSync, - mkdtempSync, - mkdirSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; +import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { tmpdir } from "node:os"; @@ -44,10 +37,7 @@ function mkPkg( } } -function buildLlmlinguaRoot( - rootDir: string, - transformersVersion = "4.2.0" -): void { +function buildLlmlinguaRoot(rootDir: string, transformersVersion = "4.2.0"): void { const rootNm = join(rootDir, "node_modules"); mkPkg( @@ -97,18 +87,13 @@ function createStandalone(rootDir: string): { recursive: true, }); - writeFileSync( - join(standaloneDir, "package.json"), - JSON.stringify({ name: "standalone-test" }) - ); + writeFileSync(join(standaloneDir, "package.json"), JSON.stringify({ name: "standalone-test" })); return { distDir, standaloneDir }; } test("#9166 standalone assembly includes the complete LLMLingua runtime closure", () => { - const root = mkdtempSync( - join(tmpdir(), "omniroute-docker-llmlingua-9166-") - ); + const root = mkdtempSync(join(tmpdir(), "omniroute-docker-llmlingua-9166-")); try { buildLlmlinguaRoot(root); @@ -128,47 +113,30 @@ test("#9166 standalone assembly includes the complete LLMLingua runtime closure" "onnxruntime-node", ]) { assert.ok( - existsSync( - join(standaloneDir, "node_modules", packageName, "package.json") - ), + existsSync(join(standaloneDir, "node_modules", packageName, "package.json")), `${packageName} must be present in the standalone runtime` ); } assert.ok( - existsSync( - join( - standaloneDir, - "node_modules", - "@atjsh", - "llmlingua-2", - "dist", - "index.js" - ) - ), + existsSync(join(standaloneDir, "node_modules", "@atjsh", "llmlingua-2", "dist", "index.js")), "the complete LLMLingua package payload must be copied" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); test("#9166 standalone assembly never overwrites an already pinned transformers instance", () => { - const root = mkdtempSync( - join(tmpdir(), "omniroute-docker-llmlingua-pinned-9166-") - ); + const root = mkdtempSync(join(tmpdir(), "omniroute-docker-llmlingua-pinned-9166-")); try { buildLlmlinguaRoot(root, "5.0.0"); const { distDir, standaloneDir } = createStandalone(root); - mkPkg( - join(standaloneDir, "node_modules"), - "@huggingface/transformers", - { - version: "4.2.0", - } - ); + mkPkg(join(standaloneDir, "node_modules"), "@huggingface/transformers", { + version: "4.2.0", + }); assembleStandalone({ distDir, @@ -179,13 +147,7 @@ test("#9166 standalone assembly never overwrites an already pinned transformers const targetManifest = JSON.parse( readFileSync( - join( - standaloneDir, - "node_modules", - "@huggingface", - "transformers", - "package.json" - ), + join(standaloneDir, "node_modules", "@huggingface", "transformers", "package.json"), "utf8" ) ); @@ -197,25 +159,16 @@ test("#9166 standalone assembly never overwrites an already pinned transformers ); assert.ok( - existsSync( - join( - standaloneDir, - "node_modules", - "onnxruntime-node", - "package.json" - ) - ), + existsSync(join(standaloneDir, "node_modules", "onnxruntime-node", "package.json")), "missing dependencies from the transformers closure must still be copied" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); test("#9166 co-location completes a partially traced package (package.json without its main)", () => { - const root = mkdtempSync( - join(tmpdir(), "omniroute-docker-llmlingua-partial-9166-") - ); + const root = mkdtempSync(join(tmpdir(), "omniroute-docker-llmlingua-partial-9166-")); try { buildLlmlinguaRoot(root); @@ -238,27 +191,16 @@ test("#9166 co-location completes a partially traced package (package.json witho }); assert.ok( - existsSync( - join( - standaloneDir, - "node_modules", - "@atjsh", - "llmlingua-2", - "dist", - "index.js" - ) - ), + existsSync(join(standaloneDir, "node_modules", "@atjsh", "llmlingua-2", "dist", "index.js")), "a partially traced package must be completed, not skipped as already present" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); test("#9166 co-location is not skipped when every closure dir exists but one is partial", () => { - const root = mkdtempSync( - join(tmpdir(), "omniroute-docker-llmlingua-partial-all-9166-") - ); + const root = mkdtempSync(join(tmpdir(), "omniroute-docker-llmlingua-partial-all-9166-")); try { buildLlmlinguaRoot(root); @@ -275,9 +217,14 @@ test("#9166 co-location is not skipped when every closure dir exists but one is "@huggingface/transformers", "onnxruntime-node", ]) { - mkPkg(standaloneNm, packageName, { main: "index.js" }, { - "index.js": "export {};\n", - }); + mkPkg( + standaloneNm, + packageName, + { main: "index.js" }, + { + "index.js": "export {};\n", + } + ); } mkPkg(standaloneNm, "@atjsh/llmlingua-2", { main: "dist/index.js" }); @@ -289,28 +236,16 @@ test("#9166 co-location is not skipped when every closure dir exists but one is }); assert.ok( - existsSync( - join( - standaloneDir, - "node_modules", - "@atjsh", - "llmlingua-2", - "dist", - "index.js" - ) - ), + existsSync(join(standaloneDir, "node_modules", "@atjsh", "llmlingua-2", "dist", "index.js")), "the closure-wide early-exit must not fire while any member is partial" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); test("#9166 Docker explicitly installs and validates LLMLingua optionals", () => { - const dockerfile = readFileSync( - new URL("../../Dockerfile", import.meta.url), - "utf8" - ); + const dockerfile = readFileSync(new URL("../../Dockerfile", import.meta.url), "utf8"); const builderStart = dockerfile.indexOf("FROM base AS builder"); const runnerStart = dockerfile.indexOf("FROM base AS runner-base"); diff --git a/tests/unit/docs-validate-svg.test.ts b/tests/unit/docs-validate-svg.test.ts index a53ff75afd..89b73e073d 100644 --- a/tests/unit/docs-validate-svg.test.ts +++ b/tests/unit/docs-validate-svg.test.ts @@ -27,7 +27,7 @@ test("SVG validator ignores Mermaid data-id attributes when checking duplicate I assert.match(result.stdout, /PASS/); assert.doesNotMatch(`${result.stdout}${result.stderr}`, /WARN/); } finally { - rmSync(fixtureDir, { recursive: true, force: true }); + rmSync(fixtureDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -46,7 +46,7 @@ test("SVG validator rejects duplicate XML id attributes", () => { assert.equal(result.status, 1, `${result.stdout}${result.stderr}`); assert.match(result.stderr, /duplicate IDs: edge-a/); } finally { - rmSync(fixtureDir, { recursive: true, force: true }); + rmSync(fixtureDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -101,6 +101,6 @@ test("SVG validator adds explicit accessible naming when requested for a generat assert.equal([...updated.matchAll(/id="auto-combo-title"/g)].length, 1); assert.equal([...updated.matchAll(/id="auto-combo-desc"/g)].length, 1); } finally { - rmSync(fixtureDir, { recursive: true, force: true }); + rmSync(fixtureDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/domain-branch-hardening.test.ts b/tests/unit/domain-branch-hardening.test.ts index bf2319d440..d5cee8dbef 100644 --- a/tests/unit/domain-branch-hardening.test.ts +++ b/tests/unit/domain-branch-hardening.test.ts @@ -34,7 +34,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -63,7 +63,7 @@ test.after(async () => { fallbackPolicy.resetAllFallbacks(); providerExpiration.resetExpirations(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("resolveComboModel covers empty combos, priority, round-robin, random, least-used and default fallback", () => { diff --git a/tests/unit/domain-cost-rules.test.ts b/tests/unit/domain-cost-rules.test.ts index 6cab0a8015..94fe9b7bae 100644 --- a/tests/unit/domain-cost-rules.test.ts +++ b/tests/unit/domain-cost-rules.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -40,7 +40,7 @@ test.beforeEach(async () => { test.after(async () => { costRules.resetCostData(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("setBudget normalizes defaults and getBudget returns the stored config", () => { diff --git a/tests/unit/domain-fallback-policy.test.ts b/tests/unit/domain-fallback-policy.test.ts index 28730aebc6..d69556f693 100644 --- a/tests/unit/domain-fallback-policy.test.ts +++ b/tests/unit/domain-fallback-policy.test.ts @@ -17,7 +17,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -39,7 +39,7 @@ test.beforeEach(async () => { test.after(async () => { fallbackPolicy.resetAllFallbacks(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("registerFallback sorts by priority and defaults missing flags to enabled", () => { diff --git a/tests/unit/domain-lockout-policy.test.ts b/tests/unit/domain-lockout-policy.test.ts index 758742dc87..bf5d492342 100644 --- a/tests/unit/domain-lockout-policy.test.ts +++ b/tests/unit/domain-lockout-policy.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { Date.now = originalDateNow; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("checkLockout starts unlocked and locks after reaching the configured threshold", () => { diff --git a/tests/unit/domain-persistence.test.ts b/tests/unit/domain-persistence.test.ts index 95ef343ad3..66c9f79e3d 100644 --- a/tests/unit/domain-persistence.test.ts +++ b/tests/unit/domain-persistence.test.ts @@ -45,7 +45,8 @@ afterEach(async () => { after(() => { process.env.DATA_DIR = originalDataDir; - if (fs.existsSync(fileTmpDir)) fs.rmSync(fileTmpDir, { recursive: true, force: true }); + if (fs.existsSync(fileTmpDir)) + fs.rmSync(fileTmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Fallback Policy Tests ──────────────────────── diff --git a/tests/unit/duckduckgo-vqd-429-misclassification-6996.test.ts b/tests/unit/duckduckgo-vqd-429-misclassification-6996.test.ts index 8b00ac5dc3..90c174b8fb 100644 --- a/tests/unit/duckduckgo-vqd-429-misclassification-6996.test.ts +++ b/tests/unit/duckduckgo-vqd-429-misclassification-6996.test.ts @@ -7,9 +7,8 @@ import path from "node:path"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-6996-")); process.env.DATA_DIR = TEST_DATA_DIR; -const { DuckDuckGoWebExecutor, STATUS_URL } = await import( - "../../open-sse/executors/duckduckgo-web.ts" -); +const { DuckDuckGoWebExecutor, STATUS_URL } = + await import("../../open-sse/executors/duckduckgo-web.ts"); const { resetDbInstance } = await import("../../src/lib/db/core.ts"); const executeInputBase = { model: "gpt-4o-mini", @@ -32,7 +31,7 @@ describe("#6996 DuckDuckGo VQD 429 misclassification", () => { after(() => { globalThis.fetch = originalFetch; resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("propagates upstream 429 instead of masking it as a generic 503", async () => { @@ -57,9 +56,7 @@ describe("#6996 DuckDuckGo VQD 429 misclassification", () => { const response = await executor.execute(executeInputBase); const httpResponse = - response instanceof Response - ? response - : (response as { response: Response }).response; + response instanceof Response ? response : (response as { response: Response }).response; const bodyText = await httpResponse.text(); assert.equal( @@ -85,9 +82,7 @@ describe("#6996 DuckDuckGo VQD 429 misclassification", () => { const response = await executor.execute(executeInputBase); const httpResponse = - response instanceof Response - ? response - : (response as { response: Response }).response; + response instanceof Response ? response : (response as { response: Response }).response; const bodyText = await httpResponse.text(); assert.equal( diff --git a/tests/unit/effort-thinking-standardization-6241.test.ts b/tests/unit/effort-thinking-standardization-6241.test.ts index 406cb82377..95d906df53 100644 --- a/tests/unit/effort-thinking-standardization-6241.test.ts +++ b/tests/unit/effort-thinking-standardization-6241.test.ts @@ -19,7 +19,7 @@ const registry = await import("../../src/lib/modelMetadataRegistry.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -29,7 +29,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Schema ───────────────────────────────────────────────────────────── diff --git a/tests/unit/effort-tiers-loop-catalog-e2e.test.ts b/tests/unit/effort-tiers-loop-catalog-e2e.test.ts index 4e6b5c2663..a3818d8ca9 100644 --- a/tests/unit/effort-tiers-loop-catalog-e2e.test.ts +++ b/tests/unit/effort-tiers-loop-catalog-e2e.test.ts @@ -23,7 +23,7 @@ const { recordLearnedReasoningEffort, __test_resetLearnedReasoningEffortCaps } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -46,7 +46,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("learned set flows end-to-end into /v1/models capabilities and variant entries", async () => { diff --git a/tests/unit/egress-ip-lock-10880.test.ts b/tests/unit/egress-ip-lock-10880.test.ts index c4b67cdb0d..34b17dedf4 100644 --- a/tests/unit/egress-ip-lock-10880.test.ts +++ b/tests/unit/egress-ip-lock-10880.test.ts @@ -55,7 +55,7 @@ let seedSeq = 0; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -97,7 +97,7 @@ function seedProxyLog(connectionId: string, egressIp: string, provider: string = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("siblings sharing the egress IP are cooled down with the same cooldown", async () => { diff --git a/tests/unit/electron-main.test.ts b/tests/unit/electron-main.test.ts index b8da073bdd..a378a3ba71 100644 --- a/tests/unit/electron-main.test.ts +++ b/tests/unit/electron-main.test.ts @@ -492,7 +492,7 @@ describe("Electron SQLite credential inspection", () => { fn(dbPath, db); } finally { db.close(); - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/electron-packaging.test.ts b/tests/unit/electron-packaging.test.ts index e08a2f9ee9..cbddd60bab 100644 --- a/tests/unit/electron-packaging.test.ts +++ b/tests/unit/electron-packaging.test.ts @@ -115,7 +115,7 @@ test("electron docs manifest prunes authoring payloads without removing runtime removedPaths: [], }); } finally { - rmSync(bundleRoot, { recursive: true, force: true }); + rmSync(bundleRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/electron-remote-server.test.ts b/tests/unit/electron-remote-server.test.ts index 9595a0d6fe..a3ed546cd9 100644 --- a/tests/unit/electron-remote-server.test.ts +++ b/tests/unit/electron-remote-server.test.ts @@ -33,7 +33,7 @@ function withTempDir(fn: (dir: string) => void) { try { fn(dir); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/electron-smoke-script.test.ts b/tests/unit/electron-smoke-script.test.ts index 874f87e281..5c1ad11dc3 100644 --- a/tests/unit/electron-smoke-script.test.ts +++ b/tests/unit/electron-smoke-script.test.ts @@ -65,7 +65,7 @@ test("electron smoke pre-creates the USERPROFILE-derived Roaming userData tree o assert.ok(fs.existsSync(viaAppData), `expected pre-created APPDATA dir: ${viaAppData}`); } } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -85,7 +85,7 @@ test("electron smoke tarPack handles absolute Windows-style tarball paths", () = assert.ok(fs.existsSync(tarballPath), "tarball should exist after tarPack"); assert.ok(fs.statSync(tarballPath).size > 0, "tarball should not be empty"); } finally { - fs.rmSync(staging, { recursive: true, force: true }); + fs.rmSync(staging, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/electron-sqlite-prebuild.test.ts b/tests/unit/electron-sqlite-prebuild.test.ts index 9c344f7db6..8f9550c5b3 100644 --- a/tests/unit/electron-sqlite-prebuild.test.ts +++ b/tests/unit/electron-sqlite-prebuild.test.ts @@ -81,6 +81,6 @@ test("prebuild verification fails fast when the selected binary is missing", () fs.writeFileSync(expected, "napi"); assert.equal(assertSqlitePrebuildExists?.(moduleDir, "darwin", "arm64"), expected); } finally { - fs.rmSync(moduleDir, { recursive: true, force: true }); + fs.rmSync(moduleDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/elevenlabs-native-routes.test.ts b/tests/unit/elevenlabs-native-routes.test.ts index ded3468f31..c3eb26718e 100644 --- a/tests/unit/elevenlabs-native-routes.test.ts +++ b/tests/unit/elevenlabs-native-routes.test.ts @@ -6,18 +6,13 @@ import path from "node:path"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-elevenlabs-native-")); process.env.DATA_DIR = TEST_DATA_DIR; -process.env.API_KEY_SECRET = - process.env.API_KEY_SECRET || "elevenlabs-native-route-test-secret"; +process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "elevenlabs-native-route-test-secret"; const core = await import("../../src/lib/db/core.ts"); const readCache = await import("../../src/lib/db/readCache.ts"); const voicesRoute = await import("../../src/app/api/v1/voices/route.ts"); -const speechRoute = await import( - "../../src/app/api/v1/text-to-speech/[voiceId]/route.ts" -); -const transcriptionRoute = await import( - "../../src/app/api/v1/speech-to-text/route.ts" -); +const speechRoute = await import("../../src/app/api/v1/text-to-speech/[voiceId]/route.ts"); +const transcriptionRoute = await import("../../src/app/api/v1/speech-to-text/route.ts"); const originalFetch = globalThis.fetch; const API_KEY = "test-elevenlabs-key"; @@ -35,9 +30,10 @@ function seedCredential() { } function clearCredentials() { - core.getDbInstance().prepare("DELETE FROM provider_connections WHERE provider = ?").run( - "elevenlabs" - ); + core + .getDbInstance() + .prepare("DELETE FROM provider_connections WHERE provider = ?") + .run("elevenlabs"); readCache.invalidateDbCache("connections"); } @@ -53,7 +49,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /v1/voices forwards query and stored xi-api-key", async () => { @@ -89,14 +85,11 @@ test("POST /v1/text-to-speech/[voiceId] forwards JSON and binary response", asyn }) as typeof fetch; const response = await speechRoute.POST( - new Request( - "http://localhost/v1/text-to-speech/voice_123?output_format=mp3_44100_128", - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: payload, - } - ), + new Request("http://localhost/v1/text-to-speech/voice_123?output_format=mp3_44100_128", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: payload, + }), { params: Promise.resolve({ voiceId: "voice_123" }) } ); assert.equal(response.status, 200); diff --git a/tests/unit/embedding-account-cooldown-10347.test.ts b/tests/unit/embedding-account-cooldown-10347.test.ts index a9c1d8b5ce..9410c1577d 100644 --- a/tests/unit/embedding-account-cooldown-10347.test.ts +++ b/tests/unit/embedding-account-cooldown-10347.test.ts @@ -14,7 +14,7 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ async function seedConnection(provider: string): Promise { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10347: markAccountUnavailable triggers cooldown on embedding 402", async () => { diff --git a/tests/unit/embedding-cooldown-integration-10347.test.ts b/tests/unit/embedding-cooldown-integration-10347.test.ts index f7bff8ea7a..15fdbe768f 100644 --- a/tests/unit/embedding-cooldown-integration-10347.test.ts +++ b/tests/unit/embedding-cooldown-integration-10347.test.ts @@ -21,7 +21,7 @@ const auth = await import("../../src/sse/services/auth.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ async function seedConnection( test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createEmbeddingResponse marks connection on upstream 402", async () => { diff --git a/tests/unit/embeddings-cost-telemetry-headers.test.ts b/tests/unit/embeddings-cost-telemetry-headers.test.ts index 30320a8f2a..1c78001ef3 100644 --- a/tests/unit/embeddings-cost-telemetry-headers.test.ts +++ b/tests/unit/embeddings-cost-telemetry-headers.test.ts @@ -15,7 +15,7 @@ const { OMNIROUTE_RESPONSE_HEADERS } = await import("../../src/shared/constants/ test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createEmbeddingResponse emits X-OmniRoute-* cost telemetry headers on success", async () => { diff --git a/tests/unit/embeddings-lan-noauth-6925.test.ts b/tests/unit/embeddings-lan-noauth-6925.test.ts index e2e07e5c0d..2b91a43c5d 100644 --- a/tests/unit/embeddings-lan-noauth-6925.test.ts +++ b/tests/unit/embeddings-lan-noauth-6925.test.ts @@ -14,7 +14,7 @@ const { createEmbeddingResponse } = await import("../../src/lib/embeddings/servi test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // #6925: a keyless LAN OpenAI-compatible embeddings provider (e.g. Ollama at diff --git a/tests/unit/embeddings-proxy-forwarding.test.ts b/tests/unit/embeddings-proxy-forwarding.test.ts index 2d93d066bf..a48cdbf65c 100644 --- a/tests/unit/embeddings-proxy-forwarding.test.ts +++ b/tests/unit/embeddings-proxy-forwarding.test.ts @@ -17,10 +17,13 @@ const { resolveProxyForRequest } = await import("../../open-sse/utils/proxyFetch test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); -async function withHttpServer(handler: http.RequestListener, fn: (baseUrl: string) => Promise) { +async function withHttpServer( + handler: http.RequestListener, + fn: (baseUrl: string) => Promise +) { const server = http.createServer(handler); await new Promise((resolve, reject) => { server.once("error", reject); diff --git a/tests/unit/embeddings-route-apikeymeta-6929.test.ts b/tests/unit/embeddings-route-apikeymeta-6929.test.ts index 8e241d731c..d3e6862979 100644 --- a/tests/unit/embeddings-route-apikeymeta-6929.test.ts +++ b/tests/unit/embeddings-route-apikeymeta-6929.test.ts @@ -44,7 +44,7 @@ const PLAYGROUND_KEY_ID_HEADER = "x-omniroute-playground-key-id"; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function sessionCookie(): Promise { diff --git a/tests/unit/emergency-fallback-service.test.ts b/tests/unit/emergency-fallback-service.test.ts index b229fb7012..65b2d2458a 100644 --- a/tests/unit/emergency-fallback-service.test.ts +++ b/tests/unit/emergency-fallback-service.test.ts @@ -29,7 +29,7 @@ function restoreEnv(name: string, value: string | undefined) { function resetTestState() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); delete process.env.OMNIROUTE_EMERGENCY_FALLBACK; resetEmergencyFallbackEnvCache(); @@ -46,7 +46,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); restoreEnv("DATA_DIR", previousDataDir); restoreEnv("DISABLE_SQLITE_AUTO_BACKUP", previousDisableSqliteAutoBackup); }); diff --git a/tests/unit/empty-choices-no-inject.test.ts b/tests/unit/empty-choices-no-inject.test.ts index a252e0c294..3de851b328 100644 --- a/tests/unit/empty-choices-no-inject.test.ts +++ b/tests/unit/empty-choices-no-inject.test.ts @@ -28,7 +28,7 @@ async function readTransformed(chunks: string[], options: Record { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/endpoint-restrictions-policy.test.ts b/tests/unit/endpoint-restrictions-policy.test.ts index 5c5bba8ec5..24ac4812e4 100644 --- a/tests/unit/endpoint-restrictions-policy.test.ts +++ b/tests/unit/endpoint-restrictions-policy.test.ts @@ -30,7 +30,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -79,7 +79,7 @@ test.after(async () => { apiKeysDb.resetApiKeyState(); costRules.resetCostData(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Policy tests ───────────────────────────────────────────────────────── @@ -137,10 +137,7 @@ test("chat-only key blocks /v1/embeddings", async () => { assert.ok(result.rejection, "Should reject the request"); assert.equal(result.rejection.status, 403); const msg = await readErrorMessage(result.rejection); - assert.ok( - msg.includes("embeddings"), - `Error message should mention 'embeddings', got: ${msg}` - ); + assert.ok(msg.includes("embeddings"), `Error message should mention 'embeddings', got: ${msg}`); }); test("search-only key blocks /v1/images/generations", async () => { diff --git a/tests/unit/error-message-sanitization.test.ts b/tests/unit/error-message-sanitization.test.ts index 4c72677164..f33a74a591 100644 --- a/tests/unit/error-message-sanitization.test.ts +++ b/tests/unit/error-message-sanitization.test.ts @@ -32,7 +32,7 @@ function makeRequest(url: string, options: { method?: string; body?: unknown } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createCombo(name: string, model: string) { diff --git a/tests/unit/evals-history.test.ts b/tests/unit/evals-history.test.ts index c4ebe9104a..033c04cd98 100644 --- a/tests/unit/evals-history.test.ts +++ b/tests/unit/evals-history.test.ts @@ -12,7 +12,7 @@ const evalsDb = await import("../../src/lib/db/evals.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("eval run history persists target metadata and newest-first ordering", () => { diff --git a/tests/unit/evals-route.test.ts b/tests/unit/evals-route.test.ts index 4893d36971..c9e5b83e8c 100644 --- a/tests/unit/evals-route.test.ts +++ b/tests/unit/evals-route.test.ts @@ -25,7 +25,7 @@ const evalSuiteByIdRoute = await import("../../src/app/api/evals/suites/[suiteId function resetDb() { core.resetDbInstance(); localDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +36,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); localDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("evals GET returns suites, target options, api key metadata, and persisted history", async () => { diff --git a/tests/unit/exclusive-connection-leases.test.ts b/tests/unit/exclusive-connection-leases.test.ts index fcfceb71c7..b2ae14c28f 100644 --- a/tests/unit/exclusive-connection-leases.test.ts +++ b/tests/unit/exclusive-connection-leases.test.ts @@ -20,7 +20,7 @@ function at(seconds: number): string { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("hashes canonical owners and never persists the raw owner", () => { @@ -463,6 +463,6 @@ test("cross-process contenders never both acquire the same connection", async () assert.equal(results.filter((result) => result.kind === "ACQUIRED").length, 1); assert.equal(results.filter((result) => result.kind === "CONNECTION_BUSY").length, 1); } finally { - fs.rmSync(raceDir, { recursive: true, force: true }); + fs.rmSync(raceDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/exclusive-lease-api-key-policy.test.ts b/tests/unit/exclusive-lease-api-key-policy.test.ts index dfd6d4dc4b..d51f4d1527 100644 --- a/tests/unit/exclusive-lease-api-key-policy.test.ts +++ b/tests/unit/exclusive-lease-api-key-policy.test.ts @@ -17,7 +17,7 @@ const CONNECTION = "00000000-0000-4000-8000-000000000001"; async function resetStorage(): Promise { core.resetDbInstance(); apiKeys.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -25,7 +25,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); apiKeys.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("managed API key create requires and atomically stores an explicit allowlist", async () => { diff --git a/tests/unit/exclusive-lease-auxiliary-isolation.test.ts b/tests/unit/exclusive-lease-auxiliary-isolation.test.ts index da6174648c..199c2aba7c 100644 --- a/tests/unit/exclusive-lease-auxiliary-isolation.test.ts +++ b/tests/unit/exclusive-lease-auxiliary-isolation.test.ts @@ -49,7 +49,7 @@ async function markLeaseOnly(connectionId: string): Promise { async function resetStorage(): Promise { core.resetDbInstance(); apiKeys.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); externalCalls = 0; } @@ -59,7 +59,7 @@ test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeys.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("translator send excludes a FREE lease-only connection before provider fetch", async () => { diff --git a/tests/unit/exclusive-lease-connection-test-isolation.test.ts b/tests/unit/exclusive-lease-connection-test-isolation.test.ts index 34e565836b..957f678dee 100644 --- a/tests/unit/exclusive-lease-connection-test-isolation.test.ts +++ b/tests/unit/exclusive-lease-connection-test-isolation.test.ts @@ -28,7 +28,7 @@ const OWNER = "vlo_TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("connection verification skips an ACTIVE exclusive lease before any probe or mutation", async () => { diff --git a/tests/unit/exclusive-lease-managed-set.test.ts b/tests/unit/exclusive-lease-managed-set.test.ts index 86e44ffb58..e5fdcc73f4 100644 --- a/tests/unit/exclusive-lease-managed-set.test.ts +++ b/tests/unit/exclusive-lease-managed-set.test.ts @@ -44,7 +44,7 @@ function insertKey(input: { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("derives the overlapping managed set from active scoped key allowlists", async () => { diff --git a/tests/unit/exclusive-session-observability.test.ts b/tests/unit/exclusive-session-observability.test.ts index d5fd11a4a8..161665ba41 100644 --- a/tests/unit/exclusive-session-observability.test.ts +++ b/tests/unit/exclusive-session-observability.test.ts @@ -42,7 +42,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("projects idle and active leases, distinct connections, legacy rows, and de-duplication", () => { diff --git a/tests/unit/execute-chat-resource-pressure-breaker.test.ts b/tests/unit/execute-chat-resource-pressure-breaker.test.ts index 4bf1f54fe7..790f309eeb 100644 --- a/tests/unit/execute-chat-resource-pressure-breaker.test.ts +++ b/tests/unit/execute-chat-resource-pressure-breaker.test.ts @@ -25,7 +25,7 @@ const MiB = 1024 ** 2; async function resetStorage() { resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // Restore a non-shedding resource pressure runtime between tests. reloadResourcePressureRuntime({ @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("executeChatWithBreaker returns typed pressure 503 before normal, bypass, and shadow breaker paths", async () => { diff --git a/tests/unit/execute-web-search-fallback-11524.test.ts b/tests/unit/execute-web-search-fallback-11524.test.ts index 1daf06a94b..517868f487 100644 --- a/tests/unit/execute-web-search-fallback-11524.test.ts +++ b/tests/unit/execute-web-search-fallback-11524.test.ts @@ -15,7 +15,7 @@ const { executeWebSearch } = await import("../../src/lib/search/executeWebSearch async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression test for #11524 — executeWebSearch must prefer a credentialed diff --git a/tests/unit/executor-devin-cli-acp-protocol-8406.test.ts b/tests/unit/executor-devin-cli-acp-protocol-8406.test.ts index ae6a3a7072..c001072773 100644 --- a/tests/unit/executor-devin-cli-acp-protocol-8406.test.ts +++ b/tests/unit/executor-devin-cli-acp-protocol-8406.test.ts @@ -115,6 +115,6 @@ rl.on('line', (line) => { } else { delete process.env.CLI_DEVIN_BIN; } - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/executor-devin-cli-agentic-acp.test.ts b/tests/unit/executor-devin-cli-agentic-acp.test.ts index 5538d3a86e..3300983904 100644 --- a/tests/unit/executor-devin-cli-agentic-acp.test.ts +++ b/tests/unit/executor-devin-cli-agentic-acp.test.ts @@ -272,7 +272,7 @@ test("DevinCliAgenticExecutor returns Anthropic tool_use JSON and sends ACP fram } finally { if (oldBin === undefined) delete process.env.CLI_DEVIN_AGENTIC_BIN; else process.env.CLI_DEVIN_AGENTIC_BIN = oldBin; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -303,7 +303,7 @@ test("no-tools summarizer does not depend on mutable ACP permission modes", asyn const body = JSON.parse(await result.response.text()); assert.equal(body.content[0].text, "unsafe"); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -323,7 +323,7 @@ test("ACP client fails closed when session/new omits the session id", async () = const body = JSON.parse(await result.response.text()); assert.equal(body.error.code, "missing_session_id"); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -351,7 +351,7 @@ test("DevinCliAgenticExecutor returns Anthropic SSE for streaming Claude clients } finally { if (oldBin === undefined) delete process.env.CLI_DEVIN_AGENTIC_BIN; else process.env.CLI_DEVIN_AGENTIC_BIN = oldBin; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -382,7 +382,7 @@ test("ACP client handles fragmented frames, multiple chunks, and stderr", async const body = JSON.parse(await result.response.text()); assert.equal(body.content[0].text, "Hello"); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -408,7 +408,7 @@ test("ACP client fails closed when Devin attempts an internal tool call", async const body = JSON.parse(await result.response.text()); assert.equal(body.error.code, "devin_internal_tool_execution"); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -439,7 +439,7 @@ test("ACP client fails closed on protocol errors and early exit", async () => { const body = JSON.parse(await result.response.text()); assert.equal(body.error.code, scenario.code, scenario.name); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } }); @@ -463,7 +463,7 @@ test("ACP client times out, cancels, and terminates a stuck process", async () = } finally { if (oldTimeout === undefined) delete process.env.DEVIN_AGENTIC_ACP_TIMEOUT_MS; else process.env.DEVIN_AGENTIC_ACP_TIMEOUT_MS = oldTimeout; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -517,7 +517,7 @@ rl.on("line", (line) => { } finally { if (oldBin === undefined) delete process.env.CLI_DEVIN_AGENTIC_BIN; else process.env.CLI_DEVIN_AGENTIC_BIN = oldBin; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -572,6 +572,6 @@ rl.on("line", (line) => { } finally { if (oldBin === undefined) delete process.env.CLI_DEVIN_AGENTIC_BIN; else process.env.CLI_DEVIN_AGENTIC_BIN = oldBin; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/executor-map-golden.test.ts b/tests/unit/executor-map-golden.test.ts index 569351d74c..b3533e267b 100644 --- a/tests/unit/executor-map-golden.test.ts +++ b/tests/unit/executor-map-golden.test.ts @@ -18,15 +18,14 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-executor- process.env.DATA_DIR = TEST_DATA_DIR; // Dynamic imports AFTER DATA_DIR is set so db/core.ts picks up the temp path. -const { getExecutor, hasSpecializedExecutor, DefaultExecutor } = await import( - "../../open-sse/executors/index.ts" -); +const { getExecutor, hasSpecializedExecutor, DefaultExecutor } = + await import("../../open-sse/executors/index.ts"); const { PROVIDERS } = await import("../../open-sse/config/constants.ts"); const { SEARCH_PROVIDERS } = await import("../../open-sse/config/searchRegistry.ts"); const { goldenSnapshot } = await import("../helpers/goldenSnapshot.ts"); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // The specialized keys are not exported; enumerate them through the public @@ -68,8 +67,7 @@ function describeExecutor(instance: unknown): { return { className: inst.constructor.name, provider: typeof inst.provider === "string" ? inst.provider : null, - configSource: - cfg == null ? null : (providerConfigKeyByRef.get(cfg) ?? ""), + configSource: cfg == null ? null : (providerConfigKeyByRef.get(cfg) ?? ""), }; } diff --git a/tests/unit/executor-registry.test.ts b/tests/unit/executor-registry.test.ts index b1c82c8099..efb4f8d20a 100644 --- a/tests/unit/executor-registry.test.ts +++ b/tests/unit/executor-registry.test.ts @@ -13,12 +13,11 @@ process.env.DATA_DIR = TEST_DATA_DIR; const { registerExecutor, getRegisteredExecutor, hasRegisteredExecutor, listExecutorAliases } = await import("../../open-sse/executors/registry.ts"); -const { getExecutor, hasSpecializedExecutor, BaseExecutor, DefaultExecutor } = await import( - "../../open-sse/executors/index.ts" -); +const { getExecutor, hasSpecializedExecutor, BaseExecutor, DefaultExecutor } = + await import("../../open-sse/executors/index.ts"); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("built-ins are registered at module load and resolve through the registry", async () => { diff --git a/tests/unit/feature-flags-settings.test.ts b/tests/unit/feature-flags-settings.test.ts index d53d9c199d..708ebed493 100644 --- a/tests/unit/feature-flags-settings.test.ts +++ b/tests/unit/feature-flags-settings.test.ts @@ -230,7 +230,7 @@ describe("featureFlagDefinitions", () => { describe("featureFlags DB module", () => { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -240,7 +240,7 @@ describe("featureFlags DB module", () => { after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("getFeatureFlagOverrides returns empty object when no overrides", () => { @@ -289,7 +289,7 @@ describe("featureFlags DB module", () => { describe("resolveFeatureFlag", () => { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -300,7 +300,7 @@ describe("resolveFeatureFlag", () => { after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env["REQUIRE_API_KEY"]; }); @@ -397,7 +397,7 @@ describe("resolveFeatureFlag", () => { console.error = () => {}; try { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); const blockerPath = path.join(tmpDir, "storage.sqlite"); fs.mkdirSync(blockerPath, { recursive: true }); @@ -405,7 +405,7 @@ describe("resolveFeatureFlag", () => { } finally { console.error = originalError; core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } }); @@ -460,7 +460,7 @@ describe("resolveFeatureFlag", () => { console.error = () => {}; try { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); const blockerPath = path.join(tmpDir, "storage.sqlite"); fs.mkdirSync(blockerPath, { recursive: true }); @@ -468,7 +468,7 @@ describe("resolveFeatureFlag", () => { } finally { console.error = originalError; core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } }); diff --git a/tests/unit/feature-triage/integration.test.mjs b/tests/unit/feature-triage/integration.test.mjs index b56b2c564e..bff7678cda 100644 --- a/tests/unit/feature-triage/integration.test.mjs +++ b/tests/unit/feature-triage/integration.test.mjs @@ -155,6 +155,6 @@ describe("feature-triage integration", () => { assert.equal(out.counts.skip_has_pr, 1); assert.equal(out.buckets.already_delivered[0].version, "v3.7.2"); - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); }); diff --git a/tests/unit/felo-web-runtime-block.test.ts b/tests/unit/felo-web-runtime-block.test.ts index 82eea583f2..f161bd2996 100644 --- a/tests/unit/felo-web-runtime-block.test.ts +++ b/tests/unit/felo-web-runtime-block.test.ts @@ -35,7 +35,7 @@ const RETIRED_PROVIDER_VARIANTS = [ async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); modelAliasResolver.invalidateAliasCache(); @@ -54,7 +54,7 @@ test.afterEach(async () => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function isRetiredError(error: unknown): boolean { diff --git a/tests/unit/file-deletion.test.ts b/tests/unit/file-deletion.test.ts index 057d02f7b5..e74f480ef1 100644 --- a/tests/unit/file-deletion.test.ts +++ b/tests/unit/file-deletion.test.ts @@ -14,7 +14,7 @@ const { getDbInstance, resetDbInstance } = await import("@/lib/db/core"); after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/fix-bare-model-precedence.test.ts b/tests/unit/fix-bare-model-precedence.test.ts index 72107710d7..c3029be742 100644 --- a/tests/unit/fix-bare-model-precedence.test.ts +++ b/tests/unit/fix-bare-model-precedence.test.ts @@ -9,9 +9,8 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); -const { CODEX_NATIVE_UNPREFIXED_MODELS, getModelInfoCore } = await import( - "../../open-sse/services/model.ts" -); +const { CODEX_NATIVE_UNPREFIXED_MODELS, getModelInfoCore } = + await import("../../open-sse/services/model.ts"); // #FIX: bare Codex-default model ids must route to the `codex` provider // (chatgpt.com OAuth) when no provider prefix is supplied, even when other @@ -37,7 +36,7 @@ async function seedActiveCodexConnection() { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("CODEX_NATIVE_UNPREFIXED_MODELS includes gpt-5.6-sol tier set", () => { diff --git a/tests/unit/fix-bare-routing-fallback.test.ts b/tests/unit/fix-bare-routing-fallback.test.ts index 6a7f693c95..46a68ee528 100644 --- a/tests/unit/fix-bare-routing-fallback.test.ts +++ b/tests/unit/fix-bare-routing-fallback.test.ts @@ -36,7 +36,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("bare gpt-5.6-sol routes to codex (precedence via CODEX_NATIVE_UNPREFIXED_MODELS)", async () => { @@ -85,4 +85,4 @@ test("bare claude-opus-5 never resolves to kiro (synced-catalog validation)", as test("bare claude-opus-4-8 also never resolves to kiro (same fix must apply to all shared models)", async () => { const info = await getModelInfoCore("claude-opus-4-8", null); assert.notEqual(info.provider, "kiro"); -}); \ No newline at end of file +}); diff --git a/tests/unit/fix-tls-client-node-binary-7802.test.ts b/tests/unit/fix-tls-client-node-binary-7802.test.ts index c4c1209949..80d735d1cb 100644 --- a/tests/unit/fix-tls-client-node-binary-7802.test.ts +++ b/tests/unit/fix-tls-client-node-binary-7802.test.ts @@ -22,7 +22,7 @@ test("no-ops when node_modules/tls-client-node is absent (module not installed)" await fixTlsClientNodeBinary({ rootDir, log }); assert.deepEqual(logs, []); } finally { - rmSync(rootDir, { recursive: true, force: true }); + rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -43,7 +43,7 @@ test("copies an already-populated root bin/ into the standalone dist bundle (#78 assert.ok(existsSync(distBin), "dist bin/ should have been created"); assert.deepEqual(readdirSync(distBin), ["tls-client-linux-ubuntu-amd64-1.0.0.so"]); } finally { - rmSync(rootDir, { recursive: true, force: true }); + rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -79,7 +79,7 @@ test("retries the download when root bin/ is empty, and stops once a file appear "expected a success log once the retry recovered" ); } finally { - rmSync(rootDir, { recursive: true, force: true }); + rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -98,9 +98,7 @@ test("warns without throwing when every retry leaves bin/ empty (still rate-limi console.warn = (m: string) => warnings.push(m); try { const { log } = collectLogs(); - await assert.doesNotReject( - fixTlsClientNodeBinary({ rootDir, log, retryDelaysMs: [1, 1] }) - ); + await assert.doesNotReject(fixTlsClientNodeBinary({ rootDir, log, retryDelaysMs: [1, 1] })); } finally { console.warn = originalWarn; } @@ -110,6 +108,6 @@ test("warns without throwing when every retry leaves bin/ empty (still rate-limi "expected a clear warning pointing at the manual fix, not a silent no-op" ); } finally { - rmSync(rootDir, { recursive: true, force: true }); + rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/fixes-p1.test.ts b/tests/unit/fixes-p1.test.ts index 186cdd7eac..93d76898d2 100644 --- a/tests/unit/fixes-p1.test.ts +++ b/tests/unit/fixes-p1.test.ts @@ -57,7 +57,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -73,7 +73,7 @@ async function resetStorage() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("token refresh dedupe key avoids collision for same-prefix tokens", async () => { diff --git a/tests/unit/free-provider-rankings-custom-models-6368.test.ts b/tests/unit/free-provider-rankings-custom-models-6368.test.ts index 98880f654a..25cb491b95 100644 --- a/tests/unit/free-provider-rankings-custom-models-6368.test.ts +++ b/tests/unit/free-provider-rankings-custom-models-6368.test.ts @@ -39,7 +39,7 @@ const CUSTOM_MODEL_ID = "claude-fable-5-6368"; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("mergeProviderModels: additively includes custom models, de-duping by id", () => { diff --git a/tests/unit/free-provider-rankings-usage-route.test.ts b/tests/unit/free-provider-rankings-usage-route.test.ts index e493ddca07..314d72b8d6 100644 --- a/tests/unit/free-provider-rankings-usage-route.test.ts +++ b/tests/unit/free-provider-rankings-usage-route.test.ts @@ -29,7 +29,7 @@ test.after(() => { core.resetDbInstance(); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("route: an unknown usageRange is rejected with 400, not coerced", async () => { diff --git a/tests/unit/free-proxies-add-to-pool.test.ts b/tests/unit/free-proxies-add-to-pool.test.ts index 3767762c5a..c16ea70e3a 100644 --- a/tests/unit/free-proxies-add-to-pool.test.ts +++ b/tests/unit/free-proxies-add-to-pool.test.ts @@ -21,7 +21,7 @@ const bulkAddRoute = async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -45,7 +45,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/free-proxies-db.test.ts b/tests/unit/free-proxies-db.test.ts index 369f5fbb34..d09ddcd345 100644 --- a/tests/unit/free-proxies-db.test.ts +++ b/tests/unit/free-proxies-db.test.ts @@ -12,13 +12,13 @@ const freeProxiesDb = await import("../../src/lib/db/freeProxies.ts"); async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("upsertFreeProxy creates a new record", async () => { diff --git a/tests/unit/free-proxies-list-search.test.ts b/tests/unit/free-proxies-list-search.test.ts index 57dea9618b..e34fa0f37a 100644 --- a/tests/unit/free-proxies-list-search.test.ts +++ b/tests/unit/free-proxies-list-search.test.ts @@ -15,13 +15,13 @@ const freeProxiesDb = await import("../../src/lib/db/freeProxies.ts"); async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function make(host: string, quality: number, latency: number): FreeProxyItem { diff --git a/tests/unit/free-proxy-auto-sync-scheduler.test.ts b/tests/unit/free-proxy-auto-sync-scheduler.test.ts index c07652be65..8bdd01bee8 100644 --- a/tests/unit/free-proxy-auto-sync-scheduler.test.ts +++ b/tests/unit/free-proxy-auto-sync-scheduler.test.ts @@ -45,7 +45,7 @@ function reset() { restoreEnv(); process.env.FREE_PROXY_AUTO_SYNC_ENABLED = "false"; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -57,7 +57,7 @@ test.after(() => { scheduler.stopFreeProxyAutoSync(); scheduler._setSyncCycleRunnerForTests(null); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); restoreEnv(); }); @@ -171,7 +171,10 @@ test("cycle delegates to the shared sync-cycle runner (same path as the manual r let called = false; scheduler._setSyncCycleRunnerForTests(async () => { called = true; - return { results: { "1proxy": { fetched: 1, added: 1, updated: 0, errors: [] } }, lastSyncAt: "x" }; + return { + results: { "1proxy": { fetched: 1, added: 1, updated: 0, errors: [] } }, + lastSyncAt: "x", + }; }); await scheduler.forceFreeProxySyncCycle(); diff --git a/tests/unit/free-proxy-providers.test.ts b/tests/unit/free-proxy-providers.test.ts index 1faa53b9cf..34de40dea0 100644 --- a/tests/unit/free-proxy-providers.test.ts +++ b/tests/unit/free-proxy-providers.test.ts @@ -18,13 +18,13 @@ const { getProvider, getEnabledProviders, getAllProviders } = async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Registry ───────────────────────────────────────────────────────────────── @@ -259,7 +259,10 @@ test("IplocateProvider.sync parses the plain-text ip:port lists (.txt, not .json seenUrls.length > 0 && seenUrls.every((u) => u.endsWith(".txt")), `expected .txt URLs, got: ${seenUrls.join(", ")}` ); - assert.ok(result.fetched > 0, `expected proxies parsed from the txt list, got ${result.fetched}`); + assert.ok( + result.fetched > 0, + `expected proxies parsed from the txt list, got ${result.fetched}` + ); const items = await p.list({ limit: 50 }); assert.ok( items.some((i) => i.host === "103.173.141.10" && i.port === 8080), diff --git a/tests/unit/free-proxy-sync-cycle.test.ts b/tests/unit/free-proxy-sync-cycle.test.ts index fd24efb432..35541ffe1f 100644 --- a/tests/unit/free-proxy-sync-cycle.test.ts +++ b/tests/unit/free-proxy-sync-cycle.test.ts @@ -25,7 +25,7 @@ const { runFreeProxySyncCycle } = await import("../../src/lib/freeProxyProviders function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function makeProvider( diff --git a/tests/unit/free-tier-summary-radar-overlay.test.ts b/tests/unit/free-tier-summary-radar-overlay.test.ts index 08d490c345..d97ab156ff 100644 --- a/tests/unit/free-tier-summary-radar-overlay.test.ts +++ b/tests/unit/free-tier-summary-radar-overlay.test.ts @@ -113,7 +113,8 @@ function feedPayload(tier: "community" | "live") { function resetState() { core.resetDbInstance(); try { - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } diff --git a/tests/unit/fusion-vision-panel-3378.test.ts b/tests/unit/fusion-vision-panel-3378.test.ts index 572891d252..7a9059dc59 100644 --- a/tests/unit/fusion-vision-panel-3378.test.ts +++ b/tests/unit/fusion-vision-panel-3378.test.ts @@ -23,14 +23,12 @@ process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "fusion-vision-3378-test-secret"; const { handleComboChat } = await import("../../open-sse/services/combo.ts"); -const { saveModelsDevCapabilities, clearModelsDevCapabilities } = await import( - "../../src/lib/modelsDevSync.ts" -); +const { saveModelsDevCapabilities, clearModelsDevCapabilities } = + await import("../../src/lib/modelsDevSync.ts"); const { resetAllComboMetrics } = await import("../../open-sse/services/comboMetrics.ts"); const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts"); -const { resetAll: resetAllSemaphores } = await import( - "../../open-sse/services/rateLimitSemaphore.ts" -); +const { resetAll: resetAllSemaphores } = + await import("../../open-sse/services/rateLimitSemaphore.ts"); const core = await import("../../src/lib/db/core.ts"); function createLog() { @@ -92,7 +90,7 @@ test.after(() => { resetAllSemaphores(); clearModelsDevCapabilities(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/g13-combo-chatcore-golden.test.ts b/tests/unit/g13-combo-chatcore-golden.test.ts index 0cd7a4cd18..8b484b562b 100644 --- a/tests/unit/g13-combo-chatcore-golden.test.ts +++ b/tests/unit/g13-combo-chatcore-golden.test.ts @@ -392,6 +392,6 @@ test("G13 golden detects a public behavior mutation", () => { } finally { if (previousUpdateGolden === undefined) delete process.env.UPDATE_GOLDEN; else process.env.UPDATE_GOLDEN = previousUpdateGolden; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/gamification/aggregate-profile-3484.test.ts b/tests/unit/gamification/aggregate-profile-3484.test.ts index 1d1fc0e7ff..8af17bc0d1 100644 --- a/tests/unit/gamification/aggregate-profile-3484.test.ts +++ b/tests/unit/gamification/aggregate-profile-3484.test.ts @@ -16,7 +16,8 @@ if (!process.env.API_KEY_SECRET) { const { getDbInstance, resetDbInstance } = await import("../../../src/lib/db/core.ts"); const gami = await import("../../../src/lib/db/gamification.ts"); -const { seedBuiltinBadges, BUILTIN_BADGES } = await import("../../../src/lib/gamification/badges.ts"); +const { seedBuiltinBadges, BUILTIN_BADGES } = + await import("../../../src/lib/gamification/badges.ts"); test.after(() => { try { @@ -29,7 +30,7 @@ test.after(() => { } catch { /* ignore */ } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3484 getAggregateXp on an empty ledger → zero XP, level 1, no throw", () => { diff --git a/tests/unit/github-copilot-retired-models.test.ts b/tests/unit/github-copilot-retired-models.test.ts index 6ce66556c0..fd8d2df10a 100644 --- a/tests/unit/github-copilot-retired-models.test.ts +++ b/tests/unit/github-copilot-retired-models.test.ts @@ -17,7 +17,7 @@ before(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GitHub Copilot sync rejects retired Gemini models", async () => { diff --git a/tests/unit/glm-provider-model-import-route.test.ts b/tests/unit/glm-provider-model-import-route.test.ts index b86c115e70..9f47f555c7 100644 --- a/tests/unit/glm-provider-model-import-route.test.ts +++ b/tests/unit/glm-provider-model-import-route.test.ts @@ -19,13 +19,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GLM import uses international coding endpoint when apiRegion is international", async () => { diff --git a/tests/unit/gpt-max-input-tokens-6191.test.ts b/tests/unit/gpt-max-input-tokens-6191.test.ts index df2a90fd60..3d8b8fb151 100644 --- a/tests/unit/gpt-max-input-tokens-6191.test.ts +++ b/tests/unit/gpt-max-input-tokens-6191.test.ts @@ -18,7 +18,7 @@ const modelCapabilities = await import("../../src/lib/modelCapabilities.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -28,7 +28,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("codex gpt-5.5 reports max_input_tokens smaller than its context window (#6191)", () => { diff --git a/tests/unit/grok-cli-device-route.test.ts b/tests/unit/grok-cli-device-route.test.ts index fc926a946c..1453f348d4 100644 --- a/tests/unit/grok-cli-device-route.test.ts +++ b/tests/unit/grok-cli-device-route.test.ts @@ -23,7 +23,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("grok-cli poll does not require a PKCE code verifier", async () => { diff --git a/tests/unit/grok-cli-provider-limits-ui.test.ts b/tests/unit/grok-cli-provider-limits-ui.test.ts index bee641c2bd..c3f3ca4c9d 100644 --- a/tests/unit/grok-cli-provider-limits-ui.test.ts +++ b/tests/unit/grok-cli-provider-limits-ui.test.ts @@ -30,7 +30,7 @@ const baseBilling = { }; test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Grok Build product aliases normalize to one stable row and preserve collisions", () => { diff --git a/tests/unit/grok-cli-provider-limits.test.ts b/tests/unit/grok-cli-provider-limits.test.ts index e3fb1689ff..081d403f5f 100644 --- a/tests/unit/grok-cli-provider-limits.test.ts +++ b/tests/unit/grok-cli-provider-limits.test.ts @@ -135,7 +135,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("grok-cli fetches the fixed read-only surfaces with the full Grok client profile", async () => { diff --git a/tests/unit/guardrails-api-3496.test.ts b/tests/unit/guardrails-api-3496.test.ts index 0a845effae..6da986b86d 100644 --- a/tests/unit/guardrails-api-3496.test.ts +++ b/tests/unit/guardrails-api-3496.test.ts @@ -34,7 +34,7 @@ test.after(() => { } catch { /* ignore */ } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3496 GET /api/guardrails lists the registered guardrails with status", async () => { @@ -119,8 +119,6 @@ test("#3496 check-docs-symbols no longer freezes guardrails/shadow + API_REFEREN const src = fs.readFileSync(path.join(process.cwd(), apiRefRel), "utf8"); const docPathsByFile = [{ file: apiRefRel, paths: extractDocApiPaths(src) }]; const misses = findStaleDocApiRefs(docPathsByFile, routeFiles, KNOWN_STALE_DOC_REFS); - const ghosts = misses.filter( - (m) => m.includes("/api/guardrails") || m.includes("/api/shadow") - ); + const ghosts = misses.filter((m) => m.includes("/api/guardrails") || m.includes("/api/shadow")); assert.deepEqual(ghosts, [], `stale guardrails/shadow refs remain: ${ghosts.join("; ")}`); }); diff --git a/tests/unit/guardrails/videoBridgeFu07StructuralSampling.test.ts b/tests/unit/guardrails/videoBridgeFu07StructuralSampling.test.ts index 5c5695f018..477c00c58c 100644 --- a/tests/unit/guardrails/videoBridgeFu07StructuralSampling.test.ts +++ b/tests/unit/guardrails/videoBridgeFu07StructuralSampling.test.ts @@ -432,7 +432,7 @@ test("real FFmpeg evidence distinguishes a frozen dark segment from dense motion assert.equal(decision.timestamps.filter((timestamp) => timestamp < 6).length, 1); assert.equal(decision.timestamps.filter((timestamp) => timestamp > 6).length, 3); } finally { - await rm(directory, { force: true, recursive: true }); + await rm(directory, { force: true, recursive: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -481,6 +481,6 @@ test("real FFmpeg abort stops preanalysis, skips frame extraction, and cleans th assert.notEqual(privateInputPath, ""); await assert.rejects(() => access(privateInputPath)); } finally { - await rm(directory, { force: true, recursive: true }); + await rm(directory, { force: true, recursive: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/guardrails/videoBridgeRuntime.test.ts b/tests/unit/guardrails/videoBridgeRuntime.test.ts index 01f56f381d..9b5402bfc4 100644 --- a/tests/unit/guardrails/videoBridgeRuntime.test.ts +++ b/tests/unit/guardrails/videoBridgeRuntime.test.ts @@ -431,7 +431,7 @@ test("checks individual and aggregate frame byte caps before returning broker ou 6 ); } finally { - await rm(directory, { recursive: true, force: true }); + await rm(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/guardrails/vision-bridge-callmodel.test.ts b/tests/unit/guardrails/vision-bridge-callmodel.test.ts index 40a0e77699..f3041c00c2 100644 --- a/tests/unit/guardrails/vision-bridge-callmodel.test.ts +++ b/tests/unit/guardrails/vision-bridge-callmodel.test.ts @@ -14,16 +14,12 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-vision-bridge-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-vision-bridge-")); process.env.DATA_DIR = TEST_DATA_DIR; // Prevent vision bridge from routing through a real API process.env.VISION_BRIDGE_ENABLED = "false"; -const { callVisionModel } = await import( - "../../../src/lib/guardrails/visionBridgeHelpers.ts" -); +const { callVisionModel } = await import("../../../src/lib/guardrails/visionBridgeHelpers.ts"); const { createProviderConnection } = await import("../../../src/lib/db/providers.ts"); // PR #8433 taught getFallbackModels() to exclude any candidate without a @@ -45,7 +41,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.afterEach(() => { @@ -53,7 +49,8 @@ test.afterEach(() => { }); // Helper: build a minimal OpenAI-compat image data URI -const TINY_PNG = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; +const TINY_PNG = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; test("callVisionModel falls through to next model when primary fails", async () => { let fetchCallCount = 0; @@ -91,16 +88,8 @@ test("callVisionModel falls through to next model when primary fails", async () { fixedModel: "openai/gpt-4o-mini", maxFallbackAttempts: 2 } ); - assert.equal( - fetchCallCount, - 2, - "must have attempted exactly 2 models (primary + 1 fallback)" - ); - assert.equal( - result, - FALLBACK_TEXT, - "must return the fallback model's response" - ); + assert.equal(fetchCallCount, 2, "must have attempted exactly 2 models (primary + 1 fallback)"); + assert.equal(result, FALLBACK_TEXT, "must return the fallback model's response"); }); test("callVisionModel throws when ALL models fail", async () => { diff --git a/tests/unit/guardrails/vision-bridge-credentials-alias-mismatch-10702.test.ts b/tests/unit/guardrails/vision-bridge-credentials-alias-mismatch-10702.test.ts index 942de03474..217eb8c989 100644 --- a/tests/unit/guardrails/vision-bridge-credentials-alias-mismatch-10702.test.ts +++ b/tests/unit/guardrails/vision-bridge-credentials-alias-mismatch-10702.test.ts @@ -10,13 +10,12 @@ process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; const core = await import("../../../src/lib/db/core.ts"); const providersDb = await import("../../../src/lib/db/providers.ts"); -const { hasUsableCredentialsForModel } = await import( - "../../../src/lib/guardrails/visionBridgeCredentials.ts" -); +const { hasUsableCredentialsForModel } = + await import("../../../src/lib/guardrails/visionBridgeCredentials.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("issue #10702: hasUsableCredentialsForModel resolves alias-prefixed model to the raw provider id (command-code / alias cmd)", async () => { diff --git a/tests/unit/guardrails/visionBridge-combo-reroute.test.ts b/tests/unit/guardrails/visionBridge-combo-reroute.test.ts index 7757d028b6..a2e4241bb3 100644 --- a/tests/unit/guardrails/visionBridge-combo-reroute.test.ts +++ b/tests/unit/guardrails/visionBridge-combo-reroute.test.ts @@ -32,7 +32,7 @@ const mappingsDb = await import("../../../src/lib/db/modelComboMappings.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createCombo(name, models, overrides = {}) { diff --git a/tests/unit/guardrails/visionBridgeCredentials.test.ts b/tests/unit/guardrails/visionBridgeCredentials.test.ts index 255c36603c..39e4b2474c 100644 --- a/tests/unit/guardrails/visionBridgeCredentials.test.ts +++ b/tests/unit/guardrails/visionBridgeCredentials.test.ts @@ -40,13 +40,13 @@ const { hasUsableCredentialsForModel, hasTerminalConnectionStatus } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── alias → canonical id resolution (#10702) ──────────────────────────────── diff --git a/tests/unit/guide-settings-route.test.ts b/tests/unit/guide-settings-route.test.ts index 0580a7c9c1..8fcb89615f 100644 --- a/tests/unit/guide-settings-route.test.ts +++ b/tests/unit/guide-settings-route.test.ts @@ -55,7 +55,9 @@ test.beforeEach(async () => { }); test.afterEach(async () => { - await fs.rm(DUMMY_HOME, { recursive: true, force: true }).catch(() => {}); + await fs + .rm(DUMMY_HOME, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }) + .catch(() => {}); if (originalXDG === undefined) delete process.env.XDG_CONFIG_HOME; else process.env.XDG_CONFIG_HOME = originalXDG; if (originalAppData === undefined) delete process.env.APPDATA; diff --git a/tests/unit/headroom-codex-quota-snapshot-6379.test.ts b/tests/unit/headroom-codex-quota-snapshot-6379.test.ts index 6472496b15..85ac9fa922 100644 --- a/tests/unit/headroom-codex-quota-snapshot-6379.test.ts +++ b/tests/unit/headroom-codex-quota-snapshot-6379.test.ts @@ -44,14 +44,12 @@ const providersDb = await import("../../src/lib/db/providers.ts"); // the DB instead of short-circuiting to []. const codexFetcher = await import("../../open-sse/services/codexQuotaFetcher.ts"); codexFetcher.registerCodexQuotaFetcher(); -const { orderTargetsByHeadroom } = await import( - "../../open-sse/services/combo/quotaStrategies.ts" -); +const { orderTargetsByHeadroom } = await import("../../open-sse/services/combo/quotaStrategies.ts"); const { _clearSaturationCache } = await import("../../src/lib/quota/saturationSignals.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); _clearSaturationCache(); } @@ -62,7 +60,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const silentLog = { warn: () => {} }; @@ -111,8 +109,7 @@ test("orderTargetsByHeadroom (codex): ranks the account with more free quota fir globalThis.fetch = (async (_url: string, init?: RequestInit) => { const headers = init?.headers as Record | undefined; const auth = headers?.["Authorization"] ?? ""; - const body = - auth === "Bearer tok-busy" ? usageResponse(90, 10) : usageResponse(5, 5); + const body = auth === "Bearer tok-busy" ? usageResponse(90, 10) : usageResponse(5, 5); return new Response(JSON.stringify(body), { status: 200 }); }) as typeof fetch; diff --git a/tests/unit/health-ping-route.test.ts b/tests/unit/health-ping-route.test.ts index d32b990c02..6cc09fcd53 100644 --- a/tests/unit/health-ping-route.test.ts +++ b/tests/unit/health-ping-route.test.ts @@ -17,7 +17,7 @@ const routeModule = await import("../../src/app/api/health/ping/route.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/health/ping returns 200 with status ok and ISO timestamp", async () => { diff --git a/tests/unit/helpers/decollidedMigrationsDir.ts b/tests/unit/helpers/decollidedMigrationsDir.ts index 00d0f42d8f..9aa11cabc8 100644 --- a/tests/unit/helpers/decollidedMigrationsDir.ts +++ b/tests/unit/helpers/decollidedMigrationsDir.ts @@ -71,7 +71,7 @@ export function useDecollidedMigrationsDir(): void { process.on("exit", () => { try { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // Best-effort cleanup — the OS reaps its temp dir eventually. } diff --git a/tests/unit/hermes-agent-settings-route-keyid-10711.test.ts b/tests/unit/hermes-agent-settings-route-keyid-10711.test.ts index 6651b8bdc4..206fbde245 100644 --- a/tests/unit/hermes-agent-settings-route-keyid-10711.test.ts +++ b/tests/unit/hermes-agent-settings-route-keyid-10711.test.ts @@ -40,7 +40,7 @@ const route = await import("../../src/app/api/cli-tools/hermes-agent-settings/ro test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function authCookie(): Promise { @@ -53,7 +53,10 @@ async function authCookie(): Promise { } test("#10711: POST hermes-agent-settings resolves keyId server-side instead of writing the placeholder", async () => { - const created = await apiKeysDb.createApiKey("hermes-agent-10711-key", "hermes-agent-10711-machine"); + const created = await apiKeysDb.createApiKey( + "hermes-agent-10711-key", + "hermes-agent-10711-machine" + ); const realKey = created.key; assert.ok(realKey && realKey.length > 0, "createApiKey must return the real plaintext key"); diff --git a/tests/unit/hidden-models-leak-v1-models-11300.test.ts b/tests/unit/hidden-models-leak-v1-models-11300.test.ts index c937d2464e..1de38b5b6f 100644 --- a/tests/unit/hidden-models-leak-v1-models-11300.test.ts +++ b/tests/unit/hidden-models-leak-v1-models-11300.test.ts @@ -36,7 +36,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function fetchCatalogIds(): Promise { @@ -93,7 +93,7 @@ test("#11300 A: hiding a static model under its ALIAS (cc) excludes it under bot ); }); -test("#11300 B: hiding a codex-native unprefixed model under \"openai\" excludes the bare model id", async () => { +test('#11300 B: hiding a codex-native unprefixed model under "openai" excludes the bare model id', async () => { await providersDb.createProviderConnection({ provider: "codex", authType: "oauth", @@ -151,9 +151,11 @@ test("#11300 C: hiding a compatible-node synced model under its configured PREFI }); const modelId = "deepseek-v4-flash-0731"; - await modelsDb.replaceSyncedAvailableModelsForConnection(NODE_ID, (connection as { id: string }).id, [ - { id: modelId, name: "DeepSeek V4 Flash", source: "imported", supportedEndpoints: ["chat"] }, - ]); + await modelsDb.replaceSyncedAvailableModelsForConnection( + NODE_ID, + (connection as { id: string }).id, + [{ id: modelId, name: "DeepSeek V4 Flash", source: "imported", supportedEndpoints: ["chat"] }] + ); let ids = await fetchCatalogIds(); assert.ok( diff --git a/tests/unit/image-compat-node-alias-shadow.test.ts b/tests/unit/image-compat-node-alias-shadow.test.ts index 06d4d1db08..3ccb76da43 100644 --- a/tests/unit/image-compat-node-alias-shadow.test.ts +++ b/tests/unit/image-compat-node-alias-shadow.test.ts @@ -18,9 +18,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-image-compat-shadow-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-image-compat-shadow-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -50,7 +48,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("compatible node with prefix=cf must NOT shadow the built-in cloudflare-ai alias", async () => { diff --git a/tests/unit/image-edits-multipart-3273.test.ts b/tests/unit/image-edits-multipart-3273.test.ts index d7e3e390dd..b0afd24e33 100644 --- a/tests/unit/image-edits-multipart-3273.test.ts +++ b/tests/unit/image-edits-multipart-3273.test.ts @@ -40,7 +40,10 @@ test("#3273 /v1/images/edits forwards model as real multipart (undici-patched fe await handleOpenAIImageEdit({ model: "gpt-image-2", provider: "customopenai", - credentials: { apiKey: "sk-test", providerSpecificData: { baseUrl: `http://127.0.0.1:${port}` } }, + credentials: { + apiKey: "sk-test", + providerSpecificData: { baseUrl: `http://127.0.0.1:${port}` }, + }, prompt: "make it blue", imageBytes: Buffer.from([0x89, 0x50, 0x4e, 0x47]), imageMime: "image/png", @@ -68,7 +71,12 @@ test.after(() => { /* ignore */ } try { - fs.rmSync(process.env.DATA_DIR as string, { recursive: true, force: true }); + fs.rmSync(process.env.DATA_DIR as string, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } catch { /* ignore */ } diff --git a/tests/unit/image-generation-route-auth.test.ts b/tests/unit/image-generation-route-auth.test.ts index e6f25631a7..03a2912832 100644 --- a/tests/unit/image-generation-route-auth.test.ts +++ b/tests/unit/image-generation-route-auth.test.ts @@ -30,7 +30,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -71,7 +71,7 @@ test.after(() => { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 image generation POST requires an API key when REQUIRE_API_KEY is enabled", async () => { diff --git a/tests/unit/image-generation-route.test.ts b/tests/unit/image-generation-route.test.ts index f08014bfee..a9526585d5 100644 --- a/tests/unit/image-generation-route.test.ts +++ b/tests/unit/image-generation-route.test.ts @@ -74,7 +74,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // #6303 moved this route onto the shared unified catalog (getUnifiedModelsResponse), // which #6408 wrapped in a 1.5s TTL response cache keyed only by (prefix, isCodex @@ -122,7 +122,7 @@ test.after(() => { globalThis.fetch = originalFetch; apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("image routes expose CORS preflight handlers", async () => { diff --git a/tests/unit/image-model-not-in-chat-catalog-6457.test.ts b/tests/unit/image-model-not-in-chat-catalog-6457.test.ts index 84187fe2f7..0e02a4e615 100644 --- a/tests/unit/image-model-not-in-chat-catalog-6457.test.ts +++ b/tests/unit/image-model-not-in-chat-catalog-6457.test.ts @@ -33,7 +33,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function seedProviderConnection(provider: string) { diff --git a/tests/unit/image-routes-combo-edits-3214-3215.test.ts b/tests/unit/image-routes-combo-edits-3214-3215.test.ts index 3976716d4e..c9559b0981 100644 --- a/tests/unit/image-routes-combo-edits-3214-3215.test.ts +++ b/tests/unit/image-routes-combo-edits-3214-3215.test.ts @@ -35,7 +35,7 @@ const { createCombo } = await import("../../src/lib/db/combos.ts"); test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/inspector-agent-bridge-hook.test.ts b/tests/unit/inspector-agent-bridge-hook.test.ts index a1a0c75b69..6249f06000 100644 --- a/tests/unit/inspector-agent-bridge-hook.test.ts +++ b/tests/unit/inspector-agent-bridge-hook.test.ts @@ -18,16 +18,13 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ab-hook-" process.env.DATA_DIR = TEST_DATA_DIR; const { resetDbInstance, getDbInstance } = await import("../../src/lib/db/core.ts"); -const { addCustomHost, toggleCustomHost } = await import( - "../../src/lib/db/inspectorCustomHosts.ts" -); -const { recordRequestStart } = await import( - "../../src/mitm/inspector/agentBridgeHook.ts" -); +const { addCustomHost, toggleCustomHost } = + await import("../../src/lib/db/inspectorCustomHosts.ts"); +const { recordRequestStart } = await import("../../src/mitm/inspector/agentBridgeHook.ts"); async function resetStorage() { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); getDbInstance(); } @@ -46,7 +43,7 @@ test.beforeEach(async () => { test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("recordRequestStart: custom-host entry → source=custom-host, agent=undefined", async () => { diff --git a/tests/unit/instrumentation-warm-catalog-cache.test.ts b/tests/unit/instrumentation-warm-catalog-cache.test.ts index 84fa161e78..56861834de 100644 --- a/tests/unit/instrumentation-warm-catalog-cache.test.ts +++ b/tests/unit/instrumentation-warm-catalog-cache.test.ts @@ -47,7 +47,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -64,7 +64,7 @@ async function resetStorage() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const REAL_FETCH = globalThis.fetch; diff --git a/tests/unit/intercept-fetch-resolver.test.ts b/tests/unit/intercept-fetch-resolver.test.ts index ff109d89e2..4b2d50e051 100644 --- a/tests/unit/intercept-fetch-resolver.test.ts +++ b/tests/unit/intercept-fetch-resolver.test.ts @@ -9,16 +9,15 @@ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-test-intercept-f process.env.DATA_DIR = tmpDir; const core = await import("../../src/lib/db/core.ts"); -const { setInterceptionRules, resolveInterceptFetch } = await import( - "../../src/lib/db/interceptionRules.ts" -); +const { setInterceptionRules, resolveInterceptFetch } = + await import("../../src/lib/db/interceptionRules.ts"); // #7339 — resolveInterceptFetch, a structural twin of resolveInterceptSearch // (tests/unit/interception-rules.test.ts), covering Phase 3 of #3384. describe("db/interceptionRules — resolveInterceptFetch precedence (#7339)", () => { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -28,7 +27,7 @@ describe("db/interceptionRules — resolveInterceptFetch precedence (#7339)", () after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("returns undefined when no provider/model rule exists", () => { diff --git a/tests/unit/interception-rules.test.ts b/tests/unit/interception-rules.test.ts index bad1e0a281..1653ebbe18 100644 --- a/tests/unit/interception-rules.test.ts +++ b/tests/unit/interception-rules.test.ts @@ -20,7 +20,7 @@ const { describe("db/interceptionRules — per-model interception rules (#3384)", () => { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -30,7 +30,7 @@ describe("db/interceptionRules — per-model interception rules (#3384)", () => after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("returns null for an unconfigured provider", () => { diff --git a/tests/unit/internal-service-auth.test.ts b/tests/unit/internal-service-auth.test.ts index 3ff053ab01..3bc5497c5b 100644 --- a/tests/unit/internal-service-auth.test.ts +++ b/tests/unit/internal-service-auth.test.ts @@ -61,6 +61,6 @@ test("internal service token file is read without exposing it to process env", ( [INTERNAL_SERVICE_AUTH_HEADER]: "file-backed-token-0123456789", }); } finally { - fs.rmSync(directory, { recursive: true, force: true }); + fs.rmSync(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/ip-filter-persistence-6131.test.ts b/tests/unit/ip-filter-persistence-6131.test.ts index 279193627e..b7f195f648 100644 --- a/tests/unit/ip-filter-persistence-6131.test.ts +++ b/tests/unit/ip-filter-persistence-6131.test.ts @@ -17,13 +17,13 @@ const ipFilter = await import("../../open-sse/services/ipFilter.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { // Fresh DB per test + fresh in-memory module state. core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); ipFilter.resetIPFilter(); }); diff --git a/tests/unit/ip-filter.test.ts b/tests/unit/ip-filter.test.ts index 4559bc6812..77bad1ea64 100644 --- a/tests/unit/ip-filter.test.ts +++ b/tests/unit/ip-filter.test.ts @@ -27,12 +27,12 @@ const { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); resetIPFilter(); }); diff --git a/tests/unit/issue-6343-v0-web-alias-collision.test.ts b/tests/unit/issue-6343-v0-web-alias-collision.test.ts index 15e672e3b2..75116efb3d 100644 --- a/tests/unit/issue-6343-v0-web-alias-collision.test.ts +++ b/tests/unit/issue-6343-v0-web-alias-collision.test.ts @@ -26,7 +26,7 @@ describe("#6343: v0-vercel-web credential detection (alias collision)", () => { } catch { // best-effort cleanup } - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("v0-vercel and v0-vercel-web no longer share an alias", async () => { diff --git a/tests/unit/issue-6686-quota-preflight-coverage.test.ts b/tests/unit/issue-6686-quota-preflight-coverage.test.ts index 488ee55f58..0b8d147d3c 100644 --- a/tests/unit/issue-6686-quota-preflight-coverage.test.ts +++ b/tests/unit/issue-6686-quota-preflight-coverage.test.ts @@ -86,7 +86,7 @@ test("#6686: getProviderCredentialsWithQuotaPreflight (now used by every credent core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); try { @@ -135,6 +135,6 @@ test("#6686: getProviderCredentialsWithQuotaPreflight (now used by every credent } finally { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/issue-agent-route-execution.test.ts b/tests/unit/issue-agent-route-execution.test.ts index 9f0c7e0b86..1d90b6d9ab 100644 --- a/tests/unit/issue-agent-route-execution.test.ts +++ b/tests/unit/issue-agent-route-execution.test.ts @@ -17,7 +17,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/json-migration-combos.test.ts b/tests/unit/json-migration-combos.test.ts index 978f9109ae..4ccdacb346 100644 --- a/tests/unit/json-migration-combos.test.ts +++ b/tests/unit/json-migration-combos.test.ts @@ -23,7 +23,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); @@ -144,7 +144,6 @@ test("runJsonMigration normalizes legacy combo strategy names at the import boun assert.equal(byId.get("combo-unknown").strategy, "priority"); }); - test("runJsonMigration rejects invalid combo invariants atomically", () => { const db = core.getDbInstance(); diff --git a/tests/unit/key-health-402-disable-5239.test.ts b/tests/unit/key-health-402-disable-5239.test.ts index 5b3a5286e1..40fa7e0240 100644 --- a/tests/unit/key-health-402-disable-5239.test.ts +++ b/tests/unit/key-health-402-disable-5239.test.ts @@ -22,16 +22,13 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-5239-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); -const { recordKeyHealthStatus } = await import( - "../../open-sse/handlers/chatCore/keyHealth.ts" -); -const { getValidApiKey, getAllKeyHealth, resetKeyStatus } = await import( - "../../open-sse/services/apiKeyRotator.ts" -); +const { recordKeyHealthStatus } = await import("../../open-sse/handlers/chatCore/keyHealth.ts"); +const { getValidApiKey, getAllKeyHealth, resetKeyStatus } = + await import("../../open-sse/services/apiKeyRotator.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Two keys live on ONE connection as API Key Round-Robin (extraApiKeys[]). diff --git a/tests/unit/kimi-coding-billing.test.ts b/tests/unit/kimi-coding-billing.test.ts index 0269228878..6720b1436d 100644 --- a/tests/unit/kimi-coding-billing.test.ts +++ b/tests/unit/kimi-coding-billing.test.ts @@ -83,7 +83,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("kimi-coding exposes the official boosterWallet Extra Usage contract", async () => { diff --git a/tests/unit/kimi-quota-reset-recovery.test.ts b/tests/unit/kimi-quota-reset-recovery.test.ts index 8771cba187..5129037c2a 100644 --- a/tests/unit/kimi-quota-reset-recovery.test.ts +++ b/tests/unit/kimi-quota-reset-recovery.test.ts @@ -17,7 +17,7 @@ const quotaCache = await import("../../src/domain/quotaCache.ts"); test.after(() => { quotaCache.__clearForTests(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Kimi billing-cycle quota errors remain active and recover at the cached reset", async () => { diff --git a/tests/unit/kimi-web-models-discovery.test.ts b/tests/unit/kimi-web-models-discovery.test.ts index b565698418..dd0ae0cdc9 100644 --- a/tests/unit/kimi-web-models-discovery.test.ts +++ b/tests/unit/kimi-web-models-discovery.test.ts @@ -13,13 +13,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("kimi-web uses the curated registry catalog without remote discovery", async () => { diff --git a/tests/unit/kiro-auto-import-idc-2059.test.ts b/tests/unit/kiro-auto-import-idc-2059.test.ts index 331637ffb5..e215036ea5 100644 --- a/tests/unit/kiro-auto-import-idc-2059.test.ts +++ b/tests/unit/kiro-auto-import-idc-2059.test.ts @@ -57,7 +57,7 @@ let tmpHome: string; test.beforeEach(() => { tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-kiro-idc-2059-")); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); process.env.HOME = tmpHome; delete process.env.APPDATA; @@ -73,12 +73,12 @@ test.afterEach(() => { delete process.env.APPDATA; } globalThis.fetch = ORIGINAL_FETCH; - if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true }); + if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Helpers ────────────────────────────────────────────────────────────────── diff --git a/tests/unit/kiro-auto-import-name-dedup-3615.test.ts b/tests/unit/kiro-auto-import-name-dedup-3615.test.ts index 748312a316..d8dac81347 100644 --- a/tests/unit/kiro-auto-import-name-dedup-3615.test.ts +++ b/tests/unit/kiro-auto-import-name-dedup-3615.test.ts @@ -24,7 +24,7 @@ process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-api-key-secret- test.after(() => { try { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best effort } diff --git a/tests/unit/kiro-builder-id-import-3333.test.ts b/tests/unit/kiro-builder-id-import-3333.test.ts index f9ba09772f..106d460b83 100644 --- a/tests/unit/kiro-builder-id-import-3333.test.ts +++ b/tests/unit/kiro-builder-id-import-3333.test.ts @@ -35,7 +35,7 @@ test.beforeEach(() => { test.afterEach(() => { process.env.HOME = ORIGINAL_HOME; globalThis.fetch = ORIGINAL_FETCH; - if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true }); + if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("validateImportToken uses cached Builder ID client creds + OIDC refresh path", async () => { diff --git a/tests/unit/kiro-import-error-3589.test.ts b/tests/unit/kiro-import-error-3589.test.ts index 4c789cae32..948b92c6af 100644 --- a/tests/unit/kiro-import-error-3589.test.ts +++ b/tests/unit/kiro-import-error-3589.test.ts @@ -23,7 +23,7 @@ const { buildKiroImportError } = await import("../../src/app/api/oauth/kiro/impo test.after(() => { try { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best effort } diff --git a/tests/unit/kiro-second-oauth-connection-10815.test.ts b/tests/unit/kiro-second-oauth-connection-10815.test.ts index 4b2640d99b..8128e9fa39 100644 --- a/tests/unit/kiro-second-oauth-connection-10815.test.ts +++ b/tests/unit/kiro-second-oauth-connection-10815.test.ts @@ -12,7 +12,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createProviderConnection keeps two Kiro oauth connections with the same email but different profileArn separate (#10815)", async () => { diff --git a/tests/unit/kiro-sso-cache-direct-clientid-1253.test.ts b/tests/unit/kiro-sso-cache-direct-clientid-1253.test.ts index 0afef36614..0f561417f6 100644 --- a/tests/unit/kiro-sso-cache-direct-clientid-1253.test.ts +++ b/tests/unit/kiro-sso-cache-direct-clientid-1253.test.ts @@ -53,7 +53,7 @@ let tmpHome: string; test.beforeEach(() => { tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-kiro-1253-")); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); process.env.HOME = tmpHome; delete process.env.APPDATA; @@ -68,12 +68,12 @@ test.afterEach(() => { delete process.env.APPDATA; } globalThis.fetch = ORIGINAL_FETCH; - if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true }); + if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function cacheDirFor(home: string) { @@ -142,7 +142,11 @@ test("auto-import: resolves clientId/clientSecret from a direct `clientId` field assert.equal(parsed.clientId, "correct-client-id"); assert.equal(parsed.clientSecret, "correct-secret"); return new Response( - JSON.stringify({ accessToken: "access-refreshed", refreshToken: "aorAAAAAGrefreshed", expiresIn: 3600 }), + JSON.stringify({ + accessToken: "access-refreshed", + refreshToken: "aorAAAAAGrefreshed", + expiresIn: 3600, + }), { status: 200, headers: { "Content-Type": "application/json" } } ); } @@ -185,7 +189,11 @@ test("KiroService.validateImportToken: prefers the client registration matching fetchedBodies.push(parsed); if (parsed.clientId === "correct-client-id" && parsed.clientSecret === "correct-secret") { return new Response( - JSON.stringify({ accessToken: "ok-access", refreshToken: "aorAAAAAGok", expiresIn: 3600 }), + JSON.stringify({ + accessToken: "ok-access", + refreshToken: "aorAAAAAGok", + expiresIn: 3600, + }), { status: 200, headers: { "Content-Type": "application/json" } } ); } diff --git a/tests/unit/kiro-windows-auto-import-3363.test.ts b/tests/unit/kiro-windows-auto-import-3363.test.ts index cc1ebd4d8a..6bd0d90a2e 100644 --- a/tests/unit/kiro-windows-auto-import-3363.test.ts +++ b/tests/unit/kiro-windows-auto-import-3363.test.ts @@ -44,7 +44,7 @@ test.beforeEach(() => { tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-kiro-3363-")); // Reset DB instance so each test gets a clean settings DB (no requireLogin). core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // Override HOME so homedir() returns a temp dir where no kiro-cli DB exists. process.env.HOME = tmpHome; @@ -69,12 +69,12 @@ test.afterEach(() => { delete process.env.APPDATA; } globalThis.fetch = ORIGINAL_FETCH; - if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true }); + if (tmpHome) fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Helper to call the GET handler and parse the JSON body. @@ -112,9 +112,7 @@ test("triedPaths does NOT include any Windows path when process.env.APPDATA is n const paths = body.triedPaths as string[]; // No path should reference "kiro/storage.db" (the Windows IDE storage path). - const hasWindowsPath = paths.some( - (p) => p.includes("storage.db") && p.includes("kiro") - ); + const hasWindowsPath = paths.some((p) => p.includes("storage.db") && p.includes("kiro")); assert.equal( hasWindowsPath, false, @@ -161,10 +159,7 @@ test("GET extracts refresh_token from a Windows storage.db with ItemTable schema expires_at: new Date(Date.now() + 3600 * 1000).toISOString(), region: "us-east-1", }); - db.prepare("INSERT INTO ItemTable (key, value) VALUES (?, ?)").run( - "kiro:auth:token", - tokenValue - ); + db.prepare("INSERT INTO ItemTable (key, value) VALUES (?, ?)").run("kiro:auth:token", tokenValue); db.close(); // Point APPDATA at tmpHome so tryKiroCliSqlite() resolves @@ -198,11 +193,7 @@ test("GET extracts refresh_token from a Windows storage.db with ItemTable schema const { status, body } = await callGet(); - assert.equal( - status, - 200, - `expected HTTP 200, got ${status}: ${JSON.stringify(body)}` - ); + assert.equal(status, 200, `expected HTTP 200, got ${status}: ${JSON.stringify(body)}`); assert.equal( body.found, true, diff --git a/tests/unit/latency-stats-ttft-6875.test.ts b/tests/unit/latency-stats-ttft-6875.test.ts index 7a05d029ef..332dea2ed3 100644 --- a/tests/unit/latency-stats-ttft-6875.test.ts +++ b/tests/unit/latency-stats-ttft-6875.test.ts @@ -20,7 +20,7 @@ const clearPendingRequests = usageHistory.clearPendingRequests; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); clearPendingRequests(); } @@ -32,7 +32,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getModelLatencyStats aggregates avgTtftMs/avgE2ELatencyMs/avgTokensPerSecond over successful rows", async () => { diff --git a/tests/unit/least-used-rotation-10945.test.ts b/tests/unit/least-used-rotation-10945.test.ts index 6218697ce1..38730dec55 100644 --- a/tests/unit/least-used-rotation-10945.test.ts +++ b/tests/unit/least-used-rotation-10945.test.ts @@ -27,13 +27,13 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** Three active apikey connections, distinct priorities, all last_used_at NULL. */ diff --git a/tests/unit/lib/consoleInterceptor-epipe.test.ts b/tests/unit/lib/consoleInterceptor-epipe.test.ts index 4a968e3bb3..664426afbb 100644 --- a/tests/unit/lib/consoleInterceptor-epipe.test.ts +++ b/tests/unit/lib/consoleInterceptor-epipe.test.ts @@ -155,7 +155,7 @@ test("a non-EPIPE stream error is still fatal: it must be re-raised (#8181)", as env: { ...process.env, DISABLE_SQLITE_AUTO_BACKUP: "true" }, }); - rmSync(childDir, { recursive: true, force: true }); + rmSync(childDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); assert.notEqual( result.status, @@ -197,7 +197,7 @@ test("the stdio guard is installed even when file logging is disabled (#8181)", env: { ...process.env, DISABLE_SQLITE_AUTO_BACKUP: "true", APP_LOG_TO_FILE: "false" }, }); - rmSync(childDir, { recursive: true, force: true }); + rmSync(childDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); assert.equal( result.status, @@ -259,5 +259,6 @@ test.after(() => { if (prevLogFilePath === undefined) delete process.env.APP_LOG_FILE_PATH; else process.env.APP_LOG_FILE_PATH = prevLogFilePath; - if (existsSync(dir)) rmSync(dir, { recursive: true, force: true }); + if (existsSync(dir)) + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/lib/consoleInterceptor-writes.test.ts b/tests/unit/lib/consoleInterceptor-writes.test.ts index 8a16c244d7..2cba3d5591 100644 --- a/tests/unit/lib/consoleInterceptor-writes.test.ts +++ b/tests/unit/lib/consoleInterceptor-writes.test.ts @@ -56,7 +56,7 @@ function runChild(body: string[]): ChildResult { .map((l) => JSON.parse(l) as Record) : []; - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return { status: result.status, stderr: String(result.stderr), lines }; } @@ -132,7 +132,7 @@ test("a log directory removed at runtime is recreated and logging recovers (#818 `const { dirname } = await import("node:path");`, `M.initConsoleInterceptor();`, `console.error("before removal");`, - `rmSync(dirname(LOG_FILE), { recursive: true, force: true });`, + `rmSync(dirname(LOG_FILE), { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });`, `if (existsSync(LOG_FILE)) { process.exit(3); }`, `console.error("after removal");`, `setTimeout(() => process.exit(0), 200);`, @@ -154,7 +154,7 @@ test("the log-unavailable notice is emitted at most once, to the real stderr", ( `M.initConsoleInterceptor();`, // Make the directory unrecreatable so the retry fails and the notice path is exercised. `const parent = dirname(dirname(LOG_FILE));`, - `rmSync(dirname(LOG_FILE), { recursive: true, force: true });`, + `rmSync(dirname(LOG_FILE), { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });`, `chmodSync(parent, 0o500);`, `for (let i = 0; i < 5; i++) console.error("unwritable " + i);`, `chmodSync(parent, 0o700);`, diff --git a/tests/unit/lib/jobRegistry/registry.test.ts b/tests/unit/lib/jobRegistry/registry.test.ts index 64ce9d2050..9be264d5b6 100644 --- a/tests/unit/lib/jobRegistry/registry.test.ts +++ b/tests/unit/lib/jobRegistry/registry.test.ts @@ -56,7 +56,7 @@ function resetAll() { } __resetJobRegistry(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -67,7 +67,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("register + start (interval) fires handler immediately", async () => { diff --git a/tests/unit/lib/jobs/backupScheduleJob.test.ts b/tests/unit/lib/jobs/backupScheduleJob.test.ts index b2d2266181..e581057b99 100644 --- a/tests/unit/lib/jobs/backupScheduleJob.test.ts +++ b/tests/unit/lib/jobs/backupScheduleJob.test.ts @@ -13,7 +13,7 @@ async function withTmpDataDir(fn: (dataDir: string) => Promise) { } finally { if (orig === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = orig; - rmSync(dataDir, { recursive: true, force: true }); + rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/lib/managementCliToken.test.ts b/tests/unit/lib/managementCliToken.test.ts index 638c4c3fd7..d2a87a5262 100644 --- a/tests/unit/lib/managementCliToken.test.ts +++ b/tests/unit/lib/managementCliToken.test.ts @@ -28,7 +28,7 @@ const { CLI_TOKEN_HEADER } = await import("../../../src/server/authz/headers.ts" test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/lib/quota-reset-events.test.ts b/tests/unit/lib/quota-reset-events.test.ts index 155d515b50..ee1ddb888a 100644 --- a/tests/unit/lib/quota-reset-events.test.ts +++ b/tests/unit/lib/quota-reset-events.test.ts @@ -25,7 +25,7 @@ const OBSERVED = "2026-01-15T00:05:00.000Z"; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("records a weekly window transition and getWindowStart returns the prior window start", () => { diff --git a/tests/unit/lib/warmupScheduler/circuitBreakerFactory.test.ts b/tests/unit/lib/warmupScheduler/circuitBreakerFactory.test.ts index c7808fd572..81c71ea387 100644 --- a/tests/unit/lib/warmupScheduler/circuitBreakerFactory.test.ts +++ b/tests/unit/lib/warmupScheduler/circuitBreakerFactory.test.ts @@ -21,7 +21,7 @@ const core = await import("../../../../src/lib/db/core.ts"); async function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -32,7 +32,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("REDIS_URL unset → SqliteCircuitBreakerStore", async () => { diff --git a/tests/unit/lib/warmupScheduler/circuitBreakerFactoryConcurrency.test.ts b/tests/unit/lib/warmupScheduler/circuitBreakerFactoryConcurrency.test.ts index 0ab9c8b808..faca11da13 100644 --- a/tests/unit/lib/warmupScheduler/circuitBreakerFactoryConcurrency.test.ts +++ b/tests/unit/lib/warmupScheduler/circuitBreakerFactoryConcurrency.test.ts @@ -24,7 +24,7 @@ const core = await import("../../../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** diff --git a/tests/unit/lib/warmupScheduler/circuitBreakerFactoryRelease.test.ts b/tests/unit/lib/warmupScheduler/circuitBreakerFactoryRelease.test.ts index 97ec79116b..3ff651f4f4 100644 --- a/tests/unit/lib/warmupScheduler/circuitBreakerFactoryRelease.test.ts +++ b/tests/unit/lib/warmupScheduler/circuitBreakerFactoryRelease.test.ts @@ -24,7 +24,7 @@ const core = await import("../../../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** diff --git a/tests/unit/lib/warmupScheduler/sqliteCircuitBreakerStore.test.ts b/tests/unit/lib/warmupScheduler/sqliteCircuitBreakerStore.test.ts index da4dae94b5..161a02393a 100644 --- a/tests/unit/lib/warmupScheduler/sqliteCircuitBreakerStore.test.ts +++ b/tests/unit/lib/warmupScheduler/sqliteCircuitBreakerStore.test.ts @@ -23,7 +23,7 @@ const store = new SqliteCircuitBreakerStore(); async function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -46,7 +46,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("recordResult(success): clears streak and records tokens", async () => { diff --git a/tests/unit/limiter-lifecycle.test.ts b/tests/unit/limiter-lifecycle.test.ts index c70981d90c..bc4f612715 100644 --- a/tests/unit/limiter-lifecycle.test.ts +++ b/tests/unit/limiter-lifecycle.test.ts @@ -50,7 +50,7 @@ await flushBackgroundWork(); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -67,7 +67,7 @@ test.after(async () => { await rateLimitManager.__resetRateLimitManagerForTests(); await flushBackgroundWork(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** diff --git a/tests/unit/live-model-catalog-reconciliation-8926.test.ts b/tests/unit/live-model-catalog-reconciliation-8926.test.ts index 2796071e43..833c2d8551 100644 --- a/tests/unit/live-model-catalog-reconciliation-8926.test.ts +++ b/tests/unit/live-model-catalog-reconciliation-8926.test.ts @@ -58,7 +58,7 @@ function seedActiveLiveCatalog() { test.beforeEach(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); assert.ok( @@ -71,7 +71,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8926: bare inference excludes a stale static model absent from the active live catalog", async () => { diff --git a/tests/unit/live-ws-public-url.test.ts b/tests/unit/live-ws-public-url.test.ts index deff8cb926..16fd8f7bb6 100644 --- a/tests/unit/live-ws-public-url.test.ts +++ b/tests/unit/live-ws-public-url.test.ts @@ -20,7 +20,7 @@ const wsRoute = await import("../../src/app/api/v1/ws/route.ts"); function resetStorage() { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(() => { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/llamacpp-model-delete.test.ts b/tests/unit/llamacpp-model-delete.test.ts index 9379cfee8f..29c8180fc3 100644 --- a/tests/unit/llamacpp-model-delete.test.ts +++ b/tests/unit/llamacpp-model-delete.test.ts @@ -12,7 +12,7 @@ const modelsDb = await import("../../src/lib/db/models.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -22,7 +22,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("removeSyncedAvailableModel deletes a single model from syncedAvailableModels", async () => { diff --git a/tests/unit/llm7-byteplus-models-fetch-3976.test.ts b/tests/unit/llm7-byteplus-models-fetch-3976.test.ts index 0223191799..d154ff066d 100644 --- a/tests/unit/llm7-byteplus-models-fetch-3976.test.ts +++ b/tests/unit/llm7-byteplus-models-fetch-3976.test.ts @@ -27,13 +27,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { diff --git a/tests/unit/lmstudio-connection-baseurl-11233.test.ts b/tests/unit/lmstudio-connection-baseurl-11233.test.ts index 78af8690e4..1d8ad7afdd 100644 --- a/tests/unit/lmstudio-connection-baseurl-11233.test.ts +++ b/tests/unit/lmstudio-connection-baseurl-11233.test.ts @@ -15,7 +15,7 @@ const { createEmbeddingResponse } = await import("../../src/lib/embeddings/servi test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Issue #11233: the dashboard stores LM Studio connections under the provider diff --git a/tests/unit/local-corpus-index.test.ts b/tests/unit/local-corpus-index.test.ts index fc26e9802b..12851efeb5 100644 --- a/tests/unit/local-corpus-index.test.ts +++ b/tests/unit/local-corpus-index.test.ts @@ -21,7 +21,7 @@ async function withCorpus( try { await run(root, index); } finally { - await fs.rm(root, { recursive: true, force: true }); + await fs.rm(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/local-corpus-lru-cache.test.ts b/tests/unit/local-corpus-lru-cache.test.ts index 1fc9598358..68d0c4f26a 100644 --- a/tests/unit/local-corpus-lru-cache.test.ts +++ b/tests/unit/local-corpus-lru-cache.test.ts @@ -25,13 +25,10 @@ test("dynamic root path traversal outside bounding box throws error", async () = const outsideFolder = fs.mkdtempSync(path.join(os.tmpdir(), "omni-corpus-outside-")); - assert.throws( - () => getConfiguredLocalCorpusStatus(outsideFolder), - /Path traversal forbidden/ - ); + assert.throws(() => getConfiguredLocalCorpusStatus(outsideFolder), /Path traversal forbidden/); - fs.rmSync(tmpBase, { recursive: true, force: true }); - fs.rmSync(outsideFolder, { recursive: true, force: true }); + fs.rmSync(tmpBase, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(outsideFolder, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("path traversal check rejects sibling directory with matching string prefix", async () => { @@ -41,13 +38,10 @@ test("path traversal check rejects sibling directory with matching string prefix setLocalCorpusRoot(tmpBase); - assert.throws( - () => getConfiguredLocalCorpusStatus(siblingFolder), - /Path traversal forbidden/ - ); + assert.throws(() => getConfiguredLocalCorpusStatus(siblingFolder), /Path traversal forbidden/); - fs.rmSync(tmpBase, { recursive: true, force: true }); - fs.rmSync(siblingFolder, { recursive: true, force: true }); + fs.rmSync(tmpBase, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(siblingFolder, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("search and read configured local corpus support dynamic root within bounds", async () => { @@ -70,7 +64,7 @@ test("search and read configured local corpus support dynamic root within bounds }); assert.ok(readResult.content.includes("searchable")); - fs.rmSync(tmpBase, { recursive: true, force: true }); + fs.rmSync(tmpBase, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("LRU cache respects access order and OMNIROUTE_CORPUS_CACHE_SIZE", async () => { @@ -101,5 +95,5 @@ test("LRU cache respects access order and OMNIROUTE_CORPUS_CACHE_SIZE", async () assert.equal(idx1.indexedBytes, idx1Again.indexedBytes); delete process.env.OMNIROUTE_CORPUS_CACHE_SIZE; - fs.rmSync(tmpRoot, { recursive: true, force: true }); + fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/local-rerank-logging.test.ts b/tests/unit/local-rerank-logging.test.ts index 3c6ec62794..820a1f7694 100644 --- a/tests/unit/local-rerank-logging.test.ts +++ b/tests/unit/local-rerank-logging.test.ts @@ -35,7 +35,7 @@ test.describe("Local rerank provider logging and fallback", () => { globalThis.fetch = originalFetch; core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } diff --git a/tests/unit/log-export-routes.test.mjs b/tests/unit/log-export-routes.test.mjs index 3ff34a36ac..12bdecbcf3 100644 --- a/tests/unit/log-export-routes.test.mjs +++ b/tests/unit/log-export-routes.test.mjs @@ -17,7 +17,7 @@ const exportAllRoute = await import("../../src/app/api/db-backups/exportAll/rout async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await settingsDb.updateSettings({ requireLogin: false }); } @@ -28,7 +28,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/logs/export returns explicit detailed payloads from artifact storage", async () => { diff --git a/tests/unit/log-retention.test.ts b/tests/unit/log-retention.test.ts index f9d83d4c8d..57a2617f58 100644 --- a/tests/unit/log-retention.test.ts +++ b/tests/unit/log-retention.test.ts @@ -16,7 +16,7 @@ const compliance = await import("../../src/lib/compliance/index.ts"); function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -158,7 +158,11 @@ test("cleanupExpiredLogs honors the dashboard usageHistory retention when env is // 30 days < the configured 90-day dashboard retention → must be kept. // With the old env-default (7d) behavior this row would be deleted. - assert.equal(result.deletedUsage, 0, "30-day usage_history must survive a 90-day dashboard retention"); + assert.equal( + result.deletedUsage, + 0, + "30-day usage_history must survive a 90-day dashboard retention" + ); assert.equal((db.prepare("SELECT COUNT(*) AS cnt FROM usage_history").get() as any).cnt, 1); } finally { if (savedCall !== undefined) process.env.CALL_LOG_RETENTION_DAYS = savedCall; diff --git a/tests/unit/logger-write-after-datadir-removed-6360.test.ts b/tests/unit/logger-write-after-datadir-removed-6360.test.ts index 26c6c2858c..ea9a8bea42 100644 --- a/tests/unit/logger-write-after-datadir-removed-6360.test.ts +++ b/tests/unit/logger-write-after-datadir-removed-6360.test.ts @@ -70,7 +70,7 @@ test("logger must not crash the process when its worker transport reports a writ // Simulate the teardown every test file already does: rip out DATA_DIR // while the logger's worker-thread transport is still alive. - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); assert.equal(existsSync(dir), false, "sanity: DATA_DIR must actually be gone"); // Simulate the worker thread reporting the resulting write failure back to @@ -104,6 +104,6 @@ test("logger must not crash the process when its worker transport reports a writ test.after(async () => { await flushLogger(); if (existsSync(dir)) { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/login-bootstrap-route.test.ts b/tests/unit/login-bootstrap-route.test.ts index c51bd9870a..8df1f6ccae 100644 --- a/tests/unit/login-bootstrap-route.test.ts +++ b/tests/unit/login-bootstrap-route.test.ts @@ -22,7 +22,7 @@ type BootstrapResponse = { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ test.afterEach(() => { test.after(() => { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const originalHash = bcrypt.hash; diff --git a/tests/unit/managed-available-models.test.ts b/tests/unit/managed-available-models.test.ts index 2635867568..db79cbcab7 100644 --- a/tests/unit/managed-available-models.test.ts +++ b/tests/unit/managed-available-models.test.ts @@ -21,7 +21,7 @@ const { getModelsByProviderId } = await import("../../src/shared/constants/model async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("CC compatible fallback models mirror the OAuth Claude Code registry list", () => { diff --git a/tests/unit/managed-model-import.test.ts b/tests/unit/managed-model-import.test.ts index e6e3bc04b7..5e75583c71 100644 --- a/tests/unit/managed-model-import.test.ts +++ b/tests/unit/managed-model-import.test.ts @@ -16,7 +16,7 @@ const { mergeProviderModelListing } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -26,7 +26,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("sync mode builds aliases from provider-level synced available models", async () => { diff --git a/tests/unit/management-password-insecure-default.test.ts b/tests/unit/management-password-insecure-default.test.ts index 752c15e30c..3abc287cdc 100644 --- a/tests/unit/management-password-insecure-default.test.ts +++ b/tests/unit/management-password-insecure-default.test.ts @@ -23,13 +23,13 @@ function makeLogger() { test.afterEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("warns when bootstrapping the management password with the CHANGEME default (Seg2)", async () => { @@ -60,5 +60,9 @@ test("does not warn when bootstrapping with a strong password", async () => { }); assert.equal(managementPassword.isBcryptHash(result.hash), true); - assert.equal(logger.warnings.length, 0, "did not expect any security warning for a strong password"); + assert.equal( + logger.warnings.length, + 0, + "did not expect any security warning for a strong password" + ); }); diff --git a/tests/unit/management-password.test.ts b/tests/unit/management-password.test.ts index eb5af4034d..1f12a3bd03 100644 --- a/tests/unit/management-password.test.ts +++ b/tests/unit/management-password.test.ts @@ -26,7 +26,7 @@ const managementPassword = await import("../../src/lib/auth/managementPassword.t async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } @@ -70,7 +70,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) { delete process.env.INITIAL_PASSWORD; } else { diff --git a/tests/unit/mark-account-unavailable-numeric-epoch-guard.test.ts b/tests/unit/mark-account-unavailable-numeric-epoch-guard.test.ts index 130481f5ad..ed964ea459 100644 --- a/tests/unit/mark-account-unavailable-numeric-epoch-guard.test.ts +++ b/tests/unit/mark-account-unavailable-numeric-epoch-guard.test.ts @@ -31,7 +31,7 @@ const { markAccountUnavailable } = await import("../../src/sse/services/auth.ts" test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const HOUR = 3_600_000; diff --git a/tests/unit/masked-200-exhaustion-fallback-6427.test.ts b/tests/unit/masked-200-exhaustion-fallback-6427.test.ts index 531c3401a3..d6cb0056f4 100644 --- a/tests/unit/masked-200-exhaustion-fallback-6427.test.ts +++ b/tests/unit/masked-200-exhaustion-fallback-6427.test.ts @@ -29,7 +29,8 @@ const core = await import("../../src/lib/db/core.ts"); const settingsDb = await import("../../src/lib/db/settings.ts"); const { resetAllComboMetrics } = await import("../../open-sse/services/comboMetrics.ts"); const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts"); -const { resetAll: resetAllSemaphores } = await import("../../open-sse/services/rateLimitSemaphore.ts"); +const { resetAll: resetAllSemaphores } = + await import("../../open-sse/services/rateLimitSemaphore.ts"); const { _resetAllDecks } = await import("../../src/shared/utils/shuffleDeck.ts"); const { clearSessions } = await import("../../open-sse/services/sessionManager.ts"); @@ -56,7 +57,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: unknown) { lastError = error; @@ -115,7 +116,9 @@ test("#6427 priority combo falls back when the first target's 200 body carries a error: { message: "Insufficient credits balance", type: "insufficient_quota" }, }); } - return jsonResponse({ choices: [{ message: { role: "assistant", content: "real answer" } }] }); + return jsonResponse({ + choices: [{ message: { role: "assistant", content: "real answer" } }], + }); }, isModelAvailable: async () => true, log: createLog(), @@ -130,7 +133,11 @@ test("#6427 priority combo falls back when the first target's 200 body carries a "combo must fail over past the masked-200 target instead of returning it" ); const bodyText = await result.clone().text(); - assert.match(bodyText, /real answer/, "the returned body must be the fallback target's real answer"); + assert.match( + bodyText, + /real answer/, + "the returned body must be the fallback target's real answer" + ); }); test("#6427 priority combo falls back when the first target's 200 body carries a known exhaustion phrase (no structured error)", async () => { @@ -154,7 +161,9 @@ test("#6427 priority combo falls back when the first target's 200 body carries a message: "Quota exceeded for this account", }); } - return jsonResponse({ choices: [{ message: { role: "assistant", content: "real answer" } }] }); + return jsonResponse({ + choices: [{ message: { role: "assistant", content: "real answer" } }], + }); }, isModelAvailable: async () => true, log: createLog(), diff --git a/tests/unit/materialize-bundled-symlinks.test.ts b/tests/unit/materialize-bundled-symlinks.test.ts index a83dc980bd..d7d11440de 100644 --- a/tests/unit/materialize-bundled-symlinks.test.ts +++ b/tests/unit/materialize-bundled-symlinks.test.ts @@ -44,7 +44,7 @@ test("materializeBundledSymlinks dereferences a live symlink into a real directo assert.equal(lstatSync(target).isDirectory(), true); assert.equal(JSON.parse(readFileSync(join(target, "package.json"), "utf8")).marker, "real-ws"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -69,7 +69,7 @@ test("materializeBundledSymlinks relinks a dangling hashed symlink to its siblin assert.equal(lstatSync(target).isSymbolicLink(), false); assert.equal(JSON.parse(readFileSync(join(target, "package.json"), "utf8")).marker, "real-bsq"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -89,7 +89,7 @@ test("materializeBundledSymlinks drops a dangling link with no resolvable siblin assert.equal(summary.removed, 1); assert.equal(existsSync(join(nm, "mystery-deadbeefcafe0001")), false); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -115,7 +115,7 @@ test("materializeBundledSymlinks handles scoped-package symlinks", () => { assert.equal(lstatSync(target).isSymbolicLink(), false); assert.equal(JSON.parse(readFileSync(join(target, "package.json"), "utf8")).marker, "real-hf"); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -133,7 +133,7 @@ test("materializeBundledSymlinks leaves real directories untouched and no-ops on const missing = materializeBundledSymlinks(join(root, "does-not-exist")); assert.deepEqual(missing, { materialized: 0, relinked: 0, removed: 0 }); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -154,7 +154,7 @@ test("syncRebuiltNativeModuleIntoHashedEntries overwrites a hashed entry with th "electron-abi-rebuilt" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -174,7 +174,7 @@ test("syncRebuiltNativeModuleIntoHashedEntries overwrites a plain-named entry to "electron-abi-rebuilt" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -195,7 +195,7 @@ test("syncRebuiltNativeModuleIntoHashedEntries no-ops when root module or nested ); assert.deepEqual(missingNm, { synced: 0 }); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -220,6 +220,6 @@ test("syncRebuiltNativeModuleIntoHashedEntries leaves unrelated entries untouche "unrelated-package" ); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/mcp-connect-scope.test.ts b/tests/unit/mcp-connect-scope.test.ts index 35734a27ff..371d686f70 100644 --- a/tests/unit/mcp-connect-scope.test.ts +++ b/tests/unit/mcp-connect-scope.test.ts @@ -19,17 +19,13 @@ const core = await import("../../src/lib/db/core.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); const settingsDb = await import("../../src/lib/db/settings.ts"); const { managementPolicy } = await import("../../src/server/authz/policies/management.ts"); -const { - isLocalOnlyPath, - isLocalOnlyBypassableByManageScope, -} = await import("../../src/server/authz/routeGuard.ts"); -const { MCP_CONNECT_SCOPE, hasMcpConnectOrManageScope } = await import( - "../../src/shared/constants/managementScopes.ts" -); +const { isLocalOnlyPath, isLocalOnlyBypassableByManageScope } = + await import("../../src/server/authz/routeGuard.ts"); +const { MCP_CONNECT_SCOPE, hasMcpConnectOrManageScope } = + await import("../../src/shared/constants/managementScopes.ts"); const { resolveMcpCallerAuthInfo } = await import("../../open-sse/mcp-server/httpAuthContext.ts"); -const { resolveCallerScopeContext, evaluateToolScopes } = await import( - "../../open-sse/mcp-server/scopeEnforcement.ts" -); +const { resolveCallerScopeContext, evaluateToolScopes } = + await import("../../open-sse/mcp-server/scopeEnforcement.ts"); const ORIGINAL_JWT = process.env.JWT_SECRET; const ORIGINAL_INITIAL = process.env.INITIAL_PASSWORD; @@ -37,7 +33,7 @@ const ORIGINAL_INITIAL = process.env.INITIAL_PASSWORD; function reset() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.JWT_SECRET; delete process.env.INITIAL_PASSWORD; @@ -49,7 +45,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_JWT === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = ORIGINAL_JWT; if (ORIGINAL_INITIAL === undefined) delete process.env.INITIAL_PASSWORD; @@ -193,20 +189,14 @@ test("per-key authInfo.scopes takes precedence over the env fallback once resolv assert.equal(scopeContext.source, "authInfo"); assert.deepEqual(scopeContext.scopes, ["read:health"]); - const allowedCheck = evaluateToolScopes( - "irrelevant-tool-name", - scopeContext.scopes, - true, - ["read:health"] - ); + const allowedCheck = evaluateToolScopes("irrelevant-tool-name", scopeContext.scopes, true, [ + "read:health", + ]); assert.equal(allowedCheck.allowed, true); - const deniedCheck = evaluateToolScopes( - "irrelevant-tool-name", - scopeContext.scopes, - true, - ["write:combos"] - ); + const deniedCheck = evaluateToolScopes("irrelevant-tool-name", scopeContext.scopes, true, [ + "write:combos", + ]); assert.equal(deniedCheck.allowed, false, "per-key scopes must gate, not the wider env fallback"); }); diff --git a/tests/unit/mcp-memory-tools-strategy.test.ts b/tests/unit/mcp-memory-tools-strategy.test.ts index ba740797ca..f89dcfcbf9 100644 --- a/tests/unit/mcp-memory-tools-strategy.test.ts +++ b/tests/unit/mcp-memory-tools-strategy.test.ts @@ -29,7 +29,7 @@ const core = await import("../../src/lib/db/core.ts"); function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,16 +37,15 @@ function cleanup() { test.afterEach(() => cleanup()); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); // ── A: toMemoryRetrievalConfig: "hybrid" → retrievalStrategy="hybrid" ───────── test("toMemoryRetrievalConfig: strategy=hybrid → retrievalStrategy=hybrid", async () => { - const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = await import( - "../../src/lib/memory/settings.ts" - ); + const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = + await import("../../src/lib/memory/settings.ts"); const settings = { ...DEFAULT_MEMORY_SETTINGS, strategy: "hybrid" as const }; const config = toMemoryRetrievalConfig(settings); assert.equal( @@ -59,9 +58,8 @@ test("toMemoryRetrievalConfig: strategy=hybrid → retrievalStrategy=hybrid", as // ── B: toMemoryRetrievalConfig: "semantic" → retrievalStrategy="semantic" ───── test("toMemoryRetrievalConfig: strategy=semantic → retrievalStrategy=semantic", async () => { - const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = await import( - "../../src/lib/memory/settings.ts" - ); + const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = + await import("../../src/lib/memory/settings.ts"); const settings = { ...DEFAULT_MEMORY_SETTINGS, strategy: "semantic" as const }; const config = toMemoryRetrievalConfig(settings); assert.equal( @@ -74,9 +72,8 @@ test("toMemoryRetrievalConfig: strategy=semantic → retrievalStrategy=semantic" // ── C: toMemoryRetrievalConfig: "recent" → retrievalStrategy="exact" ────────── test("toMemoryRetrievalConfig: strategy=recent → retrievalStrategy=exact (mapped)", async () => { - const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = await import( - "../../src/lib/memory/settings.ts" - ); + const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = + await import("../../src/lib/memory/settings.ts"); const settings = { ...DEFAULT_MEMORY_SETTINGS, strategy: "recent" as const }; const config = toMemoryRetrievalConfig(settings); assert.equal( @@ -105,9 +102,7 @@ test("omniroute_memory_search: strategy=hybrid in DB → handler returns success const { invalidateMemorySettingsCache } = await import("../../src/lib/memory/settings.ts"); invalidateMemorySettingsCache(); - const { memoryTools } = await import( - "../../open-sse/mcp-server/tools/memoryTools.ts" - ); + const { memoryTools } = await import("../../open-sse/mcp-server/tools/memoryTools.ts"); const handler = memoryTools.omniroute_memory_search.handler; const result = await handler({ apiKeyId: "api-mcp-h", query: "Paris" }); @@ -135,9 +130,7 @@ test("omniroute_memory_search: strategy=recent in DB → handler maps to exact, const { invalidateMemorySettingsCache } = await import("../../src/lib/memory/settings.ts"); invalidateMemorySettingsCache(); - const { memoryTools } = await import( - "../../open-sse/mcp-server/tools/memoryTools.ts" - ); + const { memoryTools } = await import("../../open-sse/mcp-server/tools/memoryTools.ts"); const handler = memoryTools.omniroute_memory_search.handler; const result = await handler({ apiKeyId: "api-mcp-r" }); @@ -150,9 +143,8 @@ test("omniroute_memory_search: strategy=recent in DB → handler maps to exact, // toMemoryRetrievalConfig used on DEFAULT maps to retrievalStrategy="hybrid" ── test("toMemoryRetrievalConfig: DEFAULT_MEMORY_SETTINGS maps to retrievalStrategy=hybrid", async () => { - const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = await import( - "../../src/lib/memory/settings.ts" - ); + const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = + await import("../../src/lib/memory/settings.ts"); // Verify the default strategy is "hybrid" so fallback in handler resolves to hybrid assert.equal( DEFAULT_MEMORY_SETTINGS.strategy, @@ -174,9 +166,8 @@ test("omniroute_memory_search: hardcoded fallback config has retrievalStrategy=e // We verify this by examining the fallback object directly from the source logic: // When memorySettings is null, the handler uses retrievalStrategy: "exact" as const. // We test this via toMemoryRetrievalConfig with a minimal disabled-settings object. - const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = await import( - "../../src/lib/memory/settings.ts" - ); + const { toMemoryRetrievalConfig, DEFAULT_MEMORY_SETTINGS } = + await import("../../src/lib/memory/settings.ts"); // Simulate the catch path: strategy "recent" maps to "exact" (same as hardcoded fallback) const disabledSettings = { ...DEFAULT_MEMORY_SETTINGS, strategy: "recent" as const }; diff --git a/tests/unit/mcp-route-scope-carveout.test.ts b/tests/unit/mcp-route-scope-carveout.test.ts index d64dbc7922..f35d7f8d40 100644 --- a/tests/unit/mcp-route-scope-carveout.test.ts +++ b/tests/unit/mcp-route-scope-carveout.test.ts @@ -30,7 +30,7 @@ const ORIGINAL_INITIAL = process.env.INITIAL_PASSWORD; function reset() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.JWT_SECRET; delete process.env.INITIAL_PASSWORD; @@ -42,7 +42,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_JWT === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = ORIGINAL_JWT; if (ORIGINAL_INITIAL === undefined) delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/mcp/bundle-no-sync-esm-await.test.ts b/tests/unit/mcp/bundle-no-sync-esm-await.test.ts index 7884def6a0..d6182fa078 100644 --- a/tests/unit/mcp/bundle-no-sync-esm-await.test.ts +++ b/tests/unit/mcp/bundle-no-sync-esm-await.test.ts @@ -155,7 +155,7 @@ test("MCP bundle never emits await inside a synchronous __esm initializer", () = runEsbuild(bundleArgs, ROOT); assertNoSyncEsmAwait(outputFile); } finally { - rmSync(outputDir, { recursive: true, force: true }); + rmSync(outputDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -186,6 +186,6 @@ test("esbuild propagates async initialization through wrapped import cycles", () ); assertNoSyncEsmAwait(outputFile); } finally { - rmSync(fixtureDir, { recursive: true, force: true }); + rmSync(fixtureDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/media-cost-headers-handlers.test.ts b/tests/unit/media-cost-headers-handlers.test.ts index 341c2871c7..4e8d54822b 100644 --- a/tests/unit/media-cost-headers-handlers.test.ts +++ b/tests/unit/media-cost-headers-handlers.test.ts @@ -31,7 +31,7 @@ test.afterEach(() => { test.after(() => { restoreGlobals(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 video generation failure preserves provider status and error payload", async () => { diff --git a/tests/unit/media-cost-headers.test.ts b/tests/unit/media-cost-headers.test.ts index 41ad5542fb..d0f47e8b00 100644 --- a/tests/unit/media-cost-headers.test.ts +++ b/tests/unit/media-cost-headers.test.ts @@ -36,7 +36,7 @@ test.afterEach(() => { test.after(() => { restoreGlobals(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Shared assertions: every successful media Response must carry the @@ -142,7 +142,9 @@ test("v1 music generation success Response carries cost telemetry headers", asyn return new Response( JSON.stringify({ "music-cost-1": { - outputs: { 7: { audio: [{ filename: "track.wav", subfolder: "out", type: "output" }] } }, + outputs: { + 7: { audio: [{ filename: "track.wav", subfolder: "out", type: "output" }] }, + }, }, }), { status: 200, headers: { "content-type": "application/json" } } diff --git a/tests/unit/memory-engine-status.test.ts b/tests/unit/memory-engine-status.test.ts index a3921b74a9..936a901e86 100644 --- a/tests/unit/memory-engine-status.test.ts +++ b/tests/unit/memory-engine-status.test.ts @@ -33,7 +33,7 @@ const { MemoryEngineStatusSchema } = await import("../../src/shared/schemas/memo function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -41,7 +41,7 @@ function cleanup() { test.afterEach(() => cleanup()); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -153,11 +153,7 @@ test("engineStatus(): detail strings are English, not mixed Portuguese (#5596)", "degradado", "selecionado", ]; - for (const reason of [ - status.embedding.reason, - status.vectorStore.reason, - status.rerank.reason, - ]) { + for (const reason of [status.embedding.reason, status.vectorStore.reason, status.rerank.reason]) { for (const w of ptWords) { assert.ok(!reason.includes(w), `reason "${reason}" still contains Portuguese "${w}"`); } diff --git a/tests/unit/memory-needs-reindex.test.ts b/tests/unit/memory-needs-reindex.test.ts index 8818358a48..0793676155 100644 --- a/tests/unit/memory-needs-reindex.test.ts +++ b/tests/unit/memory-needs-reindex.test.ts @@ -27,10 +27,12 @@ function insertTestMemory( content: string, key: string ): void { - db.prepare(` + db.prepare( + ` INSERT INTO memories (id, api_key_id, type, key, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?, datetime('now'), datetime('now')) - `).run(id, "test-api-key", "factual", key, content); + ` + ).run(id, "test-api-key", "factual", key, content); } async function resetStorage() { @@ -39,7 +41,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -61,7 +63,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ──────────────── markMemoryNeedsReindex ──────────────── diff --git a/tests/unit/memory-reindex-batch.test.ts b/tests/unit/memory-reindex-batch.test.ts index 26d99247d3..82e96824d0 100644 --- a/tests/unit/memory-reindex-batch.test.ts +++ b/tests/unit/memory-reindex-batch.test.ts @@ -36,7 +36,7 @@ const { runReindexBatch, getReindexPending } = await import("../../src/lib/memor function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ function cleanup() { test.afterEach(() => cleanup()); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/memory-retrieval-hybrid.test.ts b/tests/unit/memory-retrieval-hybrid.test.ts index 0c0daa119e..5614cef312 100644 --- a/tests/unit/memory-retrieval-hybrid.test.ts +++ b/tests/unit/memory-retrieval-hybrid.test.ts @@ -28,7 +28,7 @@ async function removeTestDataDir() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } return; } catch (error: unknown) { diff --git a/tests/unit/memory-retrieval-rerank.test.ts b/tests/unit/memory-retrieval-rerank.test.ts index 22c4e4121b..0e9b588a1e 100644 --- a/tests/unit/memory-retrieval-rerank.test.ts +++ b/tests/unit/memory-retrieval-rerank.test.ts @@ -32,7 +32,7 @@ const core = await import("../../src/lib/db/core.ts"); function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -40,7 +40,7 @@ function cleanup() { test.afterEach(() => cleanup()); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -144,7 +144,12 @@ test("retrieveMemories: large result set is token-budget capped before any reran const db = core.getDbInstance(); // Insert 20 memories for (let i = 1; i <= 20; i++) { - insertMemory(db, `large-${i}`, "api-large", `Content number ${i} with enough words to use tokens.`); + insertMemory( + db, + `large-${i}`, + "api-large", + `Content number ${i} with enough words to use tokens.` + ); } const { retrieveMemories } = await import("../../src/lib/memory/retrieval.ts"); diff --git a/tests/unit/memory-retrieval-semantic.test.ts b/tests/unit/memory-retrieval-semantic.test.ts index 806c2ee397..b5b0eae4bb 100644 --- a/tests/unit/memory-retrieval-semantic.test.ts +++ b/tests/unit/memory-retrieval-semantic.test.ts @@ -30,7 +30,7 @@ const core = await import("../../src/lib/db/core.ts"); function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,7 +38,7 @@ function cleanup() { test.afterEach(() => cleanup()); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -116,9 +116,30 @@ test("retrieveMemories: strategy=exact returns memories chronologically", async // Use recent dates (within last 30 days) so retention filter does not remove them const now = Date.now(); const base = new Date(now - 3 * 24 * 60 * 60 * 1000); // 3 days ago - insertMemory(db, "e1", "api-exact", "First memory", "first", new Date(base.getTime() + 3000).toISOString()); - insertMemory(db, "e2", "api-exact", "Second memory", "second", new Date(base.getTime() + 2000).toISOString()); - insertMemory(db, "e3", "api-exact", "Third memory", "third", new Date(base.getTime() + 1000).toISOString()); + insertMemory( + db, + "e1", + "api-exact", + "First memory", + "first", + new Date(base.getTime() + 3000).toISOString() + ); + insertMemory( + db, + "e2", + "api-exact", + "Second memory", + "second", + new Date(base.getTime() + 2000).toISOString() + ); + insertMemory( + db, + "e3", + "api-exact", + "Third memory", + "third", + new Date(base.getTime() + 1000).toISOString() + ); const { retrieveMemories } = await import("../../src/lib/memory/retrieval.ts"); @@ -181,7 +202,10 @@ test("retrieveMemories: returns only memories for the given apiKeyId", async () const { retrieveMemories } = await import("../../src/lib/memory/retrieval.ts"); - const result = await retrieveMemories("api-key1", { retrievalStrategy: "exact", maxTokens: 2000 }); + const result = await retrieveMemories("api-key1", { + retrievalStrategy: "exact", + maxTokens: 2000, + }); for (const m of result) { assert.equal(m.apiKeyId, "api-key1", "should only return memories for api-key1"); } diff --git a/tests/unit/memory-retrieve-preview.test.ts b/tests/unit/memory-retrieve-preview.test.ts index e4de63cb72..14fd82a2ce 100644 --- a/tests/unit/memory-retrieve-preview.test.ts +++ b/tests/unit/memory-retrieve-preview.test.ts @@ -28,7 +28,7 @@ const core = await import("../../src/lib/db/core.ts"); function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +36,7 @@ function cleanup() { test.afterEach(() => cleanup()); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -126,8 +126,7 @@ test("retrievePreview: semantic strategy with no vec store → fallbackReason is // No embedding source configured → fallback assert.ok( - bundle.resolution.fallbackReason !== null || - bundle.resolution.strategyUsed !== "semantic", + bundle.resolution.fallbackReason !== null || bundle.resolution.strategyUsed !== "semantic", "semantic preview with no vec store should indicate fallback" ); assert.ok(Array.isArray(bundle.items), "items must be array even in fallback"); diff --git a/tests/unit/memory-route.test.ts b/tests/unit/memory-route.test.ts index 7ee3621394..bcc462a94c 100644 --- a/tests/unit/memory-route.test.ts +++ b/tests/unit/memory-route.test.ts @@ -14,7 +14,7 @@ const { MemoryType } = await import("../../src/lib/memory/types.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/memory filters by q and returns matching stats", async () => { diff --git a/tests/unit/memory-store-sync.test.ts b/tests/unit/memory-store-sync.test.ts index f0d8955a69..5a358b191a 100644 --- a/tests/unit/memory-store-sync.test.ts +++ b/tests/unit/memory-store-sync.test.ts @@ -43,7 +43,7 @@ const memoryVec = await import("../../src/lib/db/memoryVec.ts"); function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.afterEach(() => { test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -87,8 +87,7 @@ test("createMemory() inserts row and returns valid Memory object", async () => { // Verify row exists in DB const db = core.getDbInstance(); const row = db.prepare("SELECT * FROM memories WHERE id = ?").get(created.id) as - | { id: string; content: string } - | undefined; + { id: string; content: string } | undefined; assert.ok(row, "row should exist in DB after createMemory"); assert.equal(row.content, "content for create test"); }); @@ -121,7 +120,9 @@ test("createMemory() UPSERT: same apiKeyId+key updates existing row", async () = // Verify only one row in DB for this key const db = core.getDbInstance(); const count = ( - db.prepare("SELECT COUNT(*) as cnt FROM memories WHERE api_key_id = ? AND key = ?").get("key-b", "upsert:test") as { + db + .prepare("SELECT COUNT(*) as cnt FROM memories WHERE api_key_id = ? AND key = ?") + .get("key-b", "upsert:test") as { cnt: number; } ).cnt; @@ -180,8 +181,7 @@ test("updateMemory() with content change returns true and updates the row", asyn // Verify the DB was updated const db = core.getDbInstance(); const row = db.prepare("SELECT content FROM memories WHERE id = ?").get(created.id) as - | { content: string } - | undefined; + { content: string } | undefined; assert.equal(row?.content, "new content changed", "content should be updated in DB"); }); @@ -208,11 +208,7 @@ test("updateMemory() metadata-only change does NOT mark needs_reindex (content u const pending = memoryVec.getMemoryReindexQueue(100); const inQueue = pending.some((item) => item.id === created.id); - assert.equal( - inQueue, - false, - "metadata-only update should NOT schedule vector re-gen" - ); + assert.equal(inQueue, false, "metadata-only update should NOT schedule vector re-gen"); }); test("getMemoryTokensUsed() returns 0 for empty DB", () => { diff --git a/tests/unit/memory-store.test.ts b/tests/unit/memory-store.test.ts index 1699955136..b48eb7b3ad 100644 --- a/tests/unit/memory-store.test.ts +++ b/tests/unit/memory-store.test.ts @@ -17,7 +17,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -76,7 +76,7 @@ test.afterEach(async () => { test.after(async () => { await drainSetImmediate(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("memory store CRUD round-trip persists to the memories table and invalidates cache on update/delete", async () => { diff --git a/tests/unit/memory-summarization-older-than.test.ts b/tests/unit/memory-summarization-older-than.test.ts index 03c618a4f4..6611ca3991 100644 --- a/tests/unit/memory-summarization-older-than.test.ts +++ b/tests/unit/memory-summarization-older-than.test.ts @@ -29,7 +29,7 @@ const { summarizeMemoriesOlderThan } = await import("../../src/lib/memory/summar function cleanup() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -53,7 +53,7 @@ test.afterEach(async () => { }); test.after(() => { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -175,7 +175,11 @@ test("summarizeMemoriesOlderThan: totalTokens equals sum of candidates' content (sum, m) => sum + Math.ceil(m.content.length / 4), 0 ); - assert.equal(result.totalTokens, expectedTokens, "totalTokens must equal sum of candidate tokens"); + assert.equal( + result.totalTokens, + expectedTokens, + "totalTokens must equal sum of candidate tokens" + ); }); test("summarizeMemoriesOlderThan: apiKeyId=undefined scopes to ALL memories", async () => { diff --git a/tests/unit/memory-summarization.test.ts b/tests/unit/memory-summarization.test.ts index 381e1a22bb..d8cdc62923 100644 --- a/tests/unit/memory-summarization.test.ts +++ b/tests/unit/memory-summarization.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -62,7 +62,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("summarizeMemories returns zeroed metrics for empty conversations", async () => { diff --git a/tests/unit/memory-tools.test.ts b/tests/unit/memory-tools.test.ts index 4e021834ce..aadbf6b433 100644 --- a/tests/unit/memory-tools.test.ts +++ b/tests/unit/memory-tools.test.ts @@ -16,7 +16,7 @@ const { invalidateMemorySettingsCache } = await import("../../src/lib/memory/set function resetStorage() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); core.getDbInstance(); } @@ -34,7 +34,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); process.env.DATA_DIR = originalDataDir; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("memory add stores entries with default session and metadata", async () => { diff --git a/tests/unit/memory-vec-meta.test.ts b/tests/unit/memory-vec-meta.test.ts index 49db9ace00..3f55166a96 100644 --- a/tests/unit/memory-vec-meta.test.ts +++ b/tests/unit/memory-vec-meta.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -46,7 +46,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ──────────────── getMemoryVecMeta initial state ──────────────── @@ -92,7 +92,7 @@ test("setMemoryVecMeta persists activeDim and embeddingSignature", () => { assert.equal(meta.activeDim, 1536); assert.equal(meta.embeddingSignature, "remote:openai/text-embedding-3-small:1536"); assert.equal(meta.lastResetAt, null); // not set - assert.equal(meta.vecLoaded, false); // not set + assert.equal(meta.vecLoaded, false); // not set }); test("setMemoryVecMeta persists vecLoaded = true", () => { @@ -119,7 +119,11 @@ test("setMemoryVecMeta updates only the provided fields (partial update)", () => const meta = memoryVec.getMemoryVecMeta(); assert.equal(meta.activeDim, 1536, "activeDim should be updated"); - assert.equal(meta.embeddingSignature, "static:potion-base-8M:768", "embeddingSignature should be preserved"); + assert.equal( + meta.embeddingSignature, + "static:potion-base-8M:768", + "embeddingSignature should be preserved" + ); assert.equal(meta.vecLoaded, true, "vecLoaded should be preserved"); }); diff --git a/tests/unit/memory-vectorstore-crud.test.ts b/tests/unit/memory-vectorstore-crud.test.ts index a1d489e186..1a3932e381 100644 --- a/tests/unit/memory-vectorstore-crud.test.ts +++ b/tests/unit/memory-vectorstore-crud.test.ts @@ -49,7 +49,7 @@ function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -61,7 +61,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -84,11 +84,11 @@ function insertMemory( db: ReturnType, id: string, apiKeyId: string, - content: string, + content: string ) { db.prepare( `INSERT INTO memories (id, api_key_id, type, key, content, created_at) - VALUES (?, ?, 'factual', ?, ?, datetime('now'))`, + VALUES (?, ?, 'factual', ?, ?, datetime('now'))` ).run(id, apiKeyId, `key-${id}`, content); } @@ -137,7 +137,7 @@ test("upsertVector: throws when memoryId does not exist in memories table", asyn await assert.rejects( () => store.upsertVector("nonexistent-id", makeVec(1.0, 0.0, 0.0, 0.0)), /memory not found/i, - "should throw when memoryId not found", + "should throw when memoryId not found" ); }); @@ -176,7 +176,7 @@ test("searchVector: returns topK=2 results ordered by distance ASC", async (t) = if (hits.length >= 2) { assert.ok( hits[0].distance <= hits[1].distance, - "results must be ordered by distance ASC (smaller = more similar)", + "results must be ordered by distance ASC (smaller = more similar)" ); } @@ -263,6 +263,6 @@ test("deleteVector: no-op when memoryId does not exist (no throw)", async (t) => // Should not throw. await assert.doesNotReject( () => store.deleteVector("nonexistent-id"), - "deleteVector for non-existent id must be a no-op (not throw)", + "deleteVector for non-existent id must be a no-op (not throw)" ); }); diff --git a/tests/unit/memory-vectorstore-ensure-ready.test.ts b/tests/unit/memory-vectorstore-ensure-ready.test.ts index 36052ead83..9208589b66 100644 --- a/tests/unit/memory-vectorstore-ensure-ready.test.ts +++ b/tests/unit/memory-vectorstore-ensure-ready.test.ts @@ -42,7 +42,7 @@ function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -126,7 +126,7 @@ test("ensureReady: signature change triggers reset + marks memories needs_reinde for (let i = 0; i < 3; i++) { db.prepare( `INSERT INTO memories (id, api_key_id, type, key, content, created_at) - VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))`, + VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))` ).run(`mem-${i}`, `key-${i}`, `content-${i}`); } @@ -154,7 +154,11 @@ test("ensureReady: signature change triggers reset + marks memories needs_reinde const needsRows = db .prepare("SELECT COUNT(*) AS cnt FROM memories WHERE needs_reindex = 1") .get() as { cnt: number }; - assert.equal(needsRows.cnt, 3, "all memories should be marked needs_reindex=1 after signature change"); + assert.equal( + needsRows.cnt, + 3, + "all memories should be marked needs_reindex=1 after signature change" + ); }); test("ensureReady: returns {ready: false} when dimensions are null (no probe done yet)", async (t) => { @@ -176,7 +180,7 @@ test("ensureReady: returns {ready: false} when dimensions are null (no probe don // Either ready (if signature already matches a loaded table) or not ready. assert.ok( typeof result.ready === "boolean", - "ensureReady must return {ready: boolean, reason: string}", + "ensureReady must return {ready: boolean, reason: string}" ); assert.ok(typeof result.reason === "string"); }); diff --git a/tests/unit/memory-vectorstore-int8-quant.test.ts b/tests/unit/memory-vectorstore-int8-quant.test.ts index e301298649..0b9d6d914c 100644 --- a/tests/unit/memory-vectorstore-int8-quant.test.ts +++ b/tests/unit/memory-vectorstore-int8-quant.test.ts @@ -70,7 +70,8 @@ function exactNearestIds(query: number[], k: number): string[] { function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -81,7 +82,8 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function getStoreOrSkip(t: { skip: (msg: string) => void }): ReturnType { @@ -97,7 +99,7 @@ function getStoreOrSkip(t: { skip: (msg: string) => void }): ReturnType, id: string) { db.prepare( `INSERT INTO memories (id, api_key_id, type, key, content, created_at) - VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))`, + VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))` ).run(id, `key-${id}`, `content-${id}`); } @@ -119,7 +121,7 @@ test("int8 mode: ensureReady stores an ':int8' signature", async (t) => { const stats = await store.stats(); assert.ok( stats.signature?.endsWith(":int8"), - `signature must carry the int8 marker, got ${stats.signature}`, + `signature must carry the int8 marker, got ${stats.signature}` ); }); @@ -139,9 +141,12 @@ test("int8 recall: nearest-neighbor matches exact float32 NN on the fixture", as assert.equal(hits[0].memoryId, exact[0], `top-1 must match exact NN (${exact[0]})`); const overlap = hits.slice(0, 3).filter((h) => exact.includes(h.memoryId)).length; - assert.ok(overlap >= 2, `top-3 overlap must be >= 2/3 (got ${overlap}; int8=${hits - .map((h) => h.memoryId) - .join(",")} exact=${exact.join(",")})`); + assert.ok( + overlap >= 2, + `top-3 overlap must be >= 2/3 (got ${overlap}; int8=${hits + .map((h) => h.memoryId) + .join(",")} exact=${exact.join(",")})` + ); }); test("switching none → int8 is a signature change that triggers reindex", async (t) => { diff --git a/tests/unit/memory-vectorstore-load.test.ts b/tests/unit/memory-vectorstore-load.test.ts index 7aec414cd9..8b2ed83fef 100644 --- a/tests/unit/memory-vectorstore-load.test.ts +++ b/tests/unit/memory-vectorstore-load.test.ts @@ -31,7 +31,7 @@ function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -43,7 +43,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -83,7 +83,7 @@ test("getVectorStore() returns null or a VectorStore instance (never throws)", ( assert.equal(threw, false, "getVectorStore() must never throw — must return null on failure"); assert.ok( result === null || (typeof result === "object" && result !== null), - `getVectorStore() must return object or null, got ${typeof result}`, + `getVectorStore() must return object or null, got ${typeof result}` ); }); @@ -109,7 +109,7 @@ test("getVectorStore() result has all required VectorStore methods when not null for (const method of requiredMethods) { assert.ok( typeof (store as Record)[method] === "function", - `VectorStore must have method ${method}`, + `VectorStore must have method ${method}` ); } }); diff --git a/tests/unit/memory-vectorstore-rrf.test.ts b/tests/unit/memory-vectorstore-rrf.test.ts index 4261ca6df2..88a3dacd4b 100644 --- a/tests/unit/memory-vectorstore-rrf.test.ts +++ b/tests/unit/memory-vectorstore-rrf.test.ts @@ -50,7 +50,7 @@ function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -62,7 +62,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -84,20 +84,19 @@ function insertMemoryWithFts( db: ReturnType, id: string, apiKeyId: string, - content: string, + content: string ) { // Insert into memories — the trigger memory_fts_ai fires automatically if the DB has it. // In a fresh test DB the trigger exists (created by migration 023). db.prepare( `INSERT INTO memories (id, api_key_id, type, key, content, created_at) - VALUES (?, ?, 'factual', ?, ?, datetime('now'))`, + VALUES (?, ?, 'factual', ?, ?, datetime('now'))` ).run(id, apiKeyId, `key-${id}`, content); // The migration 023 trigger inserts into memory_fts using memory_id (= rowid). // If the trigger didn't fire (e.g. test DB without triggers), manually sync FTS. try { const row = db.prepare("SELECT rowid, memory_id FROM memories WHERE id = ?").get(id) as - | { rowid: number; memory_id: number | null } - | undefined; + { rowid: number; memory_id: number | null } | undefined; if (row) { const ftsRowid = row.memory_id ?? row.rowid; const ftsCount = db @@ -107,7 +106,7 @@ function insertMemoryWithFts( db.prepare("INSERT INTO memory_fts(rowid, content, key) VALUES(?, ?, ?)").run( ftsRowid, content, - `key-${id}`, + `key-${id}` ); } } @@ -153,7 +152,7 @@ test("searchHybrid: results ordered DESC by rrfScore", async (t) => { for (let i = 0; i < hits.length - 1; i++) { assert.ok( hits[i].rrfScore >= hits[i + 1].rrfScore, - `results must be ordered DESC by rrfScore: ${hits[i].rrfScore} >= ${hits[i + 1].rrfScore}`, + `results must be ordered DESC by rrfScore: ${hits[i].rrfScore} >= ${hits[i + 1].rrfScore}` ); } }); @@ -183,7 +182,7 @@ test("searchHybrid: doc in both FTS and vec → highest rrfScore (sum of both co const minRrf = 1 / (RRF_K + 1); assert.ok( bothHit.rrfScore >= minRrf, - `mem-both rrfScore ${bothHit.rrfScore} should be >= ${minRrf}`, + `mem-both rrfScore ${bothHit.rrfScore} should be >= ${minRrf}` ); } }); @@ -210,7 +209,7 @@ test("searchHybrid: FTS-only hit has vecRank=null", async (t) => { // Score should be approximately the FTS contribution. assert.ok( Math.abs(ftsOnlyHit.rrfScore - expectedContrib) < 0.01, - `FTS-only rrfScore ${ftsOnlyHit.rrfScore} should ≈ ${expectedContrib}`, + `FTS-only rrfScore ${ftsOnlyHit.rrfScore} should ≈ ${expectedContrib}` ); } } @@ -236,7 +235,7 @@ test("searchHybrid: apiKeyId filters both vec and FTS results", async (t) => { // At least one of each should appear (FTS and/or vec). assert.ok( allIds.includes("mem-key1") || allIds.includes("mem-key2"), - "without filter should include at least one hit", + "without filter should include at least one hit" ); // With filter for key1 only. diff --git a/tests/unit/memory-vectorstore-stats.test.ts b/tests/unit/memory-vectorstore-stats.test.ts index 5491fdde03..038bab8653 100644 --- a/tests/unit/memory-vectorstore-stats.test.ts +++ b/tests/unit/memory-vectorstore-stats.test.ts @@ -43,13 +43,10 @@ function makeVec(...values: number[]): Float32Array { return new Float32Array(values); } -function insertMemory( - db: ReturnType, - id: string, -) { +function insertMemory(db: ReturnType, id: string) { db.prepare( `INSERT INTO memories (id, api_key_id, type, key, content, created_at) - VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))`, + VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))` ).run(id, `key-${id}`, `content-${id}`); } @@ -58,7 +55,7 @@ function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -70,7 +67,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/memory-vectorstore-upsert-self-heal.test.ts b/tests/unit/memory-vectorstore-upsert-self-heal.test.ts index de8657ff60..5180c6e954 100644 --- a/tests/unit/memory-vectorstore-upsert-self-heal.test.ts +++ b/tests/unit/memory-vectorstore-upsert-self-heal.test.ts @@ -59,7 +59,7 @@ function cleanup() { _resetVectorStoreSingleton(); core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -71,7 +71,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -89,11 +89,11 @@ function insertMemory( db: ReturnType, id: string, apiKeyId: string, - content: string, + content: string ) { db.prepare( `INSERT INTO memories (id, api_key_id, type, key, content, created_at) - VALUES (?, ?, 'factual', ?, ?, datetime('now'))`, + VALUES (?, ?, 'factual', ?, ?, datetime('now'))` ).run(id, apiKeyId, `key-${id}`, content); } @@ -116,7 +116,7 @@ test("upsertVector: self-heals when vec_memories is missing after ensureReady al assert.equal( db.prepare("SELECT name FROM sqlite_master WHERE name = 'vec_memories'").get(), undefined, - "table must actually be gone for this test to be meaningful", + "table must actually be gone for this test to be meaningful" ); // Must NOT throw "no such table: vec_memories" — must self-heal and succeed. @@ -139,7 +139,7 @@ test("deleteVector: self-heals when vec_memories is missing (no throw)", async ( await assert.doesNotReject( () => store.deleteVector("mem-a"), - "deleteVector must self-heal from a missing table, not throw", + "deleteVector must self-heal from a missing table, not throw" ); }); @@ -154,6 +154,6 @@ test("upsertVector: still throws a genuine unrelated error unchanged (no over-br await assert.rejects( () => store.upsertVector("nonexistent-id", makeVec(1.0, 0.0, 0.0, 0.0)), /memory not found/i, - "unrelated errors must not be swallowed by the self-heal retry", + "unrelated errors must not be swallowed by the self-heal retry" ); }); diff --git a/tests/unit/memory/typed-decay.test.ts b/tests/unit/memory/typed-decay.test.ts index adab781960..0af1349e59 100644 --- a/tests/unit/memory/typed-decay.test.ts +++ b/tests/unit/memory/typed-decay.test.ts @@ -14,9 +14,7 @@ before(() => { process.env.DATA_DIR = dataDir; }); -const { - MemoryType, -} = await import("../../../src/lib/memory/types.ts"); +const { MemoryType } = await import("../../../src/lib/memory/types.ts"); const { resolveTypedDecayConfig, isTypeImmune, @@ -27,9 +25,8 @@ const { DEFAULT_TTL_DAYS_BY_TYPE, DEFAULT_ACCESS_IMMUNITY_THRESHOLD, } = await import("../../../src/lib/memory/typedDecay.ts"); -const { createMemory, getMemory, recordMemoryAccess, listMemoriesForDecay } = await import( - "../../../src/lib/memory/store.ts" -); +const { createMemory, getMemory, recordMemoryAccess, listMemoriesForDecay } = + await import("../../../src/lib/memory/store.ts"); const { resetDbInstance, getDbInstance } = await import("../../../src/lib/db/core.ts"); const DAY_MS = 24 * 60 * 60 * 1000; @@ -51,7 +48,7 @@ after(() => { } catch { /* ignore */ } - if (dataDir) rmSync(dataDir, { recursive: true, force: true }); + if (dataDir) rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("typedDecay — pure predicates", () => { @@ -113,7 +110,10 @@ describe("typedDecay — env config", () => { const cfg = resolveTypedDecayConfig({} as NodeJS.ProcessEnv); assert.equal(cfg.enabled, false); assert.equal(cfg.accessImmunityThreshold, DEFAULT_ACCESS_IMMUNITY_THRESHOLD); - assert.equal(cfg.ttlDaysByType[MemoryType.EPISODIC], DEFAULT_TTL_DAYS_BY_TYPE[MemoryType.EPISODIC]); + assert.equal( + cfg.ttlDaysByType[MemoryType.EPISODIC], + DEFAULT_TTL_DAYS_BY_TYPE[MemoryType.EPISODIC] + ); }); it("MEMORY_TYPED_DECAY_EPISODIC_DAYS=0 makes episodic immune too", () => { diff --git a/tests/unit/merge-train-plan.test.ts b/tests/unit/merge-train-plan.test.ts index f3b7954521..cb53558313 100644 --- a/tests/unit/merge-train-plan.test.ts +++ b/tests/unit/merge-train-plan.test.ts @@ -121,7 +121,7 @@ test("--plan shell-quotes a hostile base before the gate command is evaluated", await assert.rejects(access(marker), { code: "ENOENT" }); } } finally { - await rm(tempDir, { recursive: true, force: true }); + await rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/messages-count-tokens-route.test.ts b/tests/unit/messages-count-tokens-route.test.ts index be78194349..56b31464ce 100644 --- a/tests/unit/messages-count-tokens-route.test.ts +++ b/tests/unit/messages-count-tokens-route.test.ts @@ -34,7 +34,7 @@ type CountTokensErrorResponse = { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -57,7 +57,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("messages/count_tokens uses real provider count when Claude-compatible upstream supports it", async () => { diff --git a/tests/unit/microsoft-designer-web-image-handler-block.test.ts b/tests/unit/microsoft-designer-web-image-handler-block.test.ts index 39fb45d6dc..66ff9734c2 100644 --- a/tests/unit/microsoft-designer-web-image-handler-block.test.ts +++ b/tests/unit/microsoft-designer-web-image-handler-block.test.ts @@ -11,7 +11,7 @@ process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; const { handleImageGeneration } = await import("../../open-sse/handlers/imageGeneration.ts"); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("image handler blocks exact retired providers before any upstream fetch", async () => { diff --git a/tests/unit/microsoft-designer-web-model-routing.test.ts b/tests/unit/microsoft-designer-web-model-routing.test.ts index 5abaf9a7f7..56c4e1f1b8 100644 --- a/tests/unit/microsoft-designer-web-model-routing.test.ts +++ b/tests/unit/microsoft-designer-web-model-routing.test.ts @@ -21,7 +21,7 @@ const { createProviderNodeSchema, updateProviderNodeSchema } = async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -48,7 +48,7 @@ function assertRetiredError(error: unknown): boolean { test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("retired Designer IDs remain reserved after leaving the live provider registry", () => { diff --git a/tests/unit/microsoft-designer-web-runtime-block.test.ts b/tests/unit/microsoft-designer-web-runtime-block.test.ts index c71662e548..3c6480eebf 100644 --- a/tests/unit/microsoft-designer-web-runtime-block.test.ts +++ b/tests/unit/microsoft-designer-web-runtime-block.test.ts @@ -18,14 +18,14 @@ const API_KEY_ID = "designer-retirement-managed-key"; async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("creating a retired Microsoft Designer connection reports its persisted tombstone", async () => { diff --git a/tests/unit/migration-135-numbering-collision.test.ts b/tests/unit/migration-135-numbering-collision.test.ts index 1a6474f450..d8fd6b0e6f 100644 --- a/tests/unit/migration-135-numbering-collision.test.ts +++ b/tests/unit/migration-135-numbering-collision.test.ts @@ -34,7 +34,7 @@ before(async () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; }); diff --git a/tests/unit/migration-159-remove-mimocode-provider.test.ts b/tests/unit/migration-159-remove-mimocode-provider.test.ts index ce62675fde..970c70ef18 100644 --- a/tests/unit/migration-159-remove-mimocode-provider.test.ts +++ b/tests/unit/migration-159-remove-mimocode-provider.test.ts @@ -11,7 +11,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 159 removes stale MiMoCode provider state and is idempotent", () => { diff --git a/tests/unit/migration-165-retire-felo-web.test.ts b/tests/unit/migration-165-retire-felo-web.test.ts index 94fe43f928..ca0c6e6f6e 100644 --- a/tests/unit/migration-165-retire-felo-web.test.ts +++ b/tests/unit/migration-165-retire-felo-web.test.ts @@ -35,7 +35,7 @@ type LeaseState = { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 165 retires every Felo id fail-closed and preserves audit history", async () => { diff --git a/tests/unit/migration-166-retire-gpl-derived-providers.test.ts b/tests/unit/migration-166-retire-gpl-derived-providers.test.ts index 88d23ad7da..679d187e59 100644 --- a/tests/unit/migration-166-retire-gpl-derived-providers.test.ts +++ b/tests/unit/migration-166-retire-gpl-derived-providers.test.ts @@ -14,7 +14,7 @@ const RETIRED_PROVIDER_IDS = ["raycast", "rc", "hailuo-web"] as const; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 166 disables GPL-derived connections fail-closed and preserves audit history", async () => { diff --git a/tests/unit/migration-167-retire-qwen-web.test.ts b/tests/unit/migration-167-retire-qwen-web.test.ts index 4007f9de80..c8f3cd6fcc 100644 --- a/tests/unit/migration-167-retire-qwen-web.test.ts +++ b/tests/unit/migration-167-retire-qwen-web.test.ts @@ -67,7 +67,7 @@ type LeaseState = { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 167 retires every Qwen Web id fail-closed and preserves audit history", async () => { diff --git a/tests/unit/migration-168-retire-chatgpt-web.test.ts b/tests/unit/migration-168-retire-chatgpt-web.test.ts index cb61510363..cc229eb48c 100644 --- a/tests/unit/migration-168-retire-chatgpt-web.test.ts +++ b/tests/unit/migration-168-retire-chatgpt-web.test.ts @@ -35,7 +35,7 @@ type LeaseState = { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("migration 168 retires every common ChatGPT Web id fail-closed and preserves audit history", async () => { diff --git a/tests/unit/minimax-m3-maxtokens.test.ts b/tests/unit/minimax-m3-maxtokens.test.ts index 93a63d9b40..f0b5c68a17 100644 --- a/tests/unit/minimax-m3-maxtokens.test.ts +++ b/tests/unit/minimax-m3-maxtokens.test.ts @@ -31,17 +31,14 @@ const { getModelSpec } = await import("../../src/shared/constants/modelSpecs.ts" test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const DEFAULT_CAP = 8192; test("#3141 MiniMax-M3 max_tokens is not capped to the 8192 default", () => { const cap = modelCapabilities.capMaxOutputTokens({ provider: "minimax", model: "MiniMax-M3" }); - assert.ok( - cap > DEFAULT_CAP, - `expected MiniMax-M3 maxOutputTokens > ${DEFAULT_CAP}, got ${cap}` - ); + assert.ok(cap > DEFAULT_CAP, `expected MiniMax-M3 maxOutputTokens > ${DEFAULT_CAP}, got ${cap}`); }); test("#3141 MiniMaxAI/MiniMax-M3 (prefixed id) resolves above the 8192 default", () => { diff --git a/tests/unit/mitm-cert-install-mode-9442.test.ts b/tests/unit/mitm-cert-install-mode-9442.test.ts index 4128719c5c..dd415ce67f 100644 --- a/tests/unit/mitm-cert-install-mode-9442.test.ts +++ b/tests/unit/mitm-cert-install-mode-9442.test.ts @@ -80,7 +80,7 @@ test.after(() => { else process.env.OMNIROUTE_NO_SUDO = originalNoSudo; if (originalSkipSystemTrust === undefined) delete process.env.OMNIROUTE_SKIP_SYSTEM_TRUST; else process.env.OMNIROUTE_SKIP_SYSTEM_TRUST = originalSkipSystemTrust; - fs.rmSync(tmpRoot, { recursive: true, force: true }); + fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function resetCaptured(): void { diff --git a/tests/unit/mitm-cert-migration-6684.test.ts b/tests/unit/mitm-cert-migration-6684.test.ts index 111eef5369..415b86884a 100644 --- a/tests/unit/mitm-cert-migration-6684.test.ts +++ b/tests/unit/mitm-cert-migration-6684.test.ts @@ -26,7 +26,7 @@ test("decideCertMigration: existing legacy leaf, no CA pair, flag off → stay o touch(path.join(certDir, "server.key")); assert.equal(decideCertMigration(certDir, false), "use-legacy-leaf"); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -35,7 +35,7 @@ test("decideCertMigration: no legacy leaf and no CA pair (fresh install) → use try { assert.equal(decideCertMigration(certDir, false), "use-root-ca"); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -46,7 +46,7 @@ test("decideCertMigration: legacy leaf present but explicit opt-in flag on → u touch(path.join(certDir, "server.key")); assert.equal(decideCertMigration(certDir, true), "use-root-ca"); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -59,7 +59,7 @@ test("decideCertMigration: CA pair already persisted → use root CA even withou touch(path.join(certDir, "ca.key")); assert.equal(decideCertMigration(certDir, false), "use-root-ca"); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -69,6 +69,6 @@ test("decideCertMigration: partial legacy pair (only server.crt) is treated as n touch(path.join(certDir, "server.crt")); assert.equal(decideCertMigration(certDir, false), "use-root-ca"); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/mitm-hosts-cleanup-on-exit.test.ts b/tests/unit/mitm-hosts-cleanup-on-exit.test.ts index f39ac88574..988c9810b2 100644 --- a/tests/unit/mitm-hosts-cleanup-on-exit.test.ts +++ b/tests/unit/mitm-hosts-cleanup-on-exit.test.ts @@ -30,7 +30,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("handleExitCleanup: with a cached sudo password, best-effort reverts managed /etc/hosts entries", async () => { @@ -99,7 +99,11 @@ test("handleExitCleanup: with a cached sudo password, best-effort reverts manage test("handleExitCleanup: with NO cached password, falls back to orphaned-state flag and skips DNS removal", async () => { manager.clearCachedPassword(); - assert.equal(manager.getCachedPassword(), null, "precondition: no password cached in this session"); + assert.equal( + manager.getCachedPassword(), + null, + "precondition: no password cached in this session" + ); let removeDNSEntryCalled = false; let removeDNSEntriesCalled = false; diff --git a/tests/unit/mitm-manager-bypass-json.test.ts b/tests/unit/mitm-manager-bypass-json.test.ts index 47dca8a683..9be2e29736 100644 --- a/tests/unit/mitm-manager-bypass-json.test.ts +++ b/tests/unit/mitm-manager-bypass-json.test.ts @@ -13,9 +13,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-mitm-bypass-json-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mitm-bypass-json-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -27,7 +25,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -48,7 +46,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("writeBypassJson — creates mitm/ dir and writes JSON file", () => { @@ -74,20 +72,12 @@ test("writeBypassJson — pulls from DB when no patterns argument passed", () => manager.writeBypassJson(); const file = path.join(TEST_DATA_DIR, "mitm", "bypass.json"); const payload = JSON.parse(fs.readFileSync(file, "utf-8")); - assert.deepEqual( - payload.patterns.sort(), - ["*.from-db.example.com", "literal.com"].sort() - ); + assert.deepEqual(payload.patterns.sort(), ["*.from-db.example.com", "literal.com"].sort()); }); test("writeBypassJson — does NOT write default patterns (those live in server.cjs)", () => { // Seed defaults via the DB module — these should NOT appear in the JSON. - bypassDb.seedDefaultBypassPatterns([ - "*.bank.test", - "*.gov.test", - "okta.com", - "auth0.com", - ]); + bypassDb.seedDefaultBypassPatterns(["*.bank.test", "*.gov.test", "okta.com", "auth0.com"]); manager.writeBypassJson(); const file = path.join(TEST_DATA_DIR, "mitm", "bypass.json"); const payload = JSON.parse(fs.readFileSync(file, "utf-8")); diff --git a/tests/unit/mitm-manager-cleanup-symmetry.test.ts b/tests/unit/mitm-manager-cleanup-symmetry.test.ts index 1175da20c4..87423d3221 100644 --- a/tests/unit/mitm-manager-cleanup-symmetry.test.ts +++ b/tests/unit/mitm-manager-cleanup-symmetry.test.ts @@ -13,9 +13,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-mitm-cleanup-symmetry-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mitm-cleanup-symmetry-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -28,7 +26,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -49,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("collectManagedHosts includes every host of every agent target", () => { @@ -66,11 +64,7 @@ test("collectManagedHosts includes every host of every agent target", () => { test("collectManagedHosts returns a de-duplicated list", () => { const list = manager.collectManagedHosts(); - assert.equal( - list.length, - new Set(list).size, - "collectManagedHosts must not return duplicates" - ); + assert.equal(list.length, new Set(list).size, "collectManagedHosts must not return duplicates"); }); test("collectManagedHosts includes custom hosts persisted in the DB", () => { diff --git a/tests/unit/mitm-manager-repair.test.ts b/tests/unit/mitm-manager-repair.test.ts index 4a72a7f1f4..a4cd075b6c 100644 --- a/tests/unit/mitm-manager-repair.test.ts +++ b/tests/unit/mitm-manager-repair.test.ts @@ -14,9 +14,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-mitm-repair-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mitm-repair-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -27,7 +25,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -48,16 +46,13 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("buildRepairPlan enumerates DNS hosts and the CA + proxy teardown steps", () => { const plan = manager.buildRepairPlan(); assert.ok(Array.isArray(plan.dnsHostsToRemove), "plan.dnsHostsToRemove must be an array"); - assert.ok( - plan.dnsHostsToRemove.length > 0, - "must remove at least the agent target hosts" - ); + assert.ok(plan.dnsHostsToRemove.length > 0, "must remove at least the agent target hosts"); assert.equal(plan.removeCert, true, "repair must include CA removal"); assert.equal(plan.revertSystemProxy, true, "repair must attempt system-proxy revert"); }); diff --git a/tests/unit/mitm-privileged-steps-sudo-gate.test.ts b/tests/unit/mitm-privileged-steps-sudo-gate.test.ts index 30701c7ad3..7c1f5c07bb 100644 --- a/tests/unit/mitm-privileged-steps-sudo-gate.test.ts +++ b/tests/unit/mitm-privileged-steps-sudo-gate.test.ts @@ -7,10 +7,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { EventEmitter } from "node:events"; -import { - canRunPrivilegedMitmSteps, - isMitmSudoPasswordRequired, -} from "../../src/mitm/sudoGate.ts"; +import { canRunPrivilegedMitmSteps, isMitmSudoPasswordRequired } from "../../src/mitm/sudoGate.ts"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mitm-sudo-gate-")); process.env.DATA_DIR = TEST_DATA_DIR; @@ -20,7 +17,7 @@ const manager = await import("../../src/mitm/manager.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("canRunPrivilegedMitmSteps is false when isMitmSudoPasswordRequired is true", () => { @@ -53,7 +50,10 @@ test("stopMitm skips DNS teardown without sudo password but still kills server ( return true; }; - manager.__setServerProcessForTest(fakeProc as unknown as import("child_process").ChildProcess, 4242); + manager.__setServerProcessForTest( + fakeProc as unknown as import("child_process").ChildProcess, + 4242 + ); await manager.stopMitm("", { removeDNSEntry: async () => { @@ -70,5 +70,8 @@ test("stopMitm skips DNS teardown without sudo password but still kills server ( 0, "must not invoke DNS teardown with empty sudo password" ); - assert.ok(events.some((event) => event.startsWith("kill:")), "server process must still be stopped"); + assert.ok( + events.some((event) => event.startsWith("kill:")), + "server process must still be stopped" + ); }); diff --git a/tests/unit/mitm-root-ca-persistence-6684.test.ts b/tests/unit/mitm-root-ca-persistence-6684.test.ts index 63d08a91c3..470ac1dd74 100644 --- a/tests/unit/mitm-root-ca-persistence-6684.test.ts +++ b/tests/unit/mitm-root-ca-persistence-6684.test.ts @@ -25,7 +25,7 @@ test("loadOrCreateMitmCa: first call with an empty dir generates and persists a assert.equal(fs.existsSync(path.join(certDir, "ca.key")), true); assert.equal(fs.existsSync(path.join(certDir, "ca.crt")), true); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -37,20 +37,24 @@ test("loadOrCreateMitmCa: a second call loads the same CA instead of regeneratin assert.equal(second.key, first.key); assert.equal(second.cert, first.cert); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); -test("loadOrCreateMitmCa: the written CA private key file mode is 0o600", { skip: process.platform === "win32" }, async () => { - const certDir = tmpCertDir(); - try { - const ca = await loadOrCreateMitmCa(certDir); - const mode = fs.statSync(ca.keyPath).mode & 0o777; - assert.equal(mode, 0o600); - } finally { - fs.rmSync(certDir, { recursive: true, force: true }); +test( + "loadOrCreateMitmCa: the written CA private key file mode is 0o600", + { skip: process.platform === "win32" }, + async () => { + const certDir = tmpCertDir(); + try { + const ca = await loadOrCreateMitmCa(certDir); + const mode = fs.statSync(ca.keyPath).mode & 0o777; + assert.equal(mode, 0o600); + } finally { + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } } -}); +); test("loadOrCreateMitmCa: the CA cert carries CA basicConstraints (matches generateMitmCa)", async () => { const certDir = tmpCertDir(); @@ -60,6 +64,6 @@ test("loadOrCreateMitmCa: the CA cert carries CA basicConstraints (matches gener const cert = new X509Certificate(ca.cert); assert.equal(cert.ca, true); } finally { - fs.rmSync(certDir, { recursive: true, force: true }); + fs.rmSync(certDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/mitm-start-guard.test.ts b/tests/unit/mitm-start-guard.test.ts index 91eb572336..b298ac51f1 100644 --- a/tests/unit/mitm-start-guard.test.ts +++ b/tests/unit/mitm-start-guard.test.ts @@ -44,7 +44,7 @@ const manager = await import("../../src/mitm/manager.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Belt-and-braces: never leave the module-level lock held across tests. diff --git a/tests/unit/mitm-stop-dns-before-kill-1809.test.ts b/tests/unit/mitm-stop-dns-before-kill-1809.test.ts index 3dd92dcaad..66de0779fb 100644 --- a/tests/unit/mitm-stop-dns-before-kill-1809.test.ts +++ b/tests/unit/mitm-stop-dns-before-kill-1809.test.ts @@ -32,7 +32,7 @@ const manager = await import("../../src/mitm/manager.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("stopMitm removes DNS entries before killing the MITM server process (#1809)", async () => { @@ -50,7 +50,10 @@ test("stopMitm removes DNS entries before killing the MITM server process (#1809 return true; }; - manager.__setServerProcessForTest(fakeProc as unknown as import("child_process").ChildProcess, 4242); + manager.__setServerProcessForTest( + fakeProc as unknown as import("child_process").ChildProcess, + 4242 + ); const removeDNSEntry = async () => { events.push("removeDNSEntry"); @@ -67,9 +70,7 @@ test("stopMitm removes DNS entries before killing the MITM server process (#1809 }); const firstKillIndex = events.findIndex((e) => e.startsWith("kill:")); - const firstDnsIndex = events.findIndex( - (e) => e === "removeDNSEntry" || e === "removeDNSEntries" - ); + const firstDnsIndex = events.findIndex((e) => e === "removeDNSEntry" || e === "removeDNSEntries"); assert.ok(firstKillIndex !== -1, "server process kill was never invoked"); assert.ok(firstDnsIndex !== -1, "DNS removal was never invoked"); diff --git a/tests/unit/mitm-upstream-ca-wiring.test.ts b/tests/unit/mitm-upstream-ca-wiring.test.ts index a98c3688a6..3a5fadeec6 100644 --- a/tests/unit/mitm-upstream-ca-wiring.test.ts +++ b/tests/unit/mitm-upstream-ca-wiring.test.ts @@ -25,9 +25,7 @@ import os from "node:os"; import path from "node:path"; // ── test isolation: dedicated DATA_DIR ──────────────────────────────────────── -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-mitm-upstream-ca-wiring-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mitm-upstream-ca-wiring-")); process.env.DATA_DIR = TEST_DATA_DIR; // Ensure the mitm subdir exists for CA path file writes. @@ -55,7 +53,11 @@ function readStoredCaPath(): string | null { } function clearStoredCaPath(): void { - try { fs.unlinkSync(CA_PATH_FILE); } catch { /* ignore */ } + try { + fs.unlinkSync(CA_PATH_FILE); + } catch { + /* ignore */ + } } // ── path-selection logic tests ──────────────────────────────────────────────── @@ -113,11 +115,15 @@ test("startMitm CA wiring — configureUpstreamCa called with bad path does not // The function throws — startMitm wraps this in try/catch, so boot continues. assert.ok(threw, "configureUpstreamCa should throw for non-existent path"); assert.ok(!caughtMsg.includes("\n at "), "error message must not include stack trace lines"); - assert.ok(caughtMsg.includes("AGENTBRIDGE_UPSTREAM_CA_CERT"), "error message should include env var label"); + assert.ok( + caughtMsg.includes("AGENTBRIDGE_UPSTREAM_CA_CERT"), + "error message should include env var label" + ); }); test("startMitm CA wiring — configureUpstreamCa no-op for undefined path", async () => { - const { configureUpstreamCa: configureUpstreamCaNoop } = await import("../../src/mitm/upstreamTrust.ts"); + const { configureUpstreamCa: configureUpstreamCaNoop } = + await import("../../src/mitm/upstreamTrust.ts"); // undefined / empty should never load undici — safe to call in tests. assert.doesNotThrow(() => configureUpstreamCaNoop(undefined)); assert.doesNotThrow(() => configureUpstreamCaNoop("")); @@ -126,9 +132,7 @@ test("startMitm CA wiring — configureUpstreamCa no-op for undefined path", asy // ── POST route wiring tests ─────────────────────────────────────────────────── test("POST upstream-ca route — returns 400 when file does not exist", async () => { - const { POST } = await import( - "../../src/app/api/tools/agent-bridge/upstream-ca/route.ts" - ); + const { POST } = await import("../../src/app/api/tools/agent-bridge/upstream-ca/route.ts"); const badPath = "/definitely/does/not/exist/ca.pem"; const req = new Request("http://localhost/api/tools/agent-bridge/upstream-ca", { @@ -159,9 +163,7 @@ test("POST upstream-ca route — persists path to upstream-ca.path file on valid // was attempted, by checking the CA_PATH_FILE exists after the response. clearStoredCaPath(); - const { POST } = await import( - "../../src/app/api/tools/agent-bridge/upstream-ca/route.ts" - ); + const { POST } = await import("../../src/app/api/tools/agent-bridge/upstream-ca/route.ts"); const req = new Request("http://localhost/api/tools/agent-bridge/upstream-ca", { method: "POST", @@ -172,19 +174,17 @@ test("POST upstream-ca route — persists path to upstream-ca.path file on valid const res = await POST(req); // Either 200 (undici loaded ok) or 400 (undici fails in this test env). - assert.ok( - res.status === 200 || res.status === 400, - `expected 200 or 400 but got ${res.status}` - ); + assert.ok(res.status === 200 || res.status === 400, `expected 200 or 400 but got ${res.status}`); // The file should have been written (persistence step happened). - assert.ok(fs.existsSync(CA_PATH_FILE), "upstream-ca.path should be written before configureUpstreamCa"); + assert.ok( + fs.existsSync(CA_PATH_FILE), + "upstream-ca.path should be written before configureUpstreamCa" + ); assert.equal(fs.readFileSync(CA_PATH_FILE, "utf8").trim(), REAL_PEM); }); test("POST upstream-ca route — error response does not leak stack trace when configureUpstreamCa throws", async () => { - const { POST } = await import( - "../../src/app/api/tools/agent-bridge/upstream-ca/route.ts" - ); + const { POST } = await import("../../src/app/api/tools/agent-bridge/upstream-ca/route.ts"); const badPath = "/nonexistent/for/configureUpstreamCa/ca.pem"; const req = new Request("http://localhost/api/tools/agent-bridge/upstream-ca", { @@ -205,7 +205,7 @@ test("POST upstream-ca route — error response does not leak stack trace when c test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } diff --git a/tests/unit/modality-bridge-video-runtime-route.test.ts b/tests/unit/modality-bridge-video-runtime-route.test.ts index b210aa7ed5..9077086517 100644 --- a/tests/unit/modality-bridge-video-runtime-route.test.ts +++ b/tests/unit/modality-bridge-video-runtime-route.test.ts @@ -25,7 +25,7 @@ async function withLocality(request: Request, locality: "loopback" | "lan"): Pro test.beforeEach(async () => { core.resetDbInstance(); - fs.rmSync(dataDirectory, { force: true, recursive: true }); + fs.rmSync(dataDirectory, { force: true, recursive: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(dataDirectory, { recursive: true }); process.env.INITIAL_PASSWORD = "video-runtime-test-password"; await settings.updateSettings({ requireLogin: true, password: "" }); @@ -33,7 +33,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(dataDirectory, { force: true, recursive: true }); + fs.rmSync(dataDirectory, { force: true, recursive: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDirectory === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDirectory; if (originalInitialPassword === undefined) delete process.env.INITIAL_PASSWORD; diff --git a/tests/unit/model-alias-route.test.ts b/tests/unit/model-alias-route.test.ts index 5517defc44..6bf42b4db3 100644 --- a/tests/unit/model-alias-route.test.ts +++ b/tests/unit/model-alias-route.test.ts @@ -20,7 +20,7 @@ const v1Catalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -30,7 +30,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("model alias route resolves a stored alias and emits diagnostics headers", async () => { diff --git a/tests/unit/model-alias-seed-fallback.test.ts b/tests/unit/model-alias-seed-fallback.test.ts index 25f9513fb9..7838049f7a 100644 --- a/tests/unit/model-alias-seed-fallback.test.ts +++ b/tests/unit/model-alias-seed-fallback.test.ts @@ -22,7 +22,7 @@ async function withEmptyAliasDb(fn: () => Promise) { resetDbInstance?.(); await fn(); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); const { resetDbInstance } = await import("../../src/lib/db/core"); resetDbInstance?.(); if (prevDataDir === undefined) delete process.env.DATA_DIR; diff --git a/tests/unit/model-alias-seed.test.ts b/tests/unit/model-alias-seed.test.ts index 3a56098def..e7b77f4f0d 100644 --- a/tests/unit/model-alias-seed.test.ts +++ b/tests/unit/model-alias-seed.test.ts @@ -15,7 +15,7 @@ const { DEFAULT_MODEL_ALIAS_SEED, seedDefaultModelAliases } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -25,7 +25,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("default model alias seed writes missing aliases and is idempotent", async () => { diff --git a/tests/unit/model-aliases-settings-route-selfheal.test.ts b/tests/unit/model-aliases-settings-route-selfheal.test.ts index 30167fdce0..2655a43ecd 100644 --- a/tests/unit/model-aliases-settings-route-selfheal.test.ts +++ b/tests/unit/model-aliases-settings-route-selfheal.test.ts @@ -29,7 +29,7 @@ const route = await import("../../src/app/api/settings/model-aliases/route.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/settings/model-aliases hydrates custom aliases from DB when in-memory state is empty", async () => { diff --git a/tests/unit/model-capabilities-kimi-k3-vision-8250.test.ts b/tests/unit/model-capabilities-kimi-k3-vision-8250.test.ts index 4e4175c476..95bff213ef 100644 --- a/tests/unit/model-capabilities-kimi-k3-vision-8250.test.ts +++ b/tests/unit/model-capabilities-kimi-k3-vision-8250.test.ts @@ -53,7 +53,7 @@ function buildCapability(overrides = {}) { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -113,7 +113,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8250 kimi-coding-apikey/k3: attachment=false + image modalities → vision=true and fields agree", () => { diff --git a/tests/unit/model-capabilities-mistral-vision-sync-4073.test.ts b/tests/unit/model-capabilities-mistral-vision-sync-4073.test.ts index 2cdc3092aa..cf4e3130dd 100644 --- a/tests/unit/model-capabilities-mistral-vision-sync-4073.test.ts +++ b/tests/unit/model-capabilities-mistral-vision-sync-4073.test.ts @@ -57,7 +57,7 @@ function buildCapability(overrides = {}) { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -98,7 +98,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4073 mistral/pixtral-12b-latest resolves vision via the synced `-latest` alias (not the heuristic)", () => { @@ -106,7 +106,11 @@ test("#4073 mistral/pixtral-12b-latest resolves vision via the synced `-latest` const latest = modelCapabilities.getResolvedModelCapabilities("mistral/pixtral-12b-latest"); // attachment === true can ONLY come from the synced row keyed `pixtral-12b`. - assert.equal(latest.attachment, true, "synced attachment must resolve via the stripped `-latest` alias"); + assert.equal( + latest.attachment, + true, + "synced attachment must resolve via the stripped `-latest` alias" + ); assert.equal(latest.supportsVision, true); }); @@ -142,7 +146,9 @@ test("#4073 the `-latest` strip never fabricates a match for an unknown id", () // No synced row for `unknown-text-model` (stripped) nor its `-latest` form, and // the heuristic doesn't recognise it → attachment null, vision null. The strip // must not invent a capability out of nothing. - const unknown = modelCapabilities.getResolvedModelCapabilities("mistral/unknown-text-model-latest"); + const unknown = modelCapabilities.getResolvedModelCapabilities( + "mistral/unknown-text-model-latest" + ); assert.equal(unknown.attachment, null); assert.equal(unknown.supportsVision, null); }); diff --git a/tests/unit/model-capabilities-path-shaped-vision-8032.test.ts b/tests/unit/model-capabilities-path-shaped-vision-8032.test.ts index ae53ebef86..730e03c3f4 100644 --- a/tests/unit/model-capabilities-path-shaped-vision-8032.test.ts +++ b/tests/unit/model-capabilities-path-shaped-vision-8032.test.ts @@ -43,7 +43,7 @@ function buildCapability(overrides: Record = {}) { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -53,7 +53,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8032 cp/cline-pass/kimi-k3: attachment=false empty modalities → vision via leaf/registry", () => { @@ -83,9 +83,7 @@ test("#8032 leaf fallback is vision-only: aihorde/deepseek/deepseek-v4-flash kee // Regression guard from PR review (#8495 / #8212): shared getStaticSpec leaf // lookup previously promoted this live-discovered AI Horde id to the real // DeepSeek V4 Flash supportsTools:true spec. Leaf lookup must stay vision-only. - const caps = modelCapabilities.getResolvedModelCapabilities( - "aihorde/deepseek/deepseek-v4-flash" - ); + const caps = modelCapabilities.getResolvedModelCapabilities("aihorde/deepseek/deepseek-v4-flash"); assert.equal(caps.toolCalling, false); assert.equal(caps.supportsTools, false); assert.equal( diff --git a/tests/unit/model-capabilities-registry.test.ts b/tests/unit/model-capabilities-registry.test.ts index 29054c2f60..7bb82681db 100644 --- a/tests/unit/model-capabilities-registry.test.ts +++ b/tests/unit/model-capabilities-registry.test.ts @@ -37,7 +37,7 @@ function buildCapability(overrides = {}) { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -47,7 +47,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("canonical model capability resolver lets exact synced metadata override global specs", () => { diff --git a/tests/unit/model-capability-overrides.test.ts b/tests/unit/model-capability-overrides.test.ts index 5053ed7520..d81a5594ed 100644 --- a/tests/unit/model-capability-overrides.test.ts +++ b/tests/unit/model-capability-overrides.test.ts @@ -15,14 +15,14 @@ const route = await import("../../src/app/api/model-capability-overrides/route.t beforeEach(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(moduleDataDir, { recursive: true }); coreDb.getDbInstance(); }); after(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function patchOverride(key: string, value: unknown) { @@ -195,10 +195,7 @@ describe("model capability overrides", () => { it("stores exact reasoning_efforts through the API and preserves native max/ultra", async () => { const before = caps.getResolvedModelCapabilities("codex/gpt-5.6"); - const accepted = await patchOverride( - "reasoning_efforts", - "​ low\r\n, medium, max‍, ultra⁠" - ); + const accepted = await patchOverride("reasoning_efforts", "​ low\r\n, medium, max‍, ultra⁠"); assert.equal(accepted.status, 200); const payload = (await accepted.json()) as { diff --git a/tests/unit/model-capability-resolution-snapshot-9199.test.ts b/tests/unit/model-capability-resolution-snapshot-9199.test.ts index 2e63420b4f..90088a5d97 100644 --- a/tests/unit/model-capability-resolution-snapshot-9199.test.ts +++ b/tests/unit/model-capability-resolution-snapshot-9199.test.ts @@ -38,7 +38,7 @@ test.after(() => { } for (const [key, value] of originalContextLengthEnv) process.env[key] = value; try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } @@ -46,7 +46,7 @@ test.after(() => { function seedFixture() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); @@ -134,7 +134,11 @@ function seedFixture() { assert.equal(aliasCanonical.model, "claude-opus-4-5-20251101"); assert.notEqual(aliasCanonical.model, "claude-4.5-opus"); assert.equal( - capabilityOverrides.setModelCapabilityOverride("github/claude-4.5-opus", "max_output_tokens", 77777), + capabilityOverrides.setModelCapabilityOverride( + "github/claude-4.5-opus", + "max_output_tokens", + 77777 + ), true ); assert.equal( @@ -223,7 +227,7 @@ function assertOrdinarySnapshotParity( test("#9199 bulk capability rows treat prototype-shaped keys as data", () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); diff --git a/tests/unit/model-catalog-cache-swr-8728.test.ts b/tests/unit/model-catalog-cache-swr-8728.test.ts index 5e5265b804..464986347f 100644 --- a/tests/unit/model-catalog-cache-swr-8728.test.ts +++ b/tests/unit/model-catalog-cache-swr-8728.test.ts @@ -53,7 +53,7 @@ test.beforeEach(() => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("the SWR window is a bounded constant, not an unbounded accessor", () => { diff --git a/tests/unit/model-catalog-policy-invalidation-8728.test.ts b/tests/unit/model-catalog-policy-invalidation-8728.test.ts index e23b672e97..144f350e2e 100644 --- a/tests/unit/model-catalog-policy-invalidation-8728.test.ts +++ b/tests/unit/model-catalog-policy-invalidation-8728.test.ts @@ -5,7 +5,7 @@ import path from "node:path"; import test from "node:test"; const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-model-catalog-policy-8728-"), + path.join(os.tmpdir(), "omniroute-model-catalog-policy-8728-") ); process.env.DATA_DIR = TEST_DATA_DIR; process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; @@ -26,7 +26,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeys.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("updateApiKeyPermissions increments only on catalog-affecting fields", async () => { @@ -108,7 +108,7 @@ test("isModelAllowedForKey cache recomputes after custom model visibility change "Catalog cache repro", "manual", "chat-completions", - ["chat"], + ["chat"] ); assert.equal(await apiKeys.isModelAllowedForKey(key.key, modelId), true); diff --git a/tests/unit/model-catalog-runtime-invalidation.test.ts b/tests/unit/model-catalog-runtime-invalidation.test.ts index c37b9831c4..4c3abe2099 100644 --- a/tests/unit/model-catalog-runtime-invalidation.test.ts +++ b/tests/unit/model-catalog-runtime-invalidation.test.ts @@ -25,7 +25,7 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -77,7 +77,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("session-affinity bookkeeping preserves the published model catalog", async () => { diff --git a/tests/unit/model-catalog-source-invalidation-8728.test.ts b/tests/unit/model-catalog-source-invalidation-8728.test.ts index 50dfa86eff..17f73ba27d 100644 --- a/tests/unit/model-catalog-source-invalidation-8728.test.ts +++ b/tests/unit/model-catalog-source-invalidation-8728.test.ts @@ -5,7 +5,7 @@ import path from "node:path"; import test from "node:test"; const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-model-catalog-sources-8728-"), + path.join(os.tmpdir(), "omniroute-model-catalog-sources-8728-") ); process.env.DATA_DIR = TEST_DATA_DIR; process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; @@ -22,7 +22,7 @@ const openRouterCatalog = await import("../../src/lib/catalog/openrouterCatalog. function resetStorage() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -57,7 +57,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); restoreRealFetch(); }); @@ -195,7 +195,7 @@ test("refreshOpenRouterCatalog invalidates only on success", async () => { assert.equal( catalogVersion(), beforeGet, - "ordinary get should not invalidate the model-catalog cache", + "ordinary get should not invalidate the model-catalog cache" ); const beforeRefreshSuccess = catalogVersion(); diff --git a/tests/unit/model-combo-mappings-db.test.ts b/tests/unit/model-combo-mappings-db.test.ts index 9470884eb4..2ce0b1bb90 100644 --- a/tests/unit/model-combo-mappings-db.test.ts +++ b/tests/unit/model-combo-mappings-db.test.ts @@ -13,7 +13,7 @@ const mappingsDb = await import("../../src/lib/db/modelComboMappings.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -23,7 +23,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createCombo(name, model, overrides = {}) { diff --git a/tests/unit/model-connid-prefix-normalization-6772.test.ts b/tests/unit/model-connid-prefix-normalization-6772.test.ts index c7b6fca7b4..88088e9519 100644 --- a/tests/unit/model-connid-prefix-normalization-6772.test.ts +++ b/tests/unit/model-connid-prefix-normalization-6772.test.ts @@ -50,7 +50,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6772 baseline: bare alias form `custpfx6772/vova/gpt-5.5` resolves to the raw model id", async () => { diff --git a/tests/unit/model-context-override-readpath.test.ts b/tests/unit/model-context-override-readpath.test.ts index 9cd6a6ea3e..b22e279006 100644 --- a/tests/unit/model-context-override-readpath.test.ts +++ b/tests/unit/model-context-override-readpath.test.ts @@ -15,14 +15,14 @@ const caps = await import("../../src/lib/modelCapabilities.ts"); beforeEach(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(moduleDataDir, { recursive: true }); coreDb.getDbInstance(); }); after(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("getModelContextLimit override precedence (5004)", () => { diff --git a/tests/unit/model-cooldowns-route-auth.test.ts b/tests/unit/model-cooldowns-route-auth.test.ts index 77ebf02ea4..c648c03465 100644 --- a/tests/unit/model-cooldowns-route-auth.test.ts +++ b/tests/unit/model-cooldowns-route-auth.test.ts @@ -23,7 +23,7 @@ const { clearModelLock, lockModel } = accountFallback; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { clearModelLock("cooldown-auth-provider", "cooldown-auth-conn", "cooldown-auth-model"); await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/model-intelligence-db.test.ts b/tests/unit/model-intelligence-db.test.ts index ba15f9f805..71fc90cee3 100644 --- a/tests/unit/model-intelligence-db.test.ts +++ b/tests/unit/model-intelligence-db.test.ts @@ -11,9 +11,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-mi-test-"), -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mi-test-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -23,9 +21,11 @@ function resetStorage(): void { core.resetDbInstance(); try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } - } catch { /* EBUSY — ignore */ } + } catch { + /* EBUSY — ignore */ + } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -38,13 +38,13 @@ function insertEntry( eloRaw?: number | null; confidence?: string | null; expiresAt?: string | null; - } = {}, + } = {} ): void { const db = core.getDbInstance(); db.prepare( `INSERT OR REPLACE INTO model_intelligence (model, source, category, score, elo_raw, confidence, synced_at, expires_at) - VALUES (?, ?, ?, ?, ?, ?, datetime('now'), ?)`, + VALUES (?, ?, ?, ?, ?, ?, datetime('now'), ?)` ).run( model, source, @@ -52,14 +52,16 @@ function insertEntry( score, opts.eloRaw ?? null, opts.confidence ?? null, - opts.expiresAt ?? null, + opts.expiresAt ?? null ); } // ─── Tests ─────────────────────────────────────────────── describe("upsertModelIntelligence", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("inserts a new entry", () => { mi.upsertModelIntelligence({ @@ -90,7 +92,7 @@ describe("upsertModelIntelligence", () => { model: "gpt-4o", source: "arena_elo", category: "coding", - score: 0.90, + score: 0.9, eloRaw: 1400, confidence: "high", expiresAt: null, @@ -98,13 +100,15 @@ describe("upsertModelIntelligence", () => { const entry = mi.getModelIntelligenceBySource("gpt-4o", "arena_elo", "coding"); assert.ok(entry); - assert.strictEqual(entry.score, 0.90); + assert.strictEqual(entry.score, 0.9); assert.strictEqual(entry.eloRaw, 1400); }); }); describe("getModelIntelligence", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("returns user_override when all three sources exist (highest priority)", () => { insertEntry("claude-sonnet", "models_dev_tier", "coding", 0.75); @@ -119,7 +123,7 @@ describe("getModelIntelligence", () => { it("returns arena_elo when no user_override exists", () => { insertEntry("gpt-4o", "arena_elo", "coding", 0.87); - insertEntry("gpt-4o", "models_dev_tier", "coding", 0.70); + insertEntry("gpt-4o", "models_dev_tier", "coding", 0.7); const entry = mi.getModelIntelligence("gpt-4o", "coding"); assert.ok(entry); @@ -145,7 +149,7 @@ describe("getModelIntelligence", () => { insertEntry("gemini-pro", "arena_elo", "coding", 0.82, { expiresAt: "2000-01-01T00:00:00Z", }); - insertEntry("gemini-pro", "models_dev_tier", "coding", 0.70); + insertEntry("gemini-pro", "models_dev_tier", "coding", 0.7); const entry = mi.getModelIntelligence("gemini-pro", "coding"); assert.ok(entry); @@ -153,7 +157,7 @@ describe("getModelIntelligence", () => { }); it("returns null when all entries for a model+category are expired", () => { - insertEntry("expired-model", "arena_elo", "coding", 0.80, { + insertEntry("expired-model", "arena_elo", "coding", 0.8, { expiresAt: "2000-01-01T00:00:00Z", }); @@ -162,7 +166,7 @@ describe("getModelIntelligence", () => { }); it("model names require exact match (case-sensitive in DB)", () => { - insertEntry("Claude-Sonnet", "arena_elo", "coding", 0.90); + insertEntry("Claude-Sonnet", "arena_elo", "coding", 0.9); const exact = mi.getModelIntelligence("Claude-Sonnet", "coding"); assert.ok(exact); @@ -173,7 +177,9 @@ describe("getModelIntelligence", () => { }); describe("getModelIntelligenceBySource", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("returns a specific source entry", () => { insertEntry("claude-sonnet", "arena_elo", "coding", 0.88); @@ -199,7 +205,9 @@ describe("getModelIntelligenceBySource", () => { }); describe("deleteModelIntelligence", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("deletes an entry and returns true", () => { insertEntry("gpt-4o", "arena_elo", "coding", 0.87); @@ -218,7 +226,9 @@ describe("deleteModelIntelligence", () => { }); describe("deleteExpiredIntelligence", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("deletes only expired entries leaving valid ones", () => { insertEntry("old-model", "arena_elo", "coding", 0.7, { @@ -263,7 +273,9 @@ describe("deleteExpiredIntelligence", () => { }); describe("listModelIntelligence", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("lists all entries when no filters provided", () => { insertEntry("model-a", "arena_elo", "coding", 0.8); @@ -312,13 +324,39 @@ describe("listModelIntelligence", () => { }); describe("bulkUpsertModelIntelligence", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("bulk inserts multiple entries", () => { const count = mi.bulkUpsertModelIntelligence([ - { model: "model-a", source: "arena_elo", category: "coding", score: 0.80, eloRaw: 1300, confidence: "high", expiresAt: "2099-12-31T23:59:59Z" }, - { model: "model-b", source: "arena_elo", category: "coding", score: 0.70, eloRaw: 1200, confidence: "medium", expiresAt: "2099-12-31T23:59:59Z" }, - { model: "model-c", source: "arena_elo", category: "review", score: 0.85, eloRaw: 1350, confidence: "high", expiresAt: "2099-12-31T23:59:59Z" }, + { + model: "model-a", + source: "arena_elo", + category: "coding", + score: 0.8, + eloRaw: 1300, + confidence: "high", + expiresAt: "2099-12-31T23:59:59Z", + }, + { + model: "model-b", + source: "arena_elo", + category: "coding", + score: 0.7, + eloRaw: 1200, + confidence: "medium", + expiresAt: "2099-12-31T23:59:59Z", + }, + { + model: "model-c", + source: "arena_elo", + category: "review", + score: 0.85, + eloRaw: 1350, + confidence: "high", + expiresAt: "2099-12-31T23:59:59Z", + }, ]); assert.strictEqual(count, 3); @@ -332,21 +370,31 @@ describe("bulkUpsertModelIntelligence", () => { }); it("replaces existing entries on conflict (INSERT OR REPLACE)", () => { - insertEntry("model-a", "arena_elo", "coding", 0.70); + insertEntry("model-a", "arena_elo", "coding", 0.7); mi.bulkUpsertModelIntelligence([ - { model: "model-a", source: "arena_elo", category: "coding", score: 0.90, eloRaw: 1450, confidence: "high", expiresAt: null }, + { + model: "model-a", + source: "arena_elo", + category: "coding", + score: 0.9, + eloRaw: 1450, + confidence: "high", + expiresAt: null, + }, ]); const entry = mi.getModelIntelligenceBySource("model-a", "arena_elo", "coding"); assert.ok(entry); - assert.strictEqual(entry.score, 0.90); + assert.strictEqual(entry.score, 0.9); assert.strictEqual(entry.eloRaw, 1450); }); }); describe("getResolvedTaskFitness", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("returns user_override score when all sources exist", () => { insertEntry("claude-sonnet", "models_dev_tier", "coding", 0.75); @@ -359,7 +407,7 @@ describe("getResolvedTaskFitness", () => { it("returns arena_elo score when no user_override exists", () => { insertEntry("gpt-4o", "arena_elo", "coding", 0.87); - insertEntry("gpt-4o", "models_dev_tier", "coding", 0.70); + insertEntry("gpt-4o", "models_dev_tier", "coding", 0.7); const score = mi.getResolvedTaskFitness("gpt-4o", "coding"); assert.strictEqual(score, 0.87); @@ -381,15 +429,17 @@ describe("getResolvedTaskFitness", () => { insertEntry("gemini-pro", "arena_elo", "coding", 0.82, { expiresAt: "2000-01-01T00:00:00Z", }); - insertEntry("gemini-pro", "models_dev_tier", "coding", 0.70); + insertEntry("gemini-pro", "models_dev_tier", "coding", 0.7); const score = mi.getResolvedTaskFitness("gemini-pro", "coding"); - assert.strictEqual(score, 0.70); + assert.strictEqual(score, 0.7); }); }); describe("edge cases", () => { - beforeEach(() => { resetStorage(); }); + beforeEach(() => { + resetStorage(); + }); it("score values are stored and retrieved with float precision", () => { mi.upsertModelIntelligence({ diff --git a/tests/unit/model-latency-stats-route.test.ts b/tests/unit/model-latency-stats-route.test.ts index 15cbc0650a..6d444ca7ac 100644 --- a/tests/unit/model-latency-stats-route.test.ts +++ b/tests/unit/model-latency-stats-route.test.ts @@ -20,7 +20,7 @@ const route = await import("../../src/app/api/usage/model-latency-stats/route.ts async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/model-lifecycle-integration.test.ts b/tests/unit/model-lifecycle-integration.test.ts index dd2426d3b1..d62923d90e 100644 --- a/tests/unit/model-lifecycle-integration.test.ts +++ b/tests/unit/model-lifecycle-integration.test.ts @@ -22,7 +22,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -47,7 +47,7 @@ test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("chatCore rejects a shutdown OpenAI model before an upstream request", async () => { diff --git a/tests/unit/model-lockout-max-cooldown.test.ts b/tests/unit/model-lockout-max-cooldown.test.ts index a5912985f6..064bfa7034 100644 --- a/tests/unit/model-lockout-max-cooldown.test.ts +++ b/tests/unit/model-lockout-max-cooldown.test.ts @@ -48,7 +48,7 @@ async function seedConnection(provider: string, overrides: any = {}): Promise { clearAllModelLockouts(); try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); diff --git a/tests/unit/model-metadata-registry.test.ts b/tests/unit/model-metadata-registry.test.ts index a85673b625..707202f8dd 100644 --- a/tests/unit/model-metadata-registry.test.ts +++ b/tests/unit/model-metadata-registry.test.ts @@ -14,7 +14,7 @@ const registry = await import("../../src/lib/modelMetadataRegistry.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -24,7 +24,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("canonical model metadata merges static and synced capabilities into one record", async () => { diff --git a/tests/unit/model-output-cap-synced-fallthrough-6714.test.ts b/tests/unit/model-output-cap-synced-fallthrough-6714.test.ts index 378a9914c5..8a4d600409 100644 --- a/tests/unit/model-output-cap-synced-fallthrough-6714.test.ts +++ b/tests/unit/model-output-cap-synced-fallthrough-6714.test.ts @@ -78,7 +78,7 @@ function buildCapability(overrides: Record = {}) { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // The synced-capabilities module keeps an in-memory cache across DB resets // (`cachedCapabilitiesLoadedAll`) — clear it too so each test starts from a @@ -92,7 +92,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6714 synced row present but limit_output missing falls through to the registry output cap", () => { diff --git a/tests/unit/model-overrides-provider-prefix-9557.test.ts b/tests/unit/model-overrides-provider-prefix-9557.test.ts index a78bb6b7ad..e6f2b506ff 100644 --- a/tests/unit/model-overrides-provider-prefix-9557.test.ts +++ b/tests/unit/model-overrides-provider-prefix-9557.test.ts @@ -22,14 +22,14 @@ const sseModel = await import("../../src/sse/services/model.ts"); beforeEach(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(moduleDataDir, { recursive: true }); coreDb.getDbInstance(); }); after(() => { coreDb.resetDbInstance(); - fs.rmSync(moduleDataDir, { recursive: true, force: true }); + fs.rmSync(moduleDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const NODE_ID = "openai-compatible-chat-02669115-2545-4896-b003-cb4dac09d441"; diff --git a/tests/unit/model-resolver.test.ts b/tests/unit/model-resolver.test.ts index d7d0d0e739..a5b0be4f58 100644 --- a/tests/unit/model-resolver.test.ts +++ b/tests/unit/model-resolver.test.ts @@ -38,7 +38,7 @@ test.after(async () => { const { invalidateDbCache } = await import("../../src/lib/db/readCache.ts"); core.resetDbInstance(); invalidateDbCache(); - fs.rmSync(modelResolverDataDir, { recursive: true, force: true }); + fs.rmSync(modelResolverDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (previousDataDir === undefined) { delete process.env.DATA_DIR; } else { @@ -185,8 +185,7 @@ test( ); test("getModelInfoCore routes unprefixed Claude models to Claude Code from settings toggle", async () => { - const previousEnvFlag = - process.env.OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS; + const previousEnvFlag = process.env.OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS; delete process.env.OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS; try { @@ -216,8 +215,7 @@ test("getModelInfoCore routes unprefixed Claude models to Claude Code from setti }); test("getModelInfoCore lets settings toggle disable Claude Code preference", async () => { - const previousEnvFlag = - process.env.OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS; + const previousEnvFlag = process.env.OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS; process.env.OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS = "true"; try { diff --git a/tests/unit/model-sync-custom-preservation.test.ts b/tests/unit/model-sync-custom-preservation.test.ts index c8f8fc7e67..759c329614 100644 --- a/tests/unit/model-sync-custom-preservation.test.ts +++ b/tests/unit/model-sync-custom-preservation.test.ts @@ -21,7 +21,7 @@ const originalFetch = globalThis.fetch; test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("model sync preserves response-only custom models during discovery", async () => { diff --git a/tests/unit/model-sync-route.test.ts b/tests/unit/model-sync-route.test.ts index ece60f730d..73f199a1ec 100644 --- a/tests/unit/model-sync-route.test.ts +++ b/tests/unit/model-sync-route.test.ts @@ -34,7 +34,7 @@ async function resetStorage() { modelSyncRoute.__resetLoopbackReadinessForTests(); core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function enableAuth() { diff --git a/tests/unit/model-sync-scheduler.test.ts b/tests/unit/model-sync-scheduler.test.ts index 449c91475b..c8a6e2bfd4 100644 --- a/tests/unit/model-sync-scheduler.test.ts +++ b/tests/unit/model-sync-scheduler.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -107,7 +107,7 @@ test.beforeEach(async () => { test.after(async () => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("modelSyncScheduler: internal auth headers validate only for scheduler requests", async () => { diff --git a/tests/unit/model-test-route.test.ts b/tests/unit/model-test-route.test.ts index 1c8efe137c..5e1c1174e5 100644 --- a/tests/unit/model-test-route.test.ts +++ b/tests/unit/model-test-route.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { core.resetDbInstance(); delete process.env.INITIAL_PASSWORD; delete process.env.REQUIRE_API_KEY; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,7 +51,7 @@ test.afterEach(() => { test.after(async () => { globalThis.fetch = originalFetch; await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/model-token-limit-catalog.test.ts b/tests/unit/model-token-limit-catalog.test.ts index b456ce42ad..7d36565f0b 100644 --- a/tests/unit/model-token-limit-catalog.test.ts +++ b/tests/unit/model-token-limit-catalog.test.ts @@ -20,14 +20,14 @@ const LIMITS = { context: 372000, input: 353400, output: 128000 }; test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); catalog.__resetCatalogBuilderRunsForTest(); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function getModel(target = TARGET) { diff --git a/tests/unit/models-catalog-auto-combos-4164.test.ts b/tests/unit/models-catalog-auto-combos-4164.test.ts index b83fc174a3..440878c370 100644 --- a/tests/unit/models-catalog-auto-combos-4164.test.ts +++ b/tests/unit/models-catalog-auto-combos-4164.test.ts @@ -25,7 +25,7 @@ const builtinCatalog = await import("../../open-sse/services/autoCombo/builtinCa function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4164 /v1/models advertises every built-in auto/* combo", async () => { @@ -113,7 +113,11 @@ test("#4189 every auto/* entry exposes token limits + baseline capabilities", as `${entry.id} must expose a numeric context_length` ); assert.ok((entry.context_length ?? 0) > 0, `${entry.id} context_length must be positive`); - assert.equal(typeof entry.max_input_tokens, "number", `${entry.id} must expose max_input_tokens`); + assert.equal( + typeof entry.max_input_tokens, + "number", + `${entry.id} must expose max_input_tokens` + ); assert.equal( typeof entry.max_output_tokens, "number", diff --git a/tests/unit/models-catalog-block-auto-5192.test.ts b/tests/unit/models-catalog-block-auto-5192.test.ts index 44de506b65..256e4930d9 100644 --- a/tests/unit/models-catalog-block-auto-5192.test.ts +++ b/tests/unit/models-catalog-block-auto-5192.test.ts @@ -28,7 +28,7 @@ type ModelsResponseBody = { data: Array<{ id: string }> }; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5192 baseline: built-in auto/* combos are listed when Auto is not blocked", async () => { diff --git a/tests/unit/models-catalog-combo-metadata.test.ts b/tests/unit/models-catalog-combo-metadata.test.ts index 1ab884f3d3..c64b46bd1a 100644 --- a/tests/unit/models-catalog-combo-metadata.test.ts +++ b/tests/unit/models-catalog-combo-metadata.test.ts @@ -19,7 +19,7 @@ const catalog = await import("../../src/app/api/v1/models/catalog.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("single-target combo preserves its direct model metadata", async () => { diff --git a/tests/unit/models-catalog-custom-node-prefix.test.ts b/tests/unit/models-catalog-custom-node-prefix.test.ts index c3684ecab7..8fe177ed59 100644 --- a/tests/unit/models-catalog-custom-node-prefix.test.ts +++ b/tests/unit/models-catalog-custom-node-prefix.test.ts @@ -24,7 +24,7 @@ const EXPECTED_IDS = [ async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); modelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -93,7 +93,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("alias mode exposes every custom node model under its configured prefix", async () => { diff --git a/tests/unit/models-catalog-envkey-6406.test.ts b/tests/unit/models-catalog-envkey-6406.test.ts index 824fd8a081..5127c9d501 100644 --- a/tests/unit/models-catalog-envkey-6406.test.ts +++ b/tests/unit/models-catalog-envkey-6406.test.ts @@ -29,7 +29,7 @@ interface ModelsCatalogResponseBody { async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.OMNIROUTE_API_KEY; }); diff --git a/tests/unit/models-catalog-functional-gateway-permissions.test.ts b/tests/unit/models-catalog-functional-gateway-permissions.test.ts index ccdcfb1903..f7f0aad41c 100644 --- a/tests/unit/models-catalog-functional-gateway-permissions.test.ts +++ b/tests/unit/models-catalog-functional-gateway-permissions.test.ts @@ -20,7 +20,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -65,7 +65,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 models catalog requires independent permission for functional gateway mirrors", async () => { diff --git a/tests/unit/models-catalog-hidden-combo-leaves.test.ts b/tests/unit/models-catalog-hidden-combo-leaves.test.ts index 670ef653b4..44e7e264d0 100644 --- a/tests/unit/models-catalog-hidden-combo-leaves.test.ts +++ b/tests/unit/models-catalog-hidden-combo-leaves.test.ts @@ -55,7 +55,7 @@ async function getCatalogData(): Promise { test.beforeEach(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); }); @@ -64,7 +64,7 @@ test.after(() => { modelsDevSync.saveModelsDevCapabilities({}); core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 models catalog keeps partially hidden combos and derives metadata from visible targets", async () => { diff --git a/tests/unit/models-catalog-hide-paid.test.ts b/tests/unit/models-catalog-hide-paid.test.ts index 4f2f8db674..8df5176bb0 100644 --- a/tests/unit/models-catalog-hide-paid.test.ts +++ b/tests/unit/models-catalog-hide-paid.test.ts @@ -31,7 +31,7 @@ async function fetchCatalog(): Promise> { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best-effort */ } diff --git a/tests/unit/models-catalog-low-noise-flag.test.ts b/tests/unit/models-catalog-low-noise-flag.test.ts index f1df7c5702..d8297ebd6b 100644 --- a/tests/unit/models-catalog-low-noise-flag.test.ts +++ b/tests/unit/models-catalog-low-noise-flag.test.ts @@ -22,7 +22,7 @@ type ModelsResponseBody = { async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("MODELS_CATALOG_PREFIX_MODE=alias suppresses canonical provider-id prefixes", async () => { diff --git a/tests/unit/models-catalog-route.test.ts b/tests/unit/models-catalog-route.test.ts index 7c2ed395d9..e6216899f0 100644 --- a/tests/unit/models-catalog-route.test.ts +++ b/tests/unit/models-catalog-route.test.ts @@ -21,7 +21,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // #6408 added a 1.5s TTL response cache to getUnifiedModelsResponse keyed only by // (prefix, isCodex client, apiKey) — NOT by DB/settings state. Without clearing it @@ -73,7 +73,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 models catalog requires auth when the route is protected and login is enabled", async () => { diff --git a/tests/unit/models-catalog-static-synced-suppression.test.ts b/tests/unit/models-catalog-static-synced-suppression.test.ts index 288e7c2e3c..52dc64564e 100644 --- a/tests/unit/models-catalog-static-synced-suppression.test.ts +++ b/tests/unit/models-catalog-static-synced-suppression.test.ts @@ -28,7 +28,7 @@ function getStaticModel(provider: string) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(path.join(TEST_DATA_DIR, "logs/application"), { recursive: true }); catalog.__resetCatalogBuilderRunsForTest(); } @@ -58,7 +58,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("active authoritative live catalog suppresses stale static registry models", async () => { @@ -109,9 +109,11 @@ test("partial discovery provider preserves uncovered static models when synced", const uncoveredStaticModel = "deepseek/deepseek-v4-flash"; const coveredSyncedModel = "claude-opus-4-7"; - await modelsDb.replaceSyncedAvailableModelsForConnection("command-code", connection.id as string, [ - { id: coveredSyncedModel, name: "Claude Opus 4.7", source: "imported" }, - ]); + await modelsDb.replaceSyncedAvailableModelsForConnection( + "command-code", + connection.id as string, + [{ id: coveredSyncedModel, name: "Claude Opus 4.7", source: "imported" }] + ); const ids = await getCatalogIds(); diff --git a/tests/unit/models-db-isfree.test.ts b/tests/unit/models-db-isfree.test.ts index 7e1234d097..df2e23485d 100644 --- a/tests/unit/models-db-isfree.test.ts +++ b/tests/unit/models-db-isfree.test.ts @@ -1,6 +1,11 @@ import { describe, it, beforeEach, afterEach } from "node:test"; import assert from "node:assert/strict"; -import { addCustomModel, replaceCustomModels, updateCustomModel, getCustomModels } from "../../src/lib/db/models.ts"; +import { + addCustomModel, + replaceCustomModels, + updateCustomModel, + getCustomModels, +} from "../../src/lib/db/models.ts"; import { resetDbInstance } from "../../src/lib/db/core.ts"; import { rmSync, mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; @@ -20,22 +25,60 @@ describe("custom isFree tri-state (DB)", () => { resetDbInstance(); if (prevDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = prevDataDir; - try { rmSync(dir, { recursive: true, force: true }); } catch {} + try { + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); it("addCustomModel round-trip isFree:true → kept, isFree absent → not set", async () => { - await addCustomModel("p", "m1", "M1", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, true); + await addCustomModel( + "p", + "m1", + "M1", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + true + ); const rows: any = await getCustomModels("p"); const r = rows.find((x: any) => x.id === "m1"); assert.equal(r.isFree, true); - await addCustomModel("p", "m2", "M2", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, undefined); + await addCustomModel( + "p", + "m2", + "M2", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + undefined + ); const rows2: any = await getCustomModels("p"); const r2 = rows2.find((x: any) => x.id === "m2"); assert.equal(r2.isFree, undefined); }); it("updateCustomModel isFree:null → delete key (tri-state clear)", async () => { - await addCustomModel("p", "m", "M", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, true); + await addCustomModel( + "p", + "m", + "M", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + true + ); await updateCustomModel("p", "m", { isFree: null } as any); const rows: any = await getCustomModels("p"); const r = rows.find((x: any) => x.id === "m"); @@ -43,7 +86,19 @@ describe("custom isFree tri-state (DB)", () => { }); it("updateCustomModel isFree:true → set, then false-effective via tri-state (Boolean) ", async () => { - await addCustomModel("p", "m", "M", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, undefined); + await addCustomModel( + "p", + "m", + "M", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + undefined + ); await updateCustomModel("p", "m", { isFree: true } as any); let rows: any = await getCustomModels("p"); assert.equal(rows.find((x: any) => x.id === "m").isFree, true); @@ -54,17 +109,60 @@ describe("custom isFree tri-state (DB)", () => { }); it("replaceCustomModels preserves isFree (new wins else prev)", async () => { - await addCustomModel("p", "keep", "K", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, true); - await addCustomModel("p", "override", "O", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, undefined); + await addCustomModel( + "p", + "keep", + "K", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + true + ); + await addCustomModel( + "p", + "override", + "O", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + undefined + ); // replace with new truth for override, omit for keep (prev should win) - await replaceCustomModels("p", [{ id: "keep", name: "keep" }, { id: "override", name: "override", isFree: true } as any]); + await replaceCustomModels("p", [ + { id: "keep", name: "keep" }, + { id: "override", name: "override", isFree: true } as any, + ]); const rows: any = await getCustomModels("p"); - assert.equal(rows.find((x: any) => x.id === "keep").isFree, true, "prev isFree preserved when new omits"); + assert.equal( + rows.find((x: any) => x.id === "keep").isFree, + true, + "prev isFree preserved when new omits" + ); assert.equal(rows.find((x: any) => x.id === "override").isFree, true, "new isFree wins"); }); it("allowEmpty:false intact (no destructive clear)", async () => { - await addCustomModel("p", "m", "M", "manual", "chat-completions", ["chat"], undefined, {}, undefined, undefined, true); + await addCustomModel( + "p", + "m", + "M", + "manual", + "chat-completions", + ["chat"], + undefined, + {}, + undefined, + undefined, + true + ); const before: any = await getCustomModels("p"); const after: any = await replaceCustomModels("p", [], { allowEmpty: false }); assert.equal(after.length, before.length); diff --git a/tests/unit/models-dev-pricing-caching-9300.test.ts b/tests/unit/models-dev-pricing-caching-9300.test.ts index a1d62025e3..9c22b2722f 100644 --- a/tests/unit/models-dev-pricing-caching-9300.test.ts +++ b/tests/unit/models-dev-pricing-caching-9300.test.ts @@ -47,7 +47,9 @@ describe("getModelsDevPricing caching (#9300)", () => { modelsDev = await importFresh("9300-cache"); // Seed pricing data into DB - modelsDev.saveModelsDevPricing(PRICING_DATA as Record>>); + modelsDev.saveModelsDevPricing( + PRICING_DATA as Record>> + ); // Reset cache to ensure a clean read from DB // (saveModelsDevPricing clears the cache, so next get will load from DB) @@ -57,7 +59,7 @@ describe("getModelsDevPricing caching (#9300)", () => { // Clean up DB handles dbCore.resetDbInstance(); try { - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } @@ -110,4 +112,4 @@ describe("getModelsDevPricing caching (#9300)", () => { // After clear, pricing should be empty assert.deepEqual(afterClear, {}, "pricing should be empty after clear"); }); -}); \ No newline at end of file +}); diff --git a/tests/unit/models-test-error-shape.test.ts b/tests/unit/models-test-error-shape.test.ts index 54f98ed493..cbe01c2143 100644 --- a/tests/unit/models-test-error-shape.test.ts +++ b/tests/unit/models-test-error-shape.test.ts @@ -26,7 +26,7 @@ test.before(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function post(body: unknown, rawText?: string) { diff --git a/tests/unit/modelsDevSync-extended.test.ts b/tests/unit/modelsDevSync-extended.test.ts index 3d0f26266e..4a6edc3dc0 100644 --- a/tests/unit/modelsDevSync-extended.test.ts +++ b/tests/unit/modelsDevSync-extended.test.ts @@ -101,7 +101,7 @@ function restoreEnv() { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -142,7 +142,7 @@ test.afterEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.describe("modelsDevSync-extended", { concurrency: 1 }, async () => { diff --git a/tests/unit/monitoring-health-public-view.test.ts b/tests/unit/monitoring-health-public-view.test.ts index 5b7249066d..20d386b296 100644 --- a/tests/unit/monitoring-health-public-view.test.ts +++ b/tests/unit/monitoring-health-public-view.test.ts @@ -20,7 +20,7 @@ const route = await import("../../src/app/api/monitoring/health/route.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("anonymous health GET is reduced to liveness only (GHSA-mvf8)", async () => { diff --git a/tests/unit/native-binary-compat.test.ts b/tests/unit/native-binary-compat.test.ts index 120c5e7853..a8867d8888 100644 --- a/tests/unit/native-binary-compat.test.ts +++ b/tests/unit/native-binary-compat.test.ts @@ -70,7 +70,7 @@ describe("isNativeBinaryCompatible", () => { try { callback(file); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/noauth-autocombo-allowlist.test.ts b/tests/unit/noauth-autocombo-allowlist.test.ts index 228193c8af..70789f5887 100644 --- a/tests/unit/noauth-autocombo-allowlist.test.ts +++ b/tests/unit/noauth-autocombo-allowlist.test.ts @@ -27,7 +27,7 @@ const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFa async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/noauth-autocombo-exclude-7622.test.ts b/tests/unit/noauth-autocombo-exclude-7622.test.ts index 0d8362cd8c..f784f21394 100644 --- a/tests/unit/noauth-autocombo-exclude-7622.test.ts +++ b/tests/unit/noauth-autocombo-exclude-7622.test.ts @@ -23,7 +23,7 @@ const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFa async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/noauth-autocombo-hidden-7620.test.ts b/tests/unit/noauth-autocombo-hidden-7620.test.ts index 630b7fe564..6ec9dea149 100644 --- a/tests/unit/noauth-autocombo-hidden-7620.test.ts +++ b/tests/unit/noauth-autocombo-hidden-7620.test.ts @@ -25,7 +25,7 @@ const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFa async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/noauth-autocombo-lockout-7623.test.ts b/tests/unit/noauth-autocombo-lockout-7623.test.ts index dea6d7b231..49c6fd0259 100644 --- a/tests/unit/noauth-autocombo-lockout-7623.test.ts +++ b/tests/unit/noauth-autocombo-lockout-7623.test.ts @@ -21,7 +21,7 @@ const accountFallback = await import("../../open-sse/services/accountFallback.ts async function resetStorage() { core.resetDbInstance(); accountFallback.clearAllModelLockouts(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/noauth-imported-models-3200.test.ts b/tests/unit/noauth-imported-models-3200.test.ts index cf23a57f8d..9f6a24d1b4 100644 --- a/tests/unit/noauth-imported-models-3200.test.ts +++ b/tests/unit/noauth-imported-models-3200.test.ts @@ -28,7 +28,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3200 imported model on a noAuth provider (theoldllm) appears in /api/v1/models", async () => { diff --git a/tests/unit/notion-web-models-discovery.test.ts b/tests/unit/notion-web-models-discovery.test.ts index 9c3b1c3d63..e6594fbf05 100644 --- a/tests/unit/notion-web-models-discovery.test.ts +++ b/tests/unit/notion-web-models-discovery.test.ts @@ -14,13 +14,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const SAMPLE_RESPONSE = { diff --git a/tests/unit/nvidia-410-model-scope.test.ts b/tests/unit/nvidia-410-model-scope.test.ts index 13fbaa6ef6..0d72fe1345 100644 --- a/tests/unit/nvidia-410-model-scope.test.ts +++ b/tests/unit/nvidia-410-model-scope.test.ts @@ -28,7 +28,7 @@ const GONE_BODY = JSON.stringify({ async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -50,7 +50,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("NVIDIA 410 Gone stays model-scoped and leaves the connection usable", async () => { diff --git a/tests/unit/oauth-400-recovery.test.ts b/tests/unit/oauth-400-recovery.test.ts index 66d40db46c..fa041ea56d 100644 --- a/tests/unit/oauth-400-recovery.test.ts +++ b/tests/unit/oauth-400-recovery.test.ts @@ -231,7 +231,7 @@ test("isReactive400Recoverable fixtures compile with the real helper signature", }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("isTokenExpired treats a corrupt expiresAt string as expired (refreshable)", () => { diff --git a/tests/unit/oauth-connection-persistence-codex-dedup.test.ts b/tests/unit/oauth-connection-persistence-codex-dedup.test.ts index 30d5a29adf..30fe9ed7fd 100644 --- a/tests/unit/oauth-connection-persistence-codex-dedup.test.ts +++ b/tests/unit/oauth-connection-persistence-codex-dedup.test.ts @@ -16,7 +16,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -36,7 +36,7 @@ test.beforeEach(async () => { }); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("persistOAuthConnection must not merge two distinct Codex accounts that share an email but have different chatgptUserId and no workspaceId", async () => { @@ -90,9 +90,17 @@ test("persistOAuthConnection still merges a re-login for the SAME Codex chatgptU providerSpecificData: { chatgptUserId: "user-solo" }, }); - assert.equal(second.id, first.id, "re-authenticating the same Codex user must update the same row"); + assert.equal( + second.id, + first.id, + "re-authenticating the same Codex user must update the same row" + ); const rows = await providersDb.getProviderConnections({ provider: "codex" }); - assert.equal(rows.length, 1, "no duplicate connection should be created for the same chatgptUserId"); + assert.equal( + rows.length, + 1, + "no duplicate connection should be created for the same chatgptUserId" + ); assert.equal(rows[0]?.accessToken, "token-second", "the row must reflect the latest tokens"); }); diff --git a/tests/unit/oauth-connection-tokenexpiresat-5326.test.ts b/tests/unit/oauth-connection-tokenexpiresat-5326.test.ts index 9507506221..a018739b8d 100644 --- a/tests/unit/oauth-connection-tokenexpiresat-5326.test.ts +++ b/tests/unit/oauth-connection-tokenexpiresat-5326.test.ts @@ -15,7 +15,7 @@ const { buildOAuthConnectionCreatePayload } = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression for #5326: a freshly created OAuth connection (e.g. antigravity) used diff --git a/tests/unit/oauth-device-code-region-ssrf.test.ts b/tests/unit/oauth-device-code-region-ssrf.test.ts index bc57659f79..c5f7f1c5e1 100644 --- a/tests/unit/oauth-device-code-region-ssrf.test.ts +++ b/tests/unit/oauth-device-code-region-ssrf.test.ts @@ -21,7 +21,7 @@ const route = await import("../../src/app/api/oauth/[provider]/[action]/route.ts test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function deviceCode(provider: string, region: string) { diff --git a/tests/unit/oauth-grok-cli-browser.test.ts b/tests/unit/oauth-grok-cli-browser.test.ts index 3e23d57a06..9d21a1ad8f 100644 --- a/tests/unit/oauth-grok-cli-browser.test.ts +++ b/tests/unit/oauth-grok-cli-browser.test.ts @@ -19,9 +19,8 @@ const settingsDb = await import("../../src/lib/db/settings.ts"); const route = await import("../../src/app/api/oauth/[provider]/[action]/route.ts"); const { generateAuthData } = await import("../../src/lib/oauth/providers.ts"); const { grokCli } = await import("../../src/lib/oauth/providers/grok-cli.ts"); -const { GROK_BUILD_OAUTH_CONFIG, XAI_OAUTH_CONFIG } = await import( - "../../src/lib/oauth/constants/oauth.ts" -); +const { GROK_BUILD_OAUTH_CONFIG, XAI_OAUTH_CONFIG } = + await import("../../src/lib/oauth/constants/oauth.ts"); const originalFetch = globalThis.fetch; @@ -32,7 +31,7 @@ test.before(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.afterEach(() => { @@ -98,7 +97,11 @@ test("grok-cli exchangeToken POSTs grant_type=authorization_code with the PKCE v assert.equal(body.get("code"), "auth-code"); assert.equal(body.get("redirect_uri"), "http://127.0.0.1:56122/callback"); assert.equal(body.get("code_verifier"), "verifier"); - return Response.json({ access_token: "gb-access", refresh_token: "gb-refresh", expires_in: 3600 }); + return Response.json({ + access_token: "gb-access", + refresh_token: "gb-refresh", + expires_in: 3600, + }); }; const tokens = await grokCli.exchangeToken( @@ -188,7 +191,8 @@ test("POST /api/oauth/grok-cli/exchange requires a codeVerifier (PKCE branch rea }); test("POST /api/oauth/grok-cli/exchange failure returns a sanitized 500 (Hard Rule #12)", async () => { - globalThis.fetch = async () => new Response("upstream secret leak: token=abc123", { status: 500 }); + globalThis.fetch = async () => + new Response("upstream secret leak: token=abc123", { status: 500 }); const res = await postRoute("grok-cli", "exchange", { code: "auth-code", diff --git a/tests/unit/oauth-import-manage-scope.test.ts b/tests/unit/oauth-import-manage-scope.test.ts index 070515c02a..dd1ef84317 100644 --- a/tests/unit/oauth-import-manage-scope.test.ts +++ b/tests/unit/oauth-import-manage-scope.test.ts @@ -30,7 +30,7 @@ test.before(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.JWT_SECRET; delete process.env.INITIAL_PASSWORD; }); @@ -60,7 +60,11 @@ test("codex/import-token: non-manage key → 403, no key → 401, manage key pas const nonManage = await apiKeysDb.createApiKey("client", "machine-client", []); const manage = await apiKeysDb.createApiKey("admin", "machine-admin", ["manage"]); - assert.equal((await post(codexImportToken, nonManage.key)).status, 403, "non-manage key rejected"); + assert.equal( + (await post(codexImportToken, nonManage.key)).status, + 403, + "non-manage key rejected" + ); assert.equal((await post(codexImportToken)).status, 401, "no credential rejected"); const withManage = await post(codexImportToken, manage.key); diff --git a/tests/unit/oauth-keychain-import-only-6041.test.ts b/tests/unit/oauth-keychain-import-only-6041.test.ts index d2363ea225..f5a676c002 100644 --- a/tests/unit/oauth-keychain-import-only-6041.test.ts +++ b/tests/unit/oauth-keychain-import-only-6041.test.ts @@ -28,7 +28,7 @@ test.before(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function get(provider: string, action: string) { @@ -42,7 +42,11 @@ test("#6041 GET /oauth/zed/authorize returns a graceful 400, not a 500 'Unknown const body = await res.json(); assert.ok(body.error, "error message present"); assert.match(body.error, /Import/i, "must point the user at the Import flow"); - assert.doesNotMatch(body.error, /Unknown provider/i, "must not leak the raw 'Unknown provider' error"); + assert.doesNotMatch( + body.error, + /Unknown provider/i, + "must not leak the raw 'Unknown provider' error" + ); // Never leak a stack trace (ERROR_SANITIZATION). assert.doesNotMatch(body.error, /at \//, "must not leak a stack trace"); }); diff --git a/tests/unit/oauth-paste-credentials-route.test.ts b/tests/unit/oauth-paste-credentials-route.test.ts index 43793bf08d..653b03ac20 100644 --- a/tests/unit/oauth-paste-credentials-route.test.ts +++ b/tests/unit/oauth-paste-credentials-route.test.ts @@ -33,7 +33,7 @@ test.before(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function postPaste(provider: string, body: unknown) { diff --git a/tests/unit/oauth-refresh-connection-dedup-8059.test.ts b/tests/unit/oauth-refresh-connection-dedup-8059.test.ts index 5724dadcb0..d0dee409e0 100644 --- a/tests/unit/oauth-refresh-connection-dedup-8059.test.ts +++ b/tests/unit/oauth-refresh-connection-dedup-8059.test.ts @@ -26,14 +26,14 @@ const { persistOAuthConnection, findExistingOAuthConnectionMatch } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); type ProviderConnection = Awaited>[number]; diff --git a/tests/unit/obsidian-config.test.ts b/tests/unit/obsidian-config.test.ts index 71239c0c7a..2d617cef2c 100644 --- a/tests/unit/obsidian-config.test.ts +++ b/tests/unit/obsidian-config.test.ts @@ -8,12 +8,18 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omni-obsidian-confi process.env.DATA_DIR = TEST_DATA_DIR; const coreDb = await import("../../src/lib/db/core.ts"); -const { getApiKeyContextSource, setApiKeyContextSource, deleteApiKeyContextSource, listApiKeyContextSources } = await import("../../src/lib/db/apiKeyContextSources.ts"); -const { getObsidianConfigForApiKey, setObsidianToken, setObsidianBaseUrl } = await import("../../src/lib/db/obsidian.ts"); +const { + getApiKeyContextSource, + setApiKeyContextSource, + deleteApiKeyContextSource, + listApiKeyContextSources, +} = await import("../../src/lib/db/apiKeyContextSources.ts"); +const { getObsidianConfigForApiKey, setObsidianToken, setObsidianBaseUrl } = + await import("../../src/lib/db/obsidian.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -30,7 +36,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("apiKeyContextSources: returns null for unknown apiKeyId", () => { @@ -88,7 +94,7 @@ test("apiKeyContextSources: list returns all sources for a key", () => { setApiKeyContextSource("key-5", "notion", { token: "not", enabled: true }); const results = listApiKeyContextSources("key-5"); assert.equal(results.length, 2); - const types = results.map(r => r.sourceType).sort(); + const types = results.map((r) => r.sourceType).sort(); assert.deepEqual(types, ["notion", "obsidian"]); }); diff --git a/tests/unit/obsidian-webdav-route.test.ts b/tests/unit/obsidian-webdav-route.test.ts index cfb9363492..a92d06d332 100644 --- a/tests/unit/obsidian-webdav-route.test.ts +++ b/tests/unit/obsidian-webdav-route.test.ts @@ -37,7 +37,7 @@ const obsidianDb = await import("../../src/lib/db/obsidian.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; @@ -103,8 +103,14 @@ test("POST with a valid temp dir → returns { username, password }, GET shows e assert.equal(res.status, 200); const body = (await res.json()) as Record; - assert.ok(typeof body.username === "string" && (body.username as string).length > 0, "username non-empty"); - assert.ok(typeof body.password === "string" && (body.password as string).length > 0, "password non-empty"); + assert.ok( + typeof body.username === "string" && (body.username as string).length > 0, + "username non-empty" + ); + assert.ok( + typeof body.password === "string" && (body.password as string).length > 0, + "password non-empty" + ); assert.ok(typeof body.vaultPath === "string", "vaultPath returned"); // GET should now reflect enabled state @@ -113,13 +119,15 @@ test("POST with a valid temp dir → returns { username, password }, GET shows e assert.equal(getRes.status, 200); const getBody = (await getRes.json()) as Record; assert.equal(getBody.webdavEnabled, true); - assert.ok(typeof getBody.webdavUsername === "string" && (getBody.webdavUsername as string).length > 0); + assert.ok( + typeof getBody.webdavUsername === "string" && (getBody.webdavUsername as string).length > 0 + ); // Anonymous GET (this request carries no management credential): the plaintext // password is masked (GHSA-62vw), but the set/unset flag still reflects state. assert.equal(getBody.webdavPassword, null); assert.equal(getBody.webdavPasswordSet, true); } finally { - fs.rmSync(vaultDir, { recursive: true, force: true }); + fs.rmSync(vaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -137,11 +145,15 @@ test("GET masks the WebDAV password for anonymous callers but reveals it to a ma assert.equal(enableRes.status, 200); // Anonymous (open-mode) caller: password masked, flag still set. - const anonBody = (await (await route.GET( - makeRequest("http://localhost/api/settings/obsidian/webdav") - )).json()) as Record; + const anonBody = (await ( + await route.GET(makeRequest("http://localhost/api/settings/obsidian/webdav")) + ).json()) as Record; assert.equal(anonBody.webdavEnabled, true); - assert.equal(anonBody.webdavPassword, null, "anonymous caller must not receive the plaintext password"); + assert.equal( + anonBody.webdavPassword, + null, + "anonymous caller must not receive the plaintext password" + ); assert.equal(anonBody.webdavPasswordSet, true); // Genuine management session: the operator's reveal-password view still works. @@ -155,7 +167,7 @@ test("GET masks the WebDAV password for anonymous callers but reveals it to a ma "a management session must still receive the plaintext password" ); } finally { - fs.rmSync(vaultDir, { recursive: true, force: true }); + fs.rmSync(vaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -170,7 +182,8 @@ test("POST with a non-existent path → 400, body does NOT contain a stack trace assert.equal(res.status, 400); const body = (await res.json()) as Record; - const errorMsg = (body.error as Record | undefined)?.message as string | undefined; + const errorMsg = (body.error as Record | undefined)?.message as + string | undefined; // Must not leak stack trace assert.ok( !errorMsg || !errorMsg.includes("at /"), @@ -217,7 +230,7 @@ test("DELETE after enable → webdavEnabled:false, creds cleared in GET", async assert.equal(getBody.webdavUsername, null); assert.equal(getBody.webdavPassword, null); } finally { - fs.rmSync(vaultDir, { recursive: true, force: true }); + fs.rmSync(vaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -243,7 +256,7 @@ test("GET when disabled does not leak password even if stale data exists", async assert.equal(getBody.webdavEnabled, false); assert.equal(getBody.webdavPassword, null); } finally { - fs.rmSync(vaultDir, { recursive: true, force: true }); + fs.rmSync(vaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -272,7 +285,7 @@ test("Unauthenticated POST → 401 when auth is required", async () => { const res = await route.POST(req); assert.equal(res.status, 401); } finally { - fs.rmSync(vaultDir, { recursive: true, force: true }); + fs.rmSync(vaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -336,5 +349,9 @@ test("encryption graceful fallback: plaintext stored without key reads back corr // Must read back the same value const retrieved = obsidianDb.getWebdavPassword(); - assert.equal(retrieved, plaintext, "Plaintext value must read back unchanged when no encryption key"); + assert.equal( + retrieved, + plaintext, + "Plaintext value must read back unchanged when no encryption key" + ); }); diff --git a/tests/unit/oidc-callback.test.ts b/tests/unit/oidc-callback.test.ts index 5d41701e42..0659edf58c 100644 --- a/tests/unit/oidc-callback.test.ts +++ b/tests/unit/oidc-callback.test.ts @@ -32,7 +32,7 @@ let capturedCookies: Record = {}; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); capturedCookies = {}; } @@ -61,7 +61,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.JWT_SECRET; }); diff --git a/tests/unit/oidc-login-state.test.ts b/tests/unit/oidc-login-state.test.ts index ea9c4e56fb..341ba53932 100644 --- a/tests/unit/oidc-login-state.test.ts +++ b/tests/unit/oidc-login-state.test.ts @@ -20,7 +20,7 @@ const loginRoute = await import("../../src/app/api/auth/oidc/login/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -30,7 +30,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.JWT_SECRET; }); diff --git a/tests/unit/ollama-404-model-lockout-11071.test.ts b/tests/unit/ollama-404-model-lockout-11071.test.ts index f58c29c07b..fbcdb32e46 100644 --- a/tests/unit/ollama-404-model-lockout-11071.test.ts +++ b/tests/unit/ollama-404-model-lockout-11071.test.ts @@ -10,17 +10,18 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const auth = await import("../../src/sse/services/auth.ts"); -const { hasPerModelQuota, isModelLocked } = await import("../../open-sse/services/accountFallback.ts"); +const { hasPerModelQuota, isModelLocked } = + await import("../../open-sse/services/accountFallback.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("hasPerModelQuota returns true for ollama-local and ollama providers", () => { @@ -53,7 +54,11 @@ test("markAccountUnavailable locks only the missing model on a 404 from ollama-l // The connection in DB must remain active / not marked unavailable for sibling models const connInDb = await providersDb.getProviderConnectionById(connection.id); - assert.notEqual(connInDb?.testStatus, "unavailable", "connection should not be marked unavailable connection-wide on a 404 model-not-found error"); + assert.notEqual( + connInDb?.testStatus, + "unavailable", + "connection should not be marked unavailable connection-wide on a 404 model-not-found error" + ); // getProviderCredentials must still serve sibling models const selectedForSibling = await auth.getProviderCredentials( @@ -62,5 +67,8 @@ test("markAccountUnavailable locks only the missing model on a 404 from ollama-l null, "model-a" ); - assert.ok(selectedForSibling && !("allExpired" in selectedForSibling), "sibling model-a must still be selected on the same connection"); + assert.ok( + selectedForSibling && !("allExpired" in selectedForSibling), + "sibling model-a must still be selected on the same connection" + ); }); diff --git a/tests/unit/ollama-local-capabilities-routing.test.ts b/tests/unit/ollama-local-capabilities-routing.test.ts index 0ce75a2983..25c1f61906 100644 --- a/tests/unit/ollama-local-capabilities-routing.test.ts +++ b/tests/unit/ollama-local-capabilities-routing.test.ts @@ -23,7 +23,7 @@ const originalFetch = globalThis.fetch; function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -45,7 +45,7 @@ test.beforeEach(resetStorage); test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Ollama discovery maps /api/show capabilities into connection-scoped model metadata", async () => { diff --git a/tests/unit/ollama-local-embedding-2824.test.ts b/tests/unit/ollama-local-embedding-2824.test.ts index 2cb4c18e2f..400f30fa8e 100644 --- a/tests/unit/ollama-local-embedding-2824.test.ts +++ b/tests/unit/ollama-local-embedding-2824.test.ts @@ -16,7 +16,7 @@ const { createEmbeddingResponse } = await import("../../src/lib/embeddings/servi test.after(() => { core.resetDbInstance(); - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("ollama-local exposes a static no-auth embedding registry entry", () => { diff --git a/tests/unit/openai-style-providers-4239-4155-3841.test.ts b/tests/unit/openai-style-providers-4239-4155-3841.test.ts index 4783262345..f5e744c96e 100644 --- a/tests/unit/openai-style-providers-4239-4155-3841.test.ts +++ b/tests/unit/openai-style-providers-4239-4155-3841.test.ts @@ -51,13 +51,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ProviderSpec { diff --git a/tests/unit/openapi-try-route.test.ts b/tests/unit/openapi-try-route.test.ts index 4ab2edab5a..bb29d2e815 100644 --- a/tests/unit/openapi-try-route.test.ts +++ b/tests/unit/openapi-try-route.test.ts @@ -21,7 +21,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -57,7 +57,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/opencode-free-tier-routing-shortcircuit-10571.test.ts b/tests/unit/opencode-free-tier-routing-shortcircuit-10571.test.ts index 76bfd17922..75a17b1603 100644 --- a/tests/unit/opencode-free-tier-routing-shortcircuit-10571.test.ts +++ b/tests/unit/opencode-free-tier-routing-shortcircuit-10571.test.ts @@ -39,7 +39,7 @@ const { getModelInfoCore } = await import("../../open-sse/services/model.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("bare big-pickle routes to an opencode-family provider when an opencode connection is active", async () => { diff --git a/tests/unit/opencode-noauth-models-route.test.ts b/tests/unit/opencode-noauth-models-route.test.ts index 6965c485ea..2b4abeaee8 100644 --- a/tests/unit/opencode-noauth-models-route.test.ts +++ b/tests/unit/opencode-noauth-models-route.test.ts @@ -13,7 +13,7 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // #3047 — OpenCode Free (no-auth) has no connection row, so the diff --git a/tests/unit/opencode-zen-alias-combo-e2e.test.ts b/tests/unit/opencode-zen-alias-combo-e2e.test.ts index 40f4cb7065..f9adbf73a2 100644 --- a/tests/unit/opencode-zen-alias-combo-e2e.test.ts +++ b/tests/unit/opencode-zen-alias-combo-e2e.test.ts @@ -120,7 +120,7 @@ before(async () => { after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Tests ────────────────────────────────────────────────────────────── diff --git a/tests/unit/openrouter-embeddings-catalog-6976.test.ts b/tests/unit/openrouter-embeddings-catalog-6976.test.ts index 3e2f27b394..e722e5c096 100644 --- a/tests/unit/openrouter-embeddings-catalog-6976.test.ts +++ b/tests/unit/openrouter-embeddings-catalog-6976.test.ts @@ -22,7 +22,7 @@ type ModelsResponseBody = { source: string; models: DiscoveredModel[] }; async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("embeddingRegistry curated openrouter catalog carries the refreshed lineup with dimensions (#6976)", () => { @@ -75,10 +75,7 @@ test("embeddingRegistry curated openrouter catalog carries the refreshed lineup const dim = config!.models.find((m) => m.id === expected)?.dimensions; assert.equal(typeof dim, "number", `${expected} must carry a dimensions value`); } - assert.equal( - config!.models.find((m) => m.id === "google/gemini-embedding-2")?.dimensions, - 3072 - ); + assert.equal(config!.models.find((m) => m.id === "google/gemini-embedding-2")?.dimensions, 3072); assert.equal( config!.models.find((m) => m.id === "google/gemini-embedding-2-preview")?.dimensions, 3072 diff --git a/tests/unit/openrouter-free-model-credits-exhausted.test.ts b/tests/unit/openrouter-free-model-credits-exhausted.test.ts index 129d2fac6d..6a56646594 100644 --- a/tests/unit/openrouter-free-model-credits-exhausted.test.ts +++ b/tests/unit/openrouter-free-model-credits-exhausted.test.ts @@ -29,13 +29,13 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getProviderCredentials still serves a :free OpenRouter model after the connection is credits_exhausted", async () => { diff --git a/tests/unit/openrouter-provider-stats.test.ts b/tests/unit/openrouter-provider-stats.test.ts index f2d0d3ec4f..4e0550a841 100644 --- a/tests/unit/openrouter-provider-stats.test.ts +++ b/tests/unit/openrouter-provider-stats.test.ts @@ -139,7 +139,7 @@ describe("getOpenRouterProviderStats / refreshOpenRouterProviderStats (cache + T afterEach(() => { restoreFetch(); - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = originalDataDir; if (originalTtl === undefined) delete process.env.OPENROUTER_PROVIDER_STATS_TTL_MS; diff --git a/tests/unit/openrouter-vision-sync-4264.test.ts b/tests/unit/openrouter-vision-sync-4264.test.ts index ac00c42e68..3b0117a1aa 100644 --- a/tests/unit/openrouter-vision-sync-4264.test.ts +++ b/tests/unit/openrouter-vision-sync-4264.test.ts @@ -24,7 +24,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4264 normalizeDiscoveredModels captures vision from OpenRouter architecture", () => { @@ -107,9 +107,7 @@ test("#4264 synced OpenRouter vision model surfaces capabilities.vision in /v1/m assert.equal(response.status, 200); const body = (await response.json()) as any; - const visionModel = body.data.find((m: any) => - String(m.id).endsWith("nex-agi/nex-n2-pro:free") - ); + const visionModel = body.data.find((m: any) => String(m.id).endsWith("nex-agi/nex-n2-pro:free")); assert.ok(visionModel, `expected the synced vision model in the catalog`); // RED before the fix: synced models carried no capabilities at all. assert.equal(visionModel.capabilities?.vision, true); diff --git a/tests/unit/ops-scripts.test.ts b/tests/unit/ops-scripts.test.ts index 2b37aae0cd..8bfb6d3e1c 100644 --- a/tests/unit/ops-scripts.test.ts +++ b/tests/unit/ops-scripts.test.ts @@ -136,7 +136,7 @@ describe("ops runbook scripts (bin/*.sh)", () => { ); db.close(); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -187,7 +187,7 @@ describe("ops runbook scripts (bin/*.sh)", () => { ); db.close(); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } ); diff --git a/tests/unit/optional-packs.test.ts b/tests/unit/optional-packs.test.ts index 5ff6eb84f6..47947c8eab 100644 --- a/tests/unit/optional-packs.test.ts +++ b/tests/unit/optional-packs.test.ts @@ -33,7 +33,7 @@ test("packs dirs derive from DATA_DIR override without touching the real home", packNodeModulesDir("browser-runtime", dataDir), path.join(dataDir, "packs", "browser-runtime", "node_modules") ); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("installedPackNodePaths lists only packs with an existing node_modules dir, in manifest order", () => { @@ -51,7 +51,7 @@ test("installedPackNodePaths lists only packs with an existing node_modules dir, path.join(dataDir, "packs", "ml-runtime", "node_modules"), path.join(dataDir, "packs", "browser-runtime", "node_modules"), ]); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("packMemberInstalled probes installed pack trees with optional node_modules prefix", () => { @@ -83,7 +83,7 @@ test("packMemberInstalled probes installed pack trees with optional node_modules packMemberInstalled("@atjsh/llmlingua-2/package.json", path.join(dataDir, "absent")), false ); - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("manifest and runtime pack lists stay in sync", async () => { diff --git a/tests/unit/paid-model-target-routes-6540.test.ts b/tests/unit/paid-model-target-routes-6540.test.ts index 63e216e84a..5e6181f629 100644 --- a/tests/unit/paid-model-target-routes-6540.test.ts +++ b/tests/unit/paid-model-target-routes-6540.test.ts @@ -12,9 +12,8 @@ const core = await import("../../src/lib/db/core.ts"); const settingsDb = await import("../../src/lib/db/settings.ts"); const settingsRoute = await import("../../src/app/api/settings/route.ts"); const comboDefaultsRoute = await import("../../src/app/api/settings/combo-defaults/route.ts"); -const backgroundDegradationRoute = await import( - "../../src/app/api/settings/background-degradation/route.ts" -); +const backgroundDegradationRoute = + await import("../../src/app/api/settings/background-degradation/route.ts"); // A provider present in the free-model catalog (so providerHasFreeModels is // true) but a model id that is NOT one of its documented free models. @@ -26,7 +25,7 @@ const UNKNOWN_TARGET = "my-combo-alias"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +35,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── PATCH /api/settings — webSearchRouteModel ────────────────────────────── diff --git a/tests/unit/param-filters-db.test.ts b/tests/unit/param-filters-db.test.ts index 2b6f83b77f..71a82aa762 100644 --- a/tests/unit/param-filters-db.test.ts +++ b/tests/unit/param-filters-db.test.ts @@ -24,7 +24,7 @@ const { stripUnsupportedParams } = await import("../../open-sse/translator/param test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/unit/payload-rules-restart-persistence.test.ts b/tests/unit/payload-rules-restart-persistence.test.ts index e08bee0870..b57f0256f2 100644 --- a/tests/unit/payload-rules-restart-persistence.test.ts +++ b/tests/unit/payload-rules-restart-persistence.test.ts @@ -27,7 +27,7 @@ const payloadRulesService = await import("../../open-sse/services/payloadRules.t test.after(() => { payloadRulesService.resetPayloadRulesConfigForTests(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#2986 payload rules survive a restart (DB fallback when override is cleared)", async () => { diff --git a/tests/unit/payload-rules-route.test.ts b/tests/unit/payload-rules-route.test.ts index 9db6cf0117..22b2b44515 100644 --- a/tests/unit/payload-rules-route.test.ts +++ b/tests/unit/payload-rules-route.test.ts @@ -21,7 +21,7 @@ async function resetStorage() { core.resetDbInstance(); payloadRulesService.resetPayloadRulesConfigForTests(); delete process.env.INITIAL_PASSWORD; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +36,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/payload-rules.test.ts b/tests/unit/payload-rules.test.ts index 1e059d4402..df9d40908b 100644 --- a/tests/unit/payload-rules.test.ts +++ b/tests/unit/payload-rules.test.ts @@ -138,5 +138,5 @@ test("payload rules load from JSON file and reload changed content", async () => assert.equal(second.defaultRaw.length, 1); assert.deepEqual(second.defaultRaw[0].params.response_format, { type: "json_object" }); - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/perf-waterfall-elimination.test.ts b/tests/unit/perf-waterfall-elimination.test.ts index 6e235ad245..eeafce4cee 100644 --- a/tests/unit/perf-waterfall-elimination.test.ts +++ b/tests/unit/perf-waterfall-elimination.test.ts @@ -48,9 +48,7 @@ function allPromiseAllBodies(src: string): string[] { test("A1: home page fetches settings + machineId concurrently (#11396)", () => { const src = readSource("src/app/(dashboard)/home/page.tsx"); - const pair = src.match( - /const \[settings, machineId\] = await Promise\.all\(\[([\s\S]*?)\]\);/s - ); + const pair = src.match(/const \[settings, machineId\] = await Promise\.all\(\[([\s\S]*?)\]\);/s); assert.ok(pair, "expected `[settings, machineId] = await Promise.all([...])`"); assert.match(pair![1], /\bgetSettings\(\)/); assert.match(pair![1], /\bgetMachineId\(\)/); @@ -77,10 +75,7 @@ test("F1: cache route GET batches its four async reads (#11396)", () => { assert.match(body, /getCacheTrend\(trendHours\)/); // settings-load failure must degrade to {} *inside* the batch, not reject // the whole Promise.all and 500 the stats endpoint - assert.match( - body, - /getCachedSettings\(\)\.catch\(\s*\(\s*\)\s*=>\s*\(\s*\{\}\s*\)\s*\)/ - ); + assert.match(body, /getCachedSettings\(\)\.catch\(\s*\(\s*\)\s*=>\s*\(\s*\{\}\s*\)\s*\)/); // no serial waterfall remains for the same reads assert.doesNotMatch(src, /await getIdempotencyStats\(\)\s*;/); @@ -102,14 +97,14 @@ test.before(async () => { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core?.resetDbInstance(); if (TEST_DATA_DIR) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } delete process.env.DATA_DIR; delete process.env.DISABLE_SQLITE_AUTO_BACKUP; @@ -147,11 +142,62 @@ test("F1: cache GET returns correct shapes + trend window after batching (#11396 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ); // cache hit (tokens_cache_read > 0) - insert.run("test-provider", "test-model", "conn-1", "key-1", "k", 1000, 100, 900, 0, 0, "ok", 1, 123, 45, null, iso(now - 3_600_000)); + insert.run( + "test-provider", + "test-model", + "conn-1", + "key-1", + "k", + 1000, + 100, + 900, + 0, + 0, + "ok", + 1, + 123, + 45, + null, + iso(now - 3_600_000) + ); // cache creation (tokens_cache_creation > 0) - insert.run("test-provider", "test-model", "conn-2", "key-2", "k", 2000, 200, 0, 1500, 0, "ok", 1, 200, 50, null, iso(now - 7_200_000)); + insert.run( + "test-provider", + "test-model", + "conn-2", + "key-2", + "k", + 2000, + 200, + 0, + 1500, + 0, + "ok", + 1, + 200, + 50, + null, + iso(now - 7_200_000) + ); // plain request — must not pollute cache metrics - insert.run("test-provider", "test-model", "conn-3", "key-3", "k", 500, 50, 0, 0, 0, "ok", 1, 90, 30, null, iso(now - 300_000)); + insert.run( + "test-provider", + "test-model", + "conn-3", + "key-3", + "k", + 500, + 50, + 0, + 0, + 0, + "ok", + 1, + 90, + 30, + null, + iso(now - 300_000) + ); const req = new Request("http://localhost/api/cache?trendHours=48", { method: "GET", @@ -174,7 +220,10 @@ test("F1: cache GET returns correct shapes + trend window after batching (#11396 assert.ok(body.idempotency && typeof body.idempotency === "object"); // trend honors the requested window and carries the seeded rows assert.ok(Array.isArray(body.trend)); - assert.equal(body.trend.reduce((s: number, p: { requests: number }) => s + p.requests, 0), 3); + assert.equal( + body.trend.reduce((s: number, p: { requests: number }) => s + p.requests, 0), + 3 + ); // config reads settings through the batched getCachedSettings(.catch → {}) assert.equal(body.config.semanticCacheEnabled, true); @@ -222,7 +271,11 @@ test("N2: provider deletion cleanup helpers run in parallel (#11396)", () => { const src = readSource("src/lib/db/providers/deletion.ts"); const batches = allPromiseAllBodies(src); - assert.equal(batches.length, 3, "expected 3 Promise.all batches in deletion.ts (one per delete function)"); + assert.equal( + batches.length, + 3, + "expected 3 Promise.all batches in deletion.ts (one per delete function)" + ); for (const batch of batches) { assert.match(batch, /_cleanupDeletedComboConnectionRefs\(/); assert.match(batch, /_cleanupDeletedLKGPConnectionRefs\(/); @@ -239,4 +292,4 @@ test("N2: provider deletion cleanup helpers run in parallel (#11396)", () => { // no serial awaits left behind assert.doesNotMatch(src, /await _cleanupDeletedComboConnectionRefs\(/); assert.doesNotMatch(src, /await _cleanupDeletedLKGPConnectionRefs\(/); -}); \ No newline at end of file +}); diff --git a/tests/unit/persist-429-cooldown-account-fallback.test.ts b/tests/unit/persist-429-cooldown-account-fallback.test.ts index e5fa987a24..82eeab2041 100644 --- a/tests/unit/persist-429-cooldown-account-fallback.test.ts +++ b/tests/unit/persist-429-cooldown-account-fallback.test.ts @@ -1,215 +1,204 @@ -/** - * TDD regression tests for the per-connection 429 cascade DB persistence. - * - * Bug: before this fix, `applyErrorState` (open-sse/services/accountFallback.ts) - * marked a connection rate-limited IN-MEMORY ONLY — the cooldown was forgotten - * when the request ended and `isConnectionRateLimited` (the DB-backed read - * helper) always returned false for non-Antigravity providers. Result: cascade - * failures against a multi-key OpenCode-Go setup retried the same exhausted key - * on the next request and the user saw no "kill for X days" behavior. - * - * After the fix: - * 1. `applyErrorState` with a non-zero cooldown also writes - * `provider_connections.rate_limited_until` via - * `setConnectionRateLimitUntil` (best-effort, never crashes the request). - * 2. `resetAccountState` with a DB id clears that column. - * 3. The localDb re-exports `markConnectionRateLimitedUntil` and - * `clearConnectionRateLimit` for direct use by other consumers - * (e.g. provider-specific executors). - * - * These tests mirror the harness from `antigravity-429-quota-cooldown.test.ts` - * so they share the same DATA_DIR sandbox and DB reset pattern. - */ - -import { test } from "node:test"; -import assert from "node:assert/strict"; -import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-fb-cascade-")); -process.env.DATA_DIR = TEST_DATA_DIR; - -const core = await import("../../src/lib/db/core.ts"); -const providersDb = await import("../../src/lib/db/providers.ts"); - -import { - applyErrorState, - resetAccountState, -} from "../../open-sse/services/accountFallback.ts"; -import { - markConnectionRateLimitedUntil, - clearConnectionRateLimit, -} from "../../src/lib/localDb.ts"; - -test.after(() => { - core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); -}); - -// ── Helpers ──────────────────────────────────────────────────────────────── - -async function makeConnection(provider: string, name: string): Promise { - const conn = await providersDb.createProviderConnection({ - provider, - authType: "api_key", - name, - }); - return (conn as any).id as string; -} - -// ── applyErrorState persistence (Bug Fix A) ──────────────────────────────── - -test("applyErrorState: 429 cascade persists cooldown via setConnectionRateLimitUntil", async () => { - const connId = await makeConnection("opencode-go", "OC-GO Cascade Test"); - - assert.equal( - providersDb.isConnectionRateLimited(connId), - false, - "should start as not rate-limited", - ); - - const before = Date.now(); - applyErrorState( - { id: connId, backoffLevel: 0, status: "active" }, - 429, - "Monthly usage limit reached. Resets in 13 days.", - "opencode-go", - ); - - assert.equal( - providersDb.isConnectionRateLimited(connId), - true, - "should be rate-limited in the DB after applyErrorState with 429", - ); - - const limited = providersDb.getRateLimitedConnections("opencode-go"); - assert.ok( - limited.some((c: any) => c.id === connId), - "should appear in getRateLimitedConnections list for the provider", - ); - - // Sanity: the persisted timestamp is in the future (within reason). - const row = limited.find((c: any) => c.id === connId) as any; - if (row?.rate_limited_until) { - const ts = Number(row.rate_limited_until); - assert.ok( - ts > before, - `cooldown timestamp ${ts} must be > request start ${before}`, - ); - } -}); - -test("applyErrorState: non-429 / non-rateLimit errors do NOT persist a cooldown", async () => { - const connId = await makeConnection("opencode-go", "OC-GO Non-429"); - - // 400 with no rate-limit signals should NOT set a DB cooldown. - applyErrorState( - { id: connId, backoffLevel: 0, status: "active" }, - 400, - "Invalid request body", - "opencode-go", - ); - - assert.equal( - providersDb.isConnectionRateLimited(connId), - false, - "non-rate-limit error should not persist a cooldown", - ); -}); - -test("applyErrorState: account with no `id` does not crash and does not persist", async () => { - // No id field → DB write is skipped. - const result = applyErrorState( - { backoffLevel: 0, status: "active" } as any, - 429, - "rate limit exceeded", - "opencode-go", - ); - - assert.ok(result, "should return a new state object"); - assert.equal((result as any).status, "error"); - assert.ok((result as any).rateLimitedUntil, "in-memory rateLimitedUntil should be set"); -}); - -// ── resetAccountState persistence (Bug Fix A) ────────────────────────────── - -test("resetAccountState clears the persisted cooldown after a success", async () => { - const connId = await makeConnection("opencode-go", "OC-GO Reset Test"); - - // Force the connection into a cooled state. - providersDb.setConnectionRateLimitUntil(connId, Date.now() + 60_000); - assert.equal( - providersDb.isConnectionRateLimited(connId), - true, - "precondition: should be rate-limited after explicit set", - ); - - resetAccountState({ id: connId, backoffLevel: 1, status: "error" }); - - assert.equal( - providersDb.isConnectionRateLimited(connId), - false, - "resetAccountState should clear the persisted cooldown", - ); -}); - -// ── localDb re-exports (Bug Fix F) ────────────────────────────────────────── - -test("localDb.markConnectionRateLimitedUntil: writes cooldown; never throws on bad id", () => { - const connId = "non-existent-id-xxxxx"; - // Must not throw even though the id doesn't exist — DB write failure - // inside the wrapper must never crash the request path. - assert.doesNotThrow(() => - markConnectionRateLimitedUntil(connId, 5_000), - ); -}); - -test("localDb.clearConnectionRateLimit: does not throw on bad id", () => { - const connId = "non-existent-id-xxxxx"; - assert.doesNotThrow(() => clearConnectionRateLimit(connId)); -}); - -test("localDb.markConnectionRateLimitedUntil + clearConnectionRateLimit round-trip", async () => { - const connId = await makeConnection("opencode-go", "OC-GO RoundTrip"); - - markConnectionRateLimitedUntil(connId, 60_000); - assert.equal( - providersDb.isConnectionRateLimited(connId), - true, - "after markConnectionRateLimitedUntil the connection should be limited", - ); - - clearConnectionRateLimit(connId); - assert.equal( - providersDb.isConnectionRateLimited(connId), - false, - "after clearConnectionRateLimit the connection should not be limited", - ); -}); - -// ── Multi-account scenario (the user's exact bug) ─────────────────────────── - -test("multi-key scenario: cooling one OpenCode-Go key does NOT poison other keys", async () => { - const connA = await makeConnection("opencode-go", "OC-GO Key A"); - const connB = await makeConnection("opencode-go", "OC-GO Key B"); - - // Account A hits the monthly quota envelope. - applyErrorState( - { id: connA, backoffLevel: 0, status: "active" }, - 429, - "Monthly usage limit reached. Resets in 13 days.", - "opencode-go", - ); - - assert.equal( - providersDb.isConnectionRateLimited(connA), - true, - "key A should be rate-limited after monthly envelope", - ); - assert.equal( - providersDb.isConnectionRateLimited(connB), - false, - "key B should remain available — scope is per-connection, not per-provider", - ); -}); \ No newline at end of file +/** + * TDD regression tests for the per-connection 429 cascade DB persistence. + * + * Bug: before this fix, `applyErrorState` (open-sse/services/accountFallback.ts) + * marked a connection rate-limited IN-MEMORY ONLY — the cooldown was forgotten + * when the request ended and `isConnectionRateLimited` (the DB-backed read + * helper) always returned false for non-Antigravity providers. Result: cascade + * failures against a multi-key OpenCode-Go setup retried the same exhausted key + * on the next request and the user saw no "kill for X days" behavior. + * + * After the fix: + * 1. `applyErrorState` with a non-zero cooldown also writes + * `provider_connections.rate_limited_until` via + * `setConnectionRateLimitUntil` (best-effort, never crashes the request). + * 2. `resetAccountState` with a DB id clears that column. + * 3. The localDb re-exports `markConnectionRateLimitedUntil` and + * `clearConnectionRateLimit` for direct use by other consumers + * (e.g. provider-specific executors). + * + * These tests mirror the harness from `antigravity-429-quota-cooldown.test.ts` + * so they share the same DATA_DIR sandbox and DB reset pattern. + */ + +import { test } from "node:test"; +import assert from "node:assert/strict"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-fb-cascade-")); +process.env.DATA_DIR = TEST_DATA_DIR; + +const core = await import("../../src/lib/db/core.ts"); +const providersDb = await import("../../src/lib/db/providers.ts"); + +import { applyErrorState, resetAccountState } from "../../open-sse/services/accountFallback.ts"; +import { markConnectionRateLimitedUntil, clearConnectionRateLimit } from "../../src/lib/localDb.ts"; + +test.after(() => { + core.resetDbInstance(); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); + +// ── Helpers ──────────────────────────────────────────────────────────────── + +async function makeConnection(provider: string, name: string): Promise { + const conn = await providersDb.createProviderConnection({ + provider, + authType: "api_key", + name, + }); + return (conn as any).id as string; +} + +// ── applyErrorState persistence (Bug Fix A) ──────────────────────────────── + +test("applyErrorState: 429 cascade persists cooldown via setConnectionRateLimitUntil", async () => { + const connId = await makeConnection("opencode-go", "OC-GO Cascade Test"); + + assert.equal( + providersDb.isConnectionRateLimited(connId), + false, + "should start as not rate-limited" + ); + + const before = Date.now(); + applyErrorState( + { id: connId, backoffLevel: 0, status: "active" }, + 429, + "Monthly usage limit reached. Resets in 13 days.", + "opencode-go" + ); + + assert.equal( + providersDb.isConnectionRateLimited(connId), + true, + "should be rate-limited in the DB after applyErrorState with 429" + ); + + const limited = providersDb.getRateLimitedConnections("opencode-go"); + assert.ok( + limited.some((c: any) => c.id === connId), + "should appear in getRateLimitedConnections list for the provider" + ); + + // Sanity: the persisted timestamp is in the future (within reason). + const row = limited.find((c: any) => c.id === connId) as any; + if (row?.rate_limited_until) { + const ts = Number(row.rate_limited_until); + assert.ok(ts > before, `cooldown timestamp ${ts} must be > request start ${before}`); + } +}); + +test("applyErrorState: non-429 / non-rateLimit errors do NOT persist a cooldown", async () => { + const connId = await makeConnection("opencode-go", "OC-GO Non-429"); + + // 400 with no rate-limit signals should NOT set a DB cooldown. + applyErrorState( + { id: connId, backoffLevel: 0, status: "active" }, + 400, + "Invalid request body", + "opencode-go" + ); + + assert.equal( + providersDb.isConnectionRateLimited(connId), + false, + "non-rate-limit error should not persist a cooldown" + ); +}); + +test("applyErrorState: account with no `id` does not crash and does not persist", async () => { + // No id field → DB write is skipped. + const result = applyErrorState( + { backoffLevel: 0, status: "active" } as any, + 429, + "rate limit exceeded", + "opencode-go" + ); + + assert.ok(result, "should return a new state object"); + assert.equal((result as any).status, "error"); + assert.ok((result as any).rateLimitedUntil, "in-memory rateLimitedUntil should be set"); +}); + +// ── resetAccountState persistence (Bug Fix A) ────────────────────────────── + +test("resetAccountState clears the persisted cooldown after a success", async () => { + const connId = await makeConnection("opencode-go", "OC-GO Reset Test"); + + // Force the connection into a cooled state. + providersDb.setConnectionRateLimitUntil(connId, Date.now() + 60_000); + assert.equal( + providersDb.isConnectionRateLimited(connId), + true, + "precondition: should be rate-limited after explicit set" + ); + + resetAccountState({ id: connId, backoffLevel: 1, status: "error" }); + + assert.equal( + providersDb.isConnectionRateLimited(connId), + false, + "resetAccountState should clear the persisted cooldown" + ); +}); + +// ── localDb re-exports (Bug Fix F) ────────────────────────────────────────── + +test("localDb.markConnectionRateLimitedUntil: writes cooldown; never throws on bad id", () => { + const connId = "non-existent-id-xxxxx"; + // Must not throw even though the id doesn't exist — DB write failure + // inside the wrapper must never crash the request path. + assert.doesNotThrow(() => markConnectionRateLimitedUntil(connId, 5_000)); +}); + +test("localDb.clearConnectionRateLimit: does not throw on bad id", () => { + const connId = "non-existent-id-xxxxx"; + assert.doesNotThrow(() => clearConnectionRateLimit(connId)); +}); + +test("localDb.markConnectionRateLimitedUntil + clearConnectionRateLimit round-trip", async () => { + const connId = await makeConnection("opencode-go", "OC-GO RoundTrip"); + + markConnectionRateLimitedUntil(connId, 60_000); + assert.equal( + providersDb.isConnectionRateLimited(connId), + true, + "after markConnectionRateLimitedUntil the connection should be limited" + ); + + clearConnectionRateLimit(connId); + assert.equal( + providersDb.isConnectionRateLimited(connId), + false, + "after clearConnectionRateLimit the connection should not be limited" + ); +}); + +// ── Multi-account scenario (the user's exact bug) ─────────────────────────── + +test("multi-key scenario: cooling one OpenCode-Go key does NOT poison other keys", async () => { + const connA = await makeConnection("opencode-go", "OC-GO Key A"); + const connB = await makeConnection("opencode-go", "OC-GO Key B"); + + // Account A hits the monthly quota envelope. + applyErrorState( + { id: connA, backoffLevel: 0, status: "active" }, + 429, + "Monthly usage limit reached. Resets in 13 days.", + "opencode-go" + ); + + assert.equal( + providersDb.isConnectionRateLimited(connA), + true, + "key A should be rate-limited after monthly envelope" + ); + assert.equal( + providersDb.isConnectionRateLimited(connB), + false, + "key B should remain available — scope is per-connection, not per-provider" + ); +}); diff --git a/tests/unit/pick-internal-api-key-6372.test.ts b/tests/unit/pick-internal-api-key-6372.test.ts index 483235feec..569f7879e6 100644 --- a/tests/unit/pick-internal-api-key-6372.test.ts +++ b/tests/unit/pick-internal-api-key-6372.test.ts @@ -19,14 +19,14 @@ const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); function reset() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(() => reset()); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6372: returns null when there are no keys", async () => { diff --git a/tests/unit/piiReproduction.test.ts b/tests/unit/piiReproduction.test.ts index a1c984b911..7c1d56bb76 100644 --- a/tests/unit/piiReproduction.test.ts +++ b/tests/unit/piiReproduction.test.ts @@ -15,11 +15,11 @@ import { sanitizePII } from "../../src/lib/piiSanitizer"; test("PII Reproduction Tests", async (t) => { // Setup overrides for tests const originalEnv = process.env; - process.env = { + process.env = { ...originalEnv, PII_RESPONSE_SANITIZATION: "true", PII_RESPONSE_SANITIZATION_MODE: "redact", - PII_TEST_BYPASS_MIN_WINDOW: "true" + PII_TEST_BYPASS_MIN_WINDOW: "true", }; await t.test("THEORY-001: Infinite Streaming Buffer Accumulation", async () => { @@ -30,25 +30,32 @@ test("PII Reproduction Tests", async (t) => { // Collect all output via pipeTo (non-blocking, handles lifecycle properly) const chunks: Uint8Array[] = []; const collector = new WritableStream({ - write(chunk) { chunks.push(chunk); } + write(chunk) { + chunks.push(chunk); + }, }); const pipePromise = transform.readable.pipeTo(collector); // Write 50 alphanumeric characters starting with "sk-" const piiText = "sk-123456789012345678901234567890123456789012345678"; // 51 chars - await writer.write(encoder.encode(`data: ${JSON.stringify({ choices: [{ delta: { content: piiText } }] })}\n`)); + await writer.write( + encoder.encode(`data: ${JSON.stringify({ choices: [{ delta: { content: piiText } }] })}\n`) + ); // Wait a bit — if the buffer is withheld (W=10, PII window), nothing should be emitted yet await new Promise((r) => setTimeout(r, 150)); - const preCloseOutput = chunks.map(c => new TextDecoder().decode(c)).join(""); - assert.ok(!preCloseOutput.includes("[API_KEY_REDACTED]"), "Nothing should be emitted before close because buffer is indefinitely withheld"); + const preCloseOutput = chunks.map((c) => new TextDecoder().decode(c)).join(""); + assert.ok( + !preCloseOutput.includes("[API_KEY_REDACTED]"), + "Nothing should be emitted before close because buffer is indefinitely withheld" + ); // Close the writer — this triggers flush which emits the redacted output await writer.close(); await pipePromise; - const decoded = chunks.map(c => new TextDecoder().decode(c)).join(""); + const decoded = chunks.map((c) => new TextDecoder().decode(c)).join(""); assert.ok(decoded.includes("[API_KEY_REDACTED]"), "Flushed output should be redacted"); }); @@ -61,8 +68,16 @@ test("PII Reproduction Tests", async (t) => { const resultSoftHyphen = sanitizePII(keyWithSoftHyphen); // Sanitizer now correctly catches unicode-obfuscated keys - assert.strictEqual(resultWordJoiner.text, "[API_KEY_REDACTED]", "API Key with Word Joiner is now correctly redacted"); - assert.strictEqual(resultSoftHyphen.text, "[API_KEY_REDACTED]", "API Key with Soft Hyphen is now correctly redacted"); + assert.strictEqual( + resultWordJoiner.text, + "[API_KEY_REDACTED]", + "API Key with Word Joiner is now correctly redacted" + ); + assert.strictEqual( + resultSoftHyphen.text, + "[API_KEY_REDACTED]", + "API Key with Soft Hyphen is now correctly redacted" + ); // 2. IPv6 lookbehind/lookahead issues // xyz::1 (preceded by non-hex alphabetic characters) should NOT be redacted @@ -71,11 +86,19 @@ test("PII Reproduction Tests", async (t) => { // abc::1 (preceded by valid hex characters) is a valid compressed IPv6 address and should be redacted const resultIpv6ValidCompressed = sanitizePII("abc::1"); - assert.strictEqual(resultIpv6ValidCompressed.text, "[IP_REDACTED]", "abc::1 should be redacted as a valid compressed IP"); + assert.strictEqual( + resultIpv6ValidCompressed.text, + "[IP_REDACTED]", + "abc::1 should be redacted as a valid compressed IP" + ); // Invalid IPv6 followed by letters should NOT be redacted const resultIpv6Lookahead = sanitizePII("2001:db8:3333:4444:5555:6666:7777:8888abcd"); - assert.strictEqual(resultIpv6Lookahead.text, "2001:db8:3333:4444:5555:6666:7777:8888abcd", "Invalid IPv6 with trailing characters should not be redacted"); + assert.strictEqual( + resultIpv6Lookahead.text, + "2001:db8:3333:4444:5555:6666:7777:8888abcd", + "Invalid IPv6 with trailing characters should not be redacted" + ); // Valid IPv6 is correctly redacted const resultIpv6Valid = sanitizePII("2001:db8:3333:4444:5555:6666:7777:8888"); @@ -86,7 +109,11 @@ test("PII Reproduction Tests", async (t) => { // 16-digit database ID/Snowflake ID — no longer falsely flagged as credit card const snowflakeId = "1234567890123456"; const resultCc = sanitizePII(snowflakeId); - assert.strictEqual(resultCc.text, snowflakeId, "16-digit numeric identifier should not be redacted as Credit Card"); + assert.strictEqual( + resultCc.text, + snowflakeId, + "16-digit numeric identifier should not be redacted as Credit Card" + ); // 11-digit database ID — now caught as phone number by sanitizer const dbId11 = "12345678901"; @@ -101,25 +128,39 @@ test("PII Reproduction Tests", async (t) => { const transformA = createPiiSseTransform({ windowSize: 10 }); const writerA = transformA.writable.getWriter(); const chunksA: Uint8Array[] = []; - const collectorA = new WritableStream({ write(chunk) { chunksA.push(chunk); } }); + const collectorA = new WritableStream({ + write(chunk) { + chunksA.push(chunk); + }, + }); const pipeA = transformA.readable.pipeTo(collectorA); await writerA.write(encoder.encode("data: Hello world\n")); await writerA.close(); await pipeA; - const outputA = chunksA.map(c => new TextDecoder().decode(c)).join(""); + const outputA = chunksA.map((c) => new TextDecoder().decode(c)).join(""); // Bug (fixed by #3021): raw-text SSE was being wrapped in an OpenAI JSON envelope on flush. // After the fix, raw text passes through as raw text — the envelope must NOT appear. - assert.ok(!outputA.includes('{"choices":'), "Scenario A: raw text must NOT be wrapped in a JSON choices envelope"); + assert.ok( + !outputA.includes('{"choices":'), + "Scenario A: raw text must NOT be wrapped in a JSON choices envelope" + ); // The content must still be present in the output (not silently dropped) - assert.ok(outputA.includes("Hello world") || outputA.length > "data: \n".length, "Scenario A: raw text content must not be silently dropped"); + assert.ok( + outputA.includes("Hello world") || outputA.length > "data: \n".length, + "Scenario A: raw text content must not be silently dropped" + ); // Scenario B: Non-standard JSON stream — use pipeTo const transformB = createPiiSseTransform({ windowSize: 10 }); const writerB = transformB.writable.getWriter(); const chunksB: Uint8Array[] = []; - const collectorB = new WritableStream({ write(chunk) { chunksB.push(chunk); } }); + const collectorB = new WritableStream({ + write(chunk) { + chunksB.push(chunk); + }, + }); const pipeB = transformB.readable.pipeTo(collectorB); await writerB.write(encoder.encode('data: {"msg": "Hello world"}\n')); @@ -127,15 +168,18 @@ test("PII Reproduction Tests", async (t) => { await writerB.close(); await pipeB; - const outputB = chunksB.map(c => new TextDecoder().decode(c)).join(""); + const outputB = chunksB.map((c) => new TextDecoder().decode(c)).join(""); // Bug (fixed by #3021): buffered content was permanently lost when the stop signal had no string fields. // After the fix, the content is emitted (possibly split across chunks due to the PII window). // Verify the content is present — "H" from first window emit + "ello world" from flush. - assert.ok(outputB.includes('"H"') && outputB.includes("ello world"), "Scenario B: buffered content must not be lost — expect window-split output containing both parts"); + assert.ok( + outputB.includes('"H"') && outputB.includes("ello world"), + "Scenario B: buffered content must not be lost — expect window-split output containing both parts" + ); }); }); test.after(() => { resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/piiSanitizer.test.ts b/tests/unit/piiSanitizer.test.ts index 8a035b358d..042ad5c45a 100644 --- a/tests/unit/piiSanitizer.test.ts +++ b/tests/unit/piiSanitizer.test.ts @@ -96,7 +96,7 @@ test("sanitizePII checks resolveFeatureFlag, not process.env", async (t) => { test.after(async () => { const coreDb = await import("@/lib/db/core"); coreDb.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getMode returns redact for invalid flag values", async () => { diff --git a/tests/unit/piiSanitizerIpv6.test.ts b/tests/unit/piiSanitizerIpv6.test.ts index 03fdb4c353..272319c9da 100644 --- a/tests/unit/piiSanitizerIpv6.test.ts +++ b/tests/unit/piiSanitizerIpv6.test.ts @@ -129,7 +129,11 @@ test("IPv6 followed by colon-hex suffix is NOT redacted (lookahead guard)", () = // being carved out of a longer colon-separated sequence. const text = "1:2:3:4:5:6:7:8:extra"; const result = sanitizePII(text); - assert.strictEqual(result.text, text, "8-segment prefix of a longer colon sequence should not be redacted"); + assert.strictEqual( + result.text, + text, + "8-segment prefix of a longer colon sequence should not be redacted" + ); }); test("IPv6 xyz::1 (non-hex prefix) is NOT redacted", () => { @@ -141,7 +145,10 @@ test("IPv6 xyz::1 (non-hex prefix) is NOT redacted", () => { test("IPv6 abc::1 (valid hex prefix) IS redacted", () => { // a, b, c are valid hex digits, so abc::1 is a valid compressed IPv6 address. const result = sanitizePII("abc::1"); - assert.ok(result.text.includes("[IP_REDACTED]"), "abc::1 should be redacted as valid compressed IPv6"); + assert.ok( + result.text.includes("[IP_REDACTED]"), + "abc::1 should be redacted as valid compressed IPv6" + ); }); test("IPv6 full 8-segment with trailing alphanumeric is NOT redacted", () => { @@ -149,7 +156,11 @@ test("IPv6 full 8-segment with trailing alphanumeric is NOT redacted", () => { // a letter/digit (8888abcd). const text = "2001:db8:3333:4444:5555:6666:7777:8888abcd"; const result = sanitizePII(text); - assert.strictEqual(result.text, text, "8-segment address with trailing alnum should not be redacted"); + assert.strictEqual( + result.text, + text, + "8-segment address with trailing alnum should not be redacted" + ); }); test("multiple IPv6 addresses in the same string are all redacted", () => { @@ -174,9 +185,11 @@ test("IPv6 address inside SSE JSON content is redacted end-to-end", async () => const encoder = new TextEncoder(); const writePromise = (async () => { - await writer.write(encoder.encode( - `data: {"choices":[{"delta":{"content":"server is at 2001:db8:3333:4444:5555:6666:7777:8888"}}]}\n\n` - )); + await writer.write( + encoder.encode( + `data: {"choices":[{"delta":{"content":"server is at 2001:db8:3333:4444:5555:6666:7777:8888"}}]}\n\n` + ) + ); await writer.write(encoder.encode(`data: [DONE]\n\n`)); await writer.close(); })(); @@ -190,13 +203,17 @@ test("IPv6 address inside SSE JSON content is redacted end-to-end", async () => await writePromise; const output = chunks.join(""); - assert.ok(!output.includes("2001:db8:3333:4444:5555:6666:7777:8888"), - "full IPv6 address in SSE stream should be redacted"); - assert.ok(output.includes("[IP_REDACTED]"), - "redaction marker should appear in SSE stream output"); + assert.ok( + !output.includes("2001:db8:3333:4444:5555:6666:7777:8888"), + "full IPv6 address in SSE stream should be redacted" + ); + assert.ok( + output.includes("[IP_REDACTED]"), + "redaction marker should appear in SSE stream output" + ); }); test.after(() => { resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); -}); \ No newline at end of file + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); diff --git a/tests/unit/playground-key-policy-3503.test.ts b/tests/unit/playground-key-policy-3503.test.ts index fd6a87850c..67263d8444 100644 --- a/tests/unit/playground-key-policy-3503.test.ts +++ b/tests/unit/playground-key-policy-3503.test.ts @@ -48,14 +48,18 @@ function req(headers: Record) { } test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#3503 — authenticated session + key-id header resolves the key secret server-side", async () => { const out = await resolvePlaygroundTestKey( req({ [PLAYGROUND_KEY_ID_HEADER]: KEY_ID, cookie: await sessionCookie() }) ); - assert.equal(out, KEY_SECRET, "an authenticated session should resolve the selected key's secret by id"); + assert.equal( + out, + KEY_SECRET, + "an authenticated session should resolve the selected key's secret by id" + ); }); test("#3503 — SECURITY: the key-id header is IGNORED without an authenticated session", async () => { diff --git a/tests/unit/playground-simulate-route-persisted-combo.test.ts b/tests/unit/playground-simulate-route-persisted-combo.test.ts index 311ee55f9f..02e2c61f12 100644 --- a/tests/unit/playground-simulate-route-persisted-combo.test.ts +++ b/tests/unit/playground-simulate-route-persisted-combo.test.ts @@ -16,7 +16,7 @@ let persistedComboId: string; test.beforeEach(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); await providersDb.createProviderConnection({ provider: "cc", @@ -42,7 +42,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function request(body: unknown): Request { @@ -76,9 +76,7 @@ test("simulates persisted combo model steps in order", async () => { // #11822 follow-up: combo-ref steps now get a specific warning naming the // referenced combo instead of folding into the generic "unsupported step" // count (that count is reserved for genuinely unrecognized step shapes). - assert.ok( - body.warnings.some((warning: string) => warning.includes('combo "nested combo"')) - ); + assert.ok(body.warnings.some((warning: string) => warning.includes('combo "nested combo"'))); assert.ok(body.warnings.every((warning: string) => !warning.includes("not configured"))); }); @@ -104,7 +102,9 @@ test("surfaces a provider-wildcard step as an unresolved target with a specific ] ); assert.ok( - body.warnings.some((warning: string) => warning.includes("groq/llama-*") && warning.includes("wildcard")) + body.warnings.some( + (warning: string) => warning.includes("groq/llama-*") && warning.includes("wildcard") + ) ); }); diff --git a/tests/unit/plugins-config-route.test.ts b/tests/unit/plugins-config-route.test.ts index 0b90bb65b3..428b47c47d 100644 --- a/tests/unit/plugins-config-route.test.ts +++ b/tests/unit/plugins-config-route.test.ts @@ -46,13 +46,19 @@ function validateConfig( return { valid: false, error: `Config key '${key}' must be a ${def.type}` }; } if (def.enum && !(def.enum as unknown[]).includes(val)) { - return { valid: false, error: `Config key '${key}' must be one of: ${(def.enum as string[]).join(", ")}` }; + return { + valid: false, + error: `Config key '${key}' must be one of: ${(def.enum as string[]).join(", ")}`, + }; } if (def.min !== undefined) { const limit = def.min; const size = typeof val === "string" ? val.length : typeof val === "number" ? val : undefined; if (size !== undefined && size < limit) { - return { valid: false, error: `Config key '${key}' must be at least ${limit}${typeof val === "string" ? " characters" : ""}` }; + return { + valid: false, + error: `Config key '${key}' must be at least ${limit}${typeof val === "string" ? " characters" : ""}`, + }; } } if (def.max !== undefined && typeof val === "number" && val > def.max) { @@ -66,13 +72,15 @@ function validateConfig( test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); // ── Test schema ── @@ -126,7 +134,9 @@ test("PUT: updates config via updatePluginConfig", () => { configSchema: testSchema, }); - const success = dbPlugins.updatePluginConfig("config-put-test", { apiUrl: "https://new.api.com" }); + const success = dbPlugins.updatePluginConfig("config-put-test", { + apiUrl: "https://new.api.com", + }); assert.ok(success); const plugin = dbPlugins.getPluginByName("config-put-test"); diff --git a/tests/unit/plugins-dev-mode.test.ts b/tests/unit/plugins-dev-mode.test.ts index 2795930c3a..dffb7b960c 100644 --- a/tests/unit/plugins-dev-mode.test.ts +++ b/tests/unit/plugins-dev-mode.test.ts @@ -10,13 +10,17 @@ describe("devMode", () => { afterEach(() => { stopDevMode(); - try { rmSync(testDir, { recursive: true, force: true }); } catch {} + try { + rmSync(testDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); it("startDevMode creates watcher without throwing", () => { mkdirSync(testDir, { recursive: true }); let reloadCalled = false; - startDevMode(testDir, async () => { reloadCalled = true; }); + startDevMode(testDir, async () => { + reloadCalled = true; + }); // Watcher is active — no crash assert.ok(true); }); diff --git a/tests/unit/plugins-doctor.test.ts b/tests/unit/plugins-doctor.test.ts index 3f2dd5d4c9..1c3b2e0e03 100644 --- a/tests/unit/plugins-doctor.test.ts +++ b/tests/unit/plugins-doctor.test.ts @@ -21,13 +21,20 @@ describe("runPluginDoctor", () => { }); afterEach(() => { - try { rmSync(testDir, { recursive: true, force: true }); } catch {} + try { + rmSync(testDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); it("healthy plugin with valid manifest and entry point", async () => { - writeFileSync(join(pluginDir, "plugin.json"), JSON.stringify({ - name: "test-plugin", version: "1.0.0", main: "index.js", - })); + writeFileSync( + join(pluginDir, "plugin.json"), + JSON.stringify({ + name: "test-plugin", + version: "1.0.0", + main: "index.js", + }) + ); writeFileSync(join(pluginDir, "index.js"), "export default {}"); const result = await runPluginDoctor(pluginDir, "test-plugin"); // Plugin not in DB → db_status_correct is "warn" → overall "degraded" @@ -48,17 +55,27 @@ describe("runPluginDoctor", () => { }); it("reports missing entry point", async () => { - writeFileSync(join(pluginDir, "plugin.json"), JSON.stringify({ - name: "no-entry", version: "1.0.0", main: "index.js", - })); + writeFileSync( + join(pluginDir, "plugin.json"), + JSON.stringify({ + name: "no-entry", + version: "1.0.0", + main: "index.js", + }) + ); const result = await runPluginDoctor(pluginDir, "no-entry"); assert.ok(result.checks.some((c) => c.name === "entry_point_exists" && c.status === "fail")); }); it("degraded when only warnings", async () => { - writeFileSync(join(pluginDir, "plugin.json"), JSON.stringify({ - name: "warn-plugin", version: "1.0.0", main: "index.ts", - })); + writeFileSync( + join(pluginDir, "plugin.json"), + JSON.stringify({ + name: "warn-plugin", + version: "1.0.0", + main: "index.ts", + }) + ); writeFileSync(join(pluginDir, "index.ts"), "export default {}"); const result = await runPluginDoctor(pluginDir, "warn-plugin"); // .ts extension should produce a warn on can_spawn diff --git a/tests/unit/plugins-edge-cases.test.ts b/tests/unit/plugins-edge-cases.test.ts index a76383c3ab..6074e23156 100644 --- a/tests/unit/plugins-edge-cases.test.ts +++ b/tests/unit/plugins-edge-cases.test.ts @@ -15,20 +15,16 @@ const core = await import("../../src/lib/db/core.ts"); const dbPlugins = await import("../../src/lib/db/plugins.ts"); const { scanPluginDir } = await import("../../src/lib/plugins/scanner.ts"); const { pluginManager } = await import("../../src/lib/plugins/manager.ts"); -const { - registerHook, - unregisterHooks, - emitHook, - emitHookBlocking, - resetHooks, - getHooks, -} = await import("../../src/lib/plugins/hooks.ts"); +const { registerHook, unregisterHooks, emitHook, emitHookBlocking, resetHooks, getHooks } = + await import("../../src/lib/plugins/hooks.ts"); const activeSourceDirs: string[] = []; function cleanupSourceDirs() { for (const dir of activeSourceDirs) { - try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} } activeSourceDirs.length = 0; } @@ -65,10 +61,14 @@ function writeTestPlugin(opts: { let indexJs = opts.indexJs; if (!indexJs) { const handlers: string[] = []; - if (opts.onRequest) handlers.push(`onRequest: function(ctx) { ctx.metadata = ctx.metadata || {}; ctx.metadata.hookCalled = true; }`); + if (opts.onRequest) + handlers.push( + `onRequest: function(ctx) { ctx.metadata = ctx.metadata || {}; ctx.metadata.hookCalled = true; }` + ); if (opts.onResponse) handlers.push(`onResponse: function(ctx, resp) { return resp; }`); if (opts.onError) handlers.push(`onError: function(ctx, err) {}`); - indexJs = handlers.length > 0 ? `module.exports = { ${handlers.join(", ")} };` : `module.exports = {};`; + indexJs = + handlers.length > 0 ? `module.exports = { ${handlers.join(", ")} };` : `module.exports = {};`; } fs.writeFileSync(path.join(pluginDir, "index.js"), indexJs); @@ -94,7 +94,7 @@ test.beforeEach(() => { // Production DB may not have the plugins table — ignore; fresh DB created below. } resetHooks(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); cleanupSourceDirs(); }); @@ -102,7 +102,9 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); cleanupSourceDirs(); - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); // ══════════════════════════════════════════ @@ -141,7 +143,9 @@ test("scanner: invalid JSON manifest reports error", async () => { const result = await scanPluginDir(badDir); assert.equal(result.plugins.length, 0); assert.equal(result.errors.length, 1); - assert.ok(result.errors[0].error.includes("invalid manifest") || result.errors[0].error.includes("JSON")); + assert.ok( + result.errors[0].error.includes("invalid manifest") || result.errors[0].error.includes("JSON") + ); }); test("scanner: missing required fields reports error", async () => { @@ -192,7 +196,9 @@ test("manager: install with null bytes in path throws", async () => { () => pluginManager.install("/tmp/test\0malicious"), (err: Error) => { assert.ok( - err.message.includes("Invalid") || err.message.includes("null") || err.message.includes("No valid plugin found"), + err.message.includes("Invalid") || + err.message.includes("null") || + err.message.includes("No valid plugin found"), `Unexpected error: ${err.message}` ); return true; @@ -204,10 +210,7 @@ test("manager: double install same plugin throws", async () => { const { sourceDir, name } = writeTestPlugin({ name: "double-install" }); await pluginManager.install(sourceDir); - await assert.rejects( - () => pluginManager.install(sourceDir), - /already installed/ - ); + await assert.rejects(() => pluginManager.install(sourceDir), /already installed/); await pluginManager.uninstall(name); }); @@ -256,7 +259,10 @@ test("manager: activate registers hooks from manifest", async () => { assert.ok(getHooks("onRequest").find((r) => r.pluginName === name)); assert.ok(getHooks("onResponse").find((r) => r.pluginName === name)); - assert.equal(getHooks("onError").find((r) => r.pluginName === name), undefined); + assert.equal( + getHooks("onError").find((r) => r.pluginName === name), + undefined + ); await pluginManager.uninstall(name); }); @@ -278,9 +284,18 @@ test("manager: deactivate unregisters all hooks", async () => { await pluginManager.deactivate(name); - assert.equal(getHooks("onRequest").find((r) => r.pluginName === name), undefined); - assert.equal(getHooks("onResponse").find((r) => r.pluginName === name), undefined); - assert.equal(getHooks("onError").find((r) => r.pluginName === name), undefined); + assert.equal( + getHooks("onRequest").find((r) => r.pluginName === name), + undefined + ); + assert.equal( + getHooks("onResponse").find((r) => r.pluginName === name), + undefined + ); + assert.equal( + getHooks("onError").find((r) => r.pluginName === name), + undefined + ); await pluginManager.uninstall(name); }); @@ -297,9 +312,30 @@ test("hooks: emitHookBlocking with no handlers returns empty body", async () => test("hooks: multiple plugins on same event fire in priority order", async () => { const order: string[] = []; - registerHook("onRequest", "low", () => { order.push("low"); }, 200); - registerHook("onRequest", "high", () => { order.push("high"); }, 10); - registerHook("onRequest", "mid", () => { order.push("mid"); }, 100); + registerHook( + "onRequest", + "low", + () => { + order.push("low"); + }, + 200 + ); + registerHook( + "onRequest", + "high", + () => { + order.push("high"); + }, + 10 + ); + registerHook( + "onRequest", + "mid", + () => { + order.push("mid"); + }, + 100 + ); await emitHookBlocking("onRequest", { body: {}, metadata: {} }); assert.deepEqual(order, ["high", "mid", "low"]); @@ -312,7 +348,9 @@ test("hooks: handler that returns undefined does not modify payload", async () = }); test("hooks: handler error in emitHookBlocking stops chain", async () => { - registerHook("onRequest", "bad", () => { throw new Error("handler error"); }); + registerHook("onRequest", "bad", () => { + throw new Error("handler error"); + }); registerHook("onRequest", "good", () => ({ metadata: { from: "good" } })); // emitHookBlocking should handle the error gracefully @@ -383,8 +421,22 @@ test("db: updatePluginConfig replaces existing config", () => { }); test("db: listPlugins with no status returns all", () => { - dbPlugins.insertPlugin({ id: "p1", name: "alpha", version: "1.0.0", main: "index.js", pluginDir: "/tmp/a", manifest: {} }); - dbPlugins.insertPlugin({ id: "p2", name: "beta", version: "1.0.0", main: "index.js", pluginDir: "/tmp/b", manifest: {} }); + dbPlugins.insertPlugin({ + id: "p1", + name: "alpha", + version: "1.0.0", + main: "index.js", + pluginDir: "/tmp/a", + manifest: {}, + }); + dbPlugins.insertPlugin({ + id: "p2", + name: "beta", + version: "1.0.0", + main: "index.js", + pluginDir: "/tmp/b", + manifest: {}, + }); const all = dbPlugins.listPlugins(); assert.equal(all.length, 2); @@ -394,8 +446,22 @@ test("db: listPlugins with no status returns all", () => { }); test("db: listPlugins with status filters correctly", () => { - dbPlugins.insertPlugin({ id: "f1", name: "installed-filter", version: "1.0.0", main: "index.js", pluginDir: "/tmp/f1", manifest: {} }); - dbPlugins.insertPlugin({ id: "f2", name: "active-filter", version: "1.0.0", main: "index.js", pluginDir: "/tmp/f2", manifest: {} }); + dbPlugins.insertPlugin({ + id: "f1", + name: "installed-filter", + version: "1.0.0", + main: "index.js", + pluginDir: "/tmp/f1", + manifest: {}, + }); + dbPlugins.insertPlugin({ + id: "f2", + name: "active-filter", + version: "1.0.0", + main: "index.js", + pluginDir: "/tmp/f2", + manifest: {}, + }); dbPlugins.updatePluginStatus("active-filter", "active"); const installed = dbPlugins.listPlugins("installed"); @@ -408,14 +474,28 @@ test("db: listPlugins with status filters correctly", () => { }); test("db: pluginExists returns true/false correctly", () => { - dbPlugins.insertPlugin({ id: "exists-test", name: "exists-test", version: "1.0.0", main: "index.js", pluginDir: "/tmp/e", manifest: {} }); + dbPlugins.insertPlugin({ + id: "exists-test", + name: "exists-test", + version: "1.0.0", + main: "index.js", + pluginDir: "/tmp/e", + manifest: {}, + }); assert.equal(dbPlugins.pluginExists("exists-test"), true); assert.equal(dbPlugins.pluginExists("nope"), false); }); test("db: deletePlugin returns true when plugin exists, false when not", () => { - dbPlugins.insertPlugin({ id: "del-test", name: "del-test", version: "1.0.0", main: "index.js", pluginDir: "/tmp/d", manifest: {} }); + dbPlugins.insertPlugin({ + id: "del-test", + name: "del-test", + version: "1.0.0", + main: "index.js", + pluginDir: "/tmp/d", + manifest: {}, + }); assert.equal(dbPlugins.deletePlugin("del-test"), true); assert.equal(dbPlugins.deletePlugin("del-test"), false); diff --git a/tests/unit/plugins-fs-safety.test.ts b/tests/unit/plugins-fs-safety.test.ts index 2e2d695fb0..f574f15971 100644 --- a/tests/unit/plugins-fs-safety.test.ts +++ b/tests/unit/plugins-fs-safety.test.ts @@ -34,10 +34,7 @@ const managerSource = readFileSync( pathResolve(process.cwd(), "src/lib/plugins/manager.ts"), "utf-8" ); -const loaderSource = readFileSync( - pathResolve(process.cwd(), "src/lib/plugins/loader.ts"), - "utf-8" -); +const loaderSource = readFileSync(pathResolve(process.cwd(), "src/lib/plugins/loader.ts"), "utf-8"); // ── Fixture helpers ─────────────────────────────────────────────────────────── @@ -74,7 +71,8 @@ function writePluginWithMain(opts: { ); // Write the main file only for safe relative paths - const shouldWrite = opts.writeMainFile !== false && !opts.main.startsWith("..") && !path.isAbsolute(opts.main); + const shouldWrite = + opts.writeMainFile !== false && !opts.main.startsWith("..") && !path.isAbsolute(opts.main); if (shouldWrite) { const mainAbs = path.join(sourceDir, opts.main); fs.mkdirSync(path.dirname(mainAbs), { recursive: true }); @@ -110,14 +108,19 @@ function cleanInstalledPluginDirs() { // Remove final dir and any staging remnants const base = path.join(DEFAULT_PLUGIN_DIR, name); try { - fs.rmSync(base, { recursive: true, force: true }); + fs.rmSync(base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} // Also clean any .staging-* leftovers if (fs.existsSync(DEFAULT_PLUGIN_DIR)) { for (const entry of fs.readdirSync(DEFAULT_PLUGIN_DIR)) { if (entry.startsWith(`${name}.staging-`)) { try { - fs.rmSync(path.join(DEFAULT_PLUGIN_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(DEFAULT_PLUGIN_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } catch {} } } @@ -128,7 +131,7 @@ function cleanInstalledPluginDirs() { function cleanSourceDirs() { for (const d of activeDirs) { try { - fs.rmSync(d, { recursive: true, force: true }); + fs.rmSync(d, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} } activeDirs.length = 0; @@ -137,7 +140,7 @@ function cleanSourceDirs() { test.beforeEach(() => { core.resetDbInstance(); hooks.resetHooks(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); cleanSourceDirs(); cleanInstalledPluginDirs(); @@ -148,7 +151,7 @@ test.after(() => { cleanSourceDirs(); cleanInstalledPluginDirs(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} }); @@ -306,7 +309,8 @@ test("source: assertWithinPluginDir is called before rm in uninstall", () => { // Get the slice from uninstall through the next method const afterUninstall = managerSource.slice(uninstallIdx); const nextMethodIdx = afterUninstall.indexOf("\n async ", 10); - const uninstallBody = nextMethodIdx !== -1 ? afterUninstall.slice(0, nextMethodIdx) : afterUninstall; + const uninstallBody = + nextMethodIdx !== -1 ? afterUninstall.slice(0, nextMethodIdx) : afterUninstall; const guardIdx = uninstallBody.indexOf("assertWithinPluginDir"); const rmIdx = uninstallBody.indexOf("await rm("); @@ -342,7 +346,9 @@ test("source: assertWithinPluginDir throws for path outside pluginDir", () => { // resolve("/tmp/evil") is not fine when root is "/plugins". // Since we can't easily import the unexported helper, verify it uses resolve + sep. assert.ok( - managerSource.includes('resolve(pluginRoot)') || managerSource.includes('resolve(this_pluginDir)') || managerSource.includes('resolve('), + managerSource.includes("resolve(pluginRoot)") || + managerSource.includes("resolve(this_pluginDir)") || + managerSource.includes("resolve("), "assertWithinPluginDir must call resolve()" ); assert.ok( diff --git a/tests/unit/plugins-loader.test.ts b/tests/unit/plugins-loader.test.ts index 90b5c6ed48..c7211c69ac 100644 --- a/tests/unit/plugins-loader.test.ts +++ b/tests/unit/plugins-loader.test.ts @@ -88,7 +88,7 @@ test( t.after(async () => { loaded?.cleanup(); - await rm(pluginDir, { recursive: true, force: true }); + await rm(pluginDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); await writeFile( @@ -148,7 +148,7 @@ test( t.after(async () => { loaded?.cleanup(); - await rm(pluginDir, { recursive: true, force: true }); + await rm(pluginDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); await writeFile( @@ -224,8 +224,8 @@ test( if (value === undefined) delete process.env[key]; else process.env[key] = value; } - await rm(pluginDir, { recursive: true, force: true }); - await rm(hostScriptDir, { recursive: true, force: true }); + await rm(pluginDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + await rm(hostScriptDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); await writeFile(entryPoint, "export async function onRequest() { return {}; }\n", "utf-8"); diff --git a/tests/unit/plugins-logger.test.ts b/tests/unit/plugins-logger.test.ts index da3b96d2a9..84c040e18c 100644 --- a/tests/unit/plugins-logger.test.ts +++ b/tests/unit/plugins-logger.test.ts @@ -9,7 +9,9 @@ describe("PluginLogger", () => { const testDir = join(tmpdir(), `plugin-logger-test-${Date.now()}`); afterEach(() => { - try { rmSync(testDir, { recursive: true, force: true }); } catch {} + try { + rmSync(testDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); it("creates log file and writes JSON entries", () => { diff --git a/tests/unit/plugins-manager-lifecycle.test.ts b/tests/unit/plugins-manager-lifecycle.test.ts index be2139cf00..02d3469756 100644 --- a/tests/unit/plugins-manager-lifecycle.test.ts +++ b/tests/unit/plugins-manager-lifecycle.test.ts @@ -58,7 +58,12 @@ describe("pluginManager lifecycle", () => { assert.ok(dbRow); assert.equal(dbRow!.status, "installed"); } finally { - rmSync(dir.split("/").slice(0, -1).join("/"), { recursive: true, force: true }); + rmSync(dir.split("/").slice(0, -1).join("/"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } }); @@ -81,7 +86,12 @@ describe("pluginManager lifecycle", () => { // the plugin's child process — without it the child outlives the test and its // IPC channel keeps this process's event loop alive after the suite finishes. await mod.pluginManager.deactivate("activate-test").catch(() => {}); - rmSync(dir.split("/").slice(0, -1).join("/"), { recursive: true, force: true }); + rmSync(dir.split("/").slice(0, -1).join("/"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } }); @@ -95,7 +105,12 @@ describe("pluginManager lifecycle", () => { const dbRow = db.getPluginByName("deactivate-test"); assert.equal(dbRow!.status, "inactive"); } finally { - rmSync(dir.split("/").slice(0, -1).join("/"), { recursive: true, force: true }); + rmSync(dir.split("/").slice(0, -1).join("/"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } }); @@ -114,7 +129,12 @@ describe("pluginManager lifecycle", () => { const dbRow = db.getPluginByName("uninstall-test"); assert.equal(dbRow, null); } finally { - rmSync(dir.split("/").slice(0, -1).join("/"), { recursive: true, force: true }); + rmSync(dir.split("/").slice(0, -1).join("/"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } }); }); diff --git a/tests/unit/plugins-manager-restart-reload-7806.test.ts b/tests/unit/plugins-manager-restart-reload-7806.test.ts index 31e4c18b80..93de2df07e 100644 --- a/tests/unit/plugins-manager-restart-reload-7806.test.ts +++ b/tests/unit/plugins-manager-restart-reload-7806.test.ts @@ -103,7 +103,12 @@ describe("pluginManager reload after restart (#7806)", () => { // Deactivate to kill the reloaded child process — otherwise it dangles and // keeps the test runner's event loop alive after the suite finishes. await mod.pluginManager.deactivate(name).catch(() => {}); - rmSync(dir.split("/").slice(0, -1).join("/"), { recursive: true, force: true }); + rmSync(dir.split("/").slice(0, -1).join("/"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } }); @@ -130,7 +135,12 @@ describe("pluginManager reload after restart (#7806)", () => { // Deactivate to kill the reloaded child process — otherwise it dangles and // keeps the test runner's event loop alive after the suite finishes. await mod.pluginManager.deactivate(name).catch(() => {}); - rmSync(dir.split("/").slice(0, -1).join("/"), { recursive: true, force: true }); + rmSync(dir.split("/").slice(0, -1).join("/"), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } }); }); diff --git a/tests/unit/plugins-metrics.test.ts b/tests/unit/plugins-metrics.test.ts index a9780c9001..f5c183d6fa 100644 --- a/tests/unit/plugins-metrics.test.ts +++ b/tests/unit/plugins-metrics.test.ts @@ -18,11 +18,14 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); test("recordPluginMetric stores call count", async () => { - const { recordPluginMetric, getPluginMetrics } = await import("../../src/lib/db/pluginMetrics.ts"); + const { recordPluginMetric, getPluginMetrics } = + await import("../../src/lib/db/pluginMetrics.ts"); recordPluginMetric("test-plugin", "onRequest", 5.2, false); recordPluginMetric("test-plugin", "onRequest", 3.1, false); @@ -34,7 +37,8 @@ test("recordPluginMetric stores call count", async () => { }); test("recordPluginMetric tracks errors", async () => { - const { recordPluginMetric, getPluginMetrics } = await import("../../src/lib/db/pluginMetrics.ts"); + const { recordPluginMetric, getPluginMetrics } = + await import("../../src/lib/db/pluginMetrics.ts"); recordPluginMetric("err-plugin", "onRequest", 1.0, true); const metrics = getPluginMetrics("err-plugin"); @@ -44,7 +48,8 @@ test("recordPluginMetric tracks errors", async () => { }); test("recordPluginMetric tracks latency", async () => { - const { recordPluginMetric, getPluginMetrics } = await import("../../src/lib/db/pluginMetrics.ts"); + const { recordPluginMetric, getPluginMetrics } = + await import("../../src/lib/db/pluginMetrics.ts"); recordPluginMetric("latency-plugin", "onRequest", 42.5, false); const metrics = getPluginMetrics("latency-plugin"); @@ -54,7 +59,8 @@ test("recordPluginMetric tracks latency", async () => { }); test("getPluginMetrics returns all plugins when no filter", async () => { - const { recordPluginMetric, getPluginMetrics } = await import("../../src/lib/db/pluginMetrics.ts"); + const { recordPluginMetric, getPluginMetrics } = + await import("../../src/lib/db/pluginMetrics.ts"); recordPluginMetric("p1", "onRequest", 1, false); recordPluginMetric("p2", "onResponse", 2, false); @@ -63,7 +69,8 @@ test("getPluginMetrics returns all plugins when no filter", async () => { }); test("clearPluginMetrics removes metrics", async () => { - const { recordPluginMetric, clearPluginMetrics, getPluginMetrics } = await import("../../src/lib/db/pluginMetrics.ts"); + const { recordPluginMetric, clearPluginMetrics, getPluginMetrics } = + await import("../../src/lib/db/pluginMetrics.ts"); recordPluginMetric("clear-test", "onRequest", 1, false); clearPluginMetrics("clear-test"); diff --git a/tests/unit/plugins-scanner.test.ts b/tests/unit/plugins-scanner.test.ts index eab34574f9..e2636a128d 100644 --- a/tests/unit/plugins-scanner.test.ts +++ b/tests/unit/plugins-scanner.test.ts @@ -36,7 +36,7 @@ describe("plugin scanner", () => { assert.ok(result.plugins[0].manifest); assert.ok(result.plugins[0].pluginDir); } finally { - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -48,7 +48,7 @@ describe("plugin scanner", () => { const result = await mod.scanPluginDir(tmp); assert.equal(result.plugins.length, 0); } finally { - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -59,7 +59,7 @@ describe("plugin scanner", () => { const result = await mod.scanPluginDir(tmp); assert.equal(result.plugins.length, 0); } finally { - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -76,7 +76,7 @@ describe("plugin scanner", () => { const result = await mod.scanPluginDir(tmp); assert.equal(result.plugins.length, 2); } finally { - rmSync(tmp, { recursive: true, force: true }); + rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); }); diff --git a/tests/unit/plugins-signing.test.ts b/tests/unit/plugins-signing.test.ts index d24b5a57fc..48b4124bfe 100644 --- a/tests/unit/plugins-signing.test.ts +++ b/tests/unit/plugins-signing.test.ts @@ -29,7 +29,9 @@ function writePlugin(dir: string, name: string, source: string, integrity?: stri const activeDirs: string[] = []; function cleanupDirs() { for (const d of activeDirs) { - try { fs.rmSync(d, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(d, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} } activeDirs.length = 0; } @@ -44,7 +46,9 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); cleanupDirs(); - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); test("computeIntegrity returns correct format", async () => { diff --git a/tests/unit/plugins-tools.test.ts b/tests/unit/plugins-tools.test.ts index 8b6a37203b..4ac81cae7f 100644 --- a/tests/unit/plugins-tools.test.ts +++ b/tests/unit/plugins-tools.test.ts @@ -45,9 +45,11 @@ function writeTestPlugin(opts?: { name?: string; onRequest?: boolean }) { }, }; fs.writeFileSync(path.join(pluginDir, "plugin.json"), JSON.stringify(manifest, null, 2)); - fs.writeFileSync(path.join(pluginDir, "index.js"), onRequest - ? `module.exports.onRequest = function(ctx) { ctx.metadata = ctx.metadata || {}; ctx.metadata.hookCalled = true; };` - : `module.exports = {};` + fs.writeFileSync( + path.join(pluginDir, "index.js"), + onRequest + ? `module.exports.onRequest = function(ctx) { ctx.metadata = ctx.metadata || {}; ctx.metadata.hookCalled = true; };` + : `module.exports = {};` ); return { sourceDir, pluginDir, name }; } @@ -56,7 +58,9 @@ const activeSourceDirs: string[] = []; function cleanupSourceDirs() { for (const dir of activeSourceDirs) { - try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} } activeSourceDirs.length = 0; } @@ -66,7 +70,7 @@ function cleanupSourceDirs() { test.beforeEach(() => { core.resetDbInstance(); hooks.resetHooks(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); cleanupSourceDirs(); }); @@ -74,7 +78,9 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); cleanupSourceDirs(); - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); // ── plugin_list ── @@ -309,7 +315,10 @@ test("plugin_configure: accepts valid config matching schema", async () => { await pluginManager.install(sourceDir); const tool = getTool("plugin_configure"); - const result = await tool.handler({ name, config: { apiUrl: "https://ok.example.com", maxRetries: 5 } }); + const result = await tool.handler({ + name, + config: { apiUrl: "https://ok.example.com", maxRetries: 5 }, + }); assert.equal(result.success, true, "should succeed for valid config"); assert.equal(result.config.apiUrl, "https://ok.example.com"); @@ -325,14 +334,17 @@ test("plugin_configure: allows any config when plugin has no configSchema", asyn const pluginDir = sourceDir + "/" + name; const fs = await import("node:fs"); const path = await import("node:path"); - fs.writeFileSync(path.join(pluginDir, "plugin.json"), JSON.stringify({ - name, - version: "1.0.0", - main: "index.js", - hooks: { onRequest: false, onResponse: false, onError: false }, - requires: { permissions: [] }, - // no configSchema - })); + fs.writeFileSync( + path.join(pluginDir, "plugin.json"), + JSON.stringify({ + name, + version: "1.0.0", + main: "index.js", + hooks: { onRequest: false, onResponse: false, onError: false }, + requires: { permissions: [] }, + // no configSchema + }) + ); const { pluginManager } = await import("../../src/lib/plugins/manager.ts"); await pluginManager.install(sourceDir); diff --git a/tests/unit/plugins-upgrade.test.ts b/tests/unit/plugins-upgrade.test.ts index 51a2f8b7c2..95b66b1386 100644 --- a/tests/unit/plugins-upgrade.test.ts +++ b/tests/unit/plugins-upgrade.test.ts @@ -20,16 +20,19 @@ function writePlugin(version: string, name = "upgrade-test") { const pluginDir = path.join(sourceDir, name); fs.mkdirSync(pluginDir, { recursive: true }); - fs.writeFileSync(path.join(pluginDir, "plugin.json"), JSON.stringify({ - name, - version, - description: `Plugin v${version}`, - author: "test", - main: "index.js", - hooks: { onRequest: true, onResponse: false, onError: false }, - enabledByDefault: false, - requires: { permissions: [] }, - })); + fs.writeFileSync( + path.join(pluginDir, "plugin.json"), + JSON.stringify({ + name, + version, + description: `Plugin v${version}`, + author: "test", + main: "index.js", + hooks: { onRequest: true, onResponse: false, onError: false }, + enabledByDefault: false, + requires: { permissions: [] }, + }) + ); fs.writeFileSync( path.join(pluginDir, "index.js"), @@ -44,19 +47,22 @@ function writePluginWithConfig(version: string, name = "upgrade-config-test") { const pluginDir = path.join(sourceDir, name); fs.mkdirSync(pluginDir, { recursive: true }); - fs.writeFileSync(path.join(pluginDir, "plugin.json"), JSON.stringify({ - name, - version, - description: `Plugin v${version}`, - author: "test", - main: "index.js", - hooks: { onRequest: true, onResponse: false, onError: false }, - enabledByDefault: false, - requires: { permissions: [] }, - configSchema: { - apiKey: { type: "string", description: "API key" }, - }, - })); + fs.writeFileSync( + path.join(pluginDir, "plugin.json"), + JSON.stringify({ + name, + version, + description: `Plugin v${version}`, + author: "test", + main: "index.js", + hooks: { onRequest: true, onResponse: false, onError: false }, + enabledByDefault: false, + requires: { permissions: [] }, + configSchema: { + apiKey: { type: "string", description: "API key" }, + }, + }) + ); fs.writeFileSync( path.join(pluginDir, "index.js"), @@ -69,7 +75,9 @@ function writePluginWithConfig(version: string, name = "upgrade-config-test") { const activeDirs: string[] = []; function cleanupDirs() { for (const dir of activeDirs) { - try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} } activeDirs.length = 0; } @@ -84,7 +92,9 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); cleanupDirs(); - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch {} + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch {} }); // ── Tests ── @@ -231,7 +241,11 @@ test("compareSemver: pre-release suffix strips cleanly (no NaN)", () => { assert.ok(compareSemver("1.0.1", "1.0.0-beta") > 0, "1.0.1 > 1.0.0-beta (treated as 1.0.0)"); assert.ok(compareSemver("1.0.0-beta", "0.9.0") > 0, "1.0.0-beta > 0.9.0"); // Both pre-release: treated as equal numeric parts - assert.equal(compareSemver("1.0.0-beta", "1.0.0-rc.1"), 0, "1.0.0-beta == 1.0.0-rc.1 (both strip to 1.0.0)"); + assert.equal( + compareSemver("1.0.0-beta", "1.0.0-rc.1"), + 0, + "1.0.0-beta == 1.0.0-rc.1 (both strip to 1.0.0)" + ); }); test("compareSemver: NaN segments coerce to 0, result is not NaN", () => { diff --git a/tests/unit/plugins-welcome-banner-e2e.test.ts b/tests/unit/plugins-welcome-banner-e2e.test.ts index 59295b07ad..e03efd1576 100644 --- a/tests/unit/plugins-welcome-banner-e2e.test.ts +++ b/tests/unit/plugins-welcome-banner-e2e.test.ts @@ -455,7 +455,7 @@ test("full lifecycle: install → activate → hook fires → deactivate → uni test("cleanup fixture directory", () => { if (existsSync(FIXTURE_DIR)) { - rmSync(FIXTURE_DIR, { recursive: true, force: true }); + rmSync(FIXTURE_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } assert.ok(!existsSync(FIXTURE_DIR)); }); diff --git a/tests/unit/poe-api-executor-regression.test.ts b/tests/unit/poe-api-executor-regression.test.ts index 85cda39850..22aba3238a 100644 --- a/tests/unit/poe-api-executor-regression.test.ts +++ b/tests/unit/poe-api-executor-regression.test.ts @@ -34,7 +34,7 @@ test.after(() => { } catch { // ignore } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const CHAT_URL = "https://api.poe.com/v1/chat/completions"; diff --git a/tests/unit/poe-provider-models-baseurl.test.ts b/tests/unit/poe-provider-models-baseurl.test.ts index 7043e4ae44..9d81cce5a3 100644 --- a/tests/unit/poe-provider-models-baseurl.test.ts +++ b/tests/unit/poe-provider-models-baseurl.test.ts @@ -24,7 +24,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider models route resolves the built-in Poe registry base URL instead of failing with 'No base URL configured for provider' (#8082)", async () => { diff --git a/tests/unit/policy-engine.test.ts b/tests/unit/policy-engine.test.ts index 79e12befc3..ad98f12867 100644 --- a/tests/unit/policy-engine.test.ts +++ b/tests/unit/policy-engine.test.ts @@ -18,7 +18,7 @@ beforeEach(() => { afterEach(() => { delete process.env.DATA_DIR; - if (tmpDir) fs.rmSync(tmpDir, { recursive: true, force: true }); + if (tmpDir) fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("policyEngine", async () => { diff --git a/tests/unit/postinstall-support.test.ts b/tests/unit/postinstall-support.test.ts index c007b35ae0..7784f2b66a 100644 --- a/tests/unit/postinstall-support.test.ts +++ b/tests/unit/postinstall-support.test.ts @@ -13,7 +13,7 @@ test("hasStandaloneAppBundle returns false for source checkout without standalon mkdirSync(join(root, "src", "app"), { recursive: true }); assert.equal(hasStandaloneAppBundle(root), false); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -25,7 +25,7 @@ test("hasStandaloneAppBundle returns true for published standalone app bundle", writeFileSync(join(root, "app", "server.js"), "export {};\n"); assert.equal(hasStandaloneAppBundle(root), true); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/pricing-route-sources.test.ts b/tests/unit/pricing-route-sources.test.ts index 1398a10ef5..348bd63c62 100644 --- a/tests/unit/pricing-route-sources.test.ts +++ b/tests/unit/pricing-route-sources.test.ts @@ -18,7 +18,7 @@ const pricingRoute = await import("../../src/app/api/pricing/route.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -28,7 +28,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("pricing GET keeps legacy payload by default and exposes source metadata on demand", async () => { diff --git a/tests/unit/pricing-sync-cross-instance.test.ts b/tests/unit/pricing-sync-cross-instance.test.ts index 1e123835c6..3b7b1d95cd 100644 --- a/tests/unit/pricing-sync-cross-instance.test.ts +++ b/tests/unit/pricing-sync-cross-instance.test.ts @@ -41,7 +41,7 @@ function buildLiteLLMFixture() { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("manual sync history remains visible without advertising a disabled future sync", async () => { diff --git a/tests/unit/pricing-sync-extended.test.ts b/tests/unit/pricing-sync-extended.test.ts index ae85d28f03..0f669e6533 100644 --- a/tests/unit/pricing-sync-extended.test.ts +++ b/tests/unit/pricing-sync-extended.test.ts @@ -33,7 +33,7 @@ function buildLiteLLMFixture() { async function resetStorage() { pricingSync.stopPeriodicSync(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -49,7 +49,7 @@ test.after(async () => { globalThis.fetch = originalFetch; console.warn = originalWarn; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("fetchLiteLLMPricing parses JSON and rejects invalid payloads", async () => { diff --git a/tests/unit/probe-6835-cyclebreaker.test.ts b/tests/unit/probe-6835-cyclebreaker.test.ts index fda653124d..a93d1e8ae0 100644 --- a/tests/unit/probe-6835-cyclebreaker.test.ts +++ b/tests/unit/probe-6835-cyclebreaker.test.ts @@ -24,5 +24,5 @@ test("getDbInstance() caps the probe-failed/restore cycle at 3 attempts (#6835)" const abortIndex = errors.findIndex((e) => e.includes("Aborting startup")); assert.notEqual(abortIndex, -1, "Expected the cap to trip; got: " + errors.join(" | ")); assert.ok(abortIndex <= 4, "Expected cap by call #4; took until #" + abortIndex); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/probe-6835-oom-uncapped.test.ts b/tests/unit/probe-6835-oom-uncapped.test.ts index 9b91101646..27215a307f 100644 --- a/tests/unit/probe-6835-oom-uncapped.test.ts +++ b/tests/unit/probe-6835-oom-uncapped.test.ts @@ -52,7 +52,8 @@ test("getDbInstance() eventually caps a persistently-OOMing sql.js probe (#6835) "Expected getDbInstance() to eventually give up with a terminal " + "'Aborting startup'-style diagnostic after repeated OOM probe failures, the same way it " + "already does for generic corruption (#6632). Instead every call re-threw an identical, " + - "uncapped OOM error:\n" + errors.map((e, i) => ` [${i}] ${e}`).join("\n") + "uncapped OOM error:\n" + + errors.map((e, i) => ` [${i}] ${e}`).join("\n") ); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/probe-9541-repro.test.ts b/tests/unit/probe-9541-repro.test.ts index 1faab99844..1a1caa76a6 100644 --- a/tests/unit/probe-9541-repro.test.ts +++ b/tests/unit/probe-9541-repro.test.ts @@ -107,7 +107,7 @@ test("BUG-CONFIRMED (regression guard): probe failure renames DB and loses persi ); } finally { try { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ok */ } diff --git a/tests/unit/probe-autodisable-isolation.test.ts b/tests/unit/probe-autodisable-isolation.test.ts index 5cb4479b67..d2e3e2da91 100644 --- a/tests/unit/probe-autodisable-isolation.test.ts +++ b/tests/unit/probe-autodisable-isolation.test.ts @@ -16,7 +16,7 @@ const { runAsProbe } = await import("../../src/shared/utils/probeOrigin.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function readIsActive(connId: string): unknown { diff --git a/tests/unit/probe-gate-autodisable.test.ts b/tests/unit/probe-gate-autodisable.test.ts index 7be8fe685a..4eb8b4c106 100644 --- a/tests/unit/probe-gate-autodisable.test.ts +++ b/tests/unit/probe-gate-autodisable.test.ts @@ -28,7 +28,7 @@ test.beforeEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function readConnectionRow(connId: string) { diff --git a/tests/unit/probe-policy.test.ts b/tests/unit/probe-policy.test.ts index bed1fc6f55..12403a6034 100644 --- a/tests/unit/probe-policy.test.ts +++ b/tests/unit/probe-policy.test.ts @@ -15,7 +15,7 @@ const { runAsProbe, shouldIsolateProbeFailures, isProbeContext } = test.after(() => { delete process.env.PROBE_CAN_DISABLE; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("outside a probe context the decision is always false (real path)", async () => { diff --git a/tests/unit/probe-production-path.test.ts b/tests/unit/probe-production-path.test.ts index 3b099b99dc..cc61c597d7 100644 --- a/tests/unit/probe-production-path.test.ts +++ b/tests/unit/probe-production-path.test.ts @@ -14,7 +14,7 @@ const { markAccountUnavailable } = await import("../../src/sse/services/auth.ts" test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function readConnectionRow(connId: string) { diff --git a/tests/unit/probe-testall-isolation.test.ts b/tests/unit/probe-testall-isolation.test.ts index 40016fec82..201fafc909 100644 --- a/tests/unit/probe-testall-isolation.test.ts +++ b/tests/unit/probe-testall-isolation.test.ts @@ -29,7 +29,7 @@ test.beforeEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function readConnectionRow(connId: string) { diff --git a/tests/unit/prompt-injection-guard-db-flag.test.ts b/tests/unit/prompt-injection-guard-db-flag.test.ts index a50b011a64..951a3f55d6 100644 --- a/tests/unit/prompt-injection-guard-db-flag.test.ts +++ b/tests/unit/prompt-injection-guard-db-flag.test.ts @@ -22,7 +22,7 @@ const ATTACK = { describe("prompt injection guard — DB feature flag override (INJECTION_GUARD_MODE)", () => { function resetDb() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); } @@ -36,7 +36,7 @@ describe("prompt injection guard — DB feature flag override (INJECTION_GUARD_M after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.INPUT_SANITIZER_ENABLED; delete process.env.INPUT_SANITIZER_MODE; delete process.env.INJECTION_GUARD_MODE; diff --git a/tests/unit/prompt-required-routes.test.ts b/tests/unit/prompt-required-routes.test.ts index b1faa3ae01..562d70326f 100644 --- a/tests/unit/prompt-required-routes.test.ts +++ b/tests/unit/prompt-required-routes.test.ts @@ -15,7 +15,7 @@ type ErrorResponseBody = { error: { message: string } }; test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 video generation POST rejects requests without a prompt", async () => { diff --git a/tests/unit/provider-connection-apikey-dedup.test.ts b/tests/unit/provider-connection-apikey-dedup.test.ts index b0e05a0d5d..0ef654c553 100644 --- a/tests/unit/provider-connection-apikey-dedup.test.ts +++ b/tests/unit/provider-connection-apikey-dedup.test.ts @@ -13,7 +13,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -21,7 +21,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function apiKeyConnections(provider: string) { diff --git a/tests/unit/provider-connection-healthcheck-interval-zero.test.ts b/tests/unit/provider-connection-healthcheck-interval-zero.test.ts index 0633f7e7d1..3ffdfb9816 100644 --- a/tests/unit/provider-connection-healthcheck-interval-zero.test.ts +++ b/tests/unit/provider-connection-healthcheck-interval-zero.test.ts @@ -6,9 +6,7 @@ import path from "node:path"; process.env.NODE_ENV = "test"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-hci-zero-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-hci-zero-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -19,7 +17,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -35,7 +33,7 @@ async function resetStorage() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression: the `_insertConnectionRow` and `_updateConnectionRow` bind helpers @@ -117,4 +115,4 @@ test("updateProviderConnection still persists a nonzero healthCheckInterval", as const stored = await providersDb.getProviderConnectionById((connection as any).id); assert.equal(stored?.healthCheckInterval, 60); -}); \ No newline at end of file +}); diff --git a/tests/unit/provider-connection-test-key-health.test.ts b/tests/unit/provider-connection-test-key-health.test.ts index 170b72f2bc..c75e9bab3f 100644 --- a/tests/unit/provider-connection-test-key-health.test.ts +++ b/tests/unit/provider-connection-test-key-health.test.ts @@ -39,7 +39,7 @@ const WARNING_HEALTH: StoredKeyHealth = { async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -83,7 +83,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("authoritative validation clears only the exact primary credential during a quota cooldown", async () => { diff --git a/tests/unit/provider-connections-pagination-2998.test.ts b/tests/unit/provider-connections-pagination-2998.test.ts index ed2025b153..3810cfff5b 100644 --- a/tests/unit/provider-connections-pagination-2998.test.ts +++ b/tests/unit/provider-connections-pagination-2998.test.ts @@ -17,7 +17,7 @@ const providersRoute = await import("../../src/app/api/providers/route.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(resetDb); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/providers filters and counts before applying limit/offset", async () => { diff --git a/tests/unit/provider-connections-quota-threshold.test.ts b/tests/unit/provider-connections-quota-threshold.test.ts index e7812557e9..16e98173cd 100644 --- a/tests/unit/provider-connections-quota-threshold.test.ts +++ b/tests/unit/provider-connections-quota-threshold.test.ts @@ -17,7 +17,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -38,7 +38,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createProviderConnection persists quotaWindowThresholds map", async () => { diff --git a/tests/unit/provider-health-matrix.test.ts b/tests/unit/provider-health-matrix.test.ts index 7e4edd12ab..d3509935da 100644 --- a/tests/unit/provider-health-matrix.test.ts +++ b/tests/unit/provider-health-matrix.test.ts @@ -27,7 +27,7 @@ const CANONICAL_ALIAS_PROVIDER = "nous-research"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); for (const lockout of accountFallback.getAllModelLockouts()) { if (lockout.provider === PROVIDER) { @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/provider-limits-local-apikey-sync-spacing.test.ts b/tests/unit/provider-limits-local-apikey-sync-spacing.test.ts index ac0a285133..c3bc8e9efa 100644 --- a/tests/unit/provider-limits-local-apikey-sync-spacing.test.ts +++ b/tests/unit/provider-limits-local-apikey-sync-spacing.test.ts @@ -27,7 +27,7 @@ const originalFetch = globalThis.fetch; test.beforeEach(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.PROVIDER_LIMITS_SYNC_SPACING_MS; }); @@ -35,7 +35,7 @@ test.beforeEach(() => { test.after(() => { globalThis.fetch = originalFetch; delete process.env.PROVIDER_LIMITS_SYNC_SPACING_MS; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createGlmApiKeyConnection(i: number) { diff --git a/tests/unit/provider-limits-oauth-sequential-sync.test.ts b/tests/unit/provider-limits-oauth-sequential-sync.test.ts index d1c99ca088..075b226501 100644 --- a/tests/unit/provider-limits-oauth-sequential-sync.test.ts +++ b/tests/unit/provider-limits-oauth-sequential-sync.test.ts @@ -29,13 +29,13 @@ const originalFetch = globalThis.fetch; test.beforeEach(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { globalThis.fetch = originalFetch; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createClaudeOAuth(i: number) { diff --git a/tests/unit/provider-limits-proxy-fail-closed.test.ts b/tests/unit/provider-limits-proxy-fail-closed.test.ts index f32cc36f1e..eb3a923fd9 100644 --- a/tests/unit/provider-limits-proxy-fail-closed.test.ts +++ b/tests/unit/provider-limits-proxy-fail-closed.test.ts @@ -17,7 +17,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -84,7 +84,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Claude provider limits fail closed when an account proxy is unreachable", async () => { diff --git a/tests/unit/provider-limits-recovery.test.ts b/tests/unit/provider-limits-recovery.test.ts index b3aedca494..809051c756 100644 --- a/tests/unit/provider-limits-recovery.test.ts +++ b/tests/unit/provider-limits-recovery.test.ts @@ -17,7 +17,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -79,7 +79,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("successful GLM quota refresh clears transient rate-limit state", async () => { diff --git a/tests/unit/provider-limits-rotating-expired-guard.test.ts b/tests/unit/provider-limits-rotating-expired-guard.test.ts index daca704d08..74ad93f080 100644 --- a/tests/unit/provider-limits-rotating-expired-guard.test.ts +++ b/tests/unit/provider-limits-rotating-expired-guard.test.ts @@ -13,7 +13,7 @@ const { quotaPathShouldMarkExpired, shouldAttemptRotatingRefresh } = await import("../../src/lib/usage/providerLimits.ts"); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression: the quota sync reuses a rotating provider's (possibly expired) diff --git a/tests/unit/provider-limits-sanitize-scope-3821.test.ts b/tests/unit/provider-limits-sanitize-scope-3821.test.ts index 60c29f0098..5b802ff38c 100644 --- a/tests/unit/provider-limits-sanitize-scope-3821.test.ts +++ b/tests/unit/provider-limits-sanitize-scope-3821.test.ts @@ -35,13 +35,13 @@ const providerLimits = await import("../../src/lib/usage/providerLimits.ts"); test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function cacheEntry(quotas: Record) { diff --git a/tests/unit/provider-limits-sync-scheduler-public-surface.test.ts b/tests/unit/provider-limits-sync-scheduler-public-surface.test.ts index 64800fbfee..aa10617c62 100644 --- a/tests/unit/provider-limits-sync-scheduler-public-surface.test.ts +++ b/tests/unit/provider-limits-sync-scheduler-public-surface.test.ts @@ -14,7 +14,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider limits sync scheduler public surface excludes unused stop helper", () => { diff --git a/tests/unit/provider-login-timeout-validation.test.ts b/tests/unit/provider-login-timeout-validation.test.ts index 36b33300e3..f8236177aa 100644 --- a/tests/unit/provider-login-timeout-validation.test.ts +++ b/tests/unit/provider-login-timeout-validation.test.ts @@ -48,7 +48,7 @@ const { inAppLoginService } = await import("../../open-sse/services/inAppLoginSe test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/provider-metrics-deleted-provider.test.ts b/tests/unit/provider-metrics-deleted-provider.test.ts index 2cfbbbbf7a..bce87d8761 100644 --- a/tests/unit/provider-metrics-deleted-provider.test.ts +++ b/tests/unit/provider-metrics-deleted-provider.test.ts @@ -4,9 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-provider-metrics-deleted-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-provider-metrics-deleted-")); const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; @@ -20,7 +18,7 @@ type ProviderMetricsResponse = { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -29,7 +27,7 @@ test.beforeEach(() => { }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); @@ -47,7 +45,14 @@ test("#10714: a provider deleted from provider_connections must NOT keep showing // Deleted provider: historical call_logs rows exist, but no provider_connections row. db.prepare( `INSERT INTO call_logs (id, timestamp, provider, status, duration, error_summary) VALUES (?, ?, ?, ?, ?, ?)` - ).run("g4f-pollinations-error", "2026-08-19T11:00:00.000Z", "g4f-pollinations", 402, 50, "payment required"); + ).run( + "g4f-pollinations-error", + "2026-08-19T11:00:00.000Z", + "g4f-pollinations", + 402, + 50, + "payment required" + ); const response = await providerMetricsRoute.GET(); const body = (await response.json()) as ProviderMetricsResponse; diff --git a/tests/unit/provider-metrics-route.test.ts b/tests/unit/provider-metrics-route.test.ts index 2d0b2d2543..d2bf2d40bd 100644 --- a/tests/unit/provider-metrics-route.test.ts +++ b/tests/unit/provider-metrics-route.test.ts @@ -33,7 +33,7 @@ type ProviderMetricsResponse = { function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -43,7 +43,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/provider-models-context-window-override-4125.test.ts b/tests/unit/provider-models-context-window-override-4125.test.ts index f7488cd04e..0e093ab48f 100644 --- a/tests/unit/provider-models-context-window-override-4125.test.ts +++ b/tests/unit/provider-models-context-window-override-4125.test.ts @@ -32,7 +32,7 @@ const providerModelsRoute = await import("../../src/app/api/provider-models/rout async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function buildRequest(method: string, body: unknown) { @@ -103,7 +103,11 @@ test("GET surfaces contextWindowOverride on the custom model row", async () => { new Request("http://localhost/api/provider-models?provider=openai-compatible-demo") ); const body = (await getRes.json()) as { - models: Array<{ id?: string; contextWindowOverride?: number; contextWindowOverrideSource?: string }>; + models: Array<{ + id?: string; + contextWindowOverride?: number; + contextWindowOverrideSource?: string; + }>; }; const row = body.models.find((m) => m.id === "m1"); diff --git a/tests/unit/provider-models-custom-merge-6247.test.ts b/tests/unit/provider-models-custom-merge-6247.test.ts index c6341ba8fb..eb5cf88b1c 100644 --- a/tests/unit/provider-models-custom-merge-6247.test.ts +++ b/tests/unit/provider-models-custom-merge-6247.test.ts @@ -30,7 +30,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -71,7 +71,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("per-connection models route includes user-added custom models on the local_catalog path (#6247)", async () => { diff --git a/tests/unit/provider-models-management-route.test.ts b/tests/unit/provider-models-management-route.test.ts index 3fee3b7132..a3039c0426 100644 --- a/tests/unit/provider-models-management-route.test.ts +++ b/tests/unit/provider-models-management-route.test.ts @@ -15,7 +15,7 @@ const providerModelsRoute = await import("../../src/app/api/provider-models/rout async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider-models GET returns an empty hiddenModelsByProvider map with no hidden models", async () => { diff --git a/tests/unit/provider-models-route-codex.test.ts b/tests/unit/provider-models-route-codex.test.ts index 0d4587218d..5a0ea5e792 100644 --- a/tests/unit/provider-models-route-codex.test.ts +++ b/tests/unit/provider-models-route-codex.test.ts @@ -47,7 +47,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; codexDiscovery.clearCodexGithubCatalogCacheForTests(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -79,7 +79,7 @@ test.after(async () => { globalThis.fetch = originalFetch; codexDiscovery.clearCodexGithubCatalogCacheForTests(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider models route merges live Codex models with the local catalog then filters denylist", async () => { diff --git a/tests/unit/provider-models-route-lan-guard.test.ts b/tests/unit/provider-models-route-lan-guard.test.ts index 92330febdd..48c7bb718b 100644 --- a/tests/unit/provider-models-route-lan-guard.test.ts +++ b/tests/unit/provider-models-route-lan-guard.test.ts @@ -38,7 +38,7 @@ async function resetStorage() { process.env.OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS = originalAllowLocalProviderUrls; } core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -69,7 +69,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6939: getProviderOutboundGuard() and getProviderValidationGuard() agree for LAN hosts under the default local-first setting", () => { diff --git a/tests/unit/provider-models-route.test.ts b/tests/unit/provider-models-route.test.ts index 237e3bc3b1..a8d6d2dd80 100644 --- a/tests/unit/provider-models-route.test.ts +++ b/tests/unit/provider-models-route.test.ts @@ -26,7 +26,7 @@ async function resetStorage() { } antigravityVersion.clearAntigravityVersionCaches(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -58,7 +58,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider models route returns a static local catalog for non-LLM search/agent providers (#5569/#5571/#5573/#5575)", async () => { diff --git a/tests/unit/provider-models-token-limits.test.ts b/tests/unit/provider-models-token-limits.test.ts index aada0b2f87..13902a16f1 100644 --- a/tests/unit/provider-models-token-limits.test.ts +++ b/tests/unit/provider-models-token-limits.test.ts @@ -15,7 +15,7 @@ const providerModelsRoute = await import("../../src/app/api/provider-models/rout async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // #1294: POST /api/provider-models must persist max_input_tokens / max_output_tokens diff --git a/tests/unit/provider-models-v1-route.test.ts b/tests/unit/provider-models-v1-route.test.ts index c20eda3544..af92b95b4f 100644 --- a/tests/unit/provider-models-v1-route.test.ts +++ b/tests/unit/provider-models-v1-route.test.ts @@ -16,9 +16,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const serviceModelsDb = await import("../../src/lib/db/serviceModels.ts"); -const routeModule = await import( - "../../src/app/api/v1/providers/[provider]/models/route.ts" -); +const routeModule = await import("../../src/app/api/v1/providers/[provider]/models/route.ts"); function makeRequest(provider: string) { return new Request(`http://localhost/api/v1/providers/${encodeURIComponent(provider)}/models`); @@ -36,7 +34,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /v1/providers/:provider/models returns 400 for completely unknown provider", async () => { diff --git a/tests/unit/provider-models-vision-override-1904.test.ts b/tests/unit/provider-models-vision-override-1904.test.ts index 508c6a1399..b3e7bed0e3 100644 --- a/tests/unit/provider-models-vision-override-1904.test.ts +++ b/tests/unit/provider-models-vision-override-1904.test.ts @@ -31,7 +31,7 @@ const catalogVision = await import("../../src/app/api/v1/models/catalogVision.ts async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function buildRequest(method: string, body: unknown) { diff --git a/tests/unit/provider-node-icon-url.test.ts b/tests/unit/provider-node-icon-url.test.ts index be4b14f0db..40ad7dad1a 100644 --- a/tests/unit/provider-node-icon-url.test.ts +++ b/tests/unit/provider-node-icon-url.test.ts @@ -19,7 +19,7 @@ const { createProviderNodeSchema, updateProviderNodeSchema } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -45,7 +45,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createProviderNodeSchema accepts a valid iconUrl", () => { diff --git a/tests/unit/provider-node-reserved-prefix.test.ts b/tests/unit/provider-node-reserved-prefix.test.ts index d2fc266101..7b13218cc4 100644 --- a/tests/unit/provider-node-reserved-prefix.test.ts +++ b/tests/unit/provider-node-reserved-prefix.test.ts @@ -41,7 +41,7 @@ const { isCommonChatGptWebRetiredProviderId } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -86,7 +86,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ──── Shared module ──── diff --git a/tests/unit/provider-nodes-route.test.ts b/tests/unit/provider-nodes-route.test.ts index eb21fa0578..681304538f 100644 --- a/tests/unit/provider-nodes-route.test.ts +++ b/tests/unit/provider-nodes-route.test.ts @@ -30,7 +30,7 @@ async function resetStorage() { process.env.OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS = originalAllowLocalProviderUrls; } core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -48,7 +48,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider nodes route lists stored nodes and exposes the CC feature flag", async () => { diff --git a/tests/unit/provider-nodes-validate-modelid.test.ts b/tests/unit/provider-nodes-validate-modelid.test.ts index f0e51a6d0e..5c644b5426 100644 --- a/tests/unit/provider-nodes-validate-modelid.test.ts +++ b/tests/unit/provider-nodes-validate-modelid.test.ts @@ -17,7 +17,7 @@ const originalFetch = globalThis.fetch; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -29,7 +29,7 @@ test.afterEach(async () => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); type FetchCall = { url: string; init: any }; diff --git a/tests/unit/provider-nodes-vibeproxy-preset.test.ts b/tests/unit/provider-nodes-vibeproxy-preset.test.ts index 59830e8650..869f7b9afe 100644 --- a/tests/unit/provider-nodes-vibeproxy-preset.test.ts +++ b/tests/unit/provider-nodes-vibeproxy-preset.test.ts @@ -36,7 +36,7 @@ async function resetStorage() { delete process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS; delete process.env.OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("vibeproxy-openai preset creates a node with defaulted name/prefix/apiType", async () => { diff --git a/tests/unit/provider-patch-ratelimit-protection-11278.test.ts b/tests/unit/provider-patch-ratelimit-protection-11278.test.ts index b41f067d25..d3f5e03fb6 100644 --- a/tests/unit/provider-patch-ratelimit-protection-11278.test.ts +++ b/tests/unit/provider-patch-ratelimit-protection-11278.test.ts @@ -38,7 +38,7 @@ const rateLimitManager = await import("../../open-sse/services/rateLimitManager. function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -48,7 +48,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createConnection(rateLimitProtection: boolean) { diff --git a/tests/unit/provider-probe-target.test.ts b/tests/unit/provider-probe-target.test.ts index 2fff1cafcc..c1995c1fae 100644 --- a/tests/unit/provider-probe-target.test.ts +++ b/tests/unit/provider-probe-target.test.ts @@ -26,7 +26,7 @@ const probeTarget = await import("../../src/lib/proxyHealth/providerProbeTarget. test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function seedProxy(name: string) { diff --git a/tests/unit/provider-request-failure-pipeline.test.ts b/tests/unit/provider-request-failure-pipeline.test.ts index 2b6684f452..d27e2f361b 100644 --- a/tests/unit/provider-request-failure-pipeline.test.ts +++ b/tests/unit/provider-request-failure-pipeline.test.ts @@ -63,7 +63,7 @@ async function resetStorage() { // under load this cache is evicted at unpredictable times, so tests that rely // on the stale cache flake. Make the reset honest and deterministic here. invalidateDbCache("settings"); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -88,7 +88,7 @@ test.after(async () => { clearPendingRequests(); resetAccountSemaphores(); await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("network failure persisted call log includes providerRequest in pipeline payloads", async () => { diff --git a/tests/unit/provider-scoped-models-route.test.ts b/tests/unit/provider-scoped-models-route.test.ts index 4d41d2cce5..cc90dc3a39 100644 --- a/tests/unit/provider-scoped-models-route.test.ts +++ b/tests/unit/provider-scoped-models-route.test.ts @@ -36,7 +36,7 @@ type ProviderModelsResponse = { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -59,7 +59,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("provider models route returns only selected provider models with unprefixed ids", async () => { diff --git a/tests/unit/provider-sweep-live-discovery.test.ts b/tests/unit/provider-sweep-live-discovery.test.ts index 2431179fa7..fe5905cb8b 100644 --- a/tests/unit/provider-sweep-live-discovery.test.ts +++ b/tests/unit/provider-sweep-live-discovery.test.ts @@ -31,13 +31,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { @@ -113,7 +113,11 @@ for (const { provider, liveUrl, source = "api" } of LIVE_CASES) { const body = (await response.json()) as ModelsBody; assert.equal(body.provider, provider); assert.ok(fetched, `should have probed ${liveUrl}`); - assert.equal(body.source, source, "should serve the live upstream catalog, not local_catalog"); + assert.equal( + body.source, + source, + "should serve the live upstream catalog, not local_catalog" + ); const ids = body.models.map((m) => m.id); assert.ok( ids.includes(`${provider}-live-a`) && ids.includes(`${provider}-live-b`), diff --git a/tests/unit/provider-translate-path-golden.test.ts b/tests/unit/provider-translate-path-golden.test.ts index 7cffac3d66..36e81677d1 100644 --- a/tests/unit/provider-translate-path-golden.test.ts +++ b/tests/unit/provider-translate-path-golden.test.ts @@ -171,6 +171,6 @@ test("GOLDEN guard catches translate-path drift", () => { assert.throws(() => goldenSnapshot("provider/translate-path", mutated, tmpDir)); } finally { delete process.env.UPDATE_GOLDEN; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/provider-validation-unsupported-neutral.test.ts b/tests/unit/provider-validation-unsupported-neutral.test.ts index d26433dfb0..2a02d0f17f 100644 --- a/tests/unit/provider-validation-unsupported-neutral.test.ts +++ b/tests/unit/provider-validation-unsupported-neutral.test.ts @@ -53,6 +53,9 @@ test.after(() => { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, + + maxRetries: 5, + retryDelay: 100, }); }); diff --git a/tests/unit/provider-window-costs.test.ts b/tests/unit/provider-window-costs.test.ts index 63ac2e23ec..46f42f5e7c 100644 --- a/tests/unit/provider-window-costs.test.ts +++ b/tests/unit/provider-window-costs.test.ts @@ -22,7 +22,7 @@ async function resetStorage() { core.resetDbInstance(); apiKeys.resetApiKeyState(); costRules.resetCostData(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.after(() => { core.resetDbInstance(); apiKeys.resetApiKeyState(); costRules.resetCostData(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Codex provider window costs use the weekly reset window and API key USD limit", async () => { diff --git a/tests/unit/providers-batch-update.test.ts b/tests/unit/providers-batch-update.test.ts index a45e3cd405..a05ed83006 100644 --- a/tests/unit/providers-batch-update.test.ts +++ b/tests/unit/providers-batch-update.test.ts @@ -9,9 +9,8 @@ process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); -const { batchUpdateProviderConnectionsSchema, providersBatchTestSchema } = await import( - "../../src/shared/validation/schemas.ts" -); +const { batchUpdateProviderConnectionsSchema, providersBatchTestSchema } = + await import("../../src/shared/validation/schemas.ts"); type Connection = Awaited>; @@ -23,7 +22,7 @@ function getConnectionId(connection: Connection): string { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -45,7 +44,7 @@ beforeEach(async () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("batchUpdateProviderConnectionsSchema", () => { diff --git a/tests/unit/providers-route-codex-account-pool.test.ts b/tests/unit/providers-route-codex-account-pool.test.ts index c5f5ad7e07..4ffa109ac5 100644 --- a/tests/unit/providers-route-codex-account-pool.test.ts +++ b/tests/unit/providers-route-codex-account-pool.test.ts @@ -19,7 +19,7 @@ const providersRoute = await import("../../src/app/api/providers/route.ts"); test.after(() => { quotaCache.__clearForTests(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET keeps one parent row and projects raw Codex state without exposing credentials", async () => { diff --git a/tests/unit/providers-route-managed-catalog.test.ts b/tests/unit/providers-route-managed-catalog.test.ts index 8e380dae84..02e8012d20 100644 --- a/tests/unit/providers-route-managed-catalog.test.ts +++ b/tests/unit/providers-route-managed-catalog.test.ts @@ -16,7 +16,7 @@ const modelsDb = await import("../../src/lib/db/models.ts"); function resetDb() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -26,7 +26,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("providers route accepts managed local, audio, web-cookie and search providers", async () => { diff --git a/tests/unit/providers-route-model-autofetch-optin.test.ts b/tests/unit/providers-route-model-autofetch-optin.test.ts index 70cf67d78f..166e7d4fda 100644 --- a/tests/unit/providers-route-model-autofetch-optin.test.ts +++ b/tests/unit/providers-route-model-autofetch-optin.test.ts @@ -58,7 +58,7 @@ async function createConnection(options: CreateOptions = {}): Promise test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); modelSyncUrls.length = 0; }); @@ -66,7 +66,7 @@ test.beforeEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("POST /api/providers does not sync models when autoFetchModels is omitted", async () => { diff --git a/tests/unit/providers-validate-route.test.ts b/tests/unit/providers-validate-route.test.ts index ba31957781..83b3a7bead 100644 --- a/tests/unit/providers-validate-route.test.ts +++ b/tests/unit/providers-validate-route.test.ts @@ -16,13 +16,13 @@ const validateRoute = await import("../../src/app/api/providers/validate/route.t async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalAllowPrivateProviderUrls === undefined) { delete process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS; } else { diff --git a/tests/unit/proxy-10348-log-redaction.test.ts b/tests/unit/proxy-10348-log-redaction.test.ts index 615cbc3adf..907bed0a4d 100644 --- a/tests/unit/proxy-10348-log-redaction.test.ts +++ b/tests/unit/proxy-10348-log-redaction.test.ts @@ -16,7 +16,7 @@ const proxyLogger = await import("../../src/lib/proxyLogger.ts"); function resetStorage() { proxyLogger.clearProxyLogs(); core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -57,4 +57,4 @@ test("[10348] default ProxyEgress console line redacts client IP, egress IP, and !line!.includes("aabbccdd"), "account prefix must be redacted from the console line by default" ); -}); \ No newline at end of file +}); diff --git a/tests/unit/proxy-assigned-unavailable-6246.test.ts b/tests/unit/proxy-assigned-unavailable-6246.test.ts index 396949108e..0f829b25e8 100644 --- a/tests/unit/proxy-assigned-unavailable-6246.test.ts +++ b/tests/unit/proxy-assigned-unavailable-6246.test.ts @@ -28,7 +28,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -51,7 +51,7 @@ async function makeConnection(): Promise { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("BLOCKS: an account proxy assigned but marked inactive (the IP-leak case)", async () => { diff --git a/tests/unit/proxy-autoselect-optin-3332.test.ts b/tests/unit/proxy-autoselect-optin-3332.test.ts index 35f58c77fe..0f1a8f5a57 100644 --- a/tests/unit/proxy-autoselect-optin-3332.test.ts +++ b/tests/unit/proxy-autoselect-optin-3332.test.ts @@ -8,9 +8,8 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-proxy-333 process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); -const { FEATURE_FLAG_DEFINITIONS } = await import( - "../../src/shared/constants/featureFlagDefinitions.ts" -); +const { FEATURE_FLAG_DEFINITIONS } = + await import("../../src/shared/constants/featureFlagDefinitions.ts"); const { isFeatureFlagEnabled } = await import("../../src/shared/utils/featureFlags.ts"); const { selectWorkingProxyFallback } = await import("../../open-sse/utils/proxyFallback.ts"); @@ -48,7 +47,7 @@ test.after(() => { /* ignore */ } try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ignore */ } diff --git a/tests/unit/proxy-batch-routes-5918.test.ts b/tests/unit/proxy-batch-routes-5918.test.ts index b5ca6ae98f..a2b64b39c7 100644 --- a/tests/unit/proxy-batch-routes-5918.test.ts +++ b/tests/unit/proxy-batch-routes-5918.test.ts @@ -20,12 +20,10 @@ delete process.env.INITIAL_PASSWORD; // auth not required in this test env const core = await import("../../src/lib/db/core.ts"); const proxiesDb = await import("../../src/lib/db/proxies.ts"); -const { POST: batchDeletePost } = await import( - "../../src/app/api/settings/proxies/batch-delete/route.ts" -); -const { POST: autoTestPost } = await import( - "../../src/app/api/settings/proxies/auto-test/route.ts" -); +const { POST: batchDeletePost } = + await import("../../src/app/api/settings/proxies/batch-delete/route.ts"); +const { POST: autoTestPost } = + await import("../../src/app/api/settings/proxies/auto-test/route.ts"); function jsonRequest(body: unknown): Request { return new Request("http://localhost/api/settings/proxies/batch-delete", { @@ -38,13 +36,13 @@ function jsonRequest(body: unknown): Request { async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("batch-delete removes multiple existing proxies in one request", async () => { diff --git a/tests/unit/proxy-bulk-import-dedup-7594.test.ts b/tests/unit/proxy-bulk-import-dedup-7594.test.ts index bec2a9660f..0a7bb0c91f 100644 --- a/tests/unit/proxy-bulk-import-dedup-7594.test.ts +++ b/tests/unit/proxy-bulk-import-dedup-7594.test.ts @@ -22,7 +22,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("upsertProxy creates distinct entries for same host:port with different credentials (#7594)", async () => { diff --git a/tests/unit/proxy-egress-route-summary.test.ts b/tests/unit/proxy-egress-route-summary.test.ts index 19cbd0be6c..c96862fd6e 100644 --- a/tests/unit/proxy-egress-route-summary.test.ts +++ b/tests/unit/proxy-egress-route-summary.test.ts @@ -24,7 +24,7 @@ const route = await import("../../src/app/api/settings/proxies/egress/route.ts") function resetStorage() { core.resetDbInstance(); proxyLogger.clearProxyLogs(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -41,23 +41,39 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("GET /api/settings/proxies/egress adds an anonymous summary to the existing payload", async () => { const bearer = await setupAuth(); // Seed two codex accounts on one egress IP (persisted proxy_logs). - proxyLogger.logProxyEvent({ status: "success", provider: "codex", targetUrl: "codex/gpt-5.5", egressIp: "100.115.194.84", account: "acc-a", connectionId: "conn-a" }); - proxyLogger.logProxyEvent({ status: "success", provider: "codex", targetUrl: "codex/gpt-5.5", egressIp: "100.115.194.84", account: "acc-b", connectionId: "conn-b" }); + proxyLogger.logProxyEvent({ + status: "success", + provider: "codex", + targetUrl: "codex/gpt-5.5", + egressIp: "100.115.194.84", + account: "acc-a", + connectionId: "conn-a", + }); + proxyLogger.logProxyEvent({ + status: "success", + provider: "codex", + targetUrl: "codex/gpt-5.5", + egressIp: "100.115.194.84", + account: "acc-b", + connectionId: "conn-b", + }); // logProxyEvent only enqueues for the 1s/100-entry background batch; the route // below reads persisted proxy_logs synchronously, so flush before asserting or // the rows are not yet on disk (timing-flaky otherwise). proxyLogger.flushProxyLogsSync(); - const response = await route.GET(new Request("https://example.com/api/settings/proxies/egress", { - headers: { authorization: `Bearer ${bearer}` }, - })); + const response = await route.GET( + new Request("https://example.com/api/settings/proxies/egress", { + headers: { authorization: `Bearer ${bearer}` }, + }) + ); assert.equal(response.status, 200); const body = await response.json(); diff --git a/tests/unit/proxy-egress-validate-pool-default.test.ts b/tests/unit/proxy-egress-validate-pool-default.test.ts index 423406e48a..3d34b159a2 100644 --- a/tests/unit/proxy-egress-validate-pool-default.test.ts +++ b/tests/unit/proxy-egress-validate-pool-default.test.ts @@ -20,16 +20,16 @@ const core = await import("../../src/lib/db/core.ts"); const proxiesDb = await import("../../src/lib/db/proxies.ts"); const egress = await import("../../src/lib/proxyEgress.ts"); const { validateProxyPool, _setEgressProbeForTests, clearEgressCache } = egress as unknown as { - validateProxyPool: (deps?: unknown) => Promise< - Array<{ proxyId: string; alive: boolean; newStatus: string }> - >; + validateProxyPool: ( + deps?: unknown + ) => Promise>; _setEgressProbeForTests: (fn: unknown) => void; clearEgressCache: () => void; }; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(() => { _setEgressProbeForTests(null); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("validateProxyPool() with no injected deps does not crash on the real listProxies() {items,total} shape", async () => { diff --git a/tests/unit/proxy-fallback-candidates-listproxies-shape.test.ts b/tests/unit/proxy-fallback-candidates-listproxies-shape.test.ts index 7194a69f1b..2014da7361 100644 --- a/tests/unit/proxy-fallback-candidates-listproxies-shape.test.ts +++ b/tests/unit/proxy-fallback-candidates-listproxies-shape.test.ts @@ -23,7 +23,7 @@ const { getProxyCandidates } = await import("../../open-sse/utils/proxyFallback. test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getProxyCandidates() surfaces user-configured proxies against the real listProxies() {items,total} shape", async () => { diff --git a/tests/unit/proxy-fallback-ssrf.test.ts b/tests/unit/proxy-fallback-ssrf.test.ts index cc90a0fef9..49c904efc6 100644 --- a/tests/unit/proxy-fallback-ssrf.test.ts +++ b/tests/unit/proxy-fallback-ssrf.test.ts @@ -13,7 +13,7 @@ const { isRetryableProxyTarget } = await import("../../src/lib/providers/validat const { isPrivateHost } = await import("../../src/shared/network/outboundUrlGuard.ts"); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** @@ -62,7 +62,11 @@ test("isRetryableProxyTarget rejects every private / link-local / metadata host" test("isRetryableProxyTarget allows public provider targets", () => { for (const url of PUBLIC_TARGETS) { - assert.equal(isRetryableProxyTarget(url), true, `${url} should be a valid proxy-fallback target`); + assert.equal( + isRetryableProxyTarget(url), + true, + `${url} should be a valid proxy-fallback target` + ); } }); diff --git a/tests/unit/proxy-health-6246.test.ts b/tests/unit/proxy-health-6246.test.ts index 72668761bf..ce0160483d 100644 --- a/tests/unit/proxy-health-6246.test.ts +++ b/tests/unit/proxy-health-6246.test.ts @@ -27,27 +27,24 @@ delete process.env.PROXY_HEALTH_AUTO_DEACTIVATE; const core = await import("../../src/lib/db/core.ts"); const proxiesDb = await import("../../src/lib/db/proxies.ts"); -const { resolveHealthCheckStatusWrite, isProxyHealthAutoDeactivateEnabled } = await import( - "../../src/lib/proxyHealth/statusPolicy.ts" -); -const { POST: autoTestPost } = await import( - "../../src/app/api/settings/proxies/auto-test/route.ts" -); -const { POST: batchActivatePost } = await import( - "../../src/app/api/settings/proxies/batch-activate/route.ts" -); +const { resolveHealthCheckStatusWrite, isProxyHealthAutoDeactivateEnabled } = + await import("../../src/lib/proxyHealth/statusPolicy.ts"); +const { POST: autoTestPost } = + await import("../../src/app/api/settings/proxies/auto-test/route.ts"); +const { POST: batchActivatePost } = + await import("../../src/app/api/settings/proxies/batch-activate/route.ts"); function resetStorage() { delete process.env.INITIAL_PASSWORD; delete process.env.PROXY_HEALTH_AUTO_DEACTIVATE; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── status-write policy ─────────────────────────────────────────────────────── @@ -146,7 +143,10 @@ test("batch-activate can bulk-disable with status=inactive", async () => { }); const res = await batchActivatePost(req); assert.equal(res.status, 200); - assert.equal((await proxiesDb.getProxyById(a!.id, { includeSecrets: false }))?.status, "inactive"); + assert.equal( + (await proxiesDb.getProxyById(a!.id, { includeSecrets: false }))?.status, + "inactive" + ); }); test("batch-activate rejects an empty ids array with 400", async () => { diff --git a/tests/unit/proxy-health-egress-line.test.ts b/tests/unit/proxy-health-egress-line.test.ts index bf75be5122..91707aaa6c 100644 --- a/tests/unit/proxy-health-egress-line.test.ts +++ b/tests/unit/proxy-health-egress-line.test.ts @@ -18,28 +18,27 @@ delete process.env.PROXY_LOG_INCLUDE_IPS; const core = await import("../../src/lib/db/core.ts"); const proxyLogger = await import("../../src/lib/proxyLogger.ts"); const proxiesDb = await import("../../src/lib/db/proxies.ts"); -const { forceProxyHealthSweep, formatEgressSharingSummaryLine } = await import( - "../../src/lib/proxyHealth/scheduler.ts" -) as unknown as { - forceProxyHealthSweep: () => Promise; - formatEgressSharingSummaryLine: ( - summary: EgressSharingSummary, - warnings: Array<{ egressIp: string; rotationGroup: string; connections: string[] }>, - includeDetails: boolean - ) => string; -}; +const { forceProxyHealthSweep, formatEgressSharingSummaryLine } = + (await import("../../src/lib/proxyHealth/scheduler.ts")) as unknown as { + forceProxyHealthSweep: () => Promise; + formatEgressSharingSummaryLine: ( + summary: EgressSharingSummary, + warnings: Array<{ egressIp: string; rotationGroup: string; connections: string[] }>, + includeDetails: boolean + ) => string; + }; import type { EgressSharingSummary } from "../../src/lib/proxyEgress.ts"; function resetStorage() { core.resetDbInstance(); proxyLogger.clearProxyLogs(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.PROXY_LOG_INCLUDE_IPS; }); @@ -48,13 +47,20 @@ test("formatEgressSharingSummaryLine is anonymous by default and raw when opted windowStart: "2026-08-20T00:00:00.000Z", windowEnd: "2026-08-21T00:00:00.000Z", distinctEgressIps: 1, - sharingByRotationGroup: [{ rotationGroup: "openai-auth0", sharedIps: 1, maxAccountsSharingOneIp: 2 }], + sharingByRotationGroup: [ + { rotationGroup: "openai-auth0", sharedIps: 1, maxAccountsSharingOneIp: 2 }, + ], maxAccountsSharingOneIp: 2, }; - const warnings = [{ egressIp: "100.115.194.84", rotationGroup: "openai-auth0", connections: ["a", "b"] }]; + const warnings = [ + { egressIp: "100.115.194.84", rotationGroup: "openai-auth0", connections: ["a", "b"] }, + ]; const anonymous = formatEgressSharingSummaryLine(summary, warnings, false); - assert.equal(anonymous, "[ProxyHealth] egress: 1 rotation group(s) share an egress IP (max 2 accounts)"); + assert.equal( + anonymous, + "[ProxyHealth] egress: 1 rotation group(s) share an egress IP (max 2 accounts)" + ); assert.ok(!anonymous.includes("100.115.194.84"), "no IP without opt-in"); const raw = formatEgressSharingSummaryLine(summary, warnings, true); @@ -72,13 +78,29 @@ test("forceProxyHealthSweep logs the anonymous egress line when accounts share a }); // Two codex accounts on one egress IP, persisted (the sweep reads the DB). - proxyLogger.logProxyEvent({ status: "success", provider: "codex", targetUrl: "codex/gpt-5.5", egressIp: "100.115.194.84", account: "acc-a", connectionId: "conn-a" }); - proxyLogger.logProxyEvent({ status: "success", provider: "codex", targetUrl: "codex/gpt-5.5", egressIp: "100.115.194.84", account: "acc-b", connectionId: "conn-b" }); + proxyLogger.logProxyEvent({ + status: "success", + provider: "codex", + targetUrl: "codex/gpt-5.5", + egressIp: "100.115.194.84", + account: "acc-a", + connectionId: "conn-a", + }); + proxyLogger.logProxyEvent({ + status: "success", + provider: "codex", + targetUrl: "codex/gpt-5.5", + egressIp: "100.115.194.84", + account: "acc-b", + connectionId: "conn-b", + }); proxyLogger.flushProxyLogsSync(); // persist the enqueued batch before the sweep reads the DB const logs: string[] = []; const originalLog = console.log; - console.log = (...args: unknown[]) => { logs.push(args.join(" ")); }; + console.log = (...args: unknown[]) => { + logs.push(args.join(" ")); + }; try { await forceProxyHealthSweep(); } finally { @@ -102,13 +124,29 @@ test("forceProxyHealthSweep logs raw details only with PROXY_LOG_INCLUDE_IPS=tru host: "127.0.0.1", port: 1, }); - proxyLogger.logProxyEvent({ status: "success", provider: "codex", targetUrl: "codex/gpt-5.5", egressIp: "100.115.194.84", account: "acc-a", connectionId: "conn-a" }); - proxyLogger.logProxyEvent({ status: "success", provider: "codex", targetUrl: "codex/gpt-5.5", egressIp: "100.115.194.84", account: "acc-b", connectionId: "conn-b" }); + proxyLogger.logProxyEvent({ + status: "success", + provider: "codex", + targetUrl: "codex/gpt-5.5", + egressIp: "100.115.194.84", + account: "acc-a", + connectionId: "conn-a", + }); + proxyLogger.logProxyEvent({ + status: "success", + provider: "codex", + targetUrl: "codex/gpt-5.5", + egressIp: "100.115.194.84", + account: "acc-b", + connectionId: "conn-b", + }); proxyLogger.flushProxyLogsSync(); // persist the enqueued batch before the sweep reads the DB const logs: string[] = []; const originalLog = console.log; - console.log = (...args: unknown[]) => { logs.push(args.join(" ")); }; + console.log = (...args: unknown[]) => { + logs.push(args.join(" ")); + }; try { await forceProxyHealthSweep(); } finally { diff --git a/tests/unit/proxy-health-scheduler-listproxies-shape.test.ts b/tests/unit/proxy-health-scheduler-listproxies-shape.test.ts index 5b9057cca1..a0c5996271 100644 --- a/tests/unit/proxy-health-scheduler-listproxies-shape.test.ts +++ b/tests/unit/proxy-health-scheduler-listproxies-shape.test.ts @@ -31,13 +31,13 @@ const { forceProxyHealthSweep } = await import("../../src/lib/proxyHealth/schedu function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("forceProxyHealthSweep() actually probes seeded proxies against the real listProxies() {items,total} shape", async () => { diff --git a/tests/unit/proxy-logger-client-ip.test.ts b/tests/unit/proxy-logger-client-ip.test.ts index 6c7829a3e0..2301ceb945 100644 --- a/tests/unit/proxy-logger-client-ip.test.ts +++ b/tests/unit/proxy-logger-client-ip.test.ts @@ -13,7 +13,7 @@ const proxyLogger = await import("../../src/lib/proxyLogger.ts"); function resetStorage() { proxyLogger.clearProxyLogs(); core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } diff --git a/tests/unit/proxy-logs-egress-ip.test.ts b/tests/unit/proxy-logs-egress-ip.test.ts index e3ca2a6331..0ff3c81565 100644 --- a/tests/unit/proxy-logs-egress-ip.test.ts +++ b/tests/unit/proxy-logs-egress-ip.test.ts @@ -20,7 +20,7 @@ const proxyLogger = await import("../../src/lib/proxyLogger.ts"); function resetStorage() { proxyLogger.clearProxyLogs(); core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -30,7 +30,7 @@ test.beforeEach(() => { test.after(() => { core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("fresh install exposes egress_ip and the reconciler is idempotent", async () => { diff --git a/tests/unit/proxy-logs-egress-lookup-10880.test.ts b/tests/unit/proxy-logs-egress-lookup-10880.test.ts index 91f9b99a13..9742b0640e 100644 --- a/tests/unit/proxy-logs-egress-lookup-10880.test.ts +++ b/tests/unit/proxy-logs-egress-lookup-10880.test.ts @@ -17,14 +17,14 @@ const { getRecentEgressIpForConnection } = await import("../../src/lib/db/proxyL function resetStorage() { proxyLogger.clearProxyLogs(); core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(() => resetStorage()); test.after(() => { core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("returns the LAST known egress IP of the connection in the window", () => { @@ -43,7 +43,10 @@ test("returns the LAST known egress IP of the connection in the window", () => { connectionId: "conn-a", }); proxyLogger.flushProxyLogsSync(); // persist the enqueued batch before the DB-backed lookup - const got = getRecentEgressIpForConnection("conn-a", new Date(Date.now() - 24 * 3600_000).toISOString()); + const got = getRecentEgressIpForConnection( + "conn-a", + new Date(Date.now() - 24 * 3600_000).toISOString() + ); assert.deepEqual(got, { egressIp: "203.0.113.9", at: got!.at }); }); @@ -55,11 +58,20 @@ test("ignores rows with NULL egress_ip (never probed)", () => { egressIp: null, connectionId: "conn-b", }); - assert.equal(getRecentEgressIpForConnection("conn-b", new Date(Date.now() - 24 * 3600_000).toISOString()), null); + assert.equal( + getRecentEgressIpForConnection("conn-b", new Date(Date.now() - 24 * 3600_000).toISOString()), + null + ); }); test("returns null when the connection has no row in the window", () => { - assert.equal(getRecentEgressIpForConnection("ghost-conn", new Date(Date.now() - 24 * 3600_000).toISOString()), null); + assert.equal( + getRecentEgressIpForConnection( + "ghost-conn", + new Date(Date.now() - 24 * 3600_000).toISOString() + ), + null + ); }); test("does not return rows outside the since window", () => { @@ -70,5 +82,8 @@ test("does not return rows outside the since window", () => { `INSERT INTO proxy_logs (id, timestamp, status, provider, target_url, egress_ip, connection_id) VALUES (?, ?, 'success', 'opencode', 'https://api.opencode.ai/chat', '203.0.113.1', 'conn-c')` ).run(randomUUID(), new Date(Date.now() - 48 * 3600_000).toISOString()); - assert.equal(getRecentEgressIpForConnection("conn-c", new Date(Date.now() - 24 * 3600_000).toISOString()), null); + assert.equal( + getRecentEgressIpForConnection("conn-c", new Date(Date.now() - 24 * 3600_000).toISOString()), + null + ); }); diff --git a/tests/unit/proxy-logs-route.test.ts b/tests/unit/proxy-logs-route.test.ts index 1589e640b1..663015faf4 100644 --- a/tests/unit/proxy-logs-route.test.ts +++ b/tests/unit/proxy-logs-route.test.ts @@ -13,14 +13,14 @@ const proxyLogsRoute = await import("../../src/app/api/usage/proxy-logs/route.ts test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); proxyLogger.clearProxyLogs(); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("proxy logger public surface excludes removed stats helper", () => { diff --git a/tests/unit/proxy-management-v1-route.test.ts b/tests/unit/proxy-management-v1-route.test.ts index 9dfdd43aa3..8dca4bc168 100644 --- a/tests/unit/proxy-management-v1-route.test.ts +++ b/tests/unit/proxy-management-v1-route.test.ts @@ -39,7 +39,7 @@ async function withEnv(name, value, fn) { async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -65,7 +65,7 @@ async function withPrepareFailure(match, message, fn) { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 management proxies supports create/list/pagination", async () => { diff --git a/tests/unit/proxy-noauth-provider-6272.test.ts b/tests/unit/proxy-noauth-provider-6272.test.ts index 610caa4214..ec64dd731c 100644 --- a/tests/unit/proxy-noauth-provider-6272.test.ts +++ b/tests/unit/proxy-noauth-provider-6272.test.ts @@ -15,7 +15,7 @@ const { safeResolveProxy } = await import("../../src/sse/handlers/chatHelpers.ts test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD; else process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD; }); diff --git a/tests/unit/proxy-pool-rotation-6365.test.ts b/tests/unit/proxy-pool-rotation-6365.test.ts index 02c21457a8..59f98787d3 100644 --- a/tests/unit/proxy-pool-rotation-6365.test.ts +++ b/tests/unit/proxy-pool-rotation-6365.test.ts @@ -31,7 +31,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -60,7 +60,7 @@ async function makeConnection(): Promise { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("round-robin (default for >1) cycles through the whole pool across calls", async () => { @@ -176,7 +176,10 @@ test("random strategy always returns a member of the alive set", async () => { // The random strategy uses crypto.randomInt (not Math.random — CodeQL js/insecure-randomness). // Over 30 picks from a 3-member alive pool it must vary, not stick on one member // (P(all 30 identical) ≈ (1/3)^29 ≈ 0). Guards that randomInt selection is uniform-ish. - assert.ok(seen.size >= 2, `random strategy must vary its pick (saw only: ${[...seen].join(", ")})`); + assert.ok( + seen.size >= 2, + `random strategy must vary its pick (saw only: ${[...seen].join(", ")})` + ); }); test("setScopeRotationStrategy round-trips via getScopeRotationStrategy", async () => { diff --git a/tests/unit/proxy-pool-route-6365.test.ts b/tests/unit/proxy-pool-route-6365.test.ts index 0cb2041e0e..594e383693 100644 --- a/tests/unit/proxy-pool-route-6365.test.ts +++ b/tests/unit/proxy-pool-route-6365.test.ts @@ -22,9 +22,8 @@ delete process.env.INITIAL_PASSWORD; // auth not required in this test env const core = await import("../../src/lib/db/core.ts"); const proxiesDb = await import("../../src/lib/db/proxies.ts"); -const { GET, PUT, DELETE, PATCH } = await import( - "../../src/app/api/settings/proxies/pool/route.ts" -); +const { GET, PUT, DELETE, PATCH } = + await import("../../src/app/api/settings/proxies/pool/route.ts"); function jsonRequest(method: string, body: unknown): Request { return new Request("http://localhost/api/settings/proxies/pool", { @@ -44,7 +43,7 @@ function getRequest(query: Record): Request { async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -64,7 +63,7 @@ async function makeProxy() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("add → list → remove round-trips a scope pool", async () => { diff --git a/tests/unit/proxy-pool-sync-4878.test.ts b/tests/unit/proxy-pool-sync-4878.test.ts index 787a2a0b50..c0b522bf67 100644 --- a/tests/unit/proxy-pool-sync-4878.test.ts +++ b/tests/unit/proxy-pool-sync-4878.test.ts @@ -13,15 +13,14 @@ delete process.env.OMNIROUTE_API_KEY; const core = await import("../../src/lib/db/core.ts"); const freeProxiesDb = await import("../../src/lib/db/freeProxies.ts"); -const addToPoolRoute = await import( - "../../src/app/api/settings/free-proxies/[id]/add-to-pool/route.ts" -); +const addToPoolRoute = + await import("../../src/app/api/settings/free-proxies/[id]/add-to-pool/route.ts"); const syncRoute = await import("../../src/app/api/settings/free-proxies/sync/route.ts"); const rateLimiter = await import("../../src/shared/utils/rateLimiter.ts"); function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +35,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/proxy-registry-route-handlers.test.ts b/tests/unit/proxy-registry-route-handlers.test.ts index b1b66b9c10..72f7d274a3 100644 --- a/tests/unit/proxy-registry-route-handlers.test.ts +++ b/tests/unit/proxy-registry-route-handlers.test.ts @@ -17,20 +17,19 @@ process.env.API_KEY_SECRET = "test-secret"; const core = await import("../../src/lib/db/core.ts"); const proxiesDb = await import("../../src/lib/db/proxies.ts"); -const { resolveProxyLookupResponse } = await import( - "../../src/lib/api/proxyRegistryRouteHandlers.ts" -); +const { resolveProxyLookupResponse } = + await import("../../src/lib/api/proxyRegistryRouteHandlers.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("resolveProxyLookupResponse returns null for the list path (no id)", async () => { diff --git a/tests/unit/proxy-registry.test.ts b/tests/unit/proxy-registry.test.ts index ced3796738..97f2f76c1a 100644 --- a/tests/unit/proxy-registry.test.ts +++ b/tests/unit/proxy-registry.test.ts @@ -14,21 +14,20 @@ const proxiesDb = await import("../../src/lib/db/proxies.ts"); const settingsDb = await import("../../src/lib/db/settings.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); const proxiesRoute = await import("../../src/app/api/settings/proxies/route.ts"); -const { createProxyRegistrySchema, updateProxyRegistrySchema } = await import( - "../../src/shared/validation/schemas.ts" -); +const { createProxyRegistrySchema, updateProxyRegistrySchema } = + await import("../../src/shared/validation/schemas.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("proxy registry blocks delete when proxy is still assigned", async () => { diff --git a/tests/unit/proxy-resolution-status-filter.test.ts b/tests/unit/proxy-resolution-status-filter.test.ts index c2286be251..1675777f0e 100644 --- a/tests/unit/proxy-resolution-status-filter.test.ts +++ b/tests/unit/proxy-resolution-status-filter.test.ts @@ -24,13 +24,13 @@ const proxiesDb = await import("../../src/lib/db/proxies.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("resolution SKIPS an account proxy marked inactive", async () => { diff --git a/tests/unit/proxy-rotation-latency.test.ts b/tests/unit/proxy-rotation-latency.test.ts index e37be50496..298d5370de 100644 --- a/tests/unit/proxy-rotation-latency.test.ts +++ b/tests/unit/proxy-rotation-latency.test.ts @@ -17,7 +17,7 @@ const proxiesDb = await import("../../src/lib/db/proxies.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -48,7 +48,7 @@ function insertLog( test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("latency strategy chooses proxy with lowest average latency within the window", async () => { diff --git a/tests/unit/proxy-subscriptions-route-validation.test.ts b/tests/unit/proxy-subscriptions-route-validation.test.ts index 4b302c7b41..8baaf1fb7b 100644 --- a/tests/unit/proxy-subscriptions-route-validation.test.ts +++ b/tests/unit/proxy-subscriptions-route-validation.test.ts @@ -35,12 +35,9 @@ process.env.API_KEY_SECRET = process.env.API_KEY_SECRET ?? "proxy-sub-route-test delete process.env.INITIAL_PASSWORD; // ensure auth is NOT required const core = await import("../../src/lib/db/core.ts"); -const collectionRoute = await import( - "../../src/app/api/v1/management/proxy-subscriptions/route.ts" -); -const itemRoute = await import( - "../../src/app/api/v1/management/proxy-subscriptions/[id]/route.ts" -); +const collectionRoute = + await import("../../src/app/api/v1/management/proxy-subscriptions/route.ts"); +const itemRoute = await import("../../src/app/api/v1/management/proxy-subscriptions/[id]/route.ts"); function jsonRequest(url: string, body: unknown, method = "POST"): Request { return new Request(url, { @@ -70,7 +67,7 @@ async function createValidSubscription(name: string) { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; @@ -129,7 +126,10 @@ test("POST proxy-subscriptions — valid-JSON non-object (string) body returns 4 // `typeof body !== "object"` guard), so it falls through to the missing-name // check instead — see the array-body test below for that path. A primitive // (string/number/boolean) is the one JSON shape that actually trips this guard. - const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", "just-a-string"); + const req = jsonRequest( + "http://localhost/api/v1/management/proxy-subscriptions", + "just-a-string" + ); const res = await collectionRoute.POST(req); assert.equal(res.status, 400); @@ -326,7 +326,11 @@ test("PATCH proxy-subscriptions/:id — a JSON array body is an 'object' in JS, ); const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: fixture.id }) }); - assert.equal(res.status, 200, "matches the original inline parser: no typed field matches, no error"); + assert.equal( + res.status, + 200, + "matches the original inline parser: no typed field matches, no error" + ); const body = (await res.json()) as { name?: string }; assert.equal(body.name, "patch-arraybody", "name is unchanged — the array had no usable fields"); }); diff --git a/tests/unit/proxySubscription.service.test.ts b/tests/unit/proxySubscription.service.test.ts index 442788eb79..2647909336 100644 --- a/tests/unit/proxySubscription.service.test.ts +++ b/tests/unit/proxySubscription.service.test.ts @@ -14,7 +14,7 @@ const sub = await import("../../src/lib/proxySubscription/index.ts"); function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -47,7 +47,7 @@ function insertSubscription( test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("global subscription binds its pool to the global scope and is resolvable", async () => { @@ -171,7 +171,9 @@ test("deleteSubscription unbinds and removes its proxy rows", async () => { assert.equal(rows.length, 0, "subscription proxy rows should be removed"); const assignments = db - .prepare("SELECT 1 FROM proxy_assignments a JOIN proxy_registry p ON p.id=a.proxy_id WHERE p.source='subscription' LIMIT 1") + .prepare( + "SELECT 1 FROM proxy_assignments a JOIN proxy_registry p ON p.id=a.proxy_id WHERE p.source='subscription' LIMIT 1" + ) .get(); assert.equal(assignments, undefined, "no subscription proxy should remain assigned"); diff --git a/tests/unit/puter-provider-removed.test.ts b/tests/unit/puter-provider-removed.test.ts index 86dd593c92..abe80ff1db 100644 --- a/tests/unit/puter-provider-removed.test.ts +++ b/tests/unit/puter-provider-removed.test.ts @@ -21,7 +21,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("puter provider is removed from the chat registry (id and alias)", () => { diff --git a/tests/unit/qiniu-provider.test.ts b/tests/unit/qiniu-provider.test.ts index f98f38623e..438c1b93a4 100644 --- a/tests/unit/qiniu-provider.test.ts +++ b/tests/unit/qiniu-provider.test.ts @@ -61,13 +61,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { diff --git a/tests/unit/qoder-cli.test.ts b/tests/unit/qoder-cli.test.ts index 12fbdce918..c94f0f641e 100644 --- a/tests/unit/qoder-cli.test.ts +++ b/tests/unit/qoder-cli.test.ts @@ -38,7 +38,7 @@ function withStubQoderCli(fn: () => void | Promise) { const restore = () => { if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }; return Promise.resolve().then(fn).finally(restore); } @@ -489,7 +489,7 @@ test("runQoderCli survives qodercli exiting before it reads a large stdin (async } finally { if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -516,7 +516,7 @@ test("runQoderCli preserves multi-byte UTF-8 output (Chinese) via stream setEnco } finally { if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -581,6 +581,6 @@ test("runQoderCli resolves the request against live --list-models and passes the qoderCli.__clearQoderModelNamesCache(); if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/qoder-executor.test.ts b/tests/unit/qoder-executor.test.ts index 9d0fd974cd..f3bcabdd58 100644 --- a/tests/unit/qoder-executor.test.ts +++ b/tests/unit/qoder-executor.test.ts @@ -49,7 +49,7 @@ function withStubQoderCli(fn: () => void | Promise) { const restore = () => { if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }; return Promise.resolve().then(fn).finally(restore); } @@ -425,7 +425,7 @@ test("QoderExecutor: surfaces qodercli stderr when is_error=true with empty resu } finally { if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/qoder-jobtoken-exchange-4683.test.ts b/tests/unit/qoder-jobtoken-exchange-4683.test.ts index b6468e16cf..3ea87f6a6e 100644 --- a/tests/unit/qoder-jobtoken-exchange-4683.test.ts +++ b/tests/unit/qoder-jobtoken-exchange-4683.test.ts @@ -198,7 +198,7 @@ test("validateQoderCliPat validates via qodercli and makes no Cosy/jobToken HTTP globalThis.fetch = originalFetch; if (prevBin === undefined) delete process.env.CLI_QODER_BIN; else process.env.CLI_QODER_BIN = prevBin; - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); __clearQoderJobTokenCache(); } }); diff --git a/tests/unit/quota-cache-hydrate-5015.test.ts b/tests/unit/quota-cache-hydrate-5015.test.ts index e692ceb711..c6ad4114cd 100644 --- a/tests/unit/quota-cache-hydrate-5015.test.ts +++ b/tests/unit/quota-cache-hydrate-5015.test.ts @@ -26,7 +26,7 @@ const quotaCache = await import("../../src/domain/quotaCache.ts"); test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5015 isAccountQuotaExhausted hydrates exhausted state from a persisted snapshot", () => { diff --git a/tests/unit/quota-cache-is-exhausted-per-window-5923.test.ts b/tests/unit/quota-cache-is-exhausted-per-window-5923.test.ts index e1f1c0cb9b..4b52d4d235 100644 --- a/tests/unit/quota-cache-is-exhausted-per-window-5923.test.ts +++ b/tests/unit/quota-cache-is-exhausted-per-window-5923.test.ts @@ -27,7 +27,7 @@ const quotaCache = await import("../../src/domain/quotaCache.ts"); test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5923 setQuotaCache writes is_exhausted per-window, not the connection-wide AND aggregate", () => { diff --git a/tests/unit/quota-combo-balancing.test.ts b/tests/unit/quota-combo-balancing.test.ts index f5cd331499..f45e12a3f4 100644 --- a/tests/unit/quota-combo-balancing.test.ts +++ b/tests/unit/quota-combo-balancing.test.ts @@ -85,7 +85,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/quota-combo-cli-providers.test.ts b/tests/unit/quota-combo-cli-providers.test.ts index a7dd90b5e5..604dc1487e 100644 --- a/tests/unit/quota-combo-cli-providers.test.ts +++ b/tests/unit/quota-combo-cli-providers.test.ts @@ -29,7 +29,8 @@ const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts"); async function resetStorage() { core.resetDbInstance(); - if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + if (fs.existsSync(TEST_DATA_DIR)) + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +40,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const CLI_PROVIDER = "codex"; // absent from PROVIDER_MODELS, present in REGISTRY diff --git a/tests/unit/quota-combo-groups.test.ts b/tests/unit/quota-combo-groups.test.ts index f182fdeb0a..7a271598fb 100644 --- a/tests/unit/quota-combo-groups.test.ts +++ b/tests/unit/quota-combo-groups.test.ts @@ -18,9 +18,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-quota-combo-groups-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-quota-combo-groups-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -29,9 +27,8 @@ const providersDb = await import("../../src/lib/db/providers.ts"); const combosDb = await import("../../src/lib/db/combos.ts"); const { createGroup } = await import("../../src/lib/db/quotaGroups.ts"); const { syncQuotaCombos } = await import("../../src/lib/quota/quotaCombos.ts"); -const { isQuotaModelName, parseQuotaModelName, quotaGroupSlug } = await import( - "../../src/lib/quota/quotaModelNaming.ts" -); +const { isQuotaModelName, parseQuotaModelName, quotaGroupSlug } = + await import("../../src/lib/quota/quotaModelNaming.ts"); // --------------------------------------------------------------------------- // Lifecycle @@ -42,7 +39,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -63,7 +60,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -139,7 +136,10 @@ test("G1: two pools in same group → combos named qtSd//provider/model ( const p = parseQuotaModelName(c.name); return p?.groupSlug === groupSlug && p?.provider === "openrouter"; }); - assert.ok(orCombos.length > 0, `Expected openrouter combos under qtSd/${groupSlug}/openrouter/...`); + assert.ok( + orCombos.length > 0, + `Expected openrouter combos under qtSd/${groupSlug}/openrouter/...` + ); // Combos for baidu must exist under the group slug const baiduCombos = allCombos.filter((c) => { @@ -287,7 +287,14 @@ test("G4: stale same-group same-provider combo is pruned on re-sync", async () = const staleComboName = `qtSd/${groupSlug}/openrouter/fake-stale-model`; await combosDb.createCombo({ name: staleComboName, - models: [{ kind: "model", model: "openrouter/fake-stale-model", providerId: "openrouter", weight: 100 }], + models: [ + { + kind: "model", + model: "openrouter/fake-stale-model", + providerId: "openrouter", + weight: 100, + }, + ], strategy: "priority", isHidden: true, }); diff --git a/tests/unit/quota-combos-sync.test.ts b/tests/unit/quota-combos-sync.test.ts index a0a1b5b502..1e6b0e54b9 100644 --- a/tests/unit/quota-combos-sync.test.ts +++ b/tests/unit/quota-combos-sync.test.ts @@ -22,12 +22,10 @@ const core = await import("../../src/lib/db/core.ts"); const poolsDb = await import("../../src/lib/db/quotaPools.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const combosDb = await import("../../src/lib/db/combos.ts"); -const { syncQuotaCombos, removeQuotaCombosForPool } = await import( - "../../src/lib/quota/quotaCombos.ts" -); -const { quotaModelName, isQuotaModelName, parseQuotaModelName, quotaPoolSlug } = await import( - "../../src/lib/quota/quotaModelNaming.ts" -); +const { syncQuotaCombos, removeQuotaCombosForPool } = + await import("../../src/lib/quota/quotaCombos.ts"); +const { quotaModelName, isQuotaModelName, parseQuotaModelName, quotaPoolSlug } = + await import("../../src/lib/quota/quotaModelNaming.ts"); const { PROVIDER_MODELS } = await import("../../open-sse/config/providerModels.ts"); // --------------------------------------------------------------------------- @@ -39,7 +37,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -60,7 +58,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -312,7 +310,11 @@ test("syncQuotaCombos: does not affect quota combos for a different provider in }); assert.equal(remainingForA.length, 0, "PoolAlpha (glm) combos should all be removed"); - assert.equal(remainingForB.length, forB.length, "PoolBeta (openrouter) combos should be untouched"); + assert.equal( + remainingForB.length, + forB.length, + "PoolBeta (openrouter) combos should be untouched" + ); }); test("syncQuotaCombos: unknown pool id — no throw, prunes nothing (no combos exist)", async () => { diff --git a/tests/unit/quota-epsilon-unconfigured-allow.test.ts b/tests/unit/quota-epsilon-unconfigured-allow.test.ts index 1d93c6053e..ba1a8ae80c 100644 --- a/tests/unit/quota-epsilon-unconfigured-allow.test.ts +++ b/tests/unit/quota-epsilon-unconfigured-allow.test.ts @@ -40,7 +40,7 @@ test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ignore */ } diff --git a/tests/unit/quota-exclusive-catalog-4806.test.ts b/tests/unit/quota-exclusive-catalog-4806.test.ts index 75cd30bcec..a55fc34146 100644 --- a/tests/unit/quota-exclusive-catalog-4806.test.ts +++ b/tests/unit/quota-exclusive-catalog-4806.test.ts @@ -47,7 +47,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -69,7 +69,7 @@ test.beforeEach(async () => { test.after(async () => { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#4806 quota-exclusive key lists its qtSd/* virtual models in GET /v1/models", async () => { diff --git a/tests/unit/quota-exclusive-catalog-short-circuit.test.ts b/tests/unit/quota-exclusive-catalog-short-circuit.test.ts index a20cb9ee60..db0c37d8a4 100644 --- a/tests/unit/quota-exclusive-catalog-short-circuit.test.ts +++ b/tests/unit/quota-exclusive-catalog-short-circuit.test.ts @@ -66,7 +66,7 @@ test.after(async () => { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* ignore */ } diff --git a/tests/unit/quota-exclusivity-reconcile.test.ts b/tests/unit/quota-exclusivity-reconcile.test.ts index 89ef35e2b3..53932921d1 100644 --- a/tests/unit/quota-exclusivity-reconcile.test.ts +++ b/tests/unit/quota-exclusivity-reconcile.test.ts @@ -17,19 +17,14 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-quota-exclusivity-"), -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-quota-exclusivity-")); process.env.DATA_DIR = TEST_DATA_DIR; -process.env.API_KEY_SECRET = - process.env.API_KEY_SECRET || "exclusivity-reconcile-test-secret"; +process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "exclusivity-reconcile-test-secret"; const core = await import("../../src/lib/db/core.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); const poolsDb = await import("../../src/lib/db/quotaPools.ts"); -const { reconcilePoolExclusivity } = await import( - "../../src/lib/quota/quotaKey.ts" -); +const { reconcilePoolExclusivity } = await import("../../src/lib/quota/quotaKey.ts"); // --------------------------------------------------------------------------- // Test lifecycle helpers @@ -42,7 +37,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -74,7 +69,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -147,7 +142,7 @@ test("reconcilePoolExclusivity: idempotent — calling twice with same args does assert.equal( quotasAfterFirst.filter((q) => q === pool.id).length, 1, - "poolId should appear exactly once", + "poolId should appear exactly once" ); // Second call — idempotent @@ -158,12 +153,12 @@ test("reconcilePoolExclusivity: idempotent — calling twice with same args does assert.deepEqual( quotasAfterSecond, quotasAfterFirst, - "allowedQuotas should be unchanged after second call", + "allowedQuotas should be unchanged after second call" ); assert.equal( quotasAfterSecond.filter((q) => q === pool.id).length, 1, - "poolId should still appear exactly once", + "poolId should still appear exactly once" ); }); @@ -194,7 +189,7 @@ test("reconcilePoolExclusivity: missing/unknown keyId is skipped defensively (no // ghost-key does not exist in the DB; must not throw await assert.doesNotReject( () => reconcilePoolExclusivity(pool.id, [], ["ghost-key-id-that-does-not-exist"], true), - "should not throw for unknown key IDs", + "should not throw for unknown key IDs" ); }); diff --git a/tests/unit/quota-exhaustion-cutoff-opencode.test.ts b/tests/unit/quota-exhaustion-cutoff-opencode.test.ts index d212fc9394..c8aaa04d12 100644 --- a/tests/unit/quota-exhaustion-cutoff-opencode.test.ts +++ b/tests/unit/quota-exhaustion-cutoff-opencode.test.ts @@ -54,15 +54,12 @@ const quotaSnapshotsDb = await import("../../src/lib/db/quotaSnapshots.ts"); const quotaCache = await import("../../src/domain/quotaCache.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); -const { fetchOpencodeQuota, invalidateOpencodeQuotaCache } = await import( - "../../open-sse/services/opencodeQuotaFetcher.ts" -); -const { evaluateQuotaCutoff, registerQuotaFetcher } = await import( - "../../open-sse/services/quotaPreflight.ts" -); -const { buildAutoQuotaThresholds } = await import( - "../../open-sse/services/combo/quotaExhaustionCutoff.ts" -); +const { fetchOpencodeQuota, invalidateOpencodeQuotaCache } = + await import("../../open-sse/services/opencodeQuotaFetcher.ts"); +const { evaluateQuotaCutoff, registerQuotaFetcher } = + await import("../../open-sse/services/quotaPreflight.ts"); +const { buildAutoQuotaThresholds } = + await import("../../open-sse/services/combo/quotaExhaustionCutoff.ts"); const { resolveResilienceSettings } = await import("../../src/lib/resilience/settings.ts"); const auth = await import("../../src/sse/services/auth.ts"); @@ -112,7 +109,7 @@ test.after(() => { globalThis.fetch = originalFetch; coreDb.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test.afterEach(() => { @@ -137,7 +134,10 @@ test("#11234 dashboard snapshots feed the quota cutoff when the live endpoint ha const quota = await fetchOpencodeQuota(connectionId, dashboardConfiguredConnection("sk-test")); - assert.ok(quota, "fetcher must synthesize quota from dashboard snapshots when the live endpoint 404s"); + assert.ok( + quota, + "fetcher must synthesize quota from dashboard snapshots when the live endpoint 404s" + ); assert.equal(fetchCalls, 1, "snapshot bridge must be read-only — no re-scrape on the hot path"); // Key mapping: weekly → window_weekly (0% remaining = 100% used), @@ -148,10 +148,7 @@ test("#11234 dashboard snapshots feed the quota cutoff when the live endpoint ha `window_5h percentUsed should be ~0.2, got ${quota.windows?.[WINDOW_5H]?.percentUsed}` ); - const decision = evaluateQuotaCutoff( - quota, - buildAutoQuotaThresholds(PROVIDER, undefined, null) - ); + const decision = evaluateQuotaCutoff(quota, buildAutoQuotaThresholds(PROVIDER, undefined, null)); assert.equal(decision.proceed, false, "weekly at 0% remaining must block the connection"); assert.equal(decision.reason, "quota_exhausted"); @@ -177,10 +174,7 @@ test("#11234 a snapshot whose reset already passed must not count as exhausted", "an expired weekly window must be dropped from the synthesized quota" ); - const decision = evaluateQuotaCutoff( - quota, - buildAutoQuotaThresholds(PROVIDER, undefined, null) - ); + const decision = evaluateQuotaCutoff(quota, buildAutoQuotaThresholds(PROVIDER, undefined, null)); assert.equal(decision.proceed, true, "an expired weekly window must not block the connection"); invalidateOpencodeQuotaCache(connectionId); diff --git a/tests/unit/quota-group-allocations.test.ts b/tests/unit/quota-group-allocations.test.ts index c8c47d6783..70e2cf9075 100644 --- a/tests/unit/quota-group-allocations.test.ts +++ b/tests/unit/quota-group-allocations.test.ts @@ -31,13 +31,10 @@ import os from "node:os"; import path from "node:path"; // ── DB / store harness ──────────────────────────────────────────────────────── -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-quota-group-alloc-"), -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-quota-group-alloc-")); process.env.DATA_DIR = TEST_DATA_DIR; // Ensure a deterministic secret for apiKey tests (check 5). -process.env.API_KEY_SECRET = - process.env.API_KEY_SECRET || "group-alloc-test-secret-32ch-xxxx"; +process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "group-alloc-test-secret-32ch-xxxx"; const core = await import("../../src/lib/db/core.ts"); const poolsDb = await import("../../src/lib/db/quotaPools.ts"); @@ -46,9 +43,8 @@ const providersDb = await import("../../src/lib/db/providers.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); const { enforceQuotaShare } = await import("../../src/lib/quota/enforce.ts"); const { resolveQuotaKeyScope } = await import("../../src/lib/quota/quotaKey.ts"); -const { isQuotaModelName, parseQuotaModelName, quotaModelName, quotaGroupSlug } = await import( - "../../src/lib/quota/quotaModelNaming.ts" -); +const { isQuotaModelName, parseQuotaModelName, quotaModelName, quotaGroupSlug } = + await import("../../src/lib/quota/quotaModelNaming.ts"); // --------------------------------------------------------------------------- // Lifecycle @@ -64,7 +60,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -89,7 +85,7 @@ test.after(async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (apiKeysDb as any).resetApiKeyState(); } - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -190,8 +186,16 @@ test("upsertAllocations: single-pool group — only that pool is written", async const groupOther = groupsDb.createGroup("GroupOther3"); const connO = await mkConn("baidu", "conn-alloc-o3"); - const poolZ = poolsDb.createPool({ connectionId: connZ, name: "Pool Z3", groupId: groupSingle.id }); - const poolO = poolsDb.createPool({ connectionId: connO, name: "Pool O3", groupId: groupOther.id }); + const poolZ = poolsDb.createPool({ + connectionId: connZ, + name: "Pool Z3", + groupId: groupSingle.id, + }); + const poolO = poolsDb.createPool({ + connectionId: connO, + name: "Pool O3", + groupId: groupOther.id, + }); poolsDb.upsertAllocations(poolZ.id, [{ apiKeyId: "k3", weight: 100, policy: "hard" }]); @@ -199,7 +203,11 @@ test("upsertAllocations: single-pool group — only that pool is written", async assert.equal(getAllocs(poolZ.id).length, 1, "poolZ should have 1 allocation"); // poolO (different group) should have NO rows - assert.equal(getAllocs(poolO.id).length, 0, "poolO (different group) must not receive propagated rows"); + assert.equal( + getAllocs(poolO.id).length, + 0, + "poolO (different group) must not receive propagated rows" + ); }); // --------------------------------------------------------------------------- @@ -212,8 +220,16 @@ test("enforceQuotaShare: key k1 allocated via pool A is enforced when calling po const connA = await mkConn("openrouter", "conn-enforce-a4"); const connB = await mkConn("baidu", "conn-enforce-b4"); - const poolA = poolsDb.createPool({ connectionId: connA, name: "Pool EnforceA4", groupId: groupG.id }); - const poolB = poolsDb.createPool({ connectionId: connB, name: "Pool EnforceB4", groupId: groupG.id }); + const poolA = poolsDb.createPool({ + connectionId: connA, + name: "Pool EnforceA4", + groupId: groupG.id, + }); + const poolB = poolsDb.createPool({ + connectionId: connB, + name: "Pool EnforceB4", + groupId: groupG.id, + }); // Allocate k1 via pool A — propagation should write to pool B as well poolsDb.upsertAllocations(poolA.id, [{ apiKeyId: "k1", weight: 50, policy: "hard" }]); @@ -244,7 +260,11 @@ test("enforceQuotaShare: key k1 allocated via pool A is enforced when calling po // rows, and the pool-connection-match loop would find no pool for connB → allow (fail-open). // Both paths return allow here, but the key difference is the allocation row IS present // in pool B (asserted above) — the enforce path will find it and proceed to plan check. - assert.equal(result.kind, "allow", "enforceQuotaShare should allow (no plan dims for test provider)"); + assert.equal( + result.kind, + "allow", + "enforceQuotaShare should allow (no plan dims for test provider)" + ); }); // --------------------------------------------------------------------------- @@ -259,13 +279,25 @@ test("apiKeyPolicy groupSlug check: key in group G allowed for B's qtSd model, d const connA = await mkConn("openrouter", "conn-policy-a5"); const connB = await mkConn("baidu", "conn-policy-b5"); - const poolA = poolsDb.createPool({ connectionId: connA, name: "Pool PolicyA5", groupId: groupG.id }); - const poolB = poolsDb.createPool({ connectionId: connB, name: "Pool PolicyB5", groupId: groupG.id }); + const poolA = poolsDb.createPool({ + connectionId: connA, + name: "Pool PolicyA5", + groupId: groupG.id, + }); + const poolB = poolsDb.createPool({ + connectionId: connB, + name: "Pool PolicyB5", + groupId: groupG.id, + }); // Also create a different group with its own pool const groupH = groupsDb.createGroup("GroupPolicyH5"); const connH = await mkConn("openrouter", "conn-policy-h5"); - const poolH = poolsDb.createPool({ connectionId: connH, name: "Pool PolicyH5", groupId: groupH.id }); + const poolH = poolsDb.createPool({ + connectionId: connH, + name: "Pool PolicyH5", + groupId: groupH.id, + }); // Key is allocated to pool A only (allowedQuotas=[poolA.id]) poolsDb.upsertAllocations(poolA.id, [{ apiKeyId: "k5", weight: 50, policy: "hard" }]); @@ -273,8 +305,8 @@ test("apiKeyPolicy groupSlug check: key in group G allowed for B's qtSd model, d // Resolve the key's scope const scope = await resolveQuotaKeyScope([poolA.id]); - const gSlug = quotaGroupSlug(groupG.name); // "grouppolicy5" - const hSlug = quotaGroupSlug(groupH.name); // "grouppolicyh5" + const gSlug = quotaGroupSlug(groupG.name); // "grouppolicy5" + const hSlug = quotaGroupSlug(groupH.name); // "grouppolicyh5" // Pool B's qtSd model (belongs to group G) const modelB = quotaModelName(groupG.name, "baidu", "ernie-4.5"); @@ -334,7 +366,11 @@ test("upsertAllocations: propagates to all 3 pools in the same group", async () { apiKeyId: "k6b", weight: 60, policy: "soft" }, ]); - for (const [label, pid] of [["A", poolA.id], ["B", poolB.id], ["C", poolC.id]] as [string, string][]) { + for (const [label, pid] of [ + ["A", poolA.id], + ["B", poolB.id], + ["C", poolC.id], + ] as [string, string][]) { const allocs = getAllocs(pid); assert.equal(allocs.length, 2, `pool ${label} should have 2 allocations`); const k6a = allocs.find((a) => a.apiKeyId === "k6a"); diff --git a/tests/unit/quota-group-scope.test.ts b/tests/unit/quota-group-scope.test.ts index f5e27630bd..814c29e68d 100644 --- a/tests/unit/quota-group-scope.test.ts +++ b/tests/unit/quota-group-scope.test.ts @@ -43,7 +43,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -64,7 +64,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- @@ -100,7 +100,10 @@ test("resolveQuotaKeyScope: key in pool A sees ALL connections/providers of grou // Must include both connections assert.ok(scope.connectionIds.includes(idA), "should include pool A connection"); - assert.ok(scope.connectionIds.includes(idB), "should include pool B connection (group expansion)"); + assert.ok( + scope.connectionIds.includes(idB), + "should include pool B connection (group expansion)" + ); assert.equal(scope.connectionIds.length, 2, "exactly 2 connections"); // Must include both providers @@ -207,7 +210,10 @@ test("filterModelsToQuotaPools: keeps both providers' qtSd//... models fr assert.equal(result.length, 2, "should return both providers' models for the group"); assert.ok(result.some((m) => m.id === `qtSd/${groupSlug}/openrouter/gpt-5.5`)); assert.ok(result.some((m) => m.id === `qtSd/${groupSlug}/baidu/ernie-4.5`)); - assert.ok(!result.some((m) => m.id === `qtSd/otherg/openrouter/gpt-5.5`), "other group filtered out"); + assert.ok( + !result.some((m) => m.id === `qtSd/otherg/openrouter/gpt-5.5`), + "other group filtered out" + ); assert.ok(!result.some((m) => m.id === "gpt-5.5"), "non-quota model filtered out"); }); @@ -240,7 +246,11 @@ test("resolveQuotaKeyScope: orphan pool in group that also has a valid pool — apiKey: "sk-partial-valid", }); const idValid = (connValid as Record).id as string; - const validPool = poolsDb.createPool({ connectionId: idValid, name: "Valid Pool G", groupId: groupG.id }); + const validPool = poolsDb.createPool({ + connectionId: idValid, + name: "Valid Pool G", + groupId: groupG.id, + }); // One orphan pool in the same group const orphanPool = poolsDb.createPool({ @@ -254,7 +264,10 @@ test("resolveQuotaKeyScope: orphan pool in group that also has a valid pool — // The group has a valid connection (the validPool's connection) so group slug should be included const expectedSlug = quotaGroupSlug(groupG.name); - assert.ok(scope.poolSlugs.includes(expectedSlug), "group slug should be included since group has valid connection"); + assert.ok( + scope.poolSlugs.includes(expectedSlug), + "group slug should be included since group has valid connection" + ); assert.ok(scope.connectionIds.includes(idValid), "should include the valid pool's connection"); assert.ok(scope.providers.includes("openrouter"), "should include openrouter from valid pool"); diff --git a/tests/unit/quota-groups-crud.test.ts b/tests/unit/quota-groups-crud.test.ts index 6bbaf313a4..057b39de40 100644 --- a/tests/unit/quota-groups-crud.test.ts +++ b/tests/unit/quota-groups-crud.test.ts @@ -31,7 +31,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -51,7 +51,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── B2.1: createGroup / getGroup / getGroupName ─────────────────────────────── diff --git a/tests/unit/quota-groups-migration.test.ts b/tests/unit/quota-groups-migration.test.ts index 88594c287a..bfaa80e6a9 100644 --- a/tests/unit/quota-groups-migration.test.ts +++ b/tests/unit/quota-groups-migration.test.ts @@ -30,7 +30,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -50,13 +50,15 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Helper to get a raw DB handle for inspection / seeding. function getDb() { return core.getDbInstance() as unknown as { - prepare: (sql: string) => { + prepare: ( + sql: string + ) => { all: (...params: unknown[]) => TRow[]; get: (...params: unknown[]) => TRow | undefined; run: (...params: unknown[]) => { changes: number }; @@ -72,10 +74,7 @@ test("migration 087 file exists", () => { }); test("migration 087 contains quota_groups CREATE TABLE", () => { - const sql = fs.readFileSync( - path.resolve("src/lib/db/migrations/088_quota_groups.sql"), - "utf8" - ); + const sql = fs.readFileSync(path.resolve("src/lib/db/migrations/088_quota_groups.sql"), "utf8"); assert.ok(sql.includes("quota_groups"), "migration SQL should reference quota_groups"); assert.ok( sql.includes("CREATE TABLE IF NOT EXISTS quota_groups"), @@ -84,14 +83,8 @@ test("migration 087 contains quota_groups CREATE TABLE", () => { }); test("migration 087 seeds group-demo", () => { - const sql = fs.readFileSync( - path.resolve("src/lib/db/migrations/088_quota_groups.sql"), - "utf8" - ); - assert.ok( - sql.includes("group-demo"), - "migration SQL should insert the 'group-demo' seed row" - ); + const sql = fs.readFileSync(path.resolve("src/lib/db/migrations/088_quota_groups.sql"), "utf8"); + assert.ok(sql.includes("group-demo"), "migration SQL should insert the 'group-demo' seed row"); assert.ok( sql.includes("INSERT OR IGNORE INTO quota_groups"), "migration SQL should use INSERT OR IGNORE for idempotency" @@ -99,10 +92,7 @@ test("migration 087 seeds group-demo", () => { }); test("migration 087 adds group_id column to quota_pools", () => { - const sql = fs.readFileSync( - path.resolve("src/lib/db/migrations/088_quota_groups.sql"), - "utf8" - ); + const sql = fs.readFileSync(path.resolve("src/lib/db/migrations/088_quota_groups.sql"), "utf8"); assert.ok( sql.includes("ALTER TABLE quota_pools ADD COLUMN group_id"), "migration SQL should ALTER TABLE quota_pools to add group_id" @@ -110,10 +100,7 @@ test("migration 087 adds group_id column to quota_pools", () => { }); test("migration 087 contains backfill UPDATE for existing pools", () => { - const sql = fs.readFileSync( - path.resolve("src/lib/db/migrations/088_quota_groups.sql"), - "utf8" - ); + const sql = fs.readFileSync(path.resolve("src/lib/db/migrations/088_quota_groups.sql"), "utf8"); assert.ok( sql.includes("UPDATE quota_pools SET group_id = 'group-demo'"), "migration SQL should backfill existing pools to group-demo" diff --git a/tests/unit/quota-key-resolve.test.ts b/tests/unit/quota-key-resolve.test.ts index 9c6630fd27..707f89ec08 100644 --- a/tests/unit/quota-key-resolve.test.ts +++ b/tests/unit/quota-key-resolve.test.ts @@ -32,7 +32,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/unit/quota-multiprovider.test.ts b/tests/unit/quota-multiprovider.test.ts index d15b0e6a5b..1b15546a1c 100644 --- a/tests/unit/quota-multiprovider.test.ts +++ b/tests/unit/quota-multiprovider.test.ts @@ -113,7 +113,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort cleanup } diff --git a/tests/unit/quota-per-key-model-hotpath.test.ts b/tests/unit/quota-per-key-model-hotpath.test.ts index ca211750f5..506ab9472e 100644 --- a/tests/unit/quota-per-key-model-hotpath.test.ts +++ b/tests/unit/quota-per-key-model-hotpath.test.ts @@ -37,9 +37,8 @@ const { createPool, upsertAllocations } = await import("../../src/lib/db/quotaPo const { setModelCap } = await import("../../src/lib/db/quotaModelCaps.ts"); const { enforceQuotaShare } = await import("../../src/lib/quota/enforce.ts"); const { resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); -const { scheduleQuotaShareConsumption } = await import( - "../../open-sse/handlers/chatCore/quotaShareConsumption.ts" -); +const { scheduleQuotaShareConsumption } = + await import("../../open-sse/handlers/chatCore/quotaShareConsumption.ts"); // ── Fixtures ────────────────────────────────────────────────────────────────── const CONN_ID = "conn-model-cap-hotpath"; @@ -55,7 +54,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -76,7 +75,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function makePool() { @@ -145,7 +144,13 @@ async function enforceUntil( // --------------------------------------------------------------------------- test("hot-path: model cap blocks after N consumptions driven through scheduleQuotaShareConsumption", async () => { const pool = makePool(); - setModelCap({ poolId: pool.id, apiKeyId: KEY_A, model: MODEL_M, capValue: CAP_N, capUnit: "requests" }); + setModelCap({ + poolId: pool.id, + apiKeyId: KEY_A, + model: MODEL_M, + capValue: CAP_N, + capUnit: "requests", + }); // Drive CAP_N consumptions through the REAL non-streaming hot-path hook. await consumeViaHotPath(MODEL_M, CAP_N); @@ -164,7 +169,7 @@ test("hot-path: model cap blocks after N consumptions driven through scheduleQuo assert.equal(blocked.kind, "block", "model M must be blocked after N hot-path consumptions"); assert.ok( "reason" in blocked && blocked.reason.includes("model-cap"), - `reason must mention model-cap; got: ${"reason" in blocked ? blocked.reason : "(no reason)"}`, + `reason must mention model-cap; got: ${"reason" in blocked ? blocked.reason : "(no reason)"}` ); // A different model in the SAME pool (no cap) must still be allowed. @@ -184,7 +189,13 @@ test("hot-path: model cap blocks after N consumptions driven through scheduleQuo // --------------------------------------------------------------------------- test("hot-path: enforce WITHOUT model never triggers model-cap block (fail-safe)", async () => { const pool = makePool(); - setModelCap({ poolId: pool.id, apiKeyId: KEY_A, model: MODEL_M, capValue: 1, capUnit: "requests" }); + setModelCap({ + poolId: pool.id, + apiKeyId: KEY_A, + model: MODEL_M, + capValue: 1, + capUnit: "requests", + }); // Consume via hot path WITH model so the bucket fills. await consumeViaHotPath(MODEL_M, 2); diff --git a/tests/unit/quota-per-key-model.test.ts b/tests/unit/quota-per-key-model.test.ts index 0ce1970382..6158a20d4b 100644 --- a/tests/unit/quota-per-key-model.test.ts +++ b/tests/unit/quota-per-key-model.test.ts @@ -39,7 +39,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -69,7 +69,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Helper: create pool with KEY_A allocation ───────────────────────────── @@ -84,7 +84,13 @@ function makePool() { // --------------------------------------------------------------------------- test("per-(key,model) cap — keyA blocked on model M after N requests", async () => { const pool = makePool(); - setModelCap({ poolId: pool.id, apiKeyId: KEY_A, model: MODEL_M, capValue: CAP_N, capUnit: "requests" }); + setModelCap({ + poolId: pool.id, + apiKeyId: KEY_A, + model: MODEL_M, + capValue: CAP_N, + capUnit: "requests", + }); // Simulate CAP_N prior consumptions for (let i = 0; i < CAP_N; i++) { @@ -108,7 +114,7 @@ test("per-(key,model) cap — keyA blocked on model M after N requests", async ( assert.equal(result.kind, "block", "must block when model cap is reached"); assert.ok( "reason" in result && result.reason.includes("model-cap"), - `reason must mention model-cap; got: ${"reason" in result ? result.reason : "(no reason)"}`, + `reason must mention model-cap; got: ${"reason" in result ? result.reason : "(no reason)"}` ); assert.equal("httpStatus" in result && result.httpStatus, 429, "must return 429"); }); @@ -118,7 +124,13 @@ test("per-(key,model) cap — keyA blocked on model M after N requests", async ( // --------------------------------------------------------------------------- test("per-(key,model) cap — keyA blocked on M, still allowed on M2 same pool", async () => { const pool = makePool(); - setModelCap({ poolId: pool.id, apiKeyId: KEY_A, model: MODEL_M, capValue: 1, capUnit: "requests" }); + setModelCap({ + poolId: pool.id, + apiKeyId: KEY_A, + model: MODEL_M, + capValue: 1, + capUnit: "requests", + }); // Consume the single request cap on model M await recordConsumption({ @@ -140,7 +152,7 @@ test("per-(key,model) cap — keyA blocked on M, still allowed on M2 same pool", assert.equal(resultM.kind, "block", "model M should be blocked"); assert.ok( "reason" in resultM && resultM.reason.includes("model-cap"), - `reason must mention model-cap; got: ${"reason" in resultM ? resultM.reason : "(no reason)"}`, + `reason must mention model-cap; got: ${"reason" in resultM ? resultM.reason : "(no reason)"}` ); // Model M2 (no cap configured) must still be allowed @@ -182,7 +194,8 @@ test("per-(key,model) cap — EPSILON cap value → ignored, request allowed", a // Insert a placeholder cap directly (Number.EPSILON > 0 passes DB CHECK constraint // but enforce.ts skips it: !(capValue > Number.EPSILON) → true for EPSILON). - core.getDbInstance() + core + .getDbInstance() .prepare( `INSERT INTO quota_allocation_model_caps (pool_id, api_key_id, model, cap_value, cap_unit) VALUES (?, ?, ?, ?, ?)` diff --git a/tests/unit/quota-phase2.test.ts b/tests/unit/quota-phase2.test.ts index 64e0600e2a..0da572c9f4 100644 --- a/tests/unit/quota-phase2.test.ts +++ b/tests/unit/quota-phase2.test.ts @@ -8,21 +8,18 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omni-quota-phase2-" process.env.DATA_DIR = TEST_DATA_DIR; const coreDb = await import("../../src/lib/db/core.ts"); -const { parseProviderQuotaHeaders, applyQuotaHeadersToState } = await import( - "../../src/lib/quota/quotaAdapters" -); +const { parseProviderQuotaHeaders, applyQuotaHeadersToState } = + await import("../../src/lib/quota/quotaAdapters"); const { getQuotaAnalyticsSummary } = await import("../../src/lib/quota/quotaAnalytics"); -const { getActiveQuotaResetItems, resetExpiredQuotaWindows } = await import( - "../../src/lib/quota/quotaResetTimers" -); -const { recordProviderQuotaUsage, getProviderQuota } = await import( - "../../src/lib/quota/providerQuotaState" -); +const { getActiveQuotaResetItems, resetExpiredQuotaWindows } = + await import("../../src/lib/quota/quotaResetTimers"); +const { recordProviderQuotaUsage, getProviderQuota } = + await import("../../src/lib/quota/providerQuotaState"); const { getDbInstance } = coreDb; async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -32,7 +29,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("parseProviderQuotaHeaders: parses OpenAI rate limit headers", () => { @@ -96,15 +93,7 @@ test("quotaResetTimers: tracks active reset items and purges expired windows", ( `INSERT OR REPLACE INTO provider_quota_state (connection_id, model, tokens_used, token_limit, window_start, window_reset, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)` - ).run( - connId, - model, - 5000, - 5000, - now - 10_000, - now - 1_000, - new Date().toISOString() - ); + ).run(connId, model, 5000, 5000, now - 10_000, now - 1_000, new Date().toISOString()); const expiredCount = resetExpiredQuotaWindows(); assert.ok(expiredCount >= 1); diff --git a/tests/unit/quota-plan-resolver.test.ts b/tests/unit/quota-plan-resolver.test.ts index 72401f2022..fad765f066 100644 --- a/tests/unit/quota-plan-resolver.test.ts +++ b/tests/unit/quota-plan-resolver.test.ts @@ -26,7 +26,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Scenario 1 ───────────────────────────────────────────────────────────── @@ -55,9 +55,12 @@ test("planResolver: DB plan present → returns DB plan (source=manual)", async const { resolvePlan } = await import("../../src/lib/quota/planResolver.ts"); // Seed a DB override - providerPlansDb.upsertPlan("conn-123", "openai", [ - { unit: "tokens", window: "hourly", limit: 10_000 }, - ], "manual"); + providerPlansDb.upsertPlan( + "conn-123", + "openai", + [{ unit: "tokens", window: "hourly", limit: 10_000 }], + "manual" + ); const plan = resolvePlan("conn-123", "openai"); assert.equal(plan.source, "manual"); @@ -95,9 +98,12 @@ test("planResolver: DB plan overrides catalog for same provider", async () => { const { resolvePlan } = await import("../../src/lib/quota/planResolver.ts"); // codex is in catalog, but we add a DB override - providerPlansDb.upsertPlan("conn-codex-override", "codex", [ - { unit: "requests", window: "daily", limit: 999 }, - ], "manual"); + providerPlansDb.upsertPlan( + "conn-codex-override", + "codex", + [{ unit: "requests", window: "daily", limit: 999 }], + "manual" + ); const plan = resolvePlan("conn-codex-override", "codex"); assert.equal(plan.source, "manual"); diff --git a/tests/unit/quota-pool-connections.test.ts b/tests/unit/quota-pool-connections.test.ts index 7f063f112f..c516001865 100644 --- a/tests/unit/quota-pool-connections.test.ts +++ b/tests/unit/quota-pool-connections.test.ts @@ -31,7 +31,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -51,7 +51,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── D1.1: Migration file ──────────────────────────────────────────────────── diff --git a/tests/unit/quota-pool-delete-prune.test.ts b/tests/unit/quota-pool-delete-prune.test.ts index ed08223b0d..8156206f77 100644 --- a/tests/unit/quota-pool-delete-prune.test.ts +++ b/tests/unit/quota-pool-delete-prune.test.ts @@ -35,7 +35,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Helper: get allowed_quotas for a key by id from DB ─────────────────────── diff --git a/tests/unit/quota-pool-single-provider.test.ts b/tests/unit/quota-pool-single-provider.test.ts index a2ce296220..d654558d08 100644 --- a/tests/unit/quota-pool-single-provider.test.ts +++ b/tests/unit/quota-pool-single-provider.test.ts @@ -29,7 +29,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: any) { @@ -49,7 +49,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── T3.1: createPool with mixed providers → throws ────────────────────────── diff --git a/tests/unit/quota-pool-update-full.test.ts b/tests/unit/quota-pool-update-full.test.ts index 1497b144b6..908ee3b0ea 100644 --- a/tests/unit/quota-pool-update-full.test.ts +++ b/tests/unit/quota-pool-update-full.test.ts @@ -24,20 +24,18 @@ const poolsDb = await import("../../src/lib/db/quotaPools.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const combosDb = await import("../../src/lib/db/combos.ts"); const { createGroup } = await import("../../src/lib/db/quotaGroups.ts"); -const { syncQuotaCombos, removeQuotaCombosForPool } = await import( - "../../src/lib/quota/quotaCombos.ts" -); +const { syncQuotaCombos, removeQuotaCombosForPool } = + await import("../../src/lib/quota/quotaCombos.ts"); const { PoolUpdateSchema } = await import("../../src/shared/schemas/quota.ts"); -const { isQuotaModelName, parseQuotaModelName, quotaGroupSlug } = await import( - "../../src/lib/quota/quotaModelNaming.ts" -); +const { isQuotaModelName, parseQuotaModelName, quotaGroupSlug } = + await import("../../src/lib/quota/quotaModelNaming.ts"); async function resetStorage() { core.resetDbInstance(); for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -58,7 +56,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Helper: list only quota-named combos ─────────────────────────────────── diff --git a/tests/unit/quota-redis-store.test.ts b/tests/unit/quota-redis-store.test.ts index 5a5ae936dc..551074c6a9 100644 --- a/tests/unit/quota-redis-store.test.ts +++ b/tests/unit/quota-redis-store.test.ts @@ -34,7 +34,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -56,7 +56,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/quota-scheduler.test.ts b/tests/unit/quota-scheduler.test.ts index d105945a0a..91cd575680 100644 --- a/tests/unit/quota-scheduler.test.ts +++ b/tests/unit/quota-scheduler.test.ts @@ -14,7 +14,7 @@ const { clearProviderQuota, getProviderQuota, recordProviderQuotaUsage } = async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -24,7 +24,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const CONN = "test-conn-quota"; diff --git a/tests/unit/quota-sharing-fixes.test.ts b/tests/unit/quota-sharing-fixes.test.ts index 83743fea83..73278130d9 100644 --- a/tests/unit/quota-sharing-fixes.test.ts +++ b/tests/unit/quota-sharing-fixes.test.ts @@ -26,7 +26,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -48,7 +48,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -146,9 +146,8 @@ test("upsertAllocations: preserves non-zero weights", async () => { // ─── Fix 4: storeRateLimitHeaders + Anthropic saturation ───────────────────── test("storeRateLimitHeaders: stores headers and getSaturation reads them", async () => { - const { storeRateLimitHeaders, _clearSaturationCache } = await import( - "../../src/lib/quota/saturationSignals.ts" - ); + const { storeRateLimitHeaders, _clearSaturationCache } = + await import("../../src/lib/quota/saturationSignals.ts"); _clearSaturationCache(); @@ -170,9 +169,8 @@ test("storeRateLimitHeaders: stores headers and getSaturation reads them", async }); test("storeRateLimitHeaders: ignores non-Anthropic headers gracefully", async () => { - const { storeRateLimitHeaders, _clearSaturationCache, getSaturation } = await import( - "../../src/lib/quota/saturationSignals.ts" - ); + const { storeRateLimitHeaders, _clearSaturationCache, getSaturation } = + await import("../../src/lib/quota/saturationSignals.ts"); _clearSaturationCache(); @@ -199,9 +197,7 @@ test("poolUsageWithDimensions: returns non-null burn rate for token dimensions", const pool = poolsDb.createPool({ connectionId: "conn-burn-rate", name: "Burn Rate Pool", - allocations: [ - { apiKeyId: "key-br-1", weight: 100, policy: "hard" }, - ], + allocations: [{ apiKeyId: "key-br-1", weight: 100, policy: "hard" }], }); const dim = { poolId: pool.id, unit: "tokens" as const, window: "hourly" as const }; @@ -229,9 +225,7 @@ test("poolUsageWithDimensions: no burn rate when consumedTotal is 0", async () = const pool = poolsDb.createPool({ connectionId: "conn-no-burn", name: "No Burn Pool", - allocations: [ - { apiKeyId: "key-nb-1", weight: 100, policy: "hard" }, - ], + allocations: [{ apiKeyId: "key-nb-1", weight: 100, policy: "hard" }], }); const snapshot = await store.poolUsageWithDimensions(pool.id, [ @@ -248,7 +242,11 @@ test("QuotaStore interface: poolUsageWithDimensions is on the interface", async // We verify at runtime that both implementations have it. const { SqliteQuotaStore } = await import("../../src/lib/quota/sqliteQuotaStore.ts"); const sqlite = new SqliteQuotaStore(); - assert.equal(typeof sqlite.poolUsageWithDimensions, "function", "SqliteQuotaStore must have poolUsageWithDimensions"); + assert.equal( + typeof sqlite.poolUsageWithDimensions, + "function", + "SqliteQuotaStore must have poolUsageWithDimensions" + ); // Redis store (just check the prototype) const { RedisQuotaStore } = await import("../../src/lib/quota/redisQuotaStore.ts"); diff --git a/tests/unit/quota-sqlite-store.test.ts b/tests/unit/quota-sqlite-store.test.ts index 3b4ecda926..d1ea939891 100644 --- a/tests/unit/quota-sqlite-store.test.ts +++ b/tests/unit/quota-sqlite-store.test.ts @@ -28,7 +28,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -50,7 +50,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/quota-store-factory.test.ts b/tests/unit/quota-store-factory.test.ts index 111960c100..a82efdcff0 100644 --- a/tests/unit/quota-store-factory.test.ts +++ b/tests/unit/quota-store-factory.test.ts @@ -25,7 +25,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -56,7 +56,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } // Restore env if (origDriver !== undefined) process.env.QUOTA_STORE_DRIVER = origDriver; @@ -68,7 +68,8 @@ test.after(async () => { // ─── Default driver ────────────────────────────────────────────────────────── test("storeFactory: default driver is sqlite", async () => { - const { getQuotaStore, resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); + const { getQuotaStore, resetQuotaStoreSingleton } = + await import("../../src/lib/quota/storeFactory.ts"); resetQuotaStoreSingleton(); const store = await getQuotaStore(); @@ -83,7 +84,8 @@ test("storeFactory: default driver is sqlite", async () => { // ─── Singleton behaviour ───────────────────────────────────────────────────── test("storeFactory: multiple calls return same singleton", async () => { - const { getQuotaStore, resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); + const { getQuotaStore, resetQuotaStoreSingleton } = + await import("../../src/lib/quota/storeFactory.ts"); resetQuotaStoreSingleton(); const store1 = await getQuotaStore(); @@ -92,7 +94,8 @@ test("storeFactory: multiple calls return same singleton", async () => { }); test("storeFactory: resetQuotaStoreSingleton() creates new instance on next call", async () => { - const { getQuotaStore, resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); + const { getQuotaStore, resetQuotaStoreSingleton } = + await import("../../src/lib/quota/storeFactory.ts"); resetQuotaStoreSingleton(); const store1 = await getQuotaStore(); @@ -107,7 +110,8 @@ test("storeFactory: resetQuotaStoreSingleton() creates new instance on next call // ─── Redis driver + no URL → fallback sqlite ───────────────────────────────── test("storeFactory: QUOTA_STORE_DRIVER=redis without URL → fallback to sqlite", async () => { - const { getQuotaStore, resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); + const { getQuotaStore, resetQuotaStoreSingleton } = + await import("../../src/lib/quota/storeFactory.ts"); resetQuotaStoreSingleton(); process.env.QUOTA_STORE_DRIVER = "redis"; @@ -122,7 +126,8 @@ test("storeFactory: QUOTA_STORE_DRIVER=redis without URL → fallback to sqlite" // ─── Unknown driver → fallback sqlite ──────────────────────────────────────── test("storeFactory: unknown driver value → falls back to sqlite silently", async () => { - const { getQuotaStore, resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); + const { getQuotaStore, resetQuotaStoreSingleton } = + await import("../../src/lib/quota/storeFactory.ts"); resetQuotaStoreSingleton(); (process.env as Record).QUOTA_STORE_DRIVER = "memcached"; @@ -135,7 +140,8 @@ test("storeFactory: unknown driver value → falls back to sqlite silently", asy // ─── Redis driver + invalid URL (ioredis not installed) → fallback ──────────── test("storeFactory: QUOTA_STORE_DRIVER=redis with invalid URL → fallback or throws gracefully", async () => { - const { getQuotaStore, resetQuotaStoreSingleton } = await import("../../src/lib/quota/storeFactory.ts"); + const { getQuotaStore, resetQuotaStoreSingleton } = + await import("../../src/lib/quota/storeFactory.ts"); resetQuotaStoreSingleton(); process.env.QUOTA_STORE_DRIVER = "redis"; diff --git a/tests/unit/quota-store-pool-total.test.ts b/tests/unit/quota-store-pool-total.test.ts index a6d44d4611..206cd20fdb 100644 --- a/tests/unit/quota-store-pool-total.test.ts +++ b/tests/unit/quota-store-pool-total.test.ts @@ -23,7 +23,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (err: unknown) { @@ -45,7 +45,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/qwen-settings-route.test.ts b/tests/unit/qwen-settings-route.test.ts index 0b1f2ab619..60f998e92d 100644 --- a/tests/unit/qwen-settings-route.test.ts +++ b/tests/unit/qwen-settings-route.test.ts @@ -38,13 +38,13 @@ const request = async (method: string, body?: unknown): Promise => }); test.beforeEach(async () => { - await fs.rm(TEST_HOME, { recursive: true, force: true }); + await fs.rm(TEST_HOME, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); await fs.mkdir(path.dirname(SETTINGS_PATH), { recursive: true }); }); test.after(async () => { os.homedir = originalHome; - await fs.rm(TEST_HOME, { recursive: true, force: true }); + await fs.rm(TEST_HOME, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalJwtSecret === undefined) delete process.env.JWT_SECRET; else process.env.JWT_SECRET = originalJwtSecret; if (originalWriteFlag === undefined) delete process.env.CLI_ALLOW_CONFIG_WRITES; diff --git a/tests/unit/qwen-web-runtime-block.test.ts b/tests/unit/qwen-web-runtime-block.test.ts index 71630ede72..8cb2e3cc45 100644 --- a/tests/unit/qwen-web-runtime-block.test.ts +++ b/tests/unit/qwen-web-runtime-block.test.ts @@ -32,7 +32,7 @@ const RETIRED_PROVIDER_VARIANTS = [ async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); core.getDbInstance(); } @@ -50,7 +50,7 @@ test.afterEach(async () => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function isRetiredError(error: unknown): boolean { diff --git a/tests/unit/radar-api-routes.test.ts b/tests/unit/radar-api-routes.test.ts index ae95272bef..92200d9a77 100644 --- a/tests/unit/radar-api-routes.test.ts +++ b/tests/unit/radar-api-routes.test.ts @@ -85,7 +85,7 @@ function resetStorage() { core.resetDbInstance(); try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } catch { // ignore @@ -563,7 +563,7 @@ test.after(() => { delete process.env.JWT_SECRET; delete process.env.INITIAL_PASSWORD; try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } diff --git a/tests/unit/radar-db.test.ts b/tests/unit/radar-db.test.ts index 1aaaaa6455..d28608a526 100644 --- a/tests/unit/radar-db.test.ts +++ b/tests/unit/radar-db.test.ts @@ -29,7 +29,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -51,7 +51,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.STORAGE_ENCRYPTION_KEY; }); diff --git a/tests/unit/radar-export.test.mjs b/tests/unit/radar-export.test.mjs index 55e1d424aa..f8f74f1799 100644 --- a/tests/unit/radar-export.test.mjs +++ b/tests/unit/radar-export.test.mjs @@ -35,7 +35,7 @@ function runExport(extraEnv = {}) { }, }); const parsed = JSON.parse(fs.readFileSync(outPath, "utf8")); - fs.rmSync(outDir, { recursive: true, force: true }); + fs.rmSync(outDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return parsed; } @@ -64,7 +64,10 @@ test("radar export provenance never fabricates unknown fields", () => { assert.equal(p.sourceRef, null); assert.equal(p.runUrl, null); // sourceCommit: SHA de 40 hex (via git no checkout) ou null se indisponível. - assert.ok(p.sourceCommit === null || /^[0-9a-f]{40}$/.test(p.sourceCommit), "sourceCommit sha|null"); + assert.ok( + p.sourceCommit === null || /^[0-9a-f]{40}$/.test(p.sourceCommit), + "sourceCommit sha|null" + ); }); test("radar export provenance reflects the GitHub Actions environment when present", () => { diff --git a/tests/unit/radar-feed-cache-generated-at.test.ts b/tests/unit/radar-feed-cache-generated-at.test.ts index d364c69cc5..df29fc0e7b 100644 --- a/tests/unit/radar-feed-cache-generated-at.test.ts +++ b/tests/unit/radar-feed-cache-generated-at.test.ts @@ -209,7 +209,7 @@ test.after(() => { delete process.env.RADAR_ENABLED; delete process.env.INITIAL_PASSWORD; try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } diff --git a/tests/unit/radar-inertia.test.ts b/tests/unit/radar-inertia.test.ts index b48b7bbb08..7071bef062 100644 --- a/tests/unit/radar-inertia.test.ts +++ b/tests/unit/radar-inertia.test.ts @@ -45,19 +45,17 @@ delete process.env.RADAR_ENABLED; const core = await import("../../src/lib/db/core.ts"); const { clearAllFeatureFlagOverrides } = await import("../../src/lib/db/featureFlags.ts"); -const { isFeatureFlagEnabled, resolveAllFeatureFlags } = await import( - "../../src/shared/utils/featureFlags.ts" -); -const { FREE_MODEL_BUDGETS, computeFreeModelTotals } = await import( - "../../open-sse/config/freeModelCatalog.ts" -); +const { isFeatureFlagEnabled, resolveAllFeatureFlags } = + await import("../../src/shared/utils/featureFlags.ts"); +const { FREE_MODEL_BUDGETS, computeFreeModelTotals } = + await import("../../open-sse/config/freeModelCatalog.ts"); const { getRadarCatalog, baselineToMergedEntries } = await import("../../src/lib/radar/index.ts"); function resetState() { core.resetDbInstance(); try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } catch { // ignore @@ -94,7 +92,7 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { assert.equal(syncRes.status, 404, "POST /api/radar/sync must 404 when disabled"); const settingsRes = await settingsPost( - mockPostRequest("http://localhost:20128/api/radar/settings", { optIn: true }), + mockPostRequest("http://localhost:20128/api/radar/settings", { optIn: true }) ); assert.equal(settingsRes.status, 404, "POST /api/radar/settings must 404 when disabled"); @@ -106,12 +104,12 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { mockPostRequest("http://localhost:20128/api/radar/settings", { optIn: true, supporterKey: "omr_abcdef01234567890abcdef01234567890abcdef", - }), + }) ); assert.equal( settingsWithKeyRes.status, 404, - "POST /api/radar/settings with optIn+supporterKey together must also 404 when disabled", + "POST /api/radar/settings with optIn+supporterKey together must also 404 when disabled" ); }); @@ -121,7 +119,7 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { assert.equal( isFeatureFlagEnabled("RADAR_ENABLED"), false, - "RADAR_ENABLED must resolve to disabled by default", + "RADAR_ENABLED must resolve to disabled by default" ); const resolved = resolveAllFeatureFlags().find((f) => f.key === "RADAR_ENABLED"); @@ -129,12 +127,12 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { assert.equal( resolved!.effectiveValue, "false", - "RADAR_ENABLED effective value must be 'false' with no override present", + "RADAR_ENABLED effective value must be 'false' with no override present" ); assert.equal( resolved!.source, "default", - "RADAR_ENABLED must resolve from the definition default, not a DB/env override", + "RADAR_ENABLED must resolve from the definition default, not a DB/env override" ); }); @@ -151,12 +149,16 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { }, }); - assert.equal(cacheReadCount, 0, "getRadarCatalog() must short-circuit before reading the cache"); + assert.equal( + cacheReadCount, + 0, + "getRadarCatalog() must short-circuit before reading the cache" + ); assert.equal(result.meta, null, "meta must be null — no feed is active"); assert.equal( result.entries.length, FREE_MODEL_BUDGETS.length, - "entry count must match the baseline catalog exactly", + "entry count must match the baseline catalog exactly" ); const baselineKeys = new Set(FREE_MODEL_BUDGETS.map((m) => `${m.provider}:${m.modelId}`)); @@ -164,18 +166,26 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { assert.deepEqual( resultKeys, baselineKeys, - "entries must be exactly the baseline provider:modelId set — no additions, no removals", + "entries must be exactly the baseline provider:modelId set — no additions, no removals" ); for (const entry of result.entries) { - assert.equal(entry.origin, "baseline", `entry ${entry.provider}:${entry.modelId} must be origin:baseline`); - assert.equal(entry.disabledBy, undefined, "no entry should carry Radar disabledBy provenance"); + assert.equal( + entry.origin, + "baseline", + `entry ${entry.provider}:${entry.modelId} must be origin:baseline` + ); + assert.equal( + entry.disabledBy, + undefined, + "no entry should carry Radar disabledBy provenance" + ); } // Cross-check against the explicit baseline converter too — same shape. const converted = baselineToMergedEntries(FREE_MODEL_BUDGETS); assert.equal(converted.length, result.entries.length); - }, + } ); await t.test( @@ -227,8 +237,12 @@ test("Radar inertia — flag off means zero behavioral delta", async (t) => { // Re-running getRadarCatalog() (flag off) must not perturb the totals either. getRadarCatalog(); const totalsAfter = computeFreeModelTotals(); - assert.deepEqual(totalsAfter, totals, "computeFreeModelTotals() must be idempotent across a getRadarCatalog() call"); - }, + assert.deepEqual( + totalsAfter, + totals, + "computeFreeModelTotals() must be idempotent across a getRadarCatalog() call" + ); + } ); }); @@ -236,7 +250,7 @@ test.after(() => { core.resetDbInstance(); delete process.env.RADAR_ENABLED; try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore } diff --git a/tests/unit/radar-intel-db.test.ts b/tests/unit/radar-intel-db.test.ts index d5f80496af..15fb923dd2 100644 --- a/tests/unit/radar-intel-db.test.ts +++ b/tests/unit/radar-intel-db.test.ts @@ -13,14 +13,14 @@ const radar = await import("../../src/lib/db/radar.ts"); function resetStorage(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Intel migration provides a byte-preserving single-row cache", () => { diff --git a/tests/unit/radar-intel-routes.test.ts b/tests/unit/radar-intel-routes.test.ts index 023056e11e..8a96cacc20 100644 --- a/tests/unit/radar-intel-routes.test.ts +++ b/tests/unit/radar-intel-routes.test.ts @@ -30,13 +30,13 @@ function request(pathname: string, method: "GET" | "POST", headers: Record { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.RADAR_ENABLED; }); diff --git a/tests/unit/radar-local-state-db.test.ts b/tests/unit/radar-local-state-db.test.ts index c6e2074d78..a59677513d 100644 --- a/tests/unit/radar-local-state-db.test.ts +++ b/tests/unit/radar-local-state-db.test.ts @@ -27,7 +27,7 @@ const { getRadarCatalog } = await import("../../src/lib/radar/index.ts"); async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.RADAR_ENABLED; }); diff --git a/tests/unit/radar-local-state-route.test.ts b/tests/unit/radar-local-state-route.test.ts index 08970609bb..a9de6f107f 100644 --- a/tests/unit/radar-local-state-route.test.ts +++ b/tests/unit/radar-local-state-route.test.ts @@ -34,7 +34,7 @@ function request(method: string, body?: unknown, headers: Record async function resetStorage(): Promise { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.DATA_DIR; delete process.env.RADAR_ENABLED; delete process.env.JWT_SECRET; diff --git a/tests/unit/radar-offers-db.test.ts b/tests/unit/radar-offers-db.test.ts index fa93225ffa..b4ee10eb4a 100644 --- a/tests/unit/radar-offers-db.test.ts +++ b/tests/unit/radar-offers-db.test.ts @@ -13,7 +13,7 @@ const radar = await import("../../src/lib/db/radar.ts"); function resetStorage(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -21,7 +21,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.STORAGE_ENCRYPTION_KEY; }); diff --git a/tests/unit/radar-offers-routes.test.ts b/tests/unit/radar-offers-routes.test.ts index 1ff65c20ff..fcfcd3dc00 100644 --- a/tests/unit/radar-offers-routes.test.ts +++ b/tests/unit/radar-offers-routes.test.ts @@ -25,7 +25,7 @@ async function authHeaders(): Promise> { function resetStorage(): void { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -44,7 +44,7 @@ function request( test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.RADAR_ENABLED; delete process.env.STORAGE_ENCRYPTION_KEY; }); diff --git a/tests/unit/radar-referrals-route.test.ts b/tests/unit/radar-referrals-route.test.ts index a8c9b71577..6f11090647 100644 --- a/tests/unit/radar-referrals-route.test.ts +++ b/tests/unit/radar-referrals-route.test.ts @@ -59,7 +59,7 @@ async function authHeaders(): Promise> { function mockGetRequest( url = "http://localhost:20128/api/radar/referrals", - headers: Record = {}, + headers: Record = {} ): Request { return new Request(url, { method: "GET", headers }); } @@ -68,7 +68,7 @@ function resetStorage() { core.resetDbInstance(); try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } catch { // ignore @@ -217,7 +217,7 @@ test("GET /api/radar/referrals: stale cached referrals feed still served (sync-o test("GET /api/radar/referrals: never proxies the private feed server (route source has no upstream fetch)", async () => { const routeSrc = fs.readFileSync( path.resolve(process.cwd(), "src/app/api/radar/referrals/route.ts"), - "utf-8", + "utf-8" ); assert.ok(!/fetch\(/.test(routeSrc), "referrals route must never call fetch() upstream"); }); diff --git a/tests/unit/radar-supporter-gamification.test.ts b/tests/unit/radar-supporter-gamification.test.ts index a3b1d4b100..a926cd064b 100644 --- a/tests/unit/radar-supporter-gamification.test.ts +++ b/tests/unit/radar-supporter-gamification.test.ts @@ -13,7 +13,7 @@ const { emitGamificationEvent } = await import("../../src/lib/gamification/event test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Radar supporter has a dedicated badge and zero-XP idempotent action", async () => { diff --git a/tests/unit/rate-limit-execution-timeout-message-4165.test.ts b/tests/unit/rate-limit-execution-timeout-message-4165.test.ts index 3cae26ebbd..894cd7a1be 100644 --- a/tests/unit/rate-limit-execution-timeout-message-4165.test.ts +++ b/tests/unit/rate-limit-execution-timeout-message-4165.test.ts @@ -39,7 +39,7 @@ test.afterEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Drive a real Bottleneck execution expiration with a function that outlives it. diff --git a/tests/unit/rate-limit-local-error-classification.test.ts b/tests/unit/rate-limit-local-error-classification.test.ts index f7c140a380..ac34cb308d 100644 --- a/tests/unit/rate-limit-local-error-classification.test.ts +++ b/tests/unit/rate-limit-local-error-classification.test.ts @@ -97,7 +97,7 @@ test.afterEach(() => { providerCooldown.clearCooldownState(); rateLimitSemaphore.resetAll(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -107,7 +107,7 @@ test.after(() => { providerCooldown.clearCooldownState(); rateLimitSemaphore.resetAll(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("execution-timeout classification requires trusted provenance; queue codes classify by string (#9164/#9342)", () => { diff --git a/tests/unit/rate-limit-manager.test.ts b/tests/unit/rate-limit-manager.test.ts index b1d411e62a..da6d29089d 100644 --- a/tests/unit/rate-limit-manager.test.ts +++ b/tests/unit/rate-limit-manager.test.ts @@ -91,7 +91,7 @@ async function flushBackgroundWork() { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -108,7 +108,7 @@ test.after(async () => { await rateLimitManager.__resetRateLimitManagerForTests(); await flushBackgroundWork(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("rate limit manager bypasses disabled connections and exposes inactive status", async () => { diff --git a/tests/unit/rate-limit-queue-timeout-lockout.test.ts b/tests/unit/rate-limit-queue-timeout-lockout.test.ts index 0fb874cc7f..8ebf77ff24 100644 --- a/tests/unit/rate-limit-queue-timeout-lockout.test.ts +++ b/tests/unit/rate-limit-queue-timeout-lockout.test.ts @@ -56,7 +56,7 @@ function errorResponseWithConnectionId(status: number, connectionId: string) { test.afterEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("RATE_LIMIT_QUEUE_TIMEOUT lockout behaves correctly depending on connection ID header", async () => { diff --git a/tests/unit/ratelimit-admission-control-6593.test.ts b/tests/unit/ratelimit-admission-control-6593.test.ts index 04f3dd9fe1..deeb461745 100644 --- a/tests/unit/ratelimit-admission-control-6593.test.ts +++ b/tests/unit/ratelimit-admission-control-6593.test.ts @@ -54,7 +54,7 @@ test.afterEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --- Pure unit tests for the extracted admission check ------------------- diff --git a/tests/unit/reasoning-probe-truncated-response-10281.test.ts b/tests/unit/reasoning-probe-truncated-response-10281.test.ts index b69a452def..286c7caea1 100644 --- a/tests/unit/reasoning-probe-truncated-response-10281.test.ts +++ b/tests/unit/reasoning-probe-truncated-response-10281.test.ts @@ -69,7 +69,7 @@ test.before(() => { test.after(() => { clearModelsDevCapabilities(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10281 isTinyBudgetReasoningProbe detects tiny explicit budgets on reasoning models", () => { diff --git a/tests/unit/reasoning-routing-api.test.ts b/tests/unit/reasoning-routing-api.test.ts index 8a32c62a32..ef47ed55f2 100644 --- a/tests/unit/reasoning-routing-api.test.ts +++ b/tests/unit/reasoning-routing-api.test.ts @@ -37,7 +37,7 @@ type SimulationResponse = { async function resetStorage() { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); rulesDb.invalidateReasoningRoutingRuleCache(); } @@ -72,7 +72,7 @@ test.beforeEach(resetStorage); test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("management API CRUD validates and persists reasoning routing rules", async () => { diff --git a/tests/unit/reasoning-routing-decision-guards.test.ts b/tests/unit/reasoning-routing-decision-guards.test.ts index 30766edc94..46430931a1 100644 --- a/tests/unit/reasoning-routing-decision-guards.test.ts +++ b/tests/unit/reasoning-routing-decision-guards.test.ts @@ -26,7 +26,7 @@ const handler = await import("../../src/sse/handlers/reasoningRouting.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function req() { diff --git a/tests/unit/reasoning-routing.test.ts b/tests/unit/reasoning-routing.test.ts index 1fea6b7b05..fc303ccc68 100644 --- a/tests/unit/reasoning-routing.test.ts +++ b/tests/unit/reasoning-routing.test.ts @@ -19,7 +19,7 @@ const schemas = await import("../../src/shared/validation/schemas/reasoningRouti async function resetStorage() { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); rulesDb.invalidateReasoningRoutingRuleCache(); } @@ -55,7 +55,7 @@ test.beforeEach(resetStorage); test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("reasoning intent distinguishes missing, discrete effort, toggle, and budget-only signals", () => { diff --git a/tests/unit/reasoning-token-buffer-6274.test.ts b/tests/unit/reasoning-token-buffer-6274.test.ts index 5af15d94e3..533b174253 100644 --- a/tests/unit/reasoning-token-buffer-6274.test.ts +++ b/tests/unit/reasoning-token-buffer-6274.test.ts @@ -78,7 +78,7 @@ test.before(() => { test.after(() => { clearModelsDevCapabilities(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6274 reasoning buffer does not inflate probe-sized max_tokens", () => { diff --git a/tests/unit/reasoning-token-buffer-9507.test.ts b/tests/unit/reasoning-token-buffer-9507.test.ts index bbe686fca7..886fa88de6 100644 --- a/tests/unit/reasoning-token-buffer-9507.test.ts +++ b/tests/unit/reasoning-token-buffer-9507.test.ts @@ -22,7 +22,7 @@ const { resolveReasoningBufferedMaxTokens } = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9507 reasoning buffer does NOT enlarge a Claude opus-5 client budget upward", () => { diff --git a/tests/unit/refresh-cursor-route.test.ts b/tests/unit/refresh-cursor-route.test.ts index 983de76e4a..ab4f65fa95 100644 --- a/tests/unit/refresh-cursor-route.test.ts +++ b/tests/unit/refresh-cursor-route.test.ts @@ -30,7 +30,7 @@ const { POST } = await import("../../src/app/api/providers/[id]/refresh-cursor/r test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function getId(connection: { id?: unknown }): string { @@ -133,7 +133,7 @@ async function withCursorEnv(fn: (env: CursorEnv) => Promise): Promise else delete process.env.USERPROFILE; delete process.env.FAKE_CURSOR_AGENT_LOG; delete process.env.FAKE_CURSOR_AGENT_STATUS_MODE; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }, }; diff --git a/tests/unit/reject-management-password-as-apikey.test.ts b/tests/unit/reject-management-password-as-apikey.test.ts index 2374f4b0c2..3c532092bb 100644 --- a/tests/unit/reject-management-password-as-apikey.test.ts +++ b/tests/unit/reject-management-password-as-apikey.test.ts @@ -31,13 +31,13 @@ async function storeDashboardPassword(plaintext: string) { beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("management password as a provider credential", () => { diff --git a/tests/unit/rejected-request-usage.test.ts b/tests/unit/rejected-request-usage.test.ts index 300e77e013..1783129e3a 100644 --- a/tests/unit/rejected-request-usage.test.ts +++ b/tests/unit/rejected-request-usage.test.ts @@ -29,14 +29,14 @@ const { recordRejectedRequestUsage, summarizeComboAttemptedModels, resolveReject test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); usageHistory.clearPendingRequests(); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("gate-rejected request is attributed to the api key in usage_history", async () => { diff --git a/tests/unit/relay-check-rate-limit-existing-token.test.ts b/tests/unit/relay-check-rate-limit-existing-token.test.ts index 2843c15a25..f635f41479 100644 --- a/tests/unit/relay-check-rate-limit-existing-token.test.ts +++ b/tests/unit/relay-check-rate-limit-existing-token.test.ts @@ -14,9 +14,7 @@ import path from "node:path"; // - the legacy re-query path (no token passed) must still work unmodified // - the per-minute cap must still be enforced correctly via the fast-path -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-relay-check-rate-limit-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-relay-check-rate-limit-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -28,7 +26,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -50,7 +48,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Inserts a relay_tokens row directly (bypassing createRelayToken, which uses diff --git a/tests/unit/relay-deploy-5128.test.ts b/tests/unit/relay-deploy-5128.test.ts index 41a30a4f8b..a0cdb69754 100644 --- a/tests/unit/relay-deploy-5128.test.ts +++ b/tests/unit/relay-deploy-5128.test.ts @@ -30,7 +30,7 @@ const proxySchemas = await import("../../src/shared/validation/schemas/proxy.ts" test.after(() => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } @@ -236,7 +236,7 @@ if (!isPrivateHostname("[fd00::1]")) throw new Error("bracketed IPv6 ULA must st ); } finally { try { - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } diff --git a/tests/unit/replace-custom-models-preserve-hidden-5086.test.ts b/tests/unit/replace-custom-models-preserve-hidden-5086.test.ts index 0b950e3f8a..6ee7ff114a 100644 --- a/tests/unit/replace-custom-models-preserve-hidden-5086.test.ts +++ b/tests/unit/replace-custom-models-preserve-hidden-5086.test.ts @@ -35,7 +35,7 @@ before(() => { after(() => { resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const PROVIDER = "llama-cpp-5086"; diff --git a/tests/unit/repro-10139-claude-thinking-output-cap.test.ts b/tests/unit/repro-10139-claude-thinking-output-cap.test.ts index 26661a518b..ab588e19dd 100644 --- a/tests/unit/repro-10139-claude-thinking-output-cap.test.ts +++ b/tests/unit/repro-10139-claude-thinking-output-cap.test.ts @@ -45,7 +45,7 @@ const THINKING_BUDGET = 131072; // effortBudgetMap.high test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#10139: a provider-scoped-only output cap is invisible without a provider argument", () => { diff --git a/tests/unit/repro-6524.test.ts b/tests/unit/repro-6524.test.ts index d99dcec855..dd56995bdf 100644 --- a/tests/unit/repro-6524.test.ts +++ b/tests/unit/repro-6524.test.ts @@ -70,7 +70,7 @@ test.before(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6524: with only the (wrong) synced catalog data, the buffer no longer inflates (#9507)", () => { diff --git a/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts b/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts index e71da092cc..b680e65ac1 100644 --- a/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts +++ b/tests/unit/repro-6557-noauth-connection-disable-ignored.test.ts @@ -37,7 +37,7 @@ const virtualFactory = await import("../../open-sse/services/autoCombo/virtualFa async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/repro-6701-claude-detect-fallback.test.ts b/tests/unit/repro-6701-claude-detect-fallback.test.ts index c17b6e1705..9f326ba8cb 100644 --- a/tests/unit/repro-6701-claude-detect-fallback.test.ts +++ b/tests/unit/repro-6701-claude-detect-fallback.test.ts @@ -55,7 +55,7 @@ describe("#6701 — claude detection should fall back to settings.json when bina }); after(() => { - fs.rmSync(configHome, { recursive: true, force: true }); + fs.rmSync(configHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (prevBin === undefined) delete process.env.CLI_CLAUDE_BIN; else process.env.CLI_CLAUDE_BIN = prevBin; if (prevConfigHome === undefined) delete process.env.CLI_CONFIG_HOME; diff --git a/tests/unit/repro-6912-volcengine-max-completion-tokens.test.ts b/tests/unit/repro-6912-volcengine-max-completion-tokens.test.ts index 601ea92d58..d1b0f6065c 100644 --- a/tests/unit/repro-6912-volcengine-max-completion-tokens.test.ts +++ b/tests/unit/repro-6912-volcengine-max-completion-tokens.test.ts @@ -20,12 +20,10 @@ const core = await import("../../src/lib/db/core.ts"); const { clearCache } = await import("../../src/lib/semanticCache.ts"); const { clearIdempotency } = await import("../../src/lib/idempotencyLayer.ts"); const { clearInflight } = await import("../../open-sse/services/requestDedup.ts"); -const { resetAll: resetAccountSemaphores } = await import( - "../../open-sse/services/accountSemaphore.ts" -); -const { handleChatCore, clearUpstreamProxyConfigCache } = await import( - "../../open-sse/handlers/chatCore.ts" -); +const { resetAll: resetAccountSemaphores } = + await import("../../open-sse/services/accountSemaphore.ts"); +const { handleChatCore, clearUpstreamProxyConfigCache } = + await import("../../open-sse/handlers/chatCore.ts"); const { resetPayloadRulesConfigForTests } = await import("../../open-sse/services/payloadRules.ts"); const originalFetch = globalThis.fetch; @@ -115,7 +113,7 @@ async function resetStorage() { clearIdempotency(); clearInflight(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -127,7 +125,7 @@ test.afterEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6912: chatCore renames max_completion_tokens to max_tokens for volcengine/DeepSeek-V4-Flash", async () => { @@ -142,7 +140,11 @@ test("#6912: chatCore renames max_completion_tokens to max_tokens for volcengine }, }); - assert.equal(call.body.max_tokens, 30, "expected max_completion_tokens to be normalized to max_tokens for volcengine"); + assert.equal( + call.body.max_tokens, + 30, + "expected max_completion_tokens to be normalized to max_tokens for volcengine" + ); assert.equal(call.body.max_completion_tokens, undefined); }); @@ -159,7 +161,11 @@ test("#6912: chatCore does not clobber an already-present max_tokens", async () }, }); - assert.equal(call.body.max_tokens, 500, "existing max_tokens must win over max_completion_tokens"); + assert.equal( + call.body.max_tokens, + 500, + "existing max_tokens must win over max_completion_tokens" + ); assert.equal(call.body.max_completion_tokens, undefined); }); diff --git a/tests/unit/repro-6952-commentary.test.ts b/tests/unit/repro-6952-commentary.test.ts index 4e622a1065..dbd9a018e0 100644 --- a/tests/unit/repro-6952-commentary.test.ts +++ b/tests/unit/repro-6952-commentary.test.ts @@ -48,7 +48,7 @@ async function readTransformed(chunks: string[], options: object): Promise { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -236,10 +236,7 @@ test("TRANSLATE mode drops commentary-phase text before translateResponse (#6952 // The real tool call must still be forwarded (arguments are JSON-escaped inside // an `input_json_delta` SSE frame, so match on the unescaped path fragment). - assert.ok( - output.includes("/tmp/real.txt"), - "the real function_call arguments must be forwarded" - ); + assert.ok(output.includes("/tmp/real.txt"), "the real function_call arguments must be forwarded"); assert.ok(output.includes(TOOL_NAME), "the real function_call name must be forwarded"); }); diff --git a/tests/unit/repro-6957.test.ts b/tests/unit/repro-6957.test.ts index 696dfada3d..a2d19dcd84 100644 --- a/tests/unit/repro-6957.test.ts +++ b/tests/unit/repro-6957.test.ts @@ -33,7 +33,7 @@ const { getComboBuilderOptions } = await import("../../src/lib/combos/builderOpt test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // A trimmed slice of the reporter's actual payload (issue #6957 comment attachment diff --git a/tests/unit/repro-6975.test.ts b/tests/unit/repro-6975.test.ts index ffe17dfe66..7d9dd6f108 100644 --- a/tests/unit/repro-6975.test.ts +++ b/tests/unit/repro-6975.test.ts @@ -13,22 +13,32 @@ const { getComboBuilderOptions } = await import("../../src/lib/combos/builderOpt test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6975 embeddings-only custom model must appear in the combo builder output", async () => { - await modelsDb.addCustomModel("opencode", "zzz-embed-6975", "Embed Model 6975", "manual", "embeddings", [ + await modelsDb.addCustomModel( + "opencode", + "zzz-embed-6975", + "Embed Model 6975", + "manual", "embeddings", - ]); + ["embeddings"] + ); const payload = await getComboBuilderOptions(); const m = payload.providers.flatMap((p) => p.models).find((m) => m.id === "zzz-embed-6975"); assert.ok(m, "embeddings-only custom model must appear in the combo builder output"); }); test("#6975 rerank-only custom model must appear in the combo builder output", async () => { - await modelsDb.addCustomModel("opencode", "zzz-rerank-6975", "Rerank Model 6975", "manual", "rerank", [ + await modelsDb.addCustomModel( + "opencode", + "zzz-rerank-6975", + "Rerank Model 6975", + "manual", "rerank", - ]); + ["rerank"] + ); const payload = await getComboBuilderOptions(); const m = payload.providers.flatMap((p) => p.models).find((m) => m.id === "zzz-rerank-6975"); assert.ok(m, "rerank-only custom model must appear in the combo builder output"); diff --git a/tests/unit/repro-8065-quota-cache-cross-instance.test.ts b/tests/unit/repro-8065-quota-cache-cross-instance.test.ts index aa1bd7970d..b8901c819b 100644 --- a/tests/unit/repro-8065-quota-cache-cross-instance.test.ts +++ b/tests/unit/repro-8065-quota-cache-cross-instance.test.ts @@ -11,7 +11,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8065 a renewed quota written by one module instance is invisible to another module instance's routing read", async () => { @@ -27,7 +27,10 @@ test("#8065 a renewed quota written by one module instance is invisible to anoth // Instance W: simulates providerLimitsSyncScheduler's instrumentation-node.ts chunk. const quotaCacheW = await import("../../src/domain/quotaCache.ts?instance=W"); quotaCacheW.setQuotaCache(connectionId, "codex", { - session: { remainingPercentage: 100, resetAt: new Date(Date.now() + 7 * 86400000).toISOString() }, + session: { + remainingPercentage: 100, + resetAt: new Date(Date.now() + 7 * 86400000).toISOString(), + }, }); assert.equal(quotaCacheW.isQuotaExhaustedForRequest(connectionId, "codex"), false); diff --git a/tests/unit/repro-8429-capability-canonicalization.test.ts b/tests/unit/repro-8429-capability-canonicalization.test.ts index 5e36bd57be..f7cb44d7e6 100644 --- a/tests/unit/repro-8429-capability-canonicalization.test.ts +++ b/tests/unit/repro-8429-capability-canonicalization.test.ts @@ -13,24 +13,39 @@ const modelCapabilities = await import("../../src/lib/modelCapabilities.ts"); function buildCapability(overrides: Record = {}) { return { - tool_call: null, reasoning: null, attachment: null, structured_output: null, - temperature: null, modalities_input: "[]", modalities_output: "[]", - knowledge_cutoff: null, release_date: null, last_updated: null, status: null, - family: null, open_weights: null, limit_context: null, limit_input: null, - limit_output: null, interleaved_field: null, ...overrides, + tool_call: null, + reasoning: null, + attachment: null, + structured_output: null, + temperature: null, + modalities_input: "[]", + modalities_output: "[]", + knowledge_cutoff: null, + release_date: null, + last_updated: null, + status: null, + family: null, + open_weights: null, + limit_context: null, + limit_input: null, + limit_output: null, + interleaved_field: null, + ...overrides, }; } function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } -test.beforeEach(() => { resetStorage(); }); +test.beforeEach(() => { + resetStorage(); +}); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8429: synced model_capabilities row written under models.dev mapping is unreachable via the canonical 'codex' provider id", () => { diff --git a/tests/unit/repro-8841-context-overflow-opencode.test.ts b/tests/unit/repro-8841-context-overflow-opencode.test.ts index 0dae913167..bd6ff9cea7 100644 --- a/tests/unit/repro-8841-context-overflow-opencode.test.ts +++ b/tests/unit/repro-8841-context-overflow-opencode.test.ts @@ -17,7 +17,7 @@ test.after(() => { core.resetDbInstance(); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const noopLog = { diff --git a/tests/unit/repro-8847.test.ts b/tests/unit/repro-8847.test.ts index 301263d35e..36a3e58ca4 100644 --- a/tests/unit/repro-8847.test.ts +++ b/tests/unit/repro-8847.test.ts @@ -66,5 +66,5 @@ test("repro-8847: better-sqlite3 prebuilds are bundled alongside the compiled bi "linux-x64 prebuild must be in the standalone bundle" ); - fs.rmSync(tmp, { recursive: true, force: true }); -}); \ No newline at end of file + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); +}); diff --git a/tests/unit/repro-8956.test.ts b/tests/unit/repro-8956.test.ts index daf76a4332..982bcc28f8 100644 --- a/tests/unit/repro-8956.test.ts +++ b/tests/unit/repro-8956.test.ts @@ -43,7 +43,7 @@ test("repro-8956: resolveProjectRoot skips synthetic .build/next/package.json (n `PROJECT_ROOT resolved to ${root}, which lacks .git` ); } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -60,6 +60,6 @@ test("repro-8956: resolveProjectRoot still finds package.json with a name field" const root = resolveProjectRoot("/fallback", subDir); assert.equal(root, repoRoot); } finally { - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/repro-8995.test.ts b/tests/unit/repro-8995.test.ts index 74dd1b8f59..5cd02076b9 100644 --- a/tests/unit/repro-8995.test.ts +++ b/tests/unit/repro-8995.test.ts @@ -15,13 +15,13 @@ const settingsDb = await import("../../src/lib/db/settings.ts"); async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#8995: resolveProxyForConnection surfaces the proxy NAME for an account-level assignment", async () => { @@ -51,4 +51,4 @@ test("#8995: resolveProxyForConnection surfaces the proxy NAME for an account-le "My US Proxy", "resolveProxyForConnection must include the proxy name so the dashboard badge can show it" ); -}); \ No newline at end of file +}); diff --git a/tests/unit/repro-9625.test.ts b/tests/unit/repro-9625.test.ts index f6ff2f68cf..1f8aba9b04 100644 --- a/tests/unit/repro-9625.test.ts +++ b/tests/unit/repro-9625.test.ts @@ -28,7 +28,7 @@ const { getDbInstance, resetDbInstance } = await import("../../src/lib/db/core.t test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const DAY_MS = 86_400_000; // milliseconds @@ -89,4 +89,4 @@ test("#9625 unit mismatch: seconds cutoff would NOT match ms timestamps", () => oldRowMs < cutoffMs, "Fix: ms timestamp IS less than ms cutoff, so row is correctly deleted" ); -}); \ No newline at end of file +}); diff --git a/tests/unit/repro-compression-run-telemetry-ms.test.ts b/tests/unit/repro-compression-run-telemetry-ms.test.ts index 143ef0037c..3b3e3e1b2c 100644 --- a/tests/unit/repro-compression-run-telemetry-ms.test.ts +++ b/tests/unit/repro-compression-run-telemetry-ms.test.ts @@ -26,14 +26,13 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-crt-ms-") process.env.DATA_DIR = TEST_DATA_DIR; const { cleanupCompressionRunTelemetry } = await import("../../src/lib/db/cleanup.ts"); -const { insertCompressionRunTelemetryRow } = await import( - "../../src/lib/db/compressionRunTelemetry.ts" -); +const { insertCompressionRunTelemetryRow } = + await import("../../src/lib/db/compressionRunTelemetry.ts"); const { getDbInstance, resetDbInstance } = await import("../../src/lib/db/core.ts"); test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const DAY_MS = 86_400_000; @@ -92,8 +91,8 @@ test("cleanupCompressionRunTelemetry deletes rows older than the retention windo assert.strictEqual(result.deleted, 3, "should delete the 3 rows aged 40 days"); assert.strictEqual(result.errors, 0); - const remaining = db - .prepare("SELECT COUNT(*) as cnt FROM compression_run_telemetry") - .get() as { cnt: number }; + const remaining = db.prepare("SELECT COUNT(*) as cnt FROM compression_run_telemetry").get() as { + cnt: number; + }; assert.strictEqual(remaining.cnt, 2, "should keep the 2 rows aged 5 days"); }); diff --git a/tests/unit/request-log-migration.test.ts b/tests/unit/request-log-migration.test.ts index 00178b9fc1..143f53e2c7 100644 --- a/tests/unit/request-log-migration.test.ts +++ b/tests/unit/request-log-migration.test.ts @@ -43,7 +43,7 @@ function cleanup() { // Retry with a short delay to let the OS release locks. for (let attempt = 0; attempt < 5; attempt++) { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch { /* retry */ @@ -82,7 +82,12 @@ test("keeps legacy files in place when zip creation fails", async () => { // Remove the archive dir created by the first test, then write a file // at that path so mkdirSync throws EEXIST. This simulates a zip // creation failure. The migration should leave legacy files intact. - fs.rmSync(migrations.LOG_ARCHIVES_DIR, { recursive: true, force: true }); + fs.rmSync(migrations.LOG_ARCHIVES_DIR, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); fs.writeFileSync(migrations.LOG_ARCHIVES_DIR, "not-a-directory"); await assert.rejects(() => migrations.archiveLegacyRequestLogs()); diff --git a/tests/unit/request-logger-endpoints.test.ts b/tests/unit/request-logger-endpoints.test.ts index 7d1b41cf7e..66823c927c 100644 --- a/tests/unit/request-logger-endpoints.test.ts +++ b/tests/unit/request-logger-endpoints.test.ts @@ -13,7 +13,7 @@ const callLogs = await import("../../src/lib/usage/callLogs.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Captured stream chunks are prefixed with a per-chunk arrival timestamp diff --git a/tests/unit/require-management-auth-access-token.test.ts b/tests/unit/require-management-auth-access-token.test.ts index 4589bc1184..97f22282df 100644 --- a/tests/unit/require-management-auth-access-token.test.ts +++ b/tests/unit/require-management-auth-access-token.test.ts @@ -31,7 +31,7 @@ test.after(() => { core.resetDbInstance(); } catch {} try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} delete process.env.INITIAL_PASSWORD; delete process.env.OMNIROUTE_INTERNAL_SERVICE_TOKEN; diff --git a/tests/unit/rerank-proxy-pinning-7350.test.ts b/tests/unit/rerank-proxy-pinning-7350.test.ts index 8f87a21932..3852814b75 100644 --- a/tests/unit/rerank-proxy-pinning-7350.test.ts +++ b/tests/unit/rerank-proxy-pinning-7350.test.ts @@ -43,7 +43,7 @@ function stubFetch(seen: { proxyUrl: string | null | undefined }[], gate?: () => test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7350 handleRerank routes the upstream call through the connection's pinned proxy", async () => { diff --git a/tests/unit/rerank-voyage-7809.test.ts b/tests/unit/rerank-voyage-7809.test.ts index 5605f19651..208fad237c 100644 --- a/tests/unit/rerank-voyage-7809.test.ts +++ b/tests/unit/rerank-voyage-7809.test.ts @@ -18,7 +18,7 @@ const { transformRequestForProvider, transformResponseFromProvider } = test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── Registry ────────────────────────────────────────────────────────────── diff --git a/tests/unit/reset-connection-backoff.test.ts b/tests/unit/reset-connection-backoff.test.ts index 0fce46fb03..0f04db6691 100644 --- a/tests/unit/reset-connection-backoff.test.ts +++ b/tests/unit/reset-connection-backoff.test.ts @@ -18,7 +18,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function createBackedOffConnection() { diff --git a/tests/unit/reset-password-cli-6261-6258.test.ts b/tests/unit/reset-password-cli-6261-6258.test.ts index 1f83d58a91..1b73ba6140 100644 --- a/tests/unit/reset-password-cli-6261-6258.test.ts +++ b/tests/unit/reset-password-cli-6261-6258.test.ts @@ -114,8 +114,8 @@ test("omniroute reset-password subcommand applies the reset over piped stdin (#6 "the stored password must verify against the piped value" ); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -143,8 +143,8 @@ test("omniroute-reset-password applies the reset over piped two-line stdin (#625 "the stored password must verify against the piped value" ); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -172,7 +172,7 @@ test("omniroute-reset-password --password-stdin reads the whole stdin as the pas "the stored password must verify against the --password-stdin value" ); } finally { - fs.rmSync(dataDir, { recursive: true, force: true }); - fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/resilience-stream-recovery-feature-flags.test.ts b/tests/unit/resilience-stream-recovery-feature-flags.test.ts index 431c3951f3..3455021e9d 100644 --- a/tests/unit/resilience-stream-recovery-feature-flags.test.ts +++ b/tests/unit/resilience-stream-recovery-feature-flags.test.ts @@ -14,7 +14,7 @@ const { resolveResilienceSettings } = await import("../../src/lib/resilience/set after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("stream recovery feature flags seed resilience defaults", () => { diff --git a/tests/unit/resolve-proxy-family.test.ts b/tests/unit/resolve-proxy-family.test.ts index 6e12f618ad..009dc4c6f7 100644 --- a/tests/unit/resolve-proxy-family.test.ts +++ b/tests/unit/resolve-proxy-family.test.ts @@ -12,7 +12,12 @@ describe("resolved proxy config → URL family encoding", () => { assert.ok(url!.endsWith("?family=ipv6"), url!); }); it("omits family marker when auto", () => { - const url = proxyConfigToUrl({ type: "http", host: "p.example.com", port: 8080, family: "auto" }); + const url = proxyConfigToUrl({ + type: "http", + host: "p.example.com", + port: 8080, + family: "auto", + }); assert.ok(!url!.includes("family="), url!); }); }); @@ -32,13 +37,13 @@ async function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("account-level registry proxy carries family=ipv6 through resolveProxyForConnection", async () => { diff --git a/tests/unit/responses-case-insensitive-combo-guard.test.ts b/tests/unit/responses-case-insensitive-combo-guard.test.ts index 532e1e1a15..bf2c684db2 100644 --- a/tests/unit/responses-case-insensitive-combo-guard.test.ts +++ b/tests/unit/responses-case-insensitive-combo-guard.test.ts @@ -68,7 +68,7 @@ const sseModelService = await import("../../src/sse/services/model.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("getComboForModel resolves a stored combo by a case-insensitive request name", async () => { diff --git a/tests/unit/responses-commentary-event-frame-6561.test.ts b/tests/unit/responses-commentary-event-frame-6561.test.ts index 99fcfeee7b..8e30a129ea 100644 --- a/tests/unit/responses-commentary-event-frame-6561.test.ts +++ b/tests/unit/responses-commentary-event-frame-6561.test.ts @@ -43,7 +43,7 @@ async function readTransformed(chunks: string[], options: object): Promise { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/responses-commentary-passthrough-6199.test.ts b/tests/unit/responses-commentary-passthrough-6199.test.ts index c1fce80786..0b2b386278 100644 --- a/tests/unit/responses-commentary-passthrough-6199.test.ts +++ b/tests/unit/responses-commentary-passthrough-6199.test.ts @@ -48,7 +48,7 @@ async function readTransformed(chunks: string[], options: object): Promise { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/responses-continuation-store.test.ts b/tests/unit/responses-continuation-store.test.ts index 4d5a5c7cb4..6c75d53c24 100644 --- a/tests/unit/responses-continuation-store.test.ts +++ b/tests/unit/responses-continuation-store.test.ts @@ -18,7 +18,7 @@ const store = await import("../../src/lib/db/responsesContinuationStore.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function insertCallLog(row: { diff --git a/tests/unit/responses-handler.test.ts b/tests/unit/responses-handler.test.ts index 3b4d4b7cde..0791c5b9c6 100644 --- a/tests/unit/responses-handler.test.ts +++ b/tests/unit/responses-handler.test.ts @@ -130,7 +130,7 @@ function buildJsonResponse(status: number, payload: unknown) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -185,7 +185,7 @@ test.afterEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("handleResponsesCore converts Responses API input, instructions, tools, metadata, and forces streaming", async () => { @@ -362,11 +362,8 @@ test("handleResponsesCore transforms Command Code executor SSE through Responses choices: [{ index: 0, delta }], })}\n\n`; return new Response( - [ - chunk({ role: "assistant" }), - chunk({ content: "command" }), - chunk({}), - ].join("") + "data: [DONE]\n\n", + [chunk({ role: "assistant" }), chunk({ content: "command" }), chunk({})].join("") + + "data: [DONE]\n\n", { status: 200, headers: { "Content-Type": "text/event-stream" } } ); }, diff --git a/tests/unit/responses-parse-once-4041.test.ts b/tests/unit/responses-parse-once-4041.test.ts index e47124013c..27d41046cc 100644 --- a/tests/unit/responses-parse-once-4041.test.ts +++ b/tests/unit/responses-parse-once-4041.test.ts @@ -6,7 +6,7 @@ import path from "node:path"; const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-responses-parse-once-")); process.env.DATA_DIR = dataDir; -after(() => fs.rmSync(dataDir, { recursive: true, force: true })); +after(() => fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })); // #4041: AI routes must parse each JSON body at most once and thread the parsed value // through model resolution and handleChat. /v1/responses now parses after raw-body admission; diff --git a/tests/unit/responses-route-early-keepalive-wiring.test.ts b/tests/unit/responses-route-early-keepalive-wiring.test.ts index 5b510d5c34..25be2970bb 100644 --- a/tests/unit/responses-route-early-keepalive-wiring.test.ts +++ b/tests/unit/responses-route-early-keepalive-wiring.test.ts @@ -8,7 +8,7 @@ const routeSource = fs.readFileSync("src/app/api/v1/responses/route.ts", "utf8") const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-responses-route-test-")); process.env.DATA_DIR = dataDir; process.env.REQUIRE_API_KEY = "false"; -after(() => fs.rmSync(dataDir, { recursive: true, force: true })); +after(() => fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })); test("Responses route wires dual-cadence neutral keepalives", () => { assert.match( diff --git a/tests/unit/responses-transformer.test.ts b/tests/unit/responses-transformer.test.ts index f8b1c5a0b1..6a29e84e54 100644 --- a/tests/unit/responses-transformer.test.ts +++ b/tests/unit/responses-transformer.test.ts @@ -404,7 +404,12 @@ test("createResponsesLogger returns null for invalid base paths and swallows flu logger.logOutput("output"); const sessionDir = readdirSync(join(logsDir, "logs"))[0]; - rmSync(join(logsDir, "logs", sessionDir), { recursive: true, force: true }); + rmSync(join(logsDir, "logs", sessionDir), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); console.log = (...args) => capturedLogs.push(args.join(" ")); try { diff --git a/tests/unit/review-reviews-v3814-fixes.test.ts b/tests/unit/review-reviews-v3814-fixes.test.ts index 7e64496349..00ac18ce57 100644 --- a/tests/unit/review-reviews-v3814-fixes.test.ts +++ b/tests/unit/review-reviews-v3814-fixes.test.ts @@ -20,13 +20,13 @@ const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts"); test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── LEDGER-1: updateProviderNode must preserve custom headers on partial update ── diff --git a/tests/unit/route-edge-coverage.test.ts b/tests/unit/route-edge-coverage.test.ts index 3788227f08..80ab12de02 100644 --- a/tests/unit/route-edge-coverage.test.ts +++ b/tests/unit/route-edge-coverage.test.ts @@ -37,7 +37,7 @@ async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -135,7 +135,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("api keys route covers auth, create, masking, pagination fallback and cloud sync", async () => { diff --git a/tests/unit/route-explainability.test.ts b/tests/unit/route-explainability.test.ts index b624cf9447..7650905584 100644 --- a/tests/unit/route-explainability.test.ts +++ b/tests/unit/route-explainability.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { clearAllModelLockouts(); resetAllCircuitBreakers(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("route explainability builds a direct-route explanation from call logs", async () => { diff --git a/tests/unit/router-eval-check.test.ts b/tests/unit/router-eval-check.test.ts index 51ae202d03..025c8761cb 100644 --- a/tests/unit/router-eval-check.test.ts +++ b/tests/unit/router-eval-check.test.ts @@ -104,7 +104,7 @@ test("router eval check writes artifacts and passes non-regressing corpora", () const artifact = JSON.parse(readFileSync(json, "utf8")) as Record; assert.equal(artifact.kind, "router-eval-comparison"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -201,7 +201,7 @@ test("router eval check can include patch compare as a retained gate", () => { assert.equal(manifest.outputs?.patchJson, "patch-comparison.json"); assert.equal(manifest.thresholds?.patch?.maxLatencyIncrease, 0.05); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -288,7 +288,7 @@ test("router eval check fails when patch gate regresses beyond thresholds", () = }; assert.equal(manifest.result?.status, 1); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -378,7 +378,7 @@ test("router eval check rejects unpaired patch inputs", () => { assert.equal(candidateOnly.status, 2); assert.match(candidateOnly.stderr ?? "", /baseline-patch and --candidate-patch/); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -479,6 +479,6 @@ test("router eval check can retain artifacts for trend summaries", () => { assert.ok((trendResult.stdout ?? "").includes(runId)); assert.ok((trendResult.stdout ?? "").includes("| jsonl | all |")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/router-eval-cli.test.ts b/tests/unit/router-eval-cli.test.ts index 8e44a7fe59..9f2902d4a9 100644 --- a/tests/unit/router-eval-cli.test.ts +++ b/tests/unit/router-eval-cli.test.ts @@ -25,7 +25,7 @@ const scriptPath = "scripts/router-eval/index.ts"; // DATA_DIR — the exact resolution the guard message prescribes — instead of loosening // the assertions. const cliDataDir = mkdtempSync(join(tmpdir(), "router-eval-cli-datadir-")); -after(() => rmSync(cliDataDir, { recursive: true, force: true })); +after(() => rmSync(cliDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })); function runCli(args: string[]) { return spawnSync(process.execPath, ["--import", "tsx", scriptPath, ...args], { @@ -68,7 +68,7 @@ test("router-eval CLI prints a markdown report for JSONL input", () => { assert.ok((result.stdout ?? "").includes("Frontier")); assert.ok((result.stdout ?? "").includes("AIQ")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -123,7 +123,7 @@ test("router-eval CLI exits non-zero when regression threshold is exceeded", () assert.ok((result.stdout ?? "").includes("Router Eval Comparison")); assert.ok((result.stdout ?? "").includes("Regressions")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -156,7 +156,7 @@ test("router-eval CLI writes machine-readable JSON artifacts", () => { path: inputPath, }); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -242,7 +242,7 @@ test("router-eval CLI reads usage_history DB source", () => { "string" ); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -285,6 +285,6 @@ test("router-eval CLI defaults --db to call_logs when available", () => { assert.ok((result.stdout ?? "").includes("Router Eval Report")); assert.ok((result.stdout ?? "").includes("priority")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/router-eval-compare.test.ts b/tests/unit/router-eval-compare.test.ts index 5eef0c2edb..a417e3a863 100644 --- a/tests/unit/router-eval-compare.test.ts +++ b/tests/unit/router-eval-compare.test.ts @@ -78,6 +78,6 @@ test("router eval compare retains named comparison artifacts", () => { assert.equal(comparison.baselineName, "policy-a"); assert.equal(comparison.candidateName, "policy-b"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/router-eval-e2e-chain.test.ts b/tests/unit/router-eval-e2e-chain.test.ts index aea92f6df0..95b5acf929 100644 --- a/tests/unit/router-eval-e2e-chain.test.ts +++ b/tests/unit/router-eval-e2e-chain.test.ts @@ -130,6 +130,6 @@ test("router eval retained chain runs search patches through the check wrapper g assert.equal(manifest.result?.status, 0); assert.equal(manifest.outputs?.patchJson, "patch-comparison.json"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/router-eval-patch-compare.test.ts b/tests/unit/router-eval-patch-compare.test.ts index 87db7d65ac..382e35af6c 100644 --- a/tests/unit/router-eval-patch-compare.test.ts +++ b/tests/unit/router-eval-patch-compare.test.ts @@ -110,7 +110,7 @@ test("router config patch compare reports recommendation and metric deltas", () ) ); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -178,7 +178,7 @@ test("router config patch compare only fails threshold regressions when requeste assert.equal(failing.status, 1); assert.ok((failing.stdout ?? "").includes("Passed: no")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -223,7 +223,7 @@ test("router config patch compare reports unchanged recommendations without fail assert.equal(comparison.result?.passed, true); assert.equal(comparison.result?.status, 0); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -256,7 +256,7 @@ test("router config patch compare rejects invalid patch inputs", () => { assert.match(result.stderr ?? "", /invalid patch kind/); assert.match(result.stderr ?? "", /router-config-suggestion/); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -307,6 +307,6 @@ test("router config patch compare rejects malformed JSON and invalid evidence", assert.equal(invalidEvidenceResult.status, 2); assert.match(invalidEvidenceResult.stderr ?? "", /invalid numeric evidence field aiq/); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/router-eval-search.test.ts b/tests/unit/router-eval-search.test.ts index 7e6b40507e..87641b11a2 100644 --- a/tests/unit/router-eval-search.test.ts +++ b/tests/unit/router-eval-search.test.ts @@ -135,7 +135,7 @@ test("router eval search ranks candidates and writes retained summary artifacts" ) ); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -197,7 +197,7 @@ test("router eval search objective modes can choose different candidates", () => assert.equal(qualitySuggestion.objective, "quality"); assert.equal(qualitySuggestion.recommendedConfigId, "cheap"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -253,6 +253,6 @@ test("router eval search cost objective can select a non-AIQ-top config inside a assert.equal(suggestion.recommendedConfigId, "cost-top"); assert.equal(patch.operations?.[0]?.value, "cost-top"); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/router-eval-trends.test.ts b/tests/unit/router-eval-trends.test.ts index 989e594f13..7ca4a9bab3 100644 --- a/tests/unit/router-eval-trends.test.ts +++ b/tests/unit/router-eval-trends.test.ts @@ -73,7 +73,7 @@ test("router eval trends reads retained and flat artifacts with limit", () => { assert.ok((result.stdout ?? "").includes("run-b")); assert.ok((result.stdout ?? "").includes("flat")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -107,7 +107,7 @@ test("router eval trends can print dashboard summaries", () => { assert.ok((result.stdout ?? "").includes("AIQ: 90.000 (+10.000)")); assert.ok((result.stdout ?? "").includes("Rolling Averages")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -123,6 +123,6 @@ test("router eval trends exits clearly for empty artifact dirs", () => { assert.equal(result.status, 2); assert.ok((result.stderr ?? "").includes("No router-eval artifacts found")); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/rule12-error-sanitization-sweep.test.ts b/tests/unit/rule12-error-sanitization-sweep.test.ts index 400bb68b9b..5790e1b5f2 100644 --- a/tests/unit/rule12-error-sanitization-sweep.test.ts +++ b/tests/unit/rule12-error-sanitization-sweep.test.ts @@ -99,7 +99,7 @@ function assertSanitized(raw: string, context: string): void { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/run-next-playwright.test.ts b/tests/unit/run-next-playwright.test.ts index 61d166d380..cca0a66c4a 100644 --- a/tests/unit/run-next-playwright.test.ts +++ b/tests/unit/run-next-playwright.test.ts @@ -124,5 +124,5 @@ test("standalone asset helpers detect and rehydrate missing standalone static as ); assert.match(logs[0] || "", /Rehydrated standalone static\/public assets/); - fs.rmSync(tempRoot, { recursive: true, force: true }); + fs.rmSync(tempRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/runner-janitor.test.ts b/tests/unit/runner-janitor.test.ts index 9519414fbc..6e6aee107a 100644 --- a/tests/unit/runner-janitor.test.ts +++ b/tests/unit/runner-janitor.test.ts @@ -98,7 +98,7 @@ describe("runner-janitor.sh", () => { assert.ok(existsSync(p), `must not delete ${p} when idleness cannot be proven`); } } finally { - rmSync(f.base, { recursive: true, force: true }); + rmSync(f.base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -130,7 +130,7 @@ describe("runner-janitor.sh", () => { assert.match(r.stdout, /zombie builds: 0/); assert.match(r.stdout, /done status=0/); } finally { - rmSync(f.base, { recursive: true, force: true }); + rmSync(f.base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -146,7 +146,7 @@ describe("runner-janitor.sh", () => { assert.ok(existsSync(f.fresh), "a fresh dir must survive"); assert.ok(existsSync(f.unrelated), "files we did not create must survive even when old"); } finally { - rmSync(f.base, { recursive: true, force: true }); + rmSync(f.base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -164,7 +164,7 @@ describe("runner-janitor.sh", () => { assert.match(body, /TMPFS_MAX_AGE_HOURS:-3\}/, "tmpfs default must stay short — it is RAM"); assert.match(body, /WORK_TEMP_MAX_AGE_HOURS:-24\}/); } finally { - rmSync(f.base, { recursive: true, force: true }); + rmSync(f.base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -185,7 +185,7 @@ describe("runner-janitor.sh", () => { assert.match(r.stdout, /ROOT DISK \d+% >= 0%/); assert.ok(existsSync(f.staleTar), "alerting never deletes"); } finally { - rmSync(f.base, { recursive: true, force: true }); + rmSync(f.base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/runtime-deps-save-exact-no-prune.test.ts b/tests/unit/runtime-deps-save-exact-no-prune.test.ts index 5cc5f9bd44..6c5a5cf042 100644 --- a/tests/unit/runtime-deps-save-exact-no-prune.test.ts +++ b/tests/unit/runtime-deps-save-exact-no-prune.test.ts @@ -11,7 +11,15 @@ // code path with zero network use. import test from "node:test"; import assert from "node:assert/strict"; -import { mkdtempSync, rmSync, mkdirSync, writeFileSync, chmodSync, existsSync, readFileSync } from "node:fs"; +import { + mkdtempSync, + rmSync, + mkdirSync, + writeFileSync, + chmodSync, + existsSync, + readFileSync, +} from "node:fs"; import { join, delimiter } from "node:path"; import { tmpdir } from "node:os"; @@ -45,7 +53,7 @@ function teardown(): void { if (v === undefined) delete process.env[k]; else process.env[k] = v; } - if (tmpDir) rmSync(tmpDir, { recursive: true, force: true }); + if (tmpDir) rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } function installLineFor(pkgPrefix: string): string | undefined { diff --git a/tests/unit/runtime/magicBytes.test.ts b/tests/unit/runtime/magicBytes.test.ts index 3680ae295c..451250a91c 100644 --- a/tests/unit/runtime/magicBytes.test.ts +++ b/tests/unit/runtime/magicBytes.test.ts @@ -59,4 +59,4 @@ test("platformBinaryLabel matches process.platform", () => { assert.equal(platformBinaryLabel(), expected); }); -test.after(() => rmSync(dir, { recursive: true, force: true })); +test.after(() => rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })); diff --git a/tests/unit/sanitizer-residual-policy.test.ts b/tests/unit/sanitizer-residual-policy.test.ts index 4032dc123d..faeb944999 100644 --- a/tests/unit/sanitizer-residual-policy.test.ts +++ b/tests/unit/sanitizer-residual-policy.test.ts @@ -13,9 +13,8 @@ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-test-sanitizer-r process.env.DATA_DIR = tmpDir; const { parseEnvBoolean } = await import("../../src/shared/utils/envBoolean.ts"); -const { resolveBlockThreshold, shouldBlockDetections } = await import( - "../../src/shared/utils/injectionSeverity.ts" -); +const { resolveBlockThreshold, shouldBlockDetections } = + await import("../../src/shared/utils/injectionSeverity.ts"); const { sanitizeRequest } = await import("../../src/shared/utils/inputSanitizer.ts"); const { evaluatePromptInjection } = await import("../../src/lib/guardrails/promptInjection.ts"); const { PIIMaskerGuardrail } = await import("../../src/lib/guardrails/piiMasker.ts"); @@ -23,7 +22,7 @@ const { resetDbInstance } = await import("../../src/lib/db/core.ts"); test.after(() => { resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function withEnv( @@ -113,17 +112,23 @@ test("sanitizeRequest and evaluatePromptInjection share high-default threshold", // Medium-only detections should not block at default threshold. // Use a content shape that is unlikely to also trip high patterns. const body = { - messages: [{ role: "user", content: "Please act as a different assistant persona for this task." }], + messages: [ + { role: "user", content: "Please act as a different assistant persona for this task." }, + ], }; const sanitized = sanitizeRequest(body, silentLogger); const evaluated = evaluatePromptInjection(body, {}, { log: silentLogger }); // If medium patterns matched, neither path should block under high threshold. - if (sanitized.detections.some((d) => d.severity === "medium") && - !sanitized.detections.some((d) => d.severity === "high")) { + if ( + sanitized.detections.some((d) => d.severity === "medium") && + !sanitized.detections.some((d) => d.severity === "high") + ) { assert.equal(sanitized.blocked, false); } - if (evaluated.result.detections.some((d) => d.severity === "medium") && - !evaluated.result.detections.some((d) => d.severity === "high")) { + if ( + evaluated.result.detections.some((d) => d.severity === "medium") && + !evaluated.result.detections.some((d) => d.severity === "high") + ) { assert.equal(evaluated.blocked, false); } } diff --git a/tests/unit/search-provider-opaque-400-10849.test.ts b/tests/unit/search-provider-opaque-400-10849.test.ts index 431675f3bb..effa71d785 100644 --- a/tests/unit/search-provider-opaque-400-10849.test.ts +++ b/tests/unit/search-provider-opaque-400-10849.test.ts @@ -12,7 +12,7 @@ const searchRoute = await import("../../src/app/api/v1/search/route.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function makeRequest(body: unknown) { @@ -49,10 +49,7 @@ test("#10849: short alias 'brave' resolves like existing 'jina' aliases (not an }); test("#10849: a genuinely bad field surfaces a non-generic, field-named 400 message", async () => { - const response = await searchRoute.POST( - makeRequest({ query: "test", search_type: "bogus" }), - {} - ); + const response = await searchRoute.POST(makeRequest({ query: "test", search_type: "bogus" }), {}); const body = (await response.json()) as ErrorBody; assert.equal(response.status, 400); diff --git a/tests/unit/search-route.test.ts b/tests/unit/search-route.test.ts index a5b897eec3..01c0bba7e3 100644 --- a/tests/unit/search-route.test.ts +++ b/tests/unit/search-route.test.ts @@ -13,7 +13,7 @@ const searchRoute = await import("../../src/app/api/v1/search/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -42,7 +42,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1 search GET lists all search providers", async () => { diff --git a/tests/unit/security-s1-s2-s4.test.ts b/tests/unit/security-s1-s2-s4.test.ts index e060bb5bb4..3229a14d7d 100644 --- a/tests/unit/security-s1-s2-s4.test.ts +++ b/tests/unit/security-s1-s2-s4.test.ts @@ -31,7 +31,9 @@ describe("S2 — agent-card topology sanitisation", () => { it("agent-card.json derives URL from request.nextUrl.origin when OMNIROUTE_BASE_URL is unset", async () => { const mod = await import("../../src/app/.well-known/agent-card.json/route.ts"); - const request = new Request("https://gateway.example.com/.well-known/agent-card.json") as unknown as NextRequest; + const request = new Request( + "https://gateway.example.com/.well-known/agent-card.json" + ) as unknown as NextRequest; Object.defineProperty(request, "nextUrl", { value: new URL("https://gateway.example.com/.well-known/agent-card.json"), configurable: true, @@ -41,7 +43,11 @@ describe("S2 — agent-card topology sanitisation", () => { assert.equal(res.status, 200); const card = (await res.json()) as { url?: string; supportedInterfaces?: { url?: string }[] }; assert.ok(card.url, "card must have a url"); - assert.equal(new URL(card.url).origin, "https://gateway.example.com", `expected gateway.example.com origin, got ${card.url}`); + assert.equal( + new URL(card.url).origin, + "https://gateway.example.com", + `expected gateway.example.com origin, got ${card.url}` + ); if (card.supportedInterfaces && card.supportedInterfaces.length > 0) { const ifaceUrl = card.supportedInterfaces[0].url; assert.equal( @@ -55,7 +61,9 @@ describe("S2 — agent-card topology sanitisation", () => { it("agent-card.json uses OMNIROUTE_BASE_URL when set", async () => { process.env.OMNIROUTE_BASE_URL = "https://custom.example.com"; const mod = await import("../../src/app/.well-known/agent-card.json/route.ts"); - const request = new Request("http://localhost:20128/.well-known/agent-card.json") as unknown as NextRequest; + const request = new Request( + "http://localhost:20128/.well-known/agent-card.json" + ) as unknown as NextRequest; Object.defineProperty(request, "nextUrl", { value: new URL("http://localhost:20128/.well-known/agent-card.json"), configurable: true, @@ -65,12 +73,18 @@ describe("S2 — agent-card topology sanitisation", () => { assert.equal(res.status, 200); const card = (await res.json()) as { url?: string }; assert.ok(card.url, "card must have a url"); - assert.equal(new URL(card.url).origin, "https://custom.example.com", `expected custom.example.com origin, got ${card.url}`); + assert.equal( + new URL(card.url).origin, + "https://custom.example.com", + `expected custom.example.com origin, got ${card.url}` + ); }); it("agent.json derives URL from request.nextUrl.origin when OMNIROUTE_BASE_URL is unset", async () => { const mod = await import("../../src/app/.well-known/agent.json/route.ts"); - const request = new Request("https://gateway.example.com/.well-known/agent.json") as unknown as NextRequest; + const request = new Request( + "https://gateway.example.com/.well-known/agent.json" + ) as unknown as NextRequest; Object.defineProperty(request, "nextUrl", { value: new URL("https://gateway.example.com/.well-known/agent.json"), configurable: true, @@ -80,7 +94,11 @@ describe("S2 — agent-card topology sanitisation", () => { assert.equal(res.status, 200); const card = (await res.json()) as { url?: string }; assert.ok(card.url, "card must have a url"); - assert.equal(new URL(card.url).origin, "https://gateway.example.com", `expected gateway.example.com origin, got ${card.url}`); + assert.equal( + new URL(card.url).origin, + "https://gateway.example.com", + `expected gateway.example.com origin, got ${card.url}` + ); }); }); @@ -90,12 +108,8 @@ const loginGuardMod = await import("../../src/server/auth/loginGuard"); // ── S4: login guard Retry-After tests ───────────────────────────────── describe("S4 — 429 Retry-After header", () => { - const { - checkLoginGuard, - recordLoginFailure, - resetLoginGuardForTests, - LOGIN_GUARD_TUNABLES, - } = loginGuardMod; + const { checkLoginGuard, recordLoginFailure, resetLoginGuardForTests, LOGIN_GUARD_TUNABLES } = + loginGuardMod; beforeEach(() => { resetLoginGuardForTests(); @@ -108,8 +122,10 @@ describe("S4 — 429 Retry-After header", () => { } const decision = checkLoginGuard(ip, { enabled: true }); assert.equal(decision.allowed, false); - assert.ok(typeof decision.retryAfterSeconds === "number" && decision.retryAfterSeconds > 0, - `retryAfterSeconds should be > 0, got ${decision.retryAfterSeconds}`); + assert.ok( + typeof decision.retryAfterSeconds === "number" && decision.retryAfterSeconds > 0, + `retryAfterSeconds should be > 0, got ${decision.retryAfterSeconds}` + ); }); it("recordLoginFailure returns retryAfterSeconds on threshold hit", () => { @@ -120,8 +136,10 @@ describe("S4 — 429 Retry-After header", () => { assert.equal(dec.allowed, true, `attempt #${i + 1} should still be allowed`); } else { assert.equal(dec.allowed, false, `attempt #${i + 1} (threshold) should be locked`); - assert.ok(typeof dec.retryAfterSeconds === "number" && dec.retryAfterSeconds > 0, - `retryAfterSeconds should be > 0 on threshold hit, got ${dec.retryAfterSeconds}`); + assert.ok( + typeof dec.retryAfterSeconds === "number" && dec.retryAfterSeconds > 0, + `retryAfterSeconds should be > 0 on threshold hit, got ${dec.retryAfterSeconds}` + ); } } }); @@ -134,7 +152,10 @@ describe("S4 — 429 Retry-After header", () => { const guardDec = checkLoginGuard(ip, { enabled: true }); assert.equal(guardDec.allowed, false); const headerValue = String(guardDec.retryAfterSeconds || 60); - assert.ok(/^\d+$/.test(headerValue), `Retry-After should be an integer string, got ${headerValue}`); + assert.ok( + /^\d+$/.test(headerValue), + `Retry-After should be an integer string, got ${headerValue}` + ); assert.ok(Number.parseInt(headerValue, 10) > 0, "Retry-After should be positive"); resetLoginGuardForTests(); @@ -145,7 +166,10 @@ describe("S4 — 429 Retry-After header", () => { } assert.equal(failureDec!.allowed, false); const headerValue2 = String(failureDec!.retryAfterSeconds || 60); - assert.ok(/^\d+$/.test(headerValue2), `Retry-After should be an integer string, got ${headerValue2}`); + assert.ok( + /^\d+$/.test(headerValue2), + `Retry-After should be an integer string, got ${headerValue2}` + ); assert.ok(Number.parseInt(headerValue2, 10) > 0, "Retry-After should be positive"); }); }); @@ -192,7 +216,7 @@ describe("S1 — login rate-limit key uses anti-spoofed peer IP", () => { }); after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (JWT_SAVED !== undefined) { process.env.JWT_SECRET = JWT_SAVED; } else { @@ -242,11 +266,16 @@ describe("S1 — login rate-limit key uses anti-spoofed peer IP", () => { // Locked out — rate-limit key is tied to the trusted peer IP, not XFF const retryAfter = res.headers.get("Retry-After"); assert.ok(retryAfter !== null, "429 response must include Retry-After header"); - assert.ok(/^\d+$/.test(retryAfter!), `Retry-After should be a positive integer, got ${retryAfter}`); + assert.ok( + /^\d+$/.test(retryAfter!), + `Retry-After should be a positive integer, got ${retryAfter}` + ); return; } } - assert.fail("Expected at least one 429 response after threshold failed attempts with the same trusted peer IP"); + assert.fail( + "Expected at least one 429 response after threshold failed attempts with the same trusted peer IP" + ); }); it("ignores spoofed x-omniroute-trusted-peer-ip when OMNIROUTE_PEER_STAMP_TOKEN is not set", async () => { @@ -288,7 +317,9 @@ describe("S1 — login rate-limit key uses anti-spoofed peer IP", () => { return; } } - assert.fail("Expected 429 after threshold failures — spoofed header should not bypass rate-limit"); + assert.fail( + "Expected 429 after threshold failures — spoofed header should not bypass rate-limit" + ); }); it("falls back to auditContext.ipAddress when trusted peer IP header is absent", async () => { @@ -320,7 +351,10 @@ describe("S1 — login rate-limit key uses anti-spoofed peer IP", () => { // Locked out — rate-limit key is tied to the XFF-derived IP const retryAfter = res.headers.get("Retry-After"); assert.ok(retryAfter !== null, "429 response must include Retry-After header"); - assert.ok(Number.parseInt(retryAfter!, 10) > 0, `Retry-After should be > 0, got ${retryAfter}`); + assert.ok( + Number.parseInt(retryAfter!, 10) > 0, + `Retry-After should be > 0, got ${retryAfter}` + ); return; } } @@ -348,10 +382,13 @@ describe("S1 — login rate-limit key uses anti-spoofed peer IP", () => { if (res.status === 429) { const retryAfter = res.headers.get("Retry-After"); assert.ok(retryAfter !== null, "429 response must include Retry-After header"); - assert.ok(Number.parseInt(retryAfter!, 10) > 0, `Retry-After should be > 0, got ${retryAfter}`); + assert.ok( + Number.parseInt(retryAfter!, 10) > 0, + `Retry-After should be > 0, got ${retryAfter}` + ); return; } } assert.fail("Expected at least one 429 response after threshold failed attempts"); }); -}); \ No newline at end of file +}); diff --git a/tests/unit/serial/combo-health-autopilot.test.ts b/tests/unit/serial/combo-health-autopilot.test.ts index 091930283b..63e7f1bd85 100644 --- a/tests/unit/serial/combo-health-autopilot.test.ts +++ b/tests/unit/serial/combo-health-autopilot.test.ts @@ -26,7 +26,7 @@ const { normalizeComboStep } = await import("../../../src/lib/combos/steps.ts"); async function resetStorage() { comboMetrics.resetAllComboMetrics(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -101,7 +101,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/serial/combo-quota-share-cooldown-wait-timing.test.ts b/tests/unit/serial/combo-quota-share-cooldown-wait-timing.test.ts index 20ab6fe40c..7e65ac39e8 100644 --- a/tests/unit/serial/combo-quota-share-cooldown-wait-timing.test.ts +++ b/tests/unit/serial/combo-quota-share-cooldown-wait-timing.test.ts @@ -89,7 +89,7 @@ function comboOf(strategy: string) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -102,7 +102,7 @@ test.after(async () => { clearAllModelLockouts(); try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } diff --git a/tests/unit/serial/combo-strategy-fallbacks-half-open-timing.test.ts b/tests/unit/serial/combo-strategy-fallbacks-half-open-timing.test.ts index f813779c78..c209724ddd 100644 --- a/tests/unit/serial/combo-strategy-fallbacks-half-open-timing.test.ts +++ b/tests/unit/serial/combo-strategy-fallbacks-half-open-timing.test.ts @@ -21,7 +21,9 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-combo-fallbacks-half-open-")); +const TEST_DATA_DIR = fs.mkdtempSync( + path.join(os.tmpdir(), "omniroute-combo-fallbacks-half-open-") +); const ORIGINAL_DATA_DIR = process.env.DATA_DIR; process.env.DATA_DIR = TEST_DATA_DIR; @@ -61,7 +63,7 @@ async function cleanupTestDataDir() { for (let attempt = 0; attempt < 5; attempt += 1) { try { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); return; } catch (error: unknown) { lastError = error; diff --git a/tests/unit/serial/provider-health-autopilot.test.ts b/tests/unit/serial/provider-health-autopilot.test.ts index 67e0b22909..964a941ea7 100644 --- a/tests/unit/serial/provider-health-autopilot.test.ts +++ b/tests/unit/serial/provider-health-autopilot.test.ts @@ -28,7 +28,7 @@ const PROVIDER = "autopilot-test-provider"; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -70,7 +70,7 @@ test.beforeEach(async () => { test.after(async () => { accountFallback.clearProviderFailure(PROVIDER); await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; diff --git a/tests/unit/serial/quota-division-blocks.test.ts b/tests/unit/serial/quota-division-blocks.test.ts index 3119f66619..a148974a95 100644 --- a/tests/unit/serial/quota-division-blocks.test.ts +++ b/tests/unit/serial/quota-division-blocks.test.ts @@ -52,7 +52,11 @@ const core = await import("../../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - try { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); } catch { /* ignore */ } + try { + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch { + /* ignore */ + } } }); @@ -66,98 +70,92 @@ const store = new SqliteQuotaStore(); await test("quota-division-blocks: countable-unit enforcement (block + allow)", async (t) => { // ── Scenario A: pool total > effectiveLimit → block ────────────────────── - await t.test( - "[A] pool total > effectiveLimit → block (global-saturated)", - async () => { - const CONN = "conn-block-a"; - const PROV = "test-provider-a2-block"; - const KEY_A = "key-block-a1"; - const KEY_B = "key-block-b1"; + await t.test("[A] pool total > effectiveLimit → block (global-saturated)", async () => { + const CONN = "conn-block-a"; + const PROV = "test-provider-a2-block"; + const KEY_A = "key-block-a1"; + const KEY_B = "key-block-b1"; - // Seed plan: requests/hourly/limit=100 - providerPlans.upsertPlan( - CONN, - PROV, - [{ unit: "requests", window: "hourly", limit: LIMIT }], - "manual" - ); + // Seed plan: requests/hourly/limit=100 + providerPlans.upsertPlan( + CONN, + PROV, + [{ unit: "requests", window: "hourly", limit: LIMIT }], + "manual" + ); - // Create pool: 2 allocations at 50/50 hard - const pool = quotaPools.createPool({ - connectionId: CONN, - name: "Block Pool A", - allocations: [ - { apiKeyId: KEY_A, weight: 50, policy: "hard" }, - { apiKeyId: KEY_B, weight: 50, policy: "hard" }, - ], - }); + // Create pool: 2 allocations at 50/50 hard + const pool = quotaPools.createPool({ + connectionId: CONN, + name: "Block Pool A", + allocations: [ + { apiKeyId: KEY_A, weight: 50, policy: "hard" }, + { apiKeyId: KEY_B, weight: 50, policy: "hard" }, + ], + }); - const dim = { poolId: pool.id, unit: "requests" as const, window: "hourly" as const }; + const dim = { poolId: pool.id, unit: "requests" as const, window: "hourly" as const }; - // Consume: keyA=60, keyB=60 → poolTotal=120 > effectiveLimit=100 - await store.consume(KEY_A, dim, 60); - await store.consume(KEY_B, dim, 60); + // Consume: keyA=60, keyB=60 → poolTotal=120 > effectiveLimit=100 + await store.consume(KEY_A, dim, 60); + await store.consume(KEY_B, dim, 60); - const decision = await enforceQuotaShare({ - apiKeyId: KEY_A, - connectionId: CONN, - provider: PROV, - estimatedCost: { requests: 1 }, - }); + const decision = await enforceQuotaShare({ + apiKeyId: KEY_A, + connectionId: CONN, + provider: PROV, + estimatedCost: { requests: 1 }, + }); - assert.equal( - decision.kind, - "block", - `[A] Expected block when poolTotal(120) ≥ effectiveLimit(100); got: ${JSON.stringify(decision)}` - ); - } - ); + assert.equal( + decision.kind, + "block", + `[A] Expected block when poolTotal(120) ≥ effectiveLimit(100); got: ${JSON.stringify(decision)}` + ); + }); // ── Scenario B: pool total < effectiveLimit, key under fair-share → allow ─ - await t.test( - "[B] pool total < effectiveLimit and key under fair-share → allow", - async () => { - const CONN = "conn-allow-b"; - const PROV = "test-provider-a2-allow"; - const KEY_A = "key-allow-a1"; - const KEY_B = "key-allow-b1"; + await t.test("[B] pool total < effectiveLimit and key under fair-share → allow", async () => { + const CONN = "conn-allow-b"; + const PROV = "test-provider-a2-allow"; + const KEY_A = "key-allow-a1"; + const KEY_B = "key-allow-b1"; - // Seed plan for separate connection: requests/hourly/limit=100 - providerPlans.upsertPlan( - CONN, - PROV, - [{ unit: "requests", window: "hourly", limit: LIMIT }], - "manual" - ); + // Seed plan for separate connection: requests/hourly/limit=100 + providerPlans.upsertPlan( + CONN, + PROV, + [{ unit: "requests", window: "hourly", limit: LIMIT }], + "manual" + ); - // Create pool: distinct from Scenario A (different poolId + connection) - const pool = quotaPools.createPool({ - connectionId: CONN, - name: "Allow Pool B", - allocations: [ - { apiKeyId: KEY_A, weight: 50, policy: "hard" }, - { apiKeyId: KEY_B, weight: 50, policy: "hard" }, - ], - }); + // Create pool: distinct from Scenario A (different poolId + connection) + const pool = quotaPools.createPool({ + connectionId: CONN, + name: "Allow Pool B", + allocations: [ + { apiKeyId: KEY_A, weight: 50, policy: "hard" }, + { apiKeyId: KEY_B, weight: 50, policy: "hard" }, + ], + }); - const dim = { poolId: pool.id, unit: "requests" as const, window: "hourly" as const }; + const dim = { poolId: pool.id, unit: "requests" as const, window: "hourly" as const }; - // Consume: keyA=20, keyB=20 → poolTotal=40 < effectiveLimit=100 - await store.consume(KEY_A, dim, 20); - await store.consume(KEY_B, dim, 20); + // Consume: keyA=20, keyB=20 → poolTotal=40 < effectiveLimit=100 + await store.consume(KEY_A, dim, 20); + await store.consume(KEY_B, dim, 20); - const decision = await enforceQuotaShare({ - apiKeyId: KEY_A, - connectionId: CONN, - provider: PROV, - estimatedCost: { requests: 1 }, - }); + const decision = await enforceQuotaShare({ + apiKeyId: KEY_A, + connectionId: CONN, + provider: PROV, + estimatedCost: { requests: 1 }, + }); - assert.equal( - decision.kind, - "allow", - `[B] Expected allow when poolTotal(40) < effectiveLimit(100); got: ${JSON.stringify(decision)}` - ); - } - ); + assert.equal( + decision.kind, + "allow", + `[B] Expected allow when poolTotal(40) < effectiveLimit(100); got: ${JSON.stringify(decision)}` + ); + }); }); diff --git a/tests/unit/services-branch-hardening.test.ts b/tests/unit/services-branch-hardening.test.ts index ca51606acb..8a04fe2faa 100644 --- a/tests/unit/services-branch-hardening.test.ts +++ b/tests/unit/services-branch-hardening.test.ts @@ -19,7 +19,7 @@ test.after(() => { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // Best effort cleanup } diff --git a/tests/unit/services/ServiceSupervisor.test.ts b/tests/unit/services/ServiceSupervisor.test.ts index 5a5441c53a..c343689a0c 100644 --- a/tests/unit/services/ServiceSupervisor.test.ts +++ b/tests/unit/services/ServiceSupervisor.test.ts @@ -77,7 +77,7 @@ function tickConfig(tool: string, port: number) { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("start spawns process and captures logs in ring buffer", async () => { diff --git a/tests/unit/services/cliproxy-health-model-auth.test.ts b/tests/unit/services/cliproxy-health-model-auth.test.ts index 3c5c6e2d52..0b17a43bc1 100644 --- a/tests/unit/services/cliproxy-health-model-auth.test.ts +++ b/tests/unit/services/cliproxy-health-model-auth.test.ts @@ -91,7 +91,7 @@ after(async () => { unregisterSupervisor("cliproxy"); await new Promise((resolve) => fakeCliproxy.close(() => resolve())); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("embedded CLIProxyAPI uses public health and dedicated model credentials", async () => { diff --git a/tests/unit/services/emergency-fallback.test.ts b/tests/unit/services/emergency-fallback.test.ts index bf6c39603b..e6a375b3a5 100644 --- a/tests/unit/services/emergency-fallback.test.ts +++ b/tests/unit/services/emergency-fallback.test.ts @@ -31,7 +31,7 @@ function restoreEnv(name: string, value: string | undefined) { function resetTestState() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); delete process.env.OMNIROUTE_EMERGENCY_FALLBACK; resetEmergencyFallbackEnvCache(); @@ -50,7 +50,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); restoreEnv("DATA_DIR", previousDataDir); restoreEnv("DISABLE_SQLITE_AUTO_BACKUP", previousDisableSqliteAutoBackup); }); diff --git a/tests/unit/services/end-to-end-shape.test.ts b/tests/unit/services/end-to-end-shape.test.ts index 2e27739869..f03f7ef1c4 100644 --- a/tests/unit/services/end-to-end-shape.test.ts +++ b/tests/unit/services/end-to-end-shape.test.ts @@ -549,5 +549,5 @@ describe("Cross-service shape consistency", () => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/services/installers/bifrost-transport-version-format.test.ts b/tests/unit/services/installers/bifrost-transport-version-format.test.ts index 480ad934bd..2950be952b 100644 --- a/tests/unit/services/installers/bifrost-transport-version-format.test.ts +++ b/tests/unit/services/installers/bifrost-transport-version-format.test.ts @@ -26,31 +26,27 @@ import path from "node:path"; describe("formatTransportVersion (pure)", () => { it("prepends v to bare semver", async () => { - const { formatTransportVersion } = await import( - "../../../../src/lib/services/installers/bifrost.ts" - ); + const { formatTransportVersion } = + await import("../../../../src/lib/services/installers/bifrost.ts"); assert.equal(formatTransportVersion("1.6.3"), "v1.6.3"); assert.equal(formatTransportVersion("2.0.0-beta.1"), "v2.0.0-beta.1"); }); it("leaves an already-v-prefixed version untouched", async () => { - const { formatTransportVersion } = await import( - "../../../../src/lib/services/installers/bifrost.ts" - ); + const { formatTransportVersion } = + await import("../../../../src/lib/services/installers/bifrost.ts"); assert.equal(formatTransportVersion("v1.6.3"), "v1.6.3"); }); it('passes through "latest" untouched', async () => { - const { formatTransportVersion } = await import( - "../../../../src/lib/services/installers/bifrost.ts" - ); + const { formatTransportVersion } = + await import("../../../../src/lib/services/installers/bifrost.ts"); assert.equal(formatTransportVersion("latest"), "latest"); }); it('defaults null to "latest"', async () => { - const { formatTransportVersion } = await import( - "../../../../src/lib/services/installers/bifrost.ts" - ); + const { formatTransportVersion } = + await import("../../../../src/lib/services/installers/bifrost.ts"); assert.equal(formatTransportVersion(null), "latest"); }); }); @@ -86,14 +82,12 @@ describe("resolveSpawnArgs BIFROST_TRANSPORT_VERSION (real filesystem)", () => { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } process.env.PATH = ORIGINAL_PATH; - fs.rmSync(dataDir, { recursive: true, force: true }); - fs.rmSync(fakeBinDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(fakeBinDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); it("BIFROST_TRANSPORT_VERSION is v-prefixed, matching what bin.js requires", async () => { - const { resolveSpawnArgs } = await import( - "../../../../src/lib/services/installers/bifrost.ts" - ); + const { resolveSpawnArgs } = await import("../../../../src/lib/services/installers/bifrost.ts"); const args = resolveSpawnArgs(8080); diff --git a/tests/unit/services/installers/bifrost.test.ts b/tests/unit/services/installers/bifrost.test.ts index f59541a436..e91918d587 100644 --- a/tests/unit/services/installers/bifrost.test.ts +++ b/tests/unit/services/installers/bifrost.test.ts @@ -64,8 +64,8 @@ const { test.after(() => { process.env.PATH = originalPath; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); - fs.rmSync(FAKE_BIN_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(FAKE_BIN_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("BIFROST_DEFAULT_PORT is 8080", () => { diff --git a/tests/unit/services/installers/cliproxy-resolve-spawn-args-6877.test.ts b/tests/unit/services/installers/cliproxy-resolve-spawn-args-6877.test.ts index 98408a999d..cb5d5d183a 100644 --- a/tests/unit/services/installers/cliproxy-resolve-spawn-args-6877.test.ts +++ b/tests/unit/services/installers/cliproxy-resolve-spawn-args-6877.test.ts @@ -39,14 +39,14 @@ after(() => { } else { process.env.DATA_DIR = ORIGINAL_DATA_DIR; } - fs.rmSync(FIXED_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(FIXED_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("resolveSpawnArgs (#6877 — real filesystem)", () => { const dataDir = FIXED_DATA_DIR; beforeEach(() => { - fs.rmSync(dataDir, { recursive: true, force: true }); + fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(dataDir, { recursive: true }); }); diff --git a/tests/unit/services/installers/ninerouter.test.ts b/tests/unit/services/installers/ninerouter.test.ts index 4554e34d3e..870dbe1846 100644 --- a/tests/unit/services/installers/ninerouter.test.ts +++ b/tests/unit/services/installers/ninerouter.test.ts @@ -72,8 +72,8 @@ const { test.after(() => { process.env.PATH = originalPath; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); - fs.rmSync(FAKE_BIN_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(FAKE_BIN_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("install creates package.json structure", async () => { diff --git a/tests/unit/services/lifecycle.test.ts b/tests/unit/services/lifecycle.test.ts index 28a6033834..95de97e39f 100644 --- a/tests/unit/services/lifecycle.test.ts +++ b/tests/unit/services/lifecycle.test.ts @@ -56,7 +56,7 @@ function makeFakeSup(tool: string) { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── status endpoint ──────────────────────────────────────────────────────── diff --git a/tests/unit/services/modelSync.test.ts b/tests/unit/services/modelSync.test.ts index f720a61d8c..fe60ebc5ce 100644 --- a/tests/unit/services/modelSync.test.ts +++ b/tests/unit/services/modelSync.test.ts @@ -30,7 +30,7 @@ afterEach(() => { after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function makeFetch( diff --git a/tests/unit/services/portProbePid.test.ts b/tests/unit/services/portProbePid.test.ts index b9df600eac..c106b1d6a9 100644 --- a/tests/unit/services/portProbePid.test.ts +++ b/tests/unit/services/portProbePid.test.ts @@ -166,6 +166,6 @@ test("resolvePortPid still resolves a pid on a host without lsof", async (t) => } finally { process.env.PATH = originalPath; await new Promise((resolve) => server.close(() => resolve())); - rmSync(shim, { recursive: true, force: true }); + rmSync(shim, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/services/ringBuffer.test.ts b/tests/unit/services/ringBuffer.test.ts index bf55f9cc0a..f62b2073a7 100644 --- a/tests/unit/services/ringBuffer.test.ts +++ b/tests/unit/services/ringBuffer.test.ts @@ -77,7 +77,7 @@ test("flush writes to file when path set", async () => { assert.ok(content.includes("line-one"), "flush file should contain log entry"); assert.ok(content.includes("[stderr]"), "flush file should contain stderr entry"); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/services/serviceSupervisorSpawnError.test.ts b/tests/unit/services/serviceSupervisorSpawnError.test.ts index 87b1f6cb9e..e781e3fd5b 100644 --- a/tests/unit/services/serviceSupervisorSpawnError.test.ts +++ b/tests/unit/services/serviceSupervisorSpawnError.test.ts @@ -69,12 +69,9 @@ describe("ServiceSupervisor spawn-failure handling", () => { const status = await supervisor.start(); assert.equal(status.state, "error"); assert.ok(status.lastError, "lastError should describe the spawn failure"); - assert.match( - status.lastError!, - /ENOENT|EACCES|EINVAL|EFTYPE|not recognized|spawn|%1|Win32/i - ); + assert.match(status.lastError!, /ENOENT|EACCES|EINVAL|EFTYPE|not recognized|spawn|%1|Win32/i); } finally { - await rm(dir, { recursive: true, force: true }); + await rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/session-affinity-combo-timeout-eviction.test.ts b/tests/unit/session-affinity-combo-timeout-eviction.test.ts index 9dfb36f260..8475588b38 100644 --- a/tests/unit/session-affinity-combo-timeout-eviction.test.ts +++ b/tests/unit/session-affinity-combo-timeout-eviction.test.ts @@ -44,13 +44,13 @@ const timedOutSignal = () => abortedWith(new Error(abortReasons.COMBO_PER_MODEL_ test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("evicts the pin when the combo per-model timeout abandons the pinned account", () => { diff --git a/tests/unit/session-affinity-generic-7274.test.ts b/tests/unit/session-affinity-generic-7274.test.ts index 3700e3ad61..b3a0f54e96 100644 --- a/tests/unit/session-affinity-generic-7274.test.ts +++ b/tests/unit/session-affinity-generic-7274.test.ts @@ -62,13 +62,14 @@ const settingsDb = await import("../../src/lib/db/settings.ts"); const apiKeysDb = await import("../../src/lib/db/apiKeys.ts"); const affinityDb = await import("../../src/lib/db/sessionAccountAffinity.ts"); const auth = await import("../../src/sse/services/auth.ts"); -const { resolveSessionAffinityTtlMs } = await import("../../src/sse/services/sessionAffinityPin.ts"); +const { resolveSessionAffinityTtlMs } = + await import("../../src/sse/services/sessionAffinityPin.ts"); const { DefaultExecutor } = await import("../../open-sse/executors/default.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -77,7 +78,8 @@ async function seedConnection(provider: string, overrides: Record) || {}, @@ -91,7 +93,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── 1. generic (non-Codex) provider now honors the TTL ────────────────────── @@ -106,7 +108,11 @@ test("#7274 a non-Codex provider with sessionAffinityTtlMs > 0 persists and reus sessionKey: "session-generic", forcedConnectionId: connectionA.id, }); - assert.equal(request1?.connectionId, connectionA.id, "first request pins to the forced connection"); + assert.equal( + request1?.connectionId, + connectionA.id, + "first request pins to the forced connection" + ); assert.equal( affinityDb.getSessionAccountAffinity("session-generic", "glm", 60_000)?.connectionId, connectionA.id, @@ -172,7 +178,7 @@ test("#7274 resolveSessionAffinityTtlMs prefers the new generic key over the leg test("#7274 resolveSessionAffinityTtlMs now applies to any provider, not just codex", () => { const ttl = resolveSessionAffinityTtlMs("openai", {}, { sessionAffinityTtlMs: 45_000 }); - assert.equal(ttl, 45_000, "the provider !== \"codex\" early-return must be gone"); + assert.equal(ttl, 45_000, 'the provider !== "codex" early-return must be gone'); }); // ── 2b. raw-SQL migration: additive, idempotent carry-over ────────────────── @@ -200,7 +206,9 @@ test("#7274 migration 124 carries codexSessionAffinityTtlMs over to sessionAffin db.exec(migrationSql); const row = db - .prepare("SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'sessionAffinityTtlMs'") + .prepare( + "SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'sessionAffinityTtlMs'" + ) .get() as { value: string } | undefined; assert.equal(row?.value, "60000", "the generic key must carry the old value over"); @@ -209,13 +217,19 @@ test("#7274 migration 124 carries codexSessionAffinityTtlMs over to sessionAffin "SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'codexSessionAffinityTtlMs'" ) .get() as { value: string } | undefined; - assert.equal(oldRow?.value, "60000", "the migration is additive — the old key/row is not deleted"); + assert.equal( + oldRow?.value, + "60000", + "the migration is additive — the old key/row is not deleted" + ); // Idempotency: re-running the migration (as the runner would on a replay) // must not throw and must not change the already-carried-over value. assert.doesNotThrow(() => db.exec(migrationSql)); const rowAfterReplay = db - .prepare("SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'sessionAffinityTtlMs'") + .prepare( + "SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'sessionAffinityTtlMs'" + ) .get() as { value: string } | undefined; assert.equal(rowAfterReplay?.value, "60000"); } finally { @@ -242,7 +256,9 @@ test("#7274 migration 124 is a no-op when the operator never configured the lega assert.doesNotThrow(() => db.exec(migrationSql)); const row = db - .prepare("SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'sessionAffinityTtlMs'") + .prepare( + "SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'sessionAffinityTtlMs'" + ) .get(); assert.equal(row, undefined, "no row should be created when there was nothing to carry over"); } finally { diff --git a/tests/unit/session-leases-route.test.ts b/tests/unit/session-leases-route.test.ts index 3d6c28dccd..c3e5e77f5c 100644 --- a/tests/unit/session-leases-route.test.ts +++ b/tests/unit/session-leases-route.test.ts @@ -67,7 +67,7 @@ async function seedKey( async function resetStorage(): Promise { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); attemptedExternalCalls = 0; modelAliasResolver.invalidateAliasCache(); @@ -84,7 +84,7 @@ test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("requires authentication, managed scope, and canonical explicit owner", async () => { diff --git a/tests/unit/settings-api.test.ts b/tests/unit/settings-api.test.ts index 8ff0dd80a1..9f359e5e61 100644 --- a/tests/unit/settings-api.test.ts +++ b/tests/unit/settings-api.test.ts @@ -20,13 +20,13 @@ async function createSettingsApiHarness() { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(testDataDir, { recursive: true }); } function cleanup() { core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } return { diff --git a/tests/unit/settings-cas-7784.test.ts b/tests/unit/settings-cas-7784.test.ts index 5c20291514..76adcb2424 100644 --- a/tests/unit/settings-cas-7784.test.ts +++ b/tests/unit/settings-cas-7784.test.ts @@ -22,13 +22,13 @@ const settingsRoute = await import("../../src/app/api/settings/route.ts"); beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); describe("#7784 settings optimistic concurrency", () => { diff --git a/tests/unit/settings-debugmode-default.test.ts b/tests/unit/settings-debugmode-default.test.ts index bd667dc120..2ded41c5a8 100644 --- a/tests/unit/settings-debugmode-default.test.ts +++ b/tests/unit/settings-debugmode-default.test.ts @@ -22,5 +22,5 @@ test("logToolSources defaults to false", async () => { }); test.after(() => { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); diff --git a/tests/unit/settings-route-password.test.ts b/tests/unit/settings-route-password.test.ts index 32f967f2ce..6599d70fe0 100644 --- a/tests/unit/settings-route-password.test.ts +++ b/tests/unit/settings-route-password.test.ts @@ -17,7 +17,7 @@ const managementPassword = await import("../../src/lib/auth/managementPassword.t async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } @@ -28,7 +28,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_INITIAL_PASSWORD === undefined) { delete process.env.INITIAL_PASSWORD; } else { diff --git a/tests/unit/shared/structuredLogger-raw-write-guard.test.ts b/tests/unit/shared/structuredLogger-raw-write-guard.test.ts index f0cf34997b..6bfbc1a19a 100644 --- a/tests/unit/shared/structuredLogger-raw-write-guard.test.ts +++ b/tests/unit/shared/structuredLogger-raw-write-guard.test.ts @@ -89,7 +89,7 @@ test("error() with a destroyed stderr does not crash, and still writes to the lo "fatal() must still reach writeToFile after the stderr write is skipped" ); - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Guard against collateral damage: #1006's suppression policy must be untouched by this change. diff --git a/tests/unit/siliconflow-model-sync.test.ts b/tests/unit/siliconflow-model-sync.test.ts index 8b9835c944..4daa52e29e 100644 --- a/tests/unit/siliconflow-model-sync.test.ts +++ b/tests/unit/siliconflow-model-sync.test.ts @@ -21,7 +21,7 @@ type JsonBody = Record; async function resetStorage() { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -54,7 +54,7 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("sync-models rejects local catalog fallback and preserves existing SiliconFlow models", async () => { diff --git a/tests/unit/skills-builtins-sandbox.test.ts b/tests/unit/skills-builtins-sandbox.test.ts index a696d3bf7a..b8991e9599 100644 --- a/tests/unit/skills-builtins-sandbox.test.ts +++ b/tests/unit/skills-builtins-sandbox.test.ts @@ -17,7 +17,7 @@ function makeTempDir(prefix) { } function removePath(targetPath) { - fs.rmSync(targetPath, { recursive: true, force: true }); + fs.rmSync(targetPath, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } async function importFresh(modulePath) { @@ -408,7 +408,7 @@ test("containerProvider: all five providers registered", () => { assert.ok(mod.ALL_PROVIDERS.length === 5); assert.deepStrictEqual( mod.ALL_PROVIDERS.map((p) => p.id), - ["docker", "apple", "wsl", "orbstack", "podman"], + ["docker", "apple", "wsl", "orbstack", "podman"] ); assert.ok(mod.PROVIDER_BY_ID.has("docker")); assert.ok(mod.PROVIDER_BY_ID.has("apple")); @@ -420,27 +420,15 @@ test("containerProvider: all five providers registered", () => { test("containerProvider: platformPriority returns correct order per OS", () => { return importFresh("src/lib/skills/containerProvider.ts").then((mod) => { - const originalPlatform = Object.getOwnPropertyDescriptor( - process, - "platform", - ); + const originalPlatform = Object.getOwnPropertyDescriptor(process, "platform"); // darwin Object.defineProperty(process, "platform", { value: "darwin" }); - assert.deepStrictEqual(mod.platformPriority(), [ - "apple", - "orbstack", - "podman", - "docker", - ]); + assert.deepStrictEqual(mod.platformPriority(), ["apple", "orbstack", "podman", "docker"]); // win32 Object.defineProperty(process, "platform", { value: "win32" }); - assert.deepStrictEqual(mod.platformPriority(), [ - "wsl", - "docker", - "podman", - ]); + assert.deepStrictEqual(mod.platformPriority(), ["wsl", "docker", "podman"]); // linux Object.defineProperty(process, "platform", { value: "linux" }); @@ -448,11 +436,7 @@ test("containerProvider: platformPriority returns correct order per OS", () => { // Restore if (originalPlatform) { - Object.defineProperty( - process, - "platform", - originalPlatform, - ); + Object.defineProperty(process, "platform", originalPlatform); } }); }); @@ -467,25 +451,10 @@ test("containerProvider: buildRun produces run as args[0] for all providers", () readOnly: true, }; for (const provider of mod.ALL_PROVIDERS) { - const resolved = provider.buildRun( - "alpine", - ["echo", "hi"], - "test-id", - config, - ); - assert.equal( - resolved.args[0], - "run", - `${provider.id}: args[0] must be "run"`, - ); - assert.ok( - resolved.args.includes("--rm"), - `${provider.id}: should include --rm`, - ); - assert.ok( - resolved.args.includes("alpine"), - `${provider.id}: should include image`, - ); + const resolved = provider.buildRun("alpine", ["echo", "hi"], "test-id", config); + assert.equal(resolved.args[0], "run", `${provider.id}: args[0] must be "run"`); + assert.ok(resolved.args.includes("--rm"), `${provider.id}: should include --rm`); + assert.ok(resolved.args.includes("alpine"), `${provider.id}: should include image`); // killArgs must return something callable const kill = resolved.killArgs("test-cont"); assert.ok(Array.isArray(kill), `${provider.id}: killArgs returns array`); @@ -555,9 +524,7 @@ test("containerProvider: resolveProvider falls back to docker when no runtime in // Auto-detect walks platform priority — if nothing is installed we // always land on docker as the fallback. const provider = await mod.resolveProvider(); - assert.ok( - ["docker", "apple", "wsl", "podman", "orbstack"].includes(provider.id), - ); + assert.ok(["docker", "apple", "wsl", "podman", "orbstack"].includes(provider.id)); // Ensure the fallback is always docker when probes fail // (this test is best-effort — on a host with docker installed, // the auto-detect will legitimately pick docker) diff --git a/tests/unit/skills-collect-routes.test.ts b/tests/unit/skills-collect-routes.test.ts index 9657937a84..ae61322183 100644 --- a/tests/unit/skills-collect-routes.test.ts +++ b/tests/unit/skills-collect-routes.test.ts @@ -56,7 +56,7 @@ test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Helpers ─────────────────────────────────────────────────────────────────── @@ -64,7 +64,7 @@ test.after(() => { async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); delete process.env.INITIAL_PASSWORD; } diff --git a/tests/unit/skills-executor.test.ts b/tests/unit/skills-executor.test.ts index 4acbaaae9e..99975c06b1 100644 --- a/tests/unit/skills-executor.test.ts +++ b/tests/unit/skills-executor.test.ts @@ -23,7 +23,7 @@ function resetSkillsRuntime() { async function resetStorage() { resetSkillsRuntime(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -47,7 +47,7 @@ test.beforeEach(async () => { test.after(() => { resetSkillsRuntime(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("skillExecutor executes a registered handler and persists execution history", async () => { diff --git a/tests/unit/skills-injection.test.ts b/tests/unit/skills-injection.test.ts index 35344b9f38..556b3d8227 100644 --- a/tests/unit/skills-injection.test.ts +++ b/tests/unit/skills-injection.test.ts @@ -28,7 +28,7 @@ function resetRegistryState() { async function resetStorage() { resetRegistryState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -60,7 +60,7 @@ test.beforeEach(async () => { test.after(() => { resetRegistryState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("injectSkills renders enabled tools in provider-specific shapes", async () => { diff --git a/tests/unit/skills-interception.test.ts b/tests/unit/skills-interception.test.ts index 075b24452a..7c796bb50b 100644 --- a/tests/unit/skills-interception.test.ts +++ b/tests/unit/skills-interception.test.ts @@ -25,7 +25,7 @@ function resetRuntime() { async function resetStorage() { resetRuntime(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -71,7 +71,7 @@ test.beforeEach(async () => { test.after(() => { resetRuntime(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("extractToolCalls supports OpenAI, Anthropic and Gemini shapes", () => { @@ -307,7 +307,10 @@ test("handleToolCallExecution intercepts a registered skill alongside an unregis }, { type: "tool_use", id: "tool-native", name: "Bash", input: { command: "ls" } }, ]); - assert.equal(mixed.content.some((b: { type: string }) => b.type === "tool_result"), false); + assert.equal( + mixed.content.some((b: { type: string }) => b.type === "tool_result"), + false + ); assert.equal(mixed.stop_reason, "tool_use"); }); @@ -337,7 +340,10 @@ test("handleToolCallExecution loads registry from DB on cold cache (covers loadF text: '[Skill result: lookup@1.0.0]\n{"record":"resolved:cold"}', }, ]); - assert.equal(result.content.some((b: { type: string }) => b.type === "tool_result"), false); + assert.equal( + result.content.some((b: { type: string }) => b.type === "tool_result"), + false + ); assert.equal(result.stop_reason, "end_turn"); assert.equal(result.stop_sequence, null); }); diff --git a/tests/unit/skills-marketplace.test.ts b/tests/unit/skills-marketplace.test.ts index 64fddb7cd9..ca63ce63dc 100644 --- a/tests/unit/skills-marketplace.test.ts +++ b/tests/unit/skills-marketplace.test.ts @@ -22,7 +22,7 @@ function clearSkillRegistry() { function resetStorage() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); clearSkillRegistry(); core.getDbInstance(); @@ -40,7 +40,7 @@ test.after(() => { core.resetDbInstance(); clearSkillRegistry(); process.env.DATA_DIR = originalDataDir; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("SkillsMP installs are available to API-key-scoped requests", async () => { diff --git a/tests/unit/skills-memory-builtins.test.ts b/tests/unit/skills-memory-builtins.test.ts index aaabcdf0a0..0cf479891a 100644 --- a/tests/unit/skills-memory-builtins.test.ts +++ b/tests/unit/skills-memory-builtins.test.ts @@ -32,7 +32,7 @@ test.beforeEach(() => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("memory_save creates a new memory entry", async () => { @@ -210,9 +210,7 @@ test("interceptToolCalls executes memory tools when allowed via builtinToolNames test("interceptToolCalls skips memory tools not allowed by builtinToolNames", async () => { const results = await interceptToolCalls( - [ - { id: "call-x", name: MEMORY_DELETE_TOOL_NAME, arguments: { id: "anything" } }, - ], + [{ id: "call-x", name: MEMORY_DELETE_TOOL_NAME, arguments: { id: "anything" } }], { apiKeyId: "key-mem", sessionId: "session-mem", diff --git a/tests/unit/skills-registry.test.ts b/tests/unit/skills-registry.test.ts index 14e6a9c6a5..af001d159a 100644 --- a/tests/unit/skills-registry.test.ts +++ b/tests/unit/skills-registry.test.ts @@ -21,7 +21,7 @@ function resetRegistryState() { async function resetStorage() { resetRegistryState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -32,7 +32,7 @@ test.beforeEach(async () => { test.after(() => { resetRegistryState(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("skillRegistry registers, lists, sorts and resolves versions", async () => { diff --git a/tests/unit/skills-routes-error-sanitization.test.ts b/tests/unit/skills-routes-error-sanitization.test.ts index 083ef363cc..18238609fb 100644 --- a/tests/unit/skills-routes-error-sanitization.test.ts +++ b/tests/unit/skills-routes-error-sanitization.test.ts @@ -28,7 +28,7 @@ const LEAKY_PATH = "/home/testuser/.omniroute/skills/evil/handler.js"; function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; if (ORIGINAL_OMNIROUTE_API_KEY === undefined) delete process.env.OMNIROUTE_API_KEY; diff --git a/tests/unit/skills-routes.test.ts b/tests/unit/skills-routes.test.ts index 0dc3ba150e..77bcf4f727 100644 --- a/tests/unit/skills-routes.test.ts +++ b/tests/unit/skills-routes.test.ts @@ -23,7 +23,7 @@ function clearSkillRegistry() { function resetStorage() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); clearSkillRegistry(); core.getDbInstance(); @@ -60,7 +60,7 @@ test.after(() => { core.resetDbInstance(); clearSkillRegistry(); process.env.DATA_DIR = originalDataDir; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("skills route GET loads skills from the database and lists them", async () => { diff --git a/tests/unit/skills-skillssh.test.ts b/tests/unit/skills-skillssh.test.ts index c5229e9b79..b55f320e79 100644 --- a/tests/unit/skills-skillssh.test.ts +++ b/tests/unit/skills-skillssh.test.ts @@ -23,7 +23,7 @@ function clearSkillRegistry() { function resetStorage() { core.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(tmpDir, { recursive: true }); clearSkillRegistry(); core.getDbInstance(); @@ -42,7 +42,7 @@ test.after(() => { clearSkillRegistry(); globalThis.fetch = originalFetch; process.env.DATA_DIR = originalDataDir; - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── Zod schema validation tests ── diff --git a/tests/unit/sonar-quality-gate-fixes.test.ts b/tests/unit/sonar-quality-gate-fixes.test.ts index 1f39367501..464aa6c05a 100644 --- a/tests/unit/sonar-quality-gate-fixes.test.ts +++ b/tests/unit/sonar-quality-gate-fixes.test.ts @@ -29,7 +29,7 @@ test("classify-pr-changes rejects a list path that escapes the workspace", () => assert.match(res.stderr, /escapes the workspace/); fs.rmSync(outside, { force: true }); } finally { - fs.rmSync(cwd, { recursive: true, force: true }); + fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -45,7 +45,7 @@ test("classify-pr-changes still accepts a workspace-relative list file", () => { assert.match(res.stdout, /docs=true/); assert.match(res.stdout, /code=false/); } finally { - fs.rmSync(cwd, { recursive: true, force: true }); + fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/specialty-model-catalog-routes.test.ts b/tests/unit/specialty-model-catalog-routes.test.ts index 01ab26691c..db1bd64211 100644 --- a/tests/unit/specialty-model-catalog-routes.test.ts +++ b/tests/unit/specialty-model-catalog-routes.test.ts @@ -18,7 +18,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // These routes all derive from the shared unified catalog (getUnifiedModelsResponse), // which #6408 wrapped in a 1.5s TTL response cache keyed only by (prefix, isCodex @@ -57,7 +57,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("image catalog GET uses the unified active-credential model list", async () => { diff --git a/tests/unit/specialty-model-hidden-openrouter-9293.test.ts b/tests/unit/specialty-model-hidden-openrouter-9293.test.ts index 4599b26909..360dfe3758 100644 --- a/tests/unit/specialty-model-hidden-openrouter-9293.test.ts +++ b/tests/unit/specialty-model-hidden-openrouter-9293.test.ts @@ -32,7 +32,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -44,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9293 hidden OpenRouter specialty models are excluded from /v1/models catalog", async () => { diff --git a/tests/unit/spend-batch-writer.test.ts b/tests/unit/spend-batch-writer.test.ts index 29253602f6..88f0b67490 100644 --- a/tests/unit/spend-batch-writer.test.ts +++ b/tests/unit/spend-batch-writer.test.ts @@ -28,7 +28,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -60,7 +60,7 @@ test.after(async () => { resetSpendBatchWriterForTests(); costRules.resetCostData(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("spend batch writer auto-flushes at the configured threshold", async () => { diff --git a/tests/unit/sre-tcp-close-analyzer.test.ts b/tests/unit/sre-tcp-close-analyzer.test.ts index 0d4d6e332c..b660bfd1c0 100644 --- a/tests/unit/sre-tcp-close-analyzer.test.ts +++ b/tests/unit/sre-tcp-close-analyzer.test.ts @@ -229,7 +229,7 @@ function withTempPcap(fn: (pcapPath: string, tmpDir: string) => T): T { try { return fn(pcapPath, tmpDir); } finally { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } diff --git a/tests/unit/sse-auth-antigravity-credits.test.ts b/tests/unit/sse-auth-antigravity-credits.test.ts index 6b038fb4b3..4335fd9c08 100644 --- a/tests/unit/sse-auth-antigravity-credits.test.ts +++ b/tests/unit/sse-auth-antigravity-credits.test.ts @@ -17,7 +17,7 @@ const quotaCache = await import("../../src/domain/quotaCache.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -28,7 +28,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Antigravity always mode bypasses request-path quota preflight", async () => { diff --git a/tests/unit/sse-auth-codex-account-pool.test.ts b/tests/unit/sse-auth-codex-account-pool.test.ts index 927775d15f..59dce44cb0 100644 --- a/tests/unit/sse-auth-codex-account-pool.test.ts +++ b/tests/unit/sse-auth-codex-account-pool.test.ts @@ -14,7 +14,7 @@ const auth = await import("../../src/sse/services/auth.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -40,7 +40,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Codex Spark preflight cooldown leaves normal models on the same parent selectable", async () => { diff --git a/tests/unit/sse-auth-exclusive-leases.test.ts b/tests/unit/sse-auth-exclusive-leases.test.ts index 6543e83f1c..9981d39ce2 100644 --- a/tests/unit/sse-auth-exclusive-leases.test.ts +++ b/tests/unit/sse-auth-exclusive-leases.test.ts @@ -68,7 +68,7 @@ async function resetStorage(): Promise { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); fallback.clearAllModelLockouts(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -76,7 +76,7 @@ test.beforeEach(resetStorage); test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("foreign top candidate is skipped and the existing selector chooses the next free candidate", async () => { @@ -273,16 +273,10 @@ test("generic lease selection is provider-neutral across GLM and OpenAI fixtures ] as const) { const connection = await seedConnection(1, { provider }); const key = await seedManagedKey([connection.id]); - const selected = await auth.getProviderCredentials( - provider, - null, - [connection.id], - model, - { - lease: { apiKeyId: key.id, context: context(OWNERS[0], 1), mode: "acquire" }, - materializeCredentials: false, - } - ); + const selected = await auth.getProviderCredentials(provider, null, [connection.id], model, { + lease: { apiKeyId: key.id, context: context(OWNERS[0], 1), mode: "acquire" }, + materializeCredentials: false, + }); assert.equal(selected?.connectionId, connection.id, provider); leaseDb.releaseExclusiveConnectionLease({ leaseOwnerId: OWNERS[0], diff --git a/tests/unit/sse-auth-resource-404.test.ts b/tests/unit/sse-auth-resource-404.test.ts index 9980627c91..2537632fe0 100644 --- a/tests/unit/sse-auth-resource-404.test.ts +++ b/tests/unit/sse-auth-resource-404.test.ts @@ -14,7 +14,7 @@ const auth = await import("../../src/sse/services/auth.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("markAccountUnavailable preserves connection health for a missing Files API resource", async () => { diff --git a/tests/unit/sse-auth.test.ts b/tests/unit/sse-auth.test.ts index 0a18c865dd..ce8032d20d 100644 --- a/tests/unit/sse-auth.test.ts +++ b/tests/unit/sse-auth.test.ts @@ -20,7 +20,7 @@ const oauthOccupancy = await import("../../open-sse/services/oauthSessionOccupan async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -72,7 +72,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("extractApiKey parses bearer headers and isValidApiKey validates persisted keys", async () => { diff --git a/tests/unit/sse-comments-optout-9305.test.ts b/tests/unit/sse-comments-optout-9305.test.ts index 8928738bbe..41d0e4e219 100644 --- a/tests/unit/sse-comments-optout-9305.test.ts +++ b/tests/unit/sse-comments-optout-9305.test.ts @@ -181,7 +181,7 @@ for (const upstreamDone of [true, false]) { test.after(() => { usageHistory.clearPendingRequests(); core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (previousDataDir === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = previousDataDir; }); diff --git a/tests/unit/sse-shim-contract.test.ts b/tests/unit/sse-shim-contract.test.ts index b27a500d44..c59238bf87 100644 --- a/tests/unit/sse-shim-contract.test.ts +++ b/tests/unit/sse-shim-contract.test.ts @@ -26,7 +26,7 @@ function listProjectFiles(relativePath: string): string[] { } test.after(() => { - rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("src/sse model shim keeps parseModel behavior aligned with open-sse core", async () => { diff --git a/tests/unit/startup-stale-cooldown-recovery.test.ts b/tests/unit/startup-stale-cooldown-recovery.test.ts index 7dab54f2bb..dee0d33c40 100644 --- a/tests/unit/startup-stale-cooldown-recovery.test.ts +++ b/tests/unit/startup-stale-cooldown-recovery.test.ts @@ -32,7 +32,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -52,7 +52,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ─── helpers ──────────────────────────────────────────────────────────────── diff --git a/tests/unit/sticky-affinity-failover-6219.test.ts b/tests/unit/sticky-affinity-failover-6219.test.ts index 44b8709b9f..8d1d8ad535 100644 --- a/tests/unit/sticky-affinity-failover-6219.test.ts +++ b/tests/unit/sticky-affinity-failover-6219.test.ts @@ -35,13 +35,13 @@ const TTL = 60_000; test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("evicts the sticky pin when the pinned connection fails over (#6219)", () => { diff --git a/tests/unit/stmt-cache-lru.test.ts b/tests/unit/stmt-cache-lru.test.ts index d50e1fdc78..8f4fca3c0e 100644 --- a/tests/unit/stmt-cache-lru.test.ts +++ b/tests/unit/stmt-cache-lru.test.ts @@ -24,7 +24,7 @@ function cleanup() { delete process.env.DATA_DIR; } try { - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} } @@ -50,9 +50,9 @@ test("statement cache handles 200+ unique SELECTs without errors (LRU eviction)" } // Verify the DB is still functional after eviction churn - const finalRow = db - .prepare("SELECT COUNT(*) AS cnt FROM stmt_cache_test") - .get() as { cnt: number }; + const finalRow = db.prepare("SELECT COUNT(*) AS cnt FROM stmt_cache_test").get() as { + cnt: number; + }; assert.equal(finalRow.cnt, 1, "table should still have 1 row after cache churn"); } finally { cleanup(); diff --git a/tests/unit/stream-claude-delta-contract.test.ts b/tests/unit/stream-claude-delta-contract.test.ts index a807d7267b..79909ccf9b 100644 --- a/tests/unit/stream-claude-delta-contract.test.ts +++ b/tests/unit/stream-claude-delta-contract.test.ts @@ -13,7 +13,7 @@ const core = await import("../../src/lib/db/core.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(testDataDir, { recursive: true, force: true }); + fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createSSEStream ignores non-string Claude deltas before estimating usage", async () => { diff --git a/tests/unit/stream-impossible-input-usage.test.ts b/tests/unit/stream-impossible-input-usage.test.ts index 1716f6851d..026f975c2c 100644 --- a/tests/unit/stream-impossible-input-usage.test.ts +++ b/tests/unit/stream-impossible-input-usage.test.ts @@ -36,7 +36,7 @@ function parseSsePayloads(text: string): Array> { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("native Claude passthrough repairs impossible AgentRouter cache usage before forwarding", async () => { diff --git a/tests/unit/stream-non-json-sse.test.ts b/tests/unit/stream-non-json-sse.test.ts index 16776c45cf..7470e88bcf 100644 --- a/tests/unit/stream-non-json-sse.test.ts +++ b/tests/unit/stream-non-json-sse.test.ts @@ -41,7 +41,7 @@ async function readTransformed(chunks: string[], options: object): Promise { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -86,10 +86,7 @@ test("non-JSON data line (plain-text rate-limit message) is NOT forwarded to cli ); // Both valid JSON chunks must appear - assert.ok( - output.includes("chatcmpl-nonjson-1"), - `First valid chunk missing.\nOutput: ${output}` - ); + assert.ok(output.includes("chatcmpl-nonjson-1"), `First valid chunk missing.\nOutput: ${output}`); assert.ok( output.includes("chatcmpl-nonjson-2"), `Second valid chunk missing.\nOutput: ${output}` @@ -117,11 +114,7 @@ test("exactly one [DONE] emitted even when upstream sends a duplicate", async () test("valid JSON chunks pass through correctly in passthrough mode", async () => { const output = await readTransformed( - [ - `data: ${validChunk1}\n\n`, - `data: ${validChunk2}\n\n`, - "data: [DONE]\n\n", - ], + [`data: ${validChunk1}\n\n`, `data: ${validChunk2}\n\n`, "data: [DONE]\n\n"], PASSTHROUGH_OPTIONS ); diff --git a/tests/unit/stream-numeric-ids.test.ts b/tests/unit/stream-numeric-ids.test.ts index ce82ad9ce3..53271a74c9 100644 --- a/tests/unit/stream-numeric-ids.test.ts +++ b/tests/unit/stream-numeric-ids.test.ts @@ -29,7 +29,7 @@ async function readTransformed(chunks, options) { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -232,7 +232,9 @@ test("createSSEStream responses passthrough coerces numeric ids to strings", asy assert.equal(typeof added.item.call_id, "string"); assert.equal(added.item.call_id, "654"); - const delta = payloads.find((payload) => payload.type === "response.function_call_arguments.delta"); + const delta = payloads.find( + (payload) => payload.type === "response.function_call_arguments.delta" + ); assert.equal(typeof delta.response_id, "string"); assert.equal(delta.response_id, "987"); assert.equal(typeof delta.item_id, "string"); diff --git a/tests/unit/stream-onfailure-callback-logging.test.ts b/tests/unit/stream-onfailure-callback-logging.test.ts index 8e9a0f7672..f3da4789bc 100644 --- a/tests/unit/stream-onfailure-callback-logging.test.ts +++ b/tests/unit/stream-onfailure-callback-logging.test.ts @@ -34,7 +34,12 @@ test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { for (const entry of fs.readdirSync(TEST_DATA_DIR)) { - fs.rmSync(path.join(TEST_DATA_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(TEST_DATA_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } } }); diff --git a/tests/unit/stream-prompt-tokens-zero-upstream.test.ts b/tests/unit/stream-prompt-tokens-zero-upstream.test.ts index dc579dc2b0..0e0404c5c9 100644 --- a/tests/unit/stream-prompt-tokens-zero-upstream.test.ts +++ b/tests/unit/stream-prompt-tokens-zero-upstream.test.ts @@ -108,7 +108,12 @@ test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { for (const entry of fs.readdirSync(TEST_DATA_DIR)) { - fs.rmSync(path.join(TEST_DATA_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(TEST_DATA_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } } }); diff --git a/tests/unit/stream-request-body-size-mark-7045.test.ts b/tests/unit/stream-request-body-size-mark-7045.test.ts index b033be2085..0b544bbb47 100644 --- a/tests/unit/stream-request-body-size-mark-7045.test.ts +++ b/tests/unit/stream-request-body-size-mark-7045.test.ts @@ -11,9 +11,7 @@ import os from "node:os"; import path from "node:path"; import { performance } from "node:perf_hooks"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-stream-body-size-mark-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-stream-body-size-mark-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); @@ -56,7 +54,7 @@ async function drainSSEStream(options) { test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/stream-utils.test.ts b/tests/unit/stream-utils.test.ts index 46d7959be0..93587ad295 100644 --- a/tests/unit/stream-utils.test.ts +++ b/tests/unit/stream-utils.test.ts @@ -147,7 +147,12 @@ test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { for (const entry of fs.readdirSync(TEST_DATA_DIR)) { - fs.rmSync(path.join(TEST_DATA_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(TEST_DATA_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } } }); diff --git a/tests/unit/streamingPiiTransform.test.ts b/tests/unit/streamingPiiTransform.test.ts index f28a31aa33..9fb515add2 100644 --- a/tests/unit/streamingPiiTransform.test.ts +++ b/tests/unit/streamingPiiTransform.test.ts @@ -490,7 +490,7 @@ test.after(async () => { const coreDb = await import("../../src/lib/db/core.ts"); coreDb.resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("createPiiSseTransform preserves tool call arguments without buffering", async () => { diff --git a/tests/unit/strict-random-deck.test.ts b/tests/unit/strict-random-deck.test.ts index 186bf75e36..8c7c331466 100644 --- a/tests/unit/strict-random-deck.test.ts +++ b/tests/unit/strict-random-deck.test.ts @@ -16,7 +16,12 @@ test.after(() => { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { for (const entry of fs.readdirSync(TEST_DATA_DIR)) { - fs.rmSync(path.join(TEST_DATA_DIR, entry), { recursive: true, force: true }); + fs.rmSync(path.join(TEST_DATA_DIR, entry), { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } } }); diff --git a/tests/unit/suggested-models-route.test.ts b/tests/unit/suggested-models-route.test.ts index bca7401838..9b0a218106 100644 --- a/tests/unit/suggested-models-route.test.ts +++ b/tests/unit/suggested-models-route.test.ts @@ -37,7 +37,7 @@ test.afterEach(() => { test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; } else { diff --git a/tests/unit/sync-bundle.test.ts b/tests/unit/sync-bundle.test.ts index 24215d0226..12e508b002 100644 --- a/tests/unit/sync-bundle.test.ts +++ b/tests/unit/sync-bundle.test.ts @@ -22,7 +22,7 @@ const syncBundle = await import("../../src/lib/sync/bundle.ts"); function resetStorage() { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ test.beforeEach(() => { test.after(() => { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/sync-env-bundled-require-5006.test.ts b/tests/unit/sync-env-bundled-require-5006.test.ts index 3082cbf551..516dda1950 100644 --- a/tests/unit/sync-env-bundled-require-5006.test.ts +++ b/tests/unit/sync-env-bundled-require-5006.test.ts @@ -97,6 +97,6 @@ test("#5006: getEnvSyncPlan(oauth) works with explicit rootDir and never throws assert.deepEqual(keys.sort(), ["CLAUDE_OAUTH_CLIENT_ID", "CODEX_OAUTH_CLIENT_ID"]); } finally { process.env.DATA_DIR = origDataDir; - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/sync-env.test.ts b/tests/unit/sync-env.test.ts index 6804e0917a..8fe04db1ee 100644 --- a/tests/unit/sync-env.test.ts +++ b/tests/unit/sync-env.test.ts @@ -81,7 +81,7 @@ test("syncEnv creates .env from .env.example and leaves runtime-owned secrets bl assert.doesNotMatch(envContent, /^COMMENTED_KEY=/m); } finally { process.env.DATA_DIR = origDataDir; - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -116,7 +116,7 @@ test("syncEnv appends only missing keys and preserves existing values", () => { assert.match(envContent, /Auto-added by sync-env/); } finally { process.env.DATA_DIR = origDataDir; - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -147,7 +147,7 @@ test("syncEnv treats quoted and unquoted values as equivalent", () => { assert.deepEqual(result, { created: false, added: 0 }); } finally { process.env.DATA_DIR = origDataDir; - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -168,7 +168,7 @@ test("syncEnv is idempotent when .env is already complete", () => { assert.equal(after, before); } finally { process.env.DATA_DIR = origDataDir; - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -187,6 +187,6 @@ test("syncEnv oauth scope only copies oauth defaults", () => { assert.doesNotMatch(envContent, /^JWT_SECRET=/m); assert.doesNotMatch(envContent, /^Provider User-Agent Overrides/m); } finally { - fs.rmSync(rootDir, { recursive: true, force: true }); + fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/sync-reasoning-supported-efforts-7694.test.ts b/tests/unit/sync-reasoning-supported-efforts-7694.test.ts index f81440ea10..2f348d31a4 100644 --- a/tests/unit/sync-reasoning-supported-efforts-7694.test.ts +++ b/tests/unit/sync-reasoning-supported-efforts-7694.test.ts @@ -24,22 +24,20 @@ const providersDb = await import("../../src/lib/db/providers.ts"); const modelsDb = await import("../../src/lib/db/models.ts"); const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); const { getModelInfo } = await import("../../src/sse/services/model.ts"); -const { normalizeDiscoveredModels, detectSupportedThinkingEfforts } = await import( - "../../src/lib/providerModels/modelDiscovery.ts" -); +const { normalizeDiscoveredModels, detectSupportedThinkingEfforts } = + await import("../../src/lib/providerModels/modelDiscovery.ts"); const { splitSyncedEffortSuffix } = await import("../../open-sse/services/model.ts"); const { appendSyncedEffortVariants, shouldExposeSyncedEffortVariants, SYNCED_EFFORT_SKIP_PROVIDERS, } = await import("../../open-sse/utils/syncedEffortVariants.ts"); -const { applyDefaultReasoningEffort } = await import( - "../../open-sse/services/defaultReasoningEffort.ts" -); +const { applyDefaultReasoningEffort } = + await import("../../open-sse/services/defaultReasoningEffort.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -50,7 +48,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); async function seedProviderConnection(provider: string) { diff --git a/tests/unit/sync-routes.test.ts b/tests/unit/sync-routes.test.ts index c12c0756ca..f863c04f6b 100644 --- a/tests/unit/sync-routes.test.ts +++ b/tests/unit/sync-routes.test.ts @@ -25,7 +25,7 @@ const localDb = await import("../../src/lib/localDb.ts"); function resetStorage() { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -37,7 +37,7 @@ test.beforeEach(async () => { test.after(() => { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/synced-effort-suffix-learned-validation.test.ts b/tests/unit/synced-effort-suffix-learned-validation.test.ts index a06ff2d479..2e3d810ca2 100644 --- a/tests/unit/synced-effort-suffix-learned-validation.test.ts +++ b/tests/unit/synced-effort-suffix-learned-validation.test.ts @@ -25,7 +25,7 @@ const { recordLearnedReasoningEffort, __test_resetLearnedReasoningEffortCaps } = async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -55,7 +55,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("-max resolves once the learned set advertises it (sync metadata does not)", async () => { diff --git a/tests/unit/synced-model-context-window-reconcile.test.ts b/tests/unit/synced-model-context-window-reconcile.test.ts index ddf629c34f..c9623085a9 100644 --- a/tests/unit/synced-model-context-window-reconcile.test.ts +++ b/tests/unit/synced-model-context-window-reconcile.test.ts @@ -39,7 +39,7 @@ type ReconcileDeps = resolver.ReconcileDeps; function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -49,7 +49,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // --------------------------------------------------------------------------- diff --git a/tests/unit/synced-model-delete-custom-sibling.test.ts b/tests/unit/synced-model-delete-custom-sibling.test.ts index 5fb31716df..ad5102359d 100644 --- a/tests/unit/synced-model-delete-custom-sibling.test.ts +++ b/tests/unit/synced-model-delete-custom-sibling.test.ts @@ -32,7 +32,7 @@ test.after(() => { // Release the SQLite handle so the Node test runner can exit, then remove the // throwaway DATA_DIR (CLAUDE.md "Database Handles in Tests"). core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); /** Invoke the real DELETE handler so the test tracks production behavior. */ diff --git a/tests/unit/synced-model-delete-resync.test.ts b/tests/unit/synced-model-delete-resync.test.ts index d1b711540b..4aaf79b167 100644 --- a/tests/unit/synced-model-delete-resync.test.ts +++ b/tests/unit/synced-model-delete-resync.test.ts @@ -23,7 +23,7 @@ before(() => { after(() => { resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("a deleted synced model is restored when upstream advertises it again", async () => { diff --git a/tests/unit/synced-model-hide-persist-3782.test.ts b/tests/unit/synced-model-hide-persist-3782.test.ts index 400a87fa01..e85ef0973b 100644 --- a/tests/unit/synced-model-hide-persist-3782.test.ts +++ b/tests/unit/synced-model-hide-persist-3782.test.ts @@ -35,7 +35,7 @@ after(() => { // Release the SQLite handle so the Node test runner can exit, then remove the // throwaway DATA_DIR (CLAUDE.md "Database Handles in Tests"). resetDbInstance(); - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const PROVIDER = "llama-cpp"; diff --git a/tests/unit/system-trust-test-guard.test.ts b/tests/unit/system-trust-test-guard.test.ts index 969c3588f8..36d55a2927 100644 --- a/tests/unit/system-trust-test-guard.test.ts +++ b/tests/unit/system-trust-test-guard.test.ts @@ -37,6 +37,6 @@ test("installCert under the guard skips the OS mutation but keeps input contract try { await installCert("", pem); } finally { - fs.rmSync(dir, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/t07-no-log-key-config.test.ts b/tests/unit/t07-no-log-key-config.test.ts index 9ce5ded52d..c1513793ef 100644 --- a/tests/unit/t07-no-log-key-config.test.ts +++ b/tests/unit/t07-no-log-key-config.test.ts @@ -23,7 +23,7 @@ const schemas = await import("../../src/shared/validation/schemas.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (originalPiiEnabled === undefined) { delete process.env.PII_RESPONSE_SANITIZATION; diff --git a/tests/unit/t08-allowed-connections.test.ts b/tests/unit/t08-allowed-connections.test.ts index 0eedb92be4..6715da654d 100644 --- a/tests/unit/t08-allowed-connections.test.ts +++ b/tests/unit/t08-allowed-connections.test.ts @@ -20,7 +20,7 @@ const ROOT_DIR = path.resolve(__dirname, "../.."); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ══════════════════════════════════════════════════════════════════ diff --git a/tests/unit/tag-routing.test.ts b/tests/unit/tag-routing.test.ts index c87f929dc7..5cb596f8fc 100644 --- a/tests/unit/tag-routing.test.ts +++ b/tests/unit/tag-routing.test.ts @@ -36,7 +36,7 @@ function okResponse(content: string) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -57,7 +57,7 @@ test.beforeEach(async () => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("tag router normalizes request metadata and matches connection tags", () => { diff --git a/tests/unit/tailscaleTunnel.test.ts b/tests/unit/tailscaleTunnel.test.ts index 43b168277c..171962702d 100644 --- a/tests/unit/tailscaleTunnel.test.ts +++ b/tests/unit/tailscaleTunnel.test.ts @@ -82,7 +82,7 @@ test.beforeEach(async () => { resetTailscaleTestEnv(fakeBinaryPath); mitmManager.clearCachedPassword(); dbCore.resetDbInstance(); - await fs.rm(TEST_DATA_DIR, { recursive: true, force: true }); + await fs.rm(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); await fs.mkdir(TEST_DATA_DIR, { recursive: true }); const recreatedBinaryPath = await createFakeTailscaleBinary(); resetTailscaleTestEnv(recreatedBinaryPath); @@ -108,7 +108,7 @@ test.after(async () => { else process.env.TAILSCALE_TEST_LOGIN_OUTPUT = originalEnv.loginOutput; if (originalEnv.loginExitCode === undefined) delete process.env.TAILSCALE_TEST_LOGIN_EXIT_CODE; else process.env.TAILSCALE_TEST_LOGIN_EXIT_CODE = originalEnv.loginExitCode; - await fs.rm(TEST_DATA_DIR, { recursive: true, force: true }); + await fs.rm(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("extractTailscaleAuthUrl and extractTailscaleEnableUrl parse login URLs", () => { diff --git a/tests/unit/telemetry-auto-cleanup-6848.test.ts b/tests/unit/telemetry-auto-cleanup-6848.test.ts index bb1ae033f4..1858dba9ee 100644 --- a/tests/unit/telemetry-auto-cleanup-6848.test.ts +++ b/tests/unit/telemetry-auto-cleanup-6848.test.ts @@ -44,7 +44,7 @@ const { getDbInstance, resetDbInstance } = await import("../../src/lib/db/core.t // or the native test runner can hang indefinitely on a dangling connection. test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const DAY_MS = 86_400_000; diff --git a/tests/unit/terminal-status-origin.test.ts b/tests/unit/terminal-status-origin.test.ts index 3a9221f2ca..c30076d22d 100644 --- a/tests/unit/terminal-status-origin.test.ts +++ b/tests/unit/terminal-status-origin.test.ts @@ -13,7 +13,7 @@ const { writeTerminalStatus } = await import("../../src/shared/utils/terminalSta test.after(() => { core.resetDbInstance(); - fs.rmSync(DIR, { recursive: true, force: true }); + fs.rmSync(DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function row(id: string): { is_active: number; test_status: string } { diff --git a/tests/unit/termux-android-cache-dir.test.ts b/tests/unit/termux-android-cache-dir.test.ts index a99c197ec7..66d15525d1 100644 --- a/tests/unit/termux-android-cache-dir.test.ts +++ b/tests/unit/termux-android-cache-dir.test.ts @@ -89,7 +89,7 @@ test("ensureAndroidCacheDir: creates ~/.cache when missing on android", () => { assert.equal(existsSync(cacheDir), true); assert.equal(env.XDG_CACHE_HOME, cacheDir); } finally { - rmSync(home, { recursive: true, force: true }); + rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -114,7 +114,7 @@ test("ensureAndroidCacheDir: does not recreate when ~/.cache already exists", () assert.equal(mkdirCalls, 0); assert.equal(env.XDG_CACHE_HOME, cacheDir); } finally { - rmSync(home, { recursive: true, force: true }); + rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -133,7 +133,7 @@ test("ensureAndroidCacheDir: respects an existing XDG_CACHE_HOME and creates tha assert.equal(existsSync(xdg), true); assert.equal(env.XDG_CACHE_HOME, xdg); } finally { - rmSync(root, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -150,7 +150,7 @@ test("ensureAndroidCacheDir: Termux-on-linux still prepares ~/.cache", () => { assert.equal(result.prepared, true); assert.equal(existsSync(join(home, ".cache")), true); } finally { - rmSync(home, { recursive: true, force: true }); + rmSync(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/thinking-budget-hydration-5312.test.ts b/tests/unit/thinking-budget-hydration-5312.test.ts index 2eca499271..63b4bccc75 100644 --- a/tests/unit/thinking-budget-hydration-5312.test.ts +++ b/tests/unit/thinking-budget-hydration-5312.test.ts @@ -33,7 +33,7 @@ test.afterEach(() => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#5312 RC-A: persisted thinkingBudget mode is restored at boot", async () => { diff --git a/tests/unit/tier-config-provider-override-route.test.ts b/tests/unit/tier-config-provider-override-route.test.ts index 93852d6e26..f3d4b70462 100644 --- a/tests/unit/tier-config-provider-override-route.test.ts +++ b/tests/unit/tier-config-provider-override-route.test.ts @@ -23,7 +23,7 @@ const route = await import("../../src/app/api/settings/tier-config/route.ts"); function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -33,7 +33,7 @@ test.beforeEach(() => { test.after(() => { resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function putRequest(body: unknown) { @@ -116,13 +116,22 @@ test("route round-trips cleanly against an already-populated tier_config table ( const getRes = (await route.GET(getRequest())) as Response; assert.equal(getRes.status, 200); const getBody = await getRes.json(); - assert.ok(Array.isArray(getBody.freeProviders), "should still expose the DEFAULT_TIER_CONFIG shape"); - assert.deepEqual(getBody.providerOverrides, [{ provider: "pre-existing-provider", tier: "cheap" }]); + assert.ok( + Array.isArray(getBody.freeProviders), + "should still expose the DEFAULT_TIER_CONFIG shape" + ); + assert.deepEqual(getBody.providerOverrides, [ + { provider: "pre-existing-provider", tier: "cheap" }, + ]); const putRes = (await route.PUT( putRequest({ provider: "my-custom-endpoint-999", tier: "free" }) )) as Response; - assert.equal(putRes.status, 200, "PUT should round-trip without error against a pre-populated row"); + assert.equal( + putRes.status, + 200, + "PUT should round-trip without error against a pre-populated row" + ); const putBody = await putRes.json(); assert.deepEqual(putBody.providerOverrides, [ { provider: "pre-existing-provider", tier: "cheap" }, diff --git a/tests/unit/tier-resolver-provider-override.test.ts b/tests/unit/tier-resolver-provider-override.test.ts index 295c0e899c..eca6cac7fa 100644 --- a/tests/unit/tier-resolver-provider-override.test.ts +++ b/tests/unit/tier-resolver-provider-override.test.ts @@ -21,7 +21,7 @@ const tierResolver = await import("../../open-sse/services/tierResolver.ts"); function resetStorage() { delete process.env.INITIAL_PASSWORD; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); // classifyTier() caches by provider::model — reset the routing-side config // too so tests don't leak assignments across each other. @@ -34,7 +34,7 @@ test.beforeEach(() => { test.after(() => { resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function putRequest(body: unknown) { diff --git a/tests/unit/token-health-check-cursor.test.ts b/tests/unit/token-health-check-cursor.test.ts index 75eb4066d1..f05933e2bb 100644 --- a/tests/unit/token-health-check-cursor.test.ts +++ b/tests/unit/token-health-check-cursor.test.ts @@ -40,7 +40,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -60,7 +60,7 @@ async function resetStorage() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function getId(connection: { id?: unknown }): string { @@ -172,7 +172,7 @@ async function withCursorEnv(fn: (env: CursorEnv) => Promise): Promise else delete process.env.USERPROFILE; delete process.env.FAKE_CURSOR_AGENT_LOG; delete process.env.FAKE_CURSOR_AGENT_STATUS_MODE; - fs.rmSync(tmpHome, { recursive: true, force: true }); + fs.rmSync(tmpHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }, }; diff --git a/tests/unit/token-health-check-devin-cli-8407.test.ts b/tests/unit/token-health-check-devin-cli-8407.test.ts index 312b61df65..ab3b71ef0d 100644 --- a/tests/unit/token-health-check-devin-cli-8407.test.ts +++ b/tests/unit/token-health-check-devin-cli-8407.test.ts @@ -20,7 +20,7 @@ const { supportsTokenRefresh } = await import("../../open-sse/services/tokenRefr async function resetStorage() { core.resetDbInstance(); if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -32,7 +32,7 @@ function getCreatedConnectionId(connection: { id?: unknown }): string { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("supportsTokenRefresh excludes import-only Devin providers", () => { diff --git a/tests/unit/token-health-check-retry-deactivation.test.ts b/tests/unit/token-health-check-retry-deactivation.test.ts index 2a99b35e65..77f5446946 100644 --- a/tests/unit/token-health-check-retry-deactivation.test.ts +++ b/tests/unit/token-health-check-retry-deactivation.test.ts @@ -39,7 +39,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -115,7 +115,7 @@ async function createRetryTestConnection(overrides: Record = {} test.after(async () => { core.resetDbInstance(); try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore cleanup errors } diff --git a/tests/unit/token-health-check-sweep.test.ts b/tests/unit/token-health-check-sweep.test.ts index afce89cde8..00b0668653 100644 --- a/tests/unit/token-health-check-sweep.test.ts +++ b/tests/unit/token-health-check-sweep.test.ts @@ -43,7 +43,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -60,7 +60,7 @@ async function resetStorage() { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); delete process.env.HEALTHCHECK_STAGGER_MS; delete process.env.HEALTHCHECK_JITTER_MIN_MS; delete process.env.HEALTHCHECK_JITTER_MAX_MS; diff --git a/tests/unit/token-health-check.test.ts b/tests/unit/token-health-check.test.ts index 274be4c126..8605c1e52b 100644 --- a/tests/unit/token-health-check.test.ts +++ b/tests/unit/token-health-check.test.ts @@ -23,7 +23,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -227,7 +227,7 @@ async function withPatchedProvider(providerId, config, fn) { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("extractResolvedProxyConfig unwraps proxy resolution metadata", () => { diff --git a/tests/unit/token-health-no-refresh-token-expired-5326.test.ts b/tests/unit/token-health-no-refresh-token-expired-5326.test.ts index ad880d725f..2b9db5f21a 100644 --- a/tests/unit/token-health-no-refresh-token-expired-5326.test.ts +++ b/tests/unit/token-health-no-refresh-token-expired-5326.test.ts @@ -18,7 +18,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: unknown) { @@ -43,7 +43,7 @@ function getCreatedConnectionId(connection: { id?: unknown }): string { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // Regression for #5326: a refresh-CAPABLE provider (antigravity) with NO refresh diff --git a/tests/unit/token-limits.test.ts b/tests/unit/token-limits.test.ts index aeb802626e..cd7900dc3a 100644 --- a/tests/unit/token-limits.test.ts +++ b/tests/unit/token-limits.test.ts @@ -28,7 +28,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -78,7 +78,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("window rollover: daily/weekly/monthly produce distinct windowStart", async () => { @@ -151,7 +151,14 @@ test("seed-on-miss equals usage_history SUM for the active window", async () => // Different month (excluded). insertUsage("k2", "openai", "gpt-4o", 999, 999, new Date(Date.UTC(2025, 11, 31)).toISOString()); // Different model (excluded). - insertUsage("k2", "openai", "gpt-4o-mini", 777, 777, new Date(Date.UTC(2026, 0, 13)).toISOString()); + insertUsage( + "k2", + "openai", + "gpt-4o-mini", + 777, + 777, + new Date(Date.UTC(2026, 0, 13)).toISOString() + ); const expected = 100 + 50 + 30 + 20; assert.equal(counter.seedWindowUsageFromHistory(limit, NOW_JAN), expected); @@ -194,11 +201,19 @@ test("seed total excludes cache tokens (no double-count) (FIX 2)", async () => { // tokens_input ALREADY INCLUDES cache_read + cache_creation (these columns are a // breakdown, per migration 012). Billable = input + output + reasoning ONLY. - insertUsage("k2c", "anthropic", "claude-sonnet", 500, 200, new Date(Date.UTC(2026, 0, 12)).toISOString(), { - cacheRead: 300, - cacheCreation: 100, - reasoning: 40, - }); + insertUsage( + "k2c", + "anthropic", + "claude-sonnet", + 500, + 200, + new Date(Date.UTC(2026, 0, 12)).toISOString(), + { + cacheRead: 300, + cacheCreation: 100, + reasoning: 40, + } + ); // 500 + 200 + 40 = 740. Must NOT add cacheRead/cacheCreation again (would be 1140). assert.equal(counter.seedWindowUsageFromHistory(limit, NOW_JAN), 740); diff --git a/tests/unit/token-refresh-route-service.test.ts b/tests/unit/token-refresh-route-service.test.ts index 0a71e72c81..89093cf011 100644 --- a/tests/unit/token-refresh-route-service.test.ts +++ b/tests/unit/token-refresh-route-service.test.ts @@ -25,7 +25,7 @@ function jsonResponse(body, status = 200) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -154,7 +154,7 @@ test.beforeEach(async () => { test.after(async () => { delete PROVIDERS["custom-oauth-local-608"]; await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("token refresh wrapper delegates provider-specific refresh helpers and formatter utilities", async () => { diff --git a/tests/unit/tokenHealthCheck-batchSize.test.ts b/tests/unit/tokenHealthCheck-batchSize.test.ts index c6a088b3f3..0a5cb5033b 100644 --- a/tests/unit/tokenHealthCheck-batchSize.test.ts +++ b/tests/unit/tokenHealthCheck-batchSize.test.ts @@ -36,7 +36,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error) { @@ -55,7 +55,7 @@ test.after(() => { core.resetDbInstance(); try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } } catch { /* best effort cleanup */ diff --git a/tests/unit/transform-stream-hwm.test.ts b/tests/unit/transform-stream-hwm.test.ts index 93e94d0378..87229e623a 100644 --- a/tests/unit/transform-stream-hwm.test.ts +++ b/tests/unit/transform-stream-hwm.test.ts @@ -24,7 +24,7 @@ function cleanupDb() { delete process.env.DATA_DIR; } try { - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch {} } diff --git a/tests/unit/tunnel-routes-error-sanitization.test.ts b/tests/unit/tunnel-routes-error-sanitization.test.ts index 2e5036e9ea..2643af5b01 100644 --- a/tests/unit/tunnel-routes-error-sanitization.test.ts +++ b/tests/unit/tunnel-routes-error-sanitization.test.ts @@ -50,7 +50,7 @@ const tailscaleEnableRoute = await import("../../src/app/api/tunnels/tailscale/e test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR; else process.env.DATA_DIR = ORIGINAL_DATA_DIR; }); diff --git a/tests/unit/turbopack-cache-heal-6289.test.ts b/tests/unit/turbopack-cache-heal-6289.test.ts index 0a30882fbe..375f008bba 100644 --- a/tests/unit/turbopack-cache-heal-6289.test.ts +++ b/tests/unit/turbopack-cache-heal-6289.test.ts @@ -66,7 +66,7 @@ test("purgeTurbopackCache removes an existing cache/turbopack dir", () => { assert.equal(removed, true); assert.equal(fs.existsSync(cacheDir), false); - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("purgeTurbopackCache is a no-op (returns false) when the dir is absent", () => { diff --git a/tests/unit/upstream-ca-test-route-3488.test.ts b/tests/unit/upstream-ca-test-route-3488.test.ts index 750345534e..1ff10e94f8 100644 --- a/tests/unit/upstream-ca-test-route-3488.test.ts +++ b/tests/unit/upstream-ca-test-route-3488.test.ts @@ -47,8 +47,8 @@ fs.writeFileSync(validCaPath, TEST_CA_PEM); fs.writeFileSync(nonPemPath, "this is not a certificate"); test.after(() => { - fs.rmSync(dir, { recursive: true, force: true }); - fs.rmSync(DATA_DIR, { recursive: true, force: true }); + fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function postJson(body: unknown): Request { diff --git a/tests/unit/usage-account-analytics-route.test.ts b/tests/unit/usage-account-analytics-route.test.ts index 42108323d8..f05a40342d 100644 --- a/tests/unit/usage-account-analytics-route.test.ts +++ b/tests/unit/usage-account-analytics-route.test.ts @@ -34,14 +34,14 @@ async function readAccounts() { test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); usageHistory.clearPendingRequests(); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("Codex account grouping follows workspace and user identity, not email", async () => { diff --git a/tests/unit/usage-analytics-model-dedup-7535.test.ts b/tests/unit/usage-analytics-model-dedup-7535.test.ts index 5d55c19f4a..460d2d0543 100644 --- a/tests/unit/usage-analytics-model-dedup-7535.test.ts +++ b/tests/unit/usage-analytics-model-dedup-7535.test.ts @@ -24,7 +24,7 @@ function makeRequest(url: string) { test.beforeEach(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); usageHistory.clearPendingRequests(); }); @@ -32,7 +32,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_API_KEY_SECRET === undefined) { delete process.env.API_KEY_SECRET; @@ -48,7 +48,18 @@ test("#7535: byModel must not list the same logical model twice under one raw/on db.prepare( `INSERT INTO usage_history (provider, model, connection_id, api_key_id, api_key_name, tokens_input, tokens_output, success, latency_ms, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` - ).run("zai", "glm-5.2", "test-conn", "test-key", "Primary Key", 100, 50, 1, 200, now.toISOString()); + ).run( + "zai", + "glm-5.2", + "test-conn", + "test-key", + "Primary Key", + 100, + 50, + 1, + 200, + now.toISOString() + ); db.prepare( `INSERT INTO usage_history (provider, model, connection_id, api_key_id, api_key_name, tokens_input, tokens_output, success, latency_ms, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` @@ -78,5 +89,9 @@ test("#7535: byModel must not list the same logical model twice under one raw/on 1, `expected exactly one "glm-5.2" row in byModel, got ${glmEntries.length}: ${JSON.stringify(glmEntries)} (#7535)` ); - assert.equal(glmEntries[0].requests, 2, "the two raw spellings should merge into one aggregated row"); + assert.equal( + glmEntries[0].requests, + 2, + "the two raw spellings should merge into one aggregated row" + ); }); diff --git a/tests/unit/usage-analytics-provider-display-name-7534.test.ts b/tests/unit/usage-analytics-provider-display-name-7534.test.ts index e060f7eb58..9880c86f28 100644 --- a/tests/unit/usage-analytics-provider-display-name-7534.test.ts +++ b/tests/unit/usage-analytics-provider-display-name-7534.test.ts @@ -24,7 +24,7 @@ function makeRequest(url: string) { test.beforeEach(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); usageHistory.clearPendingRequests(); }); @@ -32,7 +32,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_API_KEY_SECRET === undefined) { delete process.env.API_KEY_SECRET; diff --git a/tests/unit/usage-analytics-route.test.ts b/tests/unit/usage-analytics-route.test.ts index 8e57e7e88b..ed897b6733 100644 --- a/tests/unit/usage-analytics-route.test.ts +++ b/tests/unit/usage-analytics-route.test.ts @@ -22,7 +22,7 @@ const EXPECTED_TOTAL_COST = 0.020925; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); clearPendingRequests(); } @@ -76,7 +76,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_API_KEY_SECRET === undefined) { delete process.env.API_KEY_SECRET; diff --git a/tests/unit/usage-analytics.test.ts b/tests/unit/usage-analytics.test.ts index fa6c969649..e0c1d25092 100644 --- a/tests/unit/usage-analytics.test.ts +++ b/tests/unit/usage-analytics.test.ts @@ -24,7 +24,7 @@ const clearPendingRequests = usageHistory.clearPendingRequests; async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); clearPendingRequests(); } @@ -54,7 +54,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("usage history persists entries and supports filtering and usageDb compatibility", async () => { @@ -529,16 +529,20 @@ test("getUsageSummary counts total_requests from daily_usage_summary, not 1-per- // Insert a daily_usage_summary row with total_requests=50, 1000 input, 500 output. // With the old COUNT(*) query this would count as 1 request; with SUM(requests) // it must count as 50. - db.prepare(` + db.prepare( + ` INSERT INTO daily_usage_summary (provider, model, date, total_requests, total_input_tokens, total_output_tokens, total_cost) VALUES ('openai', 'gpt-4', '2024-01-10', 50, 1000, 500, 0.02) - `).run(); + ` + ).run(); // Also insert one raw row so we can verify the UNION merges both legs. - db.prepare(` + db.prepare( + ` INSERT INTO usage_history (timestamp, provider, model, tokens_input, tokens_output, success, latency_ms, service_tier) VALUES ('2024-01-20T10:00:00.000Z', 'openai', 'gpt-4', 100, 50, 1, 200, 'standard') - `).run(); + ` + ).run(); // Build a unified source with rawCutoffDate BETWEEN the two rows so both // legs are exercised: aggregated leg gets the Jan 10 row, raw leg gets the Jan 20 row. @@ -555,11 +559,23 @@ test("getUsageSummary counts total_requests from daily_usage_summary, not 1-per- const summary = getUsageSummary(unifiedSource, unifiedParams); // 50 from daily_usage_summary + 1 from raw usage_history = 51 - assert.equal(summary.totalRequests, 51, "totalRequests must be 50 (aggregated) + 1 (raw), not 1+1"); + assert.equal( + summary.totalRequests, + 51, + "totalRequests must be 50 (aggregated) + 1 (raw), not 1+1" + ); // 1000 from daily_usage_summary + 100 from raw = 1100 assert.equal(summary.promptTokens, 1100, "promptTokens must merge aggregated + raw token sums"); // 500 from daily_usage_summary + 50 from raw = 550 - assert.equal(summary.completionTokens, 550, "completionTokens must merge aggregated + raw token sums"); + assert.equal( + summary.completionTokens, + 550, + "completionTokens must merge aggregated + raw token sums" + ); // All 51 requests are successful (aggregated leg hardcodes success=1, raw has success=1) - assert.equal(summary.successfulRequests, 51, "successfulRequests must count all rolled-up requests as successful"); + assert.equal( + summary.successfulRequests, + 51, + "successfulRequests must count all rolled-up requests as successful" + ); }); diff --git a/tests/unit/usage-cache-health-route.test.ts b/tests/unit/usage-cache-health-route.test.ts index 949183b7a7..250205f3db 100644 --- a/tests/unit/usage-cache-health-route.test.ts +++ b/tests/unit/usage-cache-health-route.test.ts @@ -20,7 +20,7 @@ process.env.DATA_DIR = tmpDir; // the later ones. process.on("exit", () => { try { - fs.rmSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* best effort */ } diff --git a/tests/unit/usage-endpoint-dimension.test.ts b/tests/unit/usage-endpoint-dimension.test.ts index 9712d92407..866b55ec41 100644 --- a/tests/unit/usage-endpoint-dimension.test.ts +++ b/tests/unit/usage-endpoint-dimension.test.ts @@ -20,7 +20,7 @@ const usageAnalytics = await import("../../src/lib/db/usageAnalytics.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); usageHistory.clearPendingRequests(); } @@ -31,7 +31,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("saveRequestUsage persists endpoint and getEndpointUsageRows groups by endpoint", async () => { diff --git a/tests/unit/usage-history-db.test.ts b/tests/unit/usage-history-db.test.ts index 6a3eb1564a..70405a2969 100644 --- a/tests/unit/usage-history-db.test.ts +++ b/tests/unit/usage-history-db.test.ts @@ -14,7 +14,7 @@ const clearPendingRequests = usageHistory.clearPendingRequests; async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); clearPendingRequests(); } @@ -53,7 +53,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ──────────────── getUsageDb ──────────────── diff --git a/tests/unit/usage-history-reset.test.ts b/tests/unit/usage-history-reset.test.ts index 352473365f..01f0d86d4e 100644 --- a/tests/unit/usage-history-reset.test.ts +++ b/tests/unit/usage-history-reset.test.ts @@ -34,7 +34,7 @@ function teardown() { delete process.env.DATA_DIR; } try { - fs.rmSync(tempDir, { recursive: true, force: true }); + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // ignore cleanup errors } @@ -85,28 +85,35 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou function seed() { db.prepare( "INSERT INTO provider_nodes (id, type, name, prefix, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)" - ).run("openai-compatible-chat-test", "chat", "Custom Test", "custom-test", recentIso, recentIso); + ).run( + "openai-compatible-chat-test", + "chat", + "Custom Test", + "custom-test", + recentIso, + recentIso + ); db.prepare("INSERT INTO api_keys (id, name, key, created_at) VALUES (?, ?, ?, ?)").run( "key-test", "Test Key", "sk-test", recentIso ); - db.prepare("INSERT INTO combos (id, name, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?)").run( - "combo-test", - "Test Combo", - "{}", - recentIso, + db.prepare( + "INSERT INTO combos (id, name, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?)" + ).run("combo-test", "Test Combo", "{}", recentIso, recentIso); + + db.prepare("INSERT INTO usage_history (provider, model, timestamp) VALUES (?, ?, ?)").run( + "openai", + "gpt-test", + oldIso + ); + db.prepare("INSERT INTO usage_history (provider, model, timestamp) VALUES (?, ?, ?)").run( + "openai", + "gpt-test", recentIso ); - db.prepare( - "INSERT INTO usage_history (provider, model, timestamp) VALUES (?, ?, ?)" - ).run("openai", "gpt-test", oldIso); - db.prepare( - "INSERT INTO usage_history (provider, model, timestamp) VALUES (?, ?, ?)" - ).run("openai", "gpt-test", recentIso); - db.prepare("INSERT INTO call_logs (id, timestamp, artifact_relpath) VALUES (?, ?, ?)").run( "old-call", oldIso, @@ -126,7 +133,10 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou recentIso ); db.prepare("INSERT INTO proxy_logs (id, timestamp) VALUES (?, ?)").run("old-proxy", oldIso); - db.prepare("INSERT INTO proxy_logs (id, timestamp) VALUES (?, ?)").run("recent-proxy", recentIso); + db.prepare("INSERT INTO proxy_logs (id, timestamp) VALUES (?, ?)").run( + "recent-proxy", + recentIso + ); db.prepare( "INSERT INTO compression_analytics (timestamp, mode, original_tokens, compressed_tokens, tokens_saved) VALUES (?, ?, ?, ?, ?)" ).run(oldIso, "lite", 100, 50, 50); @@ -134,12 +144,16 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou "INSERT INTO compression_analytics (timestamp, mode, original_tokens, compressed_tokens, tokens_saved) VALUES (?, ?, ?, ?, ?)" ).run(recentIso, "lite", 100, 50, 50); - db.prepare( - "INSERT INTO daily_usage_summary (provider, model, date) VALUES (?, ?, ?)" - ).run("openai", "gpt-test", oldDate); - db.prepare( - "INSERT INTO daily_usage_summary (provider, model, date) VALUES (?, ?, ?)" - ).run("openai", "gpt-test", recentDate); + db.prepare("INSERT INTO daily_usage_summary (provider, model, date) VALUES (?, ?, ?)").run( + "openai", + "gpt-test", + oldDate + ); + db.prepare("INSERT INTO daily_usage_summary (provider, model, date) VALUES (?, ?, ?)").run( + "openai", + "gpt-test", + recentDate + ); db.prepare( "INSERT INTO hourly_usage_summary (provider, model, date_hour) VALUES (?, ?, ?)" @@ -179,7 +193,11 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou const periodResult = await resetUsageHistory("1d"); assert.equal(periodResult.errors, 0, "period reset should not report errors"); - assert.equal(periodResult.deletedUsageHistory, 1, "should delete only the old usage_history row"); + assert.equal( + periodResult.deletedUsageHistory, + 1, + "should delete only the old usage_history row" + ); assert.equal(periodResult.deletedCallLogs, 1, "should delete only the old call_logs row"); assert.equal( periodResult.deletedRequestDetailLogs, @@ -203,9 +221,21 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou "should delete only the old hourly_usage_summary row" ); assert.equal(periodResult.deleted, 7, "total deleted should sum the reset tables"); - assert.equal(periodResult.deletedCallLogArtifacts, 1, "period reset should delete only old call artifact"); - assert.equal(fs.existsSync(oldArtifactPath), false, "period reset should delete old call artifact"); - assert.equal(fs.existsSync(recentArtifactPath), true, "period reset should preserve recent call artifact"); + assert.equal( + periodResult.deletedCallLogArtifacts, + 1, + "period reset should delete only old call artifact" + ); + assert.equal( + fs.existsSync(oldArtifactPath), + false, + "period reset should delete old call artifact" + ); + assert.equal( + fs.existsSync(recentArtifactPath), + true, + "period reset should preserve recent call artifact" + ); assert.equal(countRows(db, "provider_nodes"), 1, "provider config should survive reset"); assert.equal(countRows(db, "api_keys"), 1, "API keys should survive reset"); @@ -235,9 +265,9 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou "recent hourly_usage_summary row should survive" ); - const survivingTimestamp = db - .prepare("SELECT timestamp FROM usage_history") - .get() as { timestamp: string }; + const survivingTimestamp = db.prepare("SELECT timestamp FROM usage_history").get() as { + timestamp: string; + }; assert.equal( survivingTimestamp.timestamp, recentIso, @@ -248,7 +278,11 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou const allResult = await resetUsageHistory("all"); assert.equal(allResult.errors, 0, "'all' reset should not report errors"); - assert.equal(allResult.deletedUsageHistory, 1, "'all' should delete the remaining usage_history row"); + assert.equal( + allResult.deletedUsageHistory, + 1, + "'all' should delete the remaining usage_history row" + ); assert.equal(allResult.deletedCallLogs, 1, "'all' should delete the remaining call_logs row"); assert.equal( allResult.deletedRequestDetailLogs, @@ -271,16 +305,32 @@ test("resetUsageHistory: 'all' wipes usage_history, daily_usage_summary, and hou 1, "'all' should delete the remaining hourly_usage_summary row" ); - assert.equal(allResult.deletedCallLogArtifacts, 1, "'all' should delete remaining call artifact"); - assert.equal(fs.existsSync(recentArtifactPath), false, "'all' should delete recent call artifact"); + assert.equal( + allResult.deletedCallLogArtifacts, + 1, + "'all' should delete remaining call artifact" + ); + assert.equal( + fs.existsSync(recentArtifactPath), + false, + "'all' should delete recent call artifact" + ); assert.equal(countRows(db, "usage_history"), 0, "'all' should empty usage_history"); assert.equal(countRows(db, "call_logs"), 0, "'all' should empty call_logs"); assert.equal(countRows(db, "request_detail_logs"), 0, "'all' should empty request_detail_logs"); assert.equal(countRows(db, "proxy_logs"), 0, "'all' should empty proxy_logs"); - assert.equal(countRows(db, "compression_analytics"), 0, "'all' should empty compression_analytics"); + assert.equal( + countRows(db, "compression_analytics"), + 0, + "'all' should empty compression_analytics" + ); assert.equal(countRows(db, "daily_usage_summary"), 0, "'all' should empty daily_usage_summary"); - assert.equal(countRows(db, "hourly_usage_summary"), 0, "'all' should empty hourly_usage_summary"); + assert.equal( + countRows(db, "hourly_usage_summary"), + 0, + "'all' should empty hourly_usage_summary" + ); assert.equal(countRows(db, "provider_nodes"), 1, "provider config should still survive 'all'"); assert.equal(countRows(db, "api_keys"), 1, "API keys should still survive 'all'"); assert.equal(countRows(db, "combos"), 1, "combos should still survive 'all'"); diff --git a/tests/unit/usage-migrations-legacy-archive-safety.test.ts b/tests/unit/usage-migrations-legacy-archive-safety.test.ts index 8e5eeb7465..1fc440ca77 100644 --- a/tests/unit/usage-migrations-legacy-archive-safety.test.ts +++ b/tests/unit/usage-migrations-legacy-archive-safety.test.ts @@ -59,7 +59,7 @@ test.after(() => { if (ORIGINAL_NEXT_PHASE === undefined) delete process.env.NEXT_PHASE; else process.env.NEXT_PHASE = ORIGINAL_NEXT_PHASE; - fs.rmSync(TEST_HOME_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_HOME_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6799: archiveLegacyRequestLogs() must not delete the live app-logger directory (DATA_DIR/logs/application)", async () => { diff --git a/tests/unit/usage-migrations.test.ts b/tests/unit/usage-migrations.test.ts index 0ac0e55fcf..c58b91147f 100644 --- a/tests/unit/usage-migrations.test.ts +++ b/tests/unit/usage-migrations.test.ts @@ -38,7 +38,7 @@ function writeJson(filePath, value) { function removePath(targetPath) { if (!targetPath) return; - fs.rmSync(targetPath, { recursive: true, force: true }); + fs.rmSync(targetPath, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } function resetDbTables() { diff --git a/tests/unit/usage-utilization-connection-meta.test.ts b/tests/unit/usage-utilization-connection-meta.test.ts index 6885d519f7..5c77221031 100644 --- a/tests/unit/usage-utilization-connection-meta.test.ts +++ b/tests/unit/usage-utilization-connection-meta.test.ts @@ -22,7 +22,7 @@ const { GET } = await import("../../src/app/api/usage/utilization/route.ts"); test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("utilization route does not import phantom @/lib/db/connections", () => { diff --git a/tests/unit/usage-vertex-split.test.ts b/tests/unit/usage-vertex-split.test.ts index 63f6e665f7..2f994ca47f 100644 --- a/tests/unit/usage-vertex-split.test.ts +++ b/tests/unit/usage-vertex-split.test.ts @@ -40,7 +40,7 @@ describe("vertex leaf self-tracked spend", () => { after(() => { core.resetDbInstance(); try { - fs.rmSync(TMP, { recursive: true, force: true }); + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } diff --git a/tests/unit/usage-xai-split.test.ts b/tests/unit/usage-xai-split.test.ts index 00bf99db03..ff65d658e5 100644 --- a/tests/unit/usage-xai-split.test.ts +++ b/tests/unit/usage-xai-split.test.ts @@ -39,7 +39,7 @@ describe("xai leaf self-tracked usage", () => { after(() => { core.resetDbInstance(); try { - fs.rmSync(TMP, { recursive: true, force: true }); + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } diff --git a/tests/unit/usage-xiaomi-mimo-split.test.ts b/tests/unit/usage-xiaomi-mimo-split.test.ts index 9a2f9fe91f..7a2253ae3b 100644 --- a/tests/unit/usage-xiaomi-mimo-split.test.ts +++ b/tests/unit/usage-xiaomi-mimo-split.test.ts @@ -40,7 +40,7 @@ describe("xiaomi-mimo leaf self-tracked quota", () => { after(() => { core.resetDbInstance(); try { - fs.rmSync(TMP, { recursive: true, force: true }); + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } diff --git a/tests/unit/usage/usageHistoryDedup.test.ts b/tests/unit/usage/usageHistoryDedup.test.ts index 3e8588434a..bdf2a37c43 100644 --- a/tests/unit/usage/usageHistoryDedup.test.ts +++ b/tests/unit/usage/usageHistoryDedup.test.ts @@ -27,7 +27,7 @@ const { saveRequestUsage } = await import("../../../src/lib/usage/usageHistory.t // Cleanup: close DB handle and temp directory so the test runner doesn't hang. test.after(() => { resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── helpers ────────────────────────────────────────────────────────────────── diff --git a/tests/unit/v1-chat-completions-content-type-6414.test.ts b/tests/unit/v1-chat-completions-content-type-6414.test.ts index 8212b992b4..a527d6d7e9 100644 --- a/tests/unit/v1-chat-completions-content-type-6414.test.ts +++ b/tests/unit/v1-chat-completions-content-type-6414.test.ts @@ -72,7 +72,7 @@ test("#6414 accepts application/json with charset parameter", async () => { test.after(() => { try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { /* Windows tempdir cleanup is best-effort */ } diff --git a/tests/unit/v1-models-auth-leak-9320.test.ts b/tests/unit/v1-models-auth-leak-9320.test.ts index 9dc9b17a36..0eb5875253 100644 --- a/tests/unit/v1-models-auth-leak-9320.test.ts +++ b/tests/unit/v1-models-auth-leak-9320.test.ts @@ -15,9 +15,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-9320-models-auth-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-9320-models-auth-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-secret-9320"; @@ -29,7 +27,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); try { v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); @@ -45,7 +43,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#9320 FIXED: anonymous GET /v1/models returns 401 when auth is configured", async () => { @@ -61,11 +59,7 @@ test("#9320 FIXED: anonymous GET /v1/models returns 401 when auth is configured" ); // After fix: anonymous requests must be rejected with 401 when auth is configured - assert.equal( - res.status, - 401, - `expected 401 for anonymous request, got ${res.status}` - ); + assert.equal(res.status, 401, `expected 401 for anonymous request, got ${res.status}`); const body = await res.json(); assert.ok(body.error, "response must carry an error object"); }); @@ -95,8 +89,6 @@ test("#9320: authenticated request (valid API key) returns 200 with models", asy // With a valid API key, the catalog should be accessible if (res.status !== 200) { // If the fix is in place, this should return 200 - console.log( - `[INFO] Authenticated request returned status ${res.status}` - ); + console.log(`[INFO] Authenticated request returned status ${res.status}`); } }); diff --git a/tests/unit/v1-models-catalog-generation-race.test.ts b/tests/unit/v1-models-catalog-generation-race.test.ts index 1c1e519164..da81bcc907 100644 --- a/tests/unit/v1-models-catalog-generation-race.test.ts +++ b/tests/unit/v1-models-catalog-generation-race.test.ts @@ -63,7 +63,7 @@ function deferredBuilder(body: string) { test.beforeEach(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); catalogCache.__resetCatalogBuilderRunsForTest(); }); @@ -71,7 +71,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("a build that started before invalidation is not joined and does not repopulate the cache", async () => { diff --git a/tests/unit/v1-models-catalog-ttl.test.ts b/tests/unit/v1-models-catalog-ttl.test.ts index 84369ac33a..279e824f17 100644 --- a/tests/unit/v1-models-catalog-ttl.test.ts +++ b/tests/unit/v1-models-catalog-ttl.test.ts @@ -42,7 +42,7 @@ const GAP_MS = 10_000; test.beforeEach(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); }); @@ -50,7 +50,7 @@ test.beforeEach(() => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("the settings default and the constant agree on the catalog TTL", async () => { diff --git a/tests/unit/v1-models-concurrent-6408.test.ts b/tests/unit/v1-models-concurrent-6408.test.ts index 4aa543e504..d1c0b8fd9d 100644 --- a/tests/unit/v1-models-concurrent-6408.test.ts +++ b/tests/unit/v1-models-concurrent-6408.test.ts @@ -29,7 +29,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -41,7 +41,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#6408 — 10 concurrent identical GET /v1/models calls collapse to ONE builder run", async () => { diff --git a/tests/unit/v1-models-discovery-conformance.test.ts b/tests/unit/v1-models-discovery-conformance.test.ts index 549fc28ffa..bd6e0cea53 100644 --- a/tests/unit/v1-models-discovery-conformance.test.ts +++ b/tests/unit/v1-models-discovery-conformance.test.ts @@ -31,7 +31,7 @@ const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); v1ModelsCatalog.__resetCatalogBuilderRunsForTest(); } @@ -43,7 +43,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("1. GET /v1/models never returns a 3xx redirect status (regression guard)", async () => { diff --git a/tests/unit/v1-ws-route.test.ts b/tests/unit/v1-ws-route.test.ts index e4e75ae34b..55e68c165d 100644 --- a/tests/unit/v1-ws-route.test.ts +++ b/tests/unit/v1-ws-route.test.ts @@ -19,7 +19,7 @@ const wsRoute = await import("../../src/app/api/v1/ws/route.ts"); function resetStorage() { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ test.beforeEach(async () => { test.after(() => { apiKeysDb.resetApiKeyState(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/v1beta-models-route.test.ts b/tests/unit/v1beta-models-route.test.ts index 1f66e7ae24..04cc86d9db 100644 --- a/tests/unit/v1beta-models-route.test.ts +++ b/tests/unit/v1beta-models-route.test.ts @@ -24,7 +24,7 @@ async function addActiveConnection(provider: string) { async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -34,7 +34,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("v1beta models route deduplicates custom models against built-in and synced entries", async () => { diff --git a/tests/unit/veoaifree-video-route.test.ts b/tests/unit/veoaifree-video-route.test.ts index e8dd11f68b..4c0b0fe92a 100644 --- a/tests/unit/veoaifree-video-route.test.ts +++ b/tests/unit/veoaifree-video-route.test.ts @@ -52,7 +52,7 @@ test.after(() => { globalThis.fetch = originalFetch; globalThis.setTimeout = originalSetTimeout; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("video route returns 200 with normalized b64_json for Veo AI Free", async () => { diff --git a/tests/unit/vercel-gateway-models-fetch-4249.test.ts b/tests/unit/vercel-gateway-models-fetch-4249.test.ts index 54fc16a03a..54c1cea52c 100644 --- a/tests/unit/vercel-gateway-models-fetch-4249.test.ts +++ b/tests/unit/vercel-gateway-models-fetch-4249.test.ts @@ -33,13 +33,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { @@ -66,11 +66,7 @@ test("#4249 Vercel AI Gateway import fetches the live /v1/models catalog", async fetched = true; return Response.json({ object: "list", - data: [ - { id: "xai/grok-4" }, - { id: "openai/gpt-5.1" }, - { id: "anthropic/claude-opus-4.5" }, - ], + data: [{ id: "xai/grok-4" }, { id: "openai/gpt-5.1" }, { id: "anthropic/claude-opus-4.5" }], }); } // Bogus probe variants (…/v1/v1/models, …/chat/completions/models) → 404 diff --git a/tests/unit/verified-connection-activation-11446.test.ts b/tests/unit/verified-connection-activation-11446.test.ts index 6564a3094a..dd91dd2e6d 100644 --- a/tests/unit/verified-connection-activation-11446.test.ts +++ b/tests/unit/verified-connection-activation-11446.test.ts @@ -105,7 +105,7 @@ async function createConnection( test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#11446: POST /api/providers creates a new connection inactive until verified", async () => { diff --git a/tests/unit/version-manager.test.ts b/tests/unit/version-manager.test.ts index 6aea04adc3..5279d41597 100644 --- a/tests/unit/version-manager.test.ts +++ b/tests/unit/version-manager.test.ts @@ -35,7 +35,7 @@ async function resetStorage() { for (let attempt = 0; attempt < 10; attempt++) { try { if (fs.existsSync(TEST_DATA_DIR)) { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } break; } catch (error: any) { @@ -260,7 +260,7 @@ test.afterEach(() => { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("processManager reuses an alive persisted pid without spawning a new process", async () => { diff --git a/tests/unit/vertex-passthrough-model-lockout.test.ts b/tests/unit/vertex-passthrough-model-lockout.test.ts index 68bb5fa7b2..9a35d860ef 100644 --- a/tests/unit/vertex-passthrough-model-lockout.test.ts +++ b/tests/unit/vertex-passthrough-model-lockout.test.ts @@ -19,7 +19,7 @@ const accountFallback = await import("../../open-sse/services/accountFallback.ts async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -35,7 +35,7 @@ async function seedVertex() { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test('hasPerModelQuota("vertex", ...) is true after the passthroughModels registry flag', () => { diff --git a/tests/unit/vertex-spend-usage.test.ts b/tests/unit/vertex-spend-usage.test.ts index 4a9bb5e13b..fa3d921721 100644 --- a/tests/unit/vertex-spend-usage.test.ts +++ b/tests/unit/vertex-spend-usage.test.ts @@ -1,105 +1,105 @@ -/** - * tests/unit/vertex-spend-usage.test.ts - * - * Vertex AI exposes no native usage/quota API for an API key or Service Account, so OmniRoute - * SELF-TRACKS spend: it sums the tokens it routed to the connection (usage_history) and prices - * them via the backend pricing table, surfacing a "$X used since this account was added" figure. - * These tests cover the aggregation helper + the fetcher response shape with a real temp DB. - */ - -import { describe, it, before, after } from "node:test"; -import assert from "node:assert/strict"; -import os from "node:os"; -import path from "node:path"; -import fs from "node:fs"; - -// DATA_DIR must be set before any module that opens the DB is imported. -const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "omni-vertex-")); -process.env.DATA_DIR = TMP; - -const core = await import("../../src/lib/db/core.ts"); -const { getConnectionSpendUsdSinceAdded } = await import("../../src/lib/usage/usageStats.ts"); -const { __testing } = await import("../../open-sse/services/usage.ts"); -const { getVertexUsage } = __testing; - -function insertUsage( - connectionId: string, - provider: string, - model: string, - tokensIn: number, - tokensOut: number, - success = 1 -) { - const db = core.getDbInstance(); - db.prepare( - `INSERT INTO usage_history (provider, model, connection_id, tokens_input, tokens_output, success, timestamp) - VALUES (?, ?, ?, ?, ?, ?, ?)` - ).run(provider, model, connectionId, tokensIn, tokensOut, success, new Date().toISOString()); -} - -describe("vertex self-tracked spend", () => { - before(() => { - core.getDbInstance(); // trigger migrations - // conn-v: two SUCCESSFUL priced requests across two models. - insertUsage("conn-v", "vertex", "gemini-2.5-flash", 1_000_000, 500_000, 1); - insertUsage("conn-v", "vertex", "gemini-3-pro-image-preview", 200_000, 100_000, 1); - // a FAILED request on the same connection must NOT count toward spend. - insertUsage("conn-v", "vertex", "gemini-2.5-flash", 5_000_000, 5_000_000, 0); - // a row with a different provider on the same connection id must NOT bleed in. - insertUsage("conn-v", "vertex-partner", "claude-opus-4-7", 9_000_000, 9_000_000, 1); - // a different connection must not bleed in - insertUsage("conn-other", "vertex", "gemini-2.5-flash", 9_000_000, 9_000_000, 1); - }); - - after(() => { - core.resetDbInstance(); - try { - fs.rmSync(TMP, { recursive: true, force: true }); - } catch { - // best-effort temp cleanup - } - }); - - it("counts only the connection's successful, same-provider requests", async () => { - const { costUsd, requests } = await getConnectionSpendUsdSinceAdded("vertex", "conn-v"); - assert.equal( - requests, - 2, - "only the two successful vertex rows count (failed + vertex-partner + other-conn excluded)" - ); - assert.ok(Number.isFinite(costUsd) && costUsd >= 0, "cost is a finite, non-negative number"); - }); - - it("returns 0/0 for an unknown connection (no bleed)", async () => { - const { costUsd, requests } = await getConnectionSpendUsdSinceAdded("vertex", "conn-none"); - assert.equal(requests, 0); - assert.equal(costUsd, 0); - }); - - it("getVertexUsage returns a spend quota + $ message for a used connection", async () => { - const r = (await getVertexUsage("conn-v", "vertex")) as { - plan?: string; - message?: string; - quotas?: Record; - }; - assert.ok(r.quotas?.spend, "spend quota present (so the limits cache persists it)"); - assert.equal(r.quotas!.spend.quotaSource, "localUsageHistory"); - assert.ok(typeof r.quotas!.spend.used === "number" && r.quotas!.spend.used >= 0); - assert.ok(r.message && r.message.includes("$"), "message carries the dollar figure"); - assert.ok(r.message!.includes("2 requests"), "message reports the request count"); - }); - - it("getVertexUsage reports no-usage cleanly when nothing was routed", async () => { - const r = (await getVertexUsage("conn-empty", "vertex")) as { - message?: string; - quotas?: Record; - }; - assert.ok(r.message && /no usage/i.test(r.message), "informative no-usage message"); - assert.equal(r.quotas?.spend.used, 0); - }); - - it("getVertexUsage returns a message when connection id is missing", async () => { - const r = (await getVertexUsage("", "vertex")) as { message?: string; quotas?: unknown }; - assert.ok(r.message && !r.quotas, "no spend quota without a connection id"); - }); -}); +/** + * tests/unit/vertex-spend-usage.test.ts + * + * Vertex AI exposes no native usage/quota API for an API key or Service Account, so OmniRoute + * SELF-TRACKS spend: it sums the tokens it routed to the connection (usage_history) and prices + * them via the backend pricing table, surfacing a "$X used since this account was added" figure. + * These tests cover the aggregation helper + the fetcher response shape with a real temp DB. + */ + +import { describe, it, before, after } from "node:test"; +import assert from "node:assert/strict"; +import os from "node:os"; +import path from "node:path"; +import fs from "node:fs"; + +// DATA_DIR must be set before any module that opens the DB is imported. +const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "omni-vertex-")); +process.env.DATA_DIR = TMP; + +const core = await import("../../src/lib/db/core.ts"); +const { getConnectionSpendUsdSinceAdded } = await import("../../src/lib/usage/usageStats.ts"); +const { __testing } = await import("../../open-sse/services/usage.ts"); +const { getVertexUsage } = __testing; + +function insertUsage( + connectionId: string, + provider: string, + model: string, + tokensIn: number, + tokensOut: number, + success = 1 +) { + const db = core.getDbInstance(); + db.prepare( + `INSERT INTO usage_history (provider, model, connection_id, tokens_input, tokens_output, success, timestamp) + VALUES (?, ?, ?, ?, ?, ?, ?)` + ).run(provider, model, connectionId, tokensIn, tokensOut, success, new Date().toISOString()); +} + +describe("vertex self-tracked spend", () => { + before(() => { + core.getDbInstance(); // trigger migrations + // conn-v: two SUCCESSFUL priced requests across two models. + insertUsage("conn-v", "vertex", "gemini-2.5-flash", 1_000_000, 500_000, 1); + insertUsage("conn-v", "vertex", "gemini-3-pro-image-preview", 200_000, 100_000, 1); + // a FAILED request on the same connection must NOT count toward spend. + insertUsage("conn-v", "vertex", "gemini-2.5-flash", 5_000_000, 5_000_000, 0); + // a row with a different provider on the same connection id must NOT bleed in. + insertUsage("conn-v", "vertex-partner", "claude-opus-4-7", 9_000_000, 9_000_000, 1); + // a different connection must not bleed in + insertUsage("conn-other", "vertex", "gemini-2.5-flash", 9_000_000, 9_000_000, 1); + }); + + after(() => { + core.resetDbInstance(); + try { + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + } catch { + // best-effort temp cleanup + } + }); + + it("counts only the connection's successful, same-provider requests", async () => { + const { costUsd, requests } = await getConnectionSpendUsdSinceAdded("vertex", "conn-v"); + assert.equal( + requests, + 2, + "only the two successful vertex rows count (failed + vertex-partner + other-conn excluded)" + ); + assert.ok(Number.isFinite(costUsd) && costUsd >= 0, "cost is a finite, non-negative number"); + }); + + it("returns 0/0 for an unknown connection (no bleed)", async () => { + const { costUsd, requests } = await getConnectionSpendUsdSinceAdded("vertex", "conn-none"); + assert.equal(requests, 0); + assert.equal(costUsd, 0); + }); + + it("getVertexUsage returns a spend quota + $ message for a used connection", async () => { + const r = (await getVertexUsage("conn-v", "vertex")) as { + plan?: string; + message?: string; + quotas?: Record; + }; + assert.ok(r.quotas?.spend, "spend quota present (so the limits cache persists it)"); + assert.equal(r.quotas!.spend.quotaSource, "localUsageHistory"); + assert.ok(typeof r.quotas!.spend.used === "number" && r.quotas!.spend.used >= 0); + assert.ok(r.message && r.message.includes("$"), "message carries the dollar figure"); + assert.ok(r.message!.includes("2 requests"), "message reports the request count"); + }); + + it("getVertexUsage reports no-usage cleanly when nothing was routed", async () => { + const r = (await getVertexUsage("conn-empty", "vertex")) as { + message?: string; + quotas?: Record; + }; + assert.ok(r.message && /no usage/i.test(r.message), "informative no-usage message"); + assert.equal(r.quotas?.spend.used, 0); + }); + + it("getVertexUsage returns a message when connection id is missing", async () => { + const r = (await getVertexUsage("", "vertex")) as { message?: string; quotas?: unknown }; + assert.ok(r.message && !r.quotas, "no spend quota without a connection id"); + }); +}); diff --git a/tests/unit/video-combo-route.test.ts b/tests/unit/video-combo-route.test.ts index 5f9561382d..d66bb37eb2 100644 --- a/tests/unit/video-combo-route.test.ts +++ b/tests/unit/video-combo-route.test.ts @@ -57,7 +57,7 @@ test.afterEach(() => { test.after(() => { core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("video route diverts a combo name to the combo executor and honors the ComfyUI local-override base URL", async () => { @@ -162,10 +162,7 @@ test("video route resolves a custom video model reached through combo dispatch", assert.equal(payload.data[0].url, "https://combo-custom.example.com/generated.mp4"); assert.ok(captured, "fetch should have been called for the resolved custom model"); - assert.equal( - captured!.url, - "https://combo-custom.example.com/v1/videos/generations" - ); + assert.equal(captured!.url, "https://combo-custom.example.com/v1/videos/generations"); assert.equal(captured!.headers.Authorization, "Bearer combo-custom-key"); // The upstream call strips the provider prefix — resolvedProvider flowed // through the combo path the same way it does on the direct route. diff --git a/tests/unit/video-custom-provider-route.test.ts b/tests/unit/video-custom-provider-route.test.ts index 749bef97d8..9c10d6f2cb 100644 --- a/tests/unit/video-custom-provider-route.test.ts +++ b/tests/unit/video-custom-provider-route.test.ts @@ -43,7 +43,7 @@ test.afterEach(() => { test.after(() => { core.closeDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("video route uses OpenAI-compatible handler for custom provider with videos endpoint", async () => { diff --git a/tests/unit/virtual-auto-combo.test.ts b/tests/unit/virtual-auto-combo.test.ts index 8d32b0bbbe..02a90f242a 100644 --- a/tests/unit/virtual-auto-combo.test.ts +++ b/tests/unit/virtual-auto-combo.test.ts @@ -17,7 +17,7 @@ type VirtualComboResult = Awaited { test.after(async () => { await resetStorage(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_DATA_DIR === undefined) { delete process.env.DATA_DIR; diff --git a/tests/unit/volcengine-plan-connect-validation.test.ts b/tests/unit/volcengine-plan-connect-validation.test.ts index 239576f03c..7e1e153083 100644 --- a/tests/unit/volcengine-plan-connect-validation.test.ts +++ b/tests/unit/volcengine-plan-connect-validation.test.ts @@ -30,16 +30,14 @@ process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-volc-connect-secret"; const core = await import("../../src/lib/db/core.ts"); -const codeRoute = await import( - "../../src/app/api/providers/volcengine-plan/connect/[sessionId]/code/route.ts" -); -const identityRoute = await import( - "../../src/app/api/providers/volcengine-plan/connect/[sessionId]/identity/route.ts" -); +const codeRoute = + await import("../../src/app/api/providers/volcengine-plan/connect/[sessionId]/code/route.ts"); +const identityRoute = + await import("../../src/app/api/providers/volcengine-plan/connect/[sessionId]/identity/route.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function post(body: unknown): Request { diff --git a/tests/unit/vscode-responses-models.test.ts b/tests/unit/vscode-responses-models.test.ts index 71cce125cd..336e664a65 100644 --- a/tests/unit/vscode-responses-models.test.ts +++ b/tests/unit/vscode-responses-models.test.ts @@ -28,7 +28,7 @@ type MetadataModel = { async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -39,7 +39,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("vscode model metadata routes keep Responses text-generation models", async () => { @@ -86,9 +86,7 @@ test("vscode model metadata routes keep Responses text-generation models", async ]); const rawBody = (await rawResponse.json()) as { data?: MetadataModel[] }; const groupedBody = (await groupedResponse.json()) as { data?: MetadataModel[] }; - const rawModel = (rawBody.data || []).find( - (entry) => entry.id === "cx/future-codex-responses" - ); + const rawModel = (rawBody.data || []).find((entry) => entry.id === "cx/future-codex-responses"); const groupedModel = (groupedBody.data || []).find( (entry) => entry.root === "future-codex-responses" ); diff --git a/tests/unit/vscode-token-routes-gpt56.test.ts b/tests/unit/vscode-token-routes-gpt56.test.ts index c68a85a6b7..7589634824 100644 --- a/tests/unit/vscode-token-routes-gpt56.test.ts +++ b/tests/unit/vscode-token-routes-gpt56.test.ts @@ -25,7 +25,7 @@ interface RawModel { async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -36,7 +36,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("vscode models route preserves gateway-owned Ollama Cloud effort tiers", async () => { diff --git a/tests/unit/vscode-token-routes-responses-listing.test.ts b/tests/unit/vscode-token-routes-responses-listing.test.ts index db08e1f77a..647f4fd00e 100644 --- a/tests/unit/vscode-token-routes-responses-listing.test.ts +++ b/tests/unit/vscode-token-routes-responses-listing.test.ts @@ -13,9 +13,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const TEST_DATA_DIR = fs.mkdtempSync( - path.join(os.tmpdir(), "omniroute-vscode-responses-listing-") -); +const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-vscode-responses-listing-")); process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "vscode-responses-listing-secret"; @@ -35,7 +33,7 @@ const vscodeRawShowRoute = async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -46,7 +44,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("vscode Ollama-compatible tags/show routes (token + raw) expose Codex-discovered responses-format GPT models", async () => { diff --git a/tests/unit/vscode-token-routes.test.ts b/tests/unit/vscode-token-routes.test.ts index d66118b3f2..c98fc73e2b 100644 --- a/tests/unit/vscode-token-routes.test.ts +++ b/tests/unit/vscode-token-routes.test.ts @@ -39,7 +39,7 @@ const combosDb = await import("../../src/lib/db/combos.ts"); async function resetStorage() { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -63,7 +63,7 @@ test.beforeEach(async () => { test.after(async () => { core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("vscode tokenized root route mirrors the grouped VS Code catalog without combos", async () => { diff --git a/tests/unit/warmupScheduler.test.ts b/tests/unit/warmupScheduler.test.ts index 7b77d00a85..94889de236 100644 --- a/tests/unit/warmupScheduler.test.ts +++ b/tests/unit/warmupScheduler.test.ts @@ -26,7 +26,7 @@ const providersDb = await import("../../src/lib/db/providers.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -77,7 +77,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("startWarmupScheduler: disabled → null (default)", async () => { diff --git a/tests/unit/web-fetch-dispatch.test.ts b/tests/unit/web-fetch-dispatch.test.ts index 004435305e..82fc741263 100644 --- a/tests/unit/web-fetch-dispatch.test.ts +++ b/tests/unit/web-fetch-dispatch.test.ts @@ -17,9 +17,8 @@ const { skillRegistry } = await import("../../src/lib/skills/registry.ts"); const { skillExecutor } = await import("../../src/lib/skills/executor.ts"); const { handleToolCallExecution } = await import("../../src/lib/skills/interception.ts"); const { builtinSkills } = await import("../../src/lib/skills/builtins.ts"); -const { OMNIROUTE_WEB_FETCH_FALLBACK_TOOL_NAME } = await import( - "../../open-sse/services/webFetchInterception.ts" -); +const { OMNIROUTE_WEB_FETCH_FALLBACK_TOOL_NAME } = + await import("../../open-sse/services/webFetchInterception.ts"); const originalWebFetchHandler = builtinSkills.web_fetch; @@ -33,7 +32,7 @@ function resetRuntime() { test.beforeEach(() => { resetRuntime(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); @@ -41,7 +40,7 @@ test.after(() => { builtinSkills.web_fetch = originalWebFetchHandler; resetRuntime(); coreDb.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); const contextWithFetchBuiltin = { diff --git a/tests/unit/web-fetch-quota-fallback.test.ts b/tests/unit/web-fetch-quota-fallback.test.ts index 4c7a77f595..ef63053061 100644 --- a/tests/unit/web-fetch-quota-fallback.test.ts +++ b/tests/unit/web-fetch-quota-fallback.test.ts @@ -13,7 +13,7 @@ const webFetchRoute = await import("../../src/app/api/v1/web/fetch/route.ts"); async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -64,7 +64,7 @@ test.beforeEach(async () => { test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); // ── (a) credential-time: rate-limited stub is skipped, not short-circuited ── @@ -80,10 +80,10 @@ test("auto-select skips a rate-limited firecrawl and falls to jina-reader", asyn throw new Error("firecrawl should never be called once rate-limited"); } if (u.includes("r.jina.ai")) { - return new Response( - JSON.stringify({ data: { content: "jina content", links: [] } }), - { status: 200, headers: { "content-type": "application/json" } } - ); + return new Response(JSON.stringify({ data: { content: "jina content", links: [] } }), { + status: 200, + headers: { "content-type": "application/json" }, + }); } throw new Error(`unexpected fetch to ${u}`); }; @@ -116,10 +116,10 @@ test("auto-select falls through to jina-reader when firecrawl returns 429 at req }); } if (u.includes("r.jina.ai")) { - return new Response( - JSON.stringify({ data: { content: "jina content", links: [] } }), - { status: 200, headers: { "content-type": "application/json" } } - ); + return new Response(JSON.stringify({ data: { content: "jina content", links: [] } }), { + status: 200, + headers: { "content-type": "application/json" }, + }); } throw new Error(`unexpected fetch to ${u}`); }; @@ -151,10 +151,10 @@ test("auto-select falls through to jina-reader when firecrawl returns 403 (quota }); } if (u.includes("r.jina.ai")) { - return new Response( - JSON.stringify({ data: { content: "jina content", links: [] } }), - { status: 200, headers: { "content-type": "application/json" } } - ); + return new Response(JSON.stringify({ data: { content: "jina content", links: [] } }), { + status: 200, + headers: { "content-type": "application/json" }, + }); } throw new Error(`unexpected fetch to ${u}`); }; @@ -186,10 +186,10 @@ test("auto-select does NOT fall through when firecrawl returns a plain 400 bad r } if (u.includes("r.jina.ai")) { jinaWasCalled = true; - return new Response( - JSON.stringify({ data: { content: "jina content", links: [] } }), - { status: 200, headers: { "content-type": "application/json" } } - ); + return new Response(JSON.stringify({ data: { content: "jina content", links: [] } }), { + status: 200, + headers: { "content-type": "application/json" }, + }); } throw new Error(`unexpected fetch to ${u}`); }; diff --git a/tests/unit/webdav-server-3485.test.ts b/tests/unit/webdav-server-3485.test.ts index 04f0be1c34..f30d5824e3 100644 --- a/tests/unit/webdav-server-3485.test.ts +++ b/tests/unit/webdav-server-3485.test.ts @@ -144,7 +144,7 @@ const VAULT_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), "omni-webdav-vault-")); const ORIG_KEY = process.env.STORAGE_ENCRYPTION_KEY; test.after(() => { - fs.rmSync(VAULT_ROOT, { recursive: true, force: true }); + fs.rmSync(VAULT_ROOT, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIG_KEY === undefined) { delete process.env.STORAGE_ENCRYPTION_KEY; } else { @@ -253,10 +253,7 @@ test("verifyBasicAuth: empty header returns false", async () => { test("verifyBasicAuth: non-Basic scheme returns false", async () => { const { verifyBasicAuth } = await importHandler(); - assert.equal( - verifyBasicAuth("Bearer some-token", "alice", "s3cr3t"), - false - ); + assert.equal(verifyBasicAuth("Bearer some-token", "alice", "s3cr3t"), false); }); test("verifyBasicAuth: malformed base64 returns false", async () => { @@ -372,7 +369,15 @@ test("buildPropfindXml: escapes XML special chars in names", async () => { test("buildPropfindXml: file entry has no D:collection resourcetype", async () => { const { buildPropfindXml } = await importHandler(); const xml = buildPropfindXml( - [{ name: "note.md", href: "/api/v1/webdav/note.md", isDir: false, size: 99, mtime: new Date() }], + [ + { + name: "note.md", + href: "/api/v1/webdav/note.md", + isDir: false, + size: 99, + mtime: new Date(), + }, + ], "/api/v1/webdav/" ); // File should have empty resourcetype, not a collection @@ -471,8 +476,8 @@ test.before(async () => { }); test.after(() => { - fs.rmSync(intDataDir, { recursive: true, force: true }); - fs.rmSync(intVaultDir, { recursive: true, force: true }); + fs.rmSync(intDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(intVaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("PUT then GET round-trips a file correctly", async () => { @@ -657,8 +662,8 @@ test("disabled WebDAV returns 503", async () => { }); assert.equal(res.status, 503); } finally { - fs.rmSync(disabledDataDir, { recursive: true, force: true }); - fs.rmSync(disabledVaultDir, { recursive: true, force: true }); + fs.rmSync(disabledDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(disabledVaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -675,7 +680,7 @@ test("no DB / missing config returns 503", async () => { }); assert.equal(res.status, 503); } finally { - fs.rmSync(emptyDataDir, { recursive: true, force: true }); + fs.rmSync(emptyDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); @@ -740,8 +745,8 @@ test("encrypted password in DB is decrypted and auth works", async () => { // OPTIONS with correct creds should succeed (200 or 207) assert.ok(res.status < 400, `Expected success with encrypted password, got ${res.status}`); } finally { - fs.rmSync(encDataDir, { recursive: true, force: true }); - fs.rmSync(encVaultDir, { recursive: true, force: true }); + fs.rmSync(encDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.rmSync(encVaultDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); // Restore encryption key state if (ORIG_KEY === undefined) { delete process.env.STORAGE_ENCRYPTION_KEY; @@ -789,6 +794,6 @@ test("resolveDataDir: parity with src/lib/dataPaths.ts across env combos", async else process.env.DATA_DIR = ORIG_DATA; if (ORIG_XDG === undefined) delete process.env.XDG_CONFIG_HOME; else process.env.XDG_CONFIG_HOME = ORIG_XDG; - fs.rmSync(tmp, { recursive: true, force: true }); + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } }); diff --git a/tests/unit/webhook-deliveries-db.test.ts b/tests/unit/webhook-deliveries-db.test.ts index c98ba9cf7a..e469a8a29d 100644 --- a/tests/unit/webhook-deliveries-db.test.ts +++ b/tests/unit/webhook-deliveries-db.test.ts @@ -13,7 +13,7 @@ const deliveriesDb = await import("../../src/lib/db/webhookDeliveries.ts"); async function resetStorage() { coreDb.resetDbInstance(); - fs.rmSync(TEST_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DIR, { recursive: true }); } @@ -23,7 +23,7 @@ test.beforeEach(async () => { test.after(() => { coreDb.resetDbInstance(); - fs.rmSync(TEST_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("insertDelivery stores a row and getDeliveries returns it", () => { diff --git a/tests/unit/webhook-metadata-guard-3269.test.ts b/tests/unit/webhook-metadata-guard-3269.test.ts index b08396d859..14dbc92771 100644 --- a/tests/unit/webhook-metadata-guard-3269.test.ts +++ b/tests/unit/webhook-metadata-guard-3269.test.ts @@ -14,12 +14,10 @@ import path from "node:path"; process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omni-wh-meta-3269-")); -const { isCloudMetadataHost, OutboundUrlGuardError } = await import( - "../../src/shared/network/outboundUrlGuard.ts" -); -const { parseAndValidateWebhookUrl } = await import( - "../../src/shared/network/outboundUrlGuardPolicy.ts" -); +const { isCloudMetadataHost, OutboundUrlGuardError } = + await import("../../src/shared/network/outboundUrlGuard.ts"); +const { parseAndValidateWebhookUrl } = + await import("../../src/shared/network/outboundUrlGuardPolicy.ts"); const { resetDbInstance } = await import("../../src/lib/db/core.ts"); const FLAG = "OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS"; @@ -73,7 +71,12 @@ after(() => { /* ignore */ } try { - fs.rmSync(process.env.DATA_DIR as string, { recursive: true, force: true }); + fs.rmSync(process.env.DATA_DIR as string, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } catch { /* ignore */ } diff --git a/tests/unit/webhook-private-optin-3269.test.ts b/tests/unit/webhook-private-optin-3269.test.ts index 196b9ef337..3bb2b6142b 100644 --- a/tests/unit/webhook-private-optin-3269.test.ts +++ b/tests/unit/webhook-private-optin-3269.test.ts @@ -15,9 +15,8 @@ import path from "node:path"; process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omni-wh-3269-")); const { OutboundUrlGuardError } = await import("../../src/shared/network/outboundUrlGuard.ts"); -const { parseAndValidateWebhookUrl } = await import( - "../../src/shared/network/outboundUrlGuardPolicy.ts" -); +const { parseAndValidateWebhookUrl } = + await import("../../src/shared/network/outboundUrlGuardPolicy.ts"); const { resetDbInstance } = await import("../../src/lib/db/core.ts"); const FLAG = "OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS"; @@ -76,7 +75,12 @@ after(() => { /* ignore */ } try { - fs.rmSync(process.env.DATA_DIR as string, { recursive: true, force: true }); + fs.rmSync(process.env.DATA_DIR as string, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }); } catch { /* ignore */ } diff --git a/tests/unit/webshare-sync.test.ts b/tests/unit/webshare-sync.test.ts index 184641bf08..ea61451090 100644 --- a/tests/unit/webshare-sync.test.ts +++ b/tests/unit/webshare-sync.test.ts @@ -21,13 +21,13 @@ const freeProxiesDb = await import("../../src/lib/db/freeProxies.ts"); async function reset() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function webshareResponse(results: unknown[], next: string | null = null) { @@ -291,8 +291,7 @@ test("WebshareProvider.sync never leaks the API key in error messages on an HTTP const originalFetch = globalThis.fetch; process.env.FREE_PROXY_WEBSHARE_API_KEY = FAKE_API_KEY; - globalThis.fetch = (async () => - new Response("Unauthorized", { status: 401 })) as typeof fetch; + globalThis.fetch = (async () => new Response("Unauthorized", { status: 401 })) as typeof fetch; try { const p = getProvider("webshare")!; @@ -302,7 +301,10 @@ test("WebshareProvider.sync never leaks the API key in error messages on an HTTP assert.ok(result.errors.length > 0); for (const err of result.errors) { assert.ok(!err.includes(FAKE_API_KEY), `error must not leak the API key: ${err}`); - assert.ok(!err.toLowerCase().includes("authorization"), `error must not leak the auth header: ${err}`); + assert.ok( + !err.toLowerCase().includes("authorization"), + `error must not leak the auth header: ${err}` + ); } } finally { globalThis.fetch = originalFetch; diff --git a/tests/unit/wildcard-alias-settings-not-applied-7693.test.ts b/tests/unit/wildcard-alias-settings-not-applied-7693.test.ts index 0890d535e5..ee7f10d6cd 100644 --- a/tests/unit/wildcard-alias-settings-not-applied-7693.test.ts +++ b/tests/unit/wildcard-alias-settings-not-applied-7693.test.ts @@ -15,13 +15,13 @@ const { getModelInfo } = await import("../../src/sse/services/model.ts"); test.beforeEach(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); }); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); if (ORIGINAL_API_KEY_SECRET === undefined) { delete process.env.API_KEY_SECRET; } else { diff --git a/tests/unit/windows-cert-identity-7275.test.ts b/tests/unit/windows-cert-identity-7275.test.ts index 9d9d6bc6cf..4c43200688 100644 --- a/tests/unit/windows-cert-identity-7275.test.ts +++ b/tests/unit/windows-cert-identity-7275.test.ts @@ -56,21 +56,23 @@ Object.defineProperty(process, "platform", { value: "win32", configurable: true process.env.PATH = `${binDir}${path.delimiter}${originalPath}`; // Imported AFTER forcing win32: IS_WIN inside install.ts is a load-time const. -const { checkCertInstalled, certutilThumbprint, buildWindowsDelstoreScript } = await import( - "../../src/mitm/cert/install.ts" -); +const { checkCertInstalled, certutilThumbprint, buildWindowsDelstoreScript } = + await import("../../src/mitm/cert/install.ts"); test.after(() => { Object.defineProperty(process, "platform", originalPlatformDescriptor); process.env.PATH = originalPath; - fs.rmSync(tmpRoot, { recursive: true, force: true }); + fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); function fakeCertFile(seed: string): string { const der = crypto.createHash("sha256").update(seed).digest(); const pem = "-----BEGIN CERTIFICATE-----\n" + - der.toString("base64").match(/.{1,64}/g)!.join("\n") + + der + .toString("base64") + .match(/.{1,64}/g)! + .join("\n") + "\n-----END CERTIFICATE-----\n"; const certPath = path.join(tmpRoot, `${seed}.crt`); fs.writeFileSync(certPath, pem); diff --git a/tests/unit/xai-oauth-usage.test.ts b/tests/unit/xai-oauth-usage.test.ts index 5060afa385..52a3170d88 100644 --- a/tests/unit/xai-oauth-usage.test.ts +++ b/tests/unit/xai-oauth-usage.test.ts @@ -92,7 +92,7 @@ describe("xAI OAuth usage dispatch", () => { globalThis.fetch = originalFetch; core.resetDbInstance(); try { - fs.rmSync(TMP, { recursive: true, force: true }); + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } diff --git a/tests/unit/xai-usage.test.ts b/tests/unit/xai-usage.test.ts index 5e027f3c2d..cd82ae8e9c 100644 --- a/tests/unit/xai-usage.test.ts +++ b/tests/unit/xai-usage.test.ts @@ -21,12 +21,9 @@ const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "omni-xai-usage-")); process.env.DATA_DIR = TMP; const core = await import("../../src/lib/db/core.ts"); -const { getMonthlyProviderTokensForConnection } = await import( - "../../src/lib/usage/usageStats.ts" -); -const { __testing, USAGE_FETCHER_PROVIDERS, getUsageForProvider } = await import( - "../../open-sse/services/usage.ts" -); +const { getMonthlyProviderTokensForConnection } = await import("../../src/lib/usage/usageStats.ts"); +const { __testing, USAGE_FETCHER_PROVIDERS, getUsageForProvider } = + await import("../../open-sse/services/usage.ts"); const { getXaiUsage } = __testing; function insertUsage( @@ -65,7 +62,7 @@ describe("xAI self-tracked usage", () => { after(() => { core.resetDbInstance(); try { - fs.rmSync(TMP, { recursive: true, force: true }); + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } diff --git a/tests/unit/xiaomi-mimo-selftrack-usage.test.ts b/tests/unit/xiaomi-mimo-selftrack-usage.test.ts index f84af5f61f..bbcdda04cf 100644 --- a/tests/unit/xiaomi-mimo-selftrack-usage.test.ts +++ b/tests/unit/xiaomi-mimo-selftrack-usage.test.ts @@ -20,9 +20,7 @@ const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "omni-xiaomi-")); process.env.DATA_DIR = TMP; const core = await import("../../src/lib/db/core.ts"); -const { getMonthlyProviderTokensForConnection } = await import( - "../../src/lib/usage/usageStats.ts" -); +const { getMonthlyProviderTokensForConnection } = await import("../../src/lib/usage/usageStats.ts"); const { __testing } = await import("../../open-sse/services/usage.ts"); const { getXiaomiMimoUsage } = __testing; @@ -64,7 +62,7 @@ describe("xiaomi-mimo self-tracked quota", () => { after(() => { core.resetDbInstance(); try { - fs.rmSync(TMP, { recursive: true, force: true }); + fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } catch { // best-effort temp cleanup } @@ -82,7 +80,16 @@ describe("xiaomi-mimo self-tracked quota", () => { it("getXiaomiMimoUsage returns a monthly quota against the 4.1B limit", async () => { const r = (await getXiaomiMimoUsage("conn-x")) as { plan?: string; - quotas?: Record; + quotas?: Record< + string, + { + used: number; + total: number; + remaining?: number; + remainingPercentage?: number; + resetAt: string | null; + } + >; message?: string; }; assert.ok(r.quotas, `expected quotas, got message: ${r.message}`); diff --git a/tests/unit/zai-glm-max-tokens-clamp-7364.test.ts b/tests/unit/zai-glm-max-tokens-clamp-7364.test.ts index 70ff6ec557..a86b834f64 100644 --- a/tests/unit/zai-glm-max-tokens-clamp-7364.test.ts +++ b/tests/unit/zai-glm-max-tokens-clamp-7364.test.ts @@ -8,14 +8,12 @@ const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-7364-max- process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); -const { - stripUnsupportedParams, - __STRIP_RULES_FOR_TEST, -} = await import("../../open-sse/translator/paramSupport.ts"); +const { stripUnsupportedParams, __STRIP_RULES_FOR_TEST } = + await import("../../open-sse/translator/paramSupport.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7364 Defect B: zai/glm-4.6v max_tokens above the 32768 ceiling is clamped before dispatch", () => { diff --git a/tests/unit/zai-glm-target-format-override.test.ts b/tests/unit/zai-glm-target-format-override.test.ts index 44ef3d5033..d3d79d1670 100644 --- a/tests/unit/zai-glm-target-format-override.test.ts +++ b/tests/unit/zai-glm-target-format-override.test.ts @@ -14,7 +14,7 @@ const { DefaultExecutor } = await import("../../open-sse/executors/default.ts"); test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("#7364 Defect A (URL): DefaultExecutor.buildUrl('zai', ...) ignores a per-model targetFormat:'openai' override and still returns the Anthropic Messages URL", () => { @@ -43,7 +43,11 @@ test("#7364 Defect A (case-sensitivity): a custom model saved as 'glm-4.6v' is n ); const exact = (await getModelInfo("zai/glm-4.6v")) as { targetFormat?: string }; - assert.equal(exact.targetFormat, "openai", "sanity check: exact-case lookup must surface the saved targetFormat"); + assert.equal( + exact.targetFormat, + "openai", + "sanity check: exact-case lookup must surface the saved targetFormat" + ); const mixedCase = (await getModelInfo("zai/glm-4.6V")) as { targetFormat?: string }; assert.equal( diff --git a/tests/unit/zai-web-model-sync-route.test.ts b/tests/unit/zai-web-model-sync-route.test.ts index 58f340198e..2ceb261c1d 100644 --- a/tests/unit/zai-web-model-sync-route.test.ts +++ b/tests/unit/zai-web-model-sync-route.test.ts @@ -24,7 +24,7 @@ async function resetStorage() { modelSyncRoute.__resetLoopbackReadinessForTests(); core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -32,7 +32,7 @@ test.after(() => { globalThis.fetch = originalFetch; core.resetDbInstance(); apiKeysDb.resetApiKeyState(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("curated zai-web sync removes stale imported models without touching manual models", async () => { diff --git a/tests/unit/zai-web-models-discovery-7678.test.ts b/tests/unit/zai-web-models-discovery-7678.test.ts index 678bddee88..82837c541f 100644 --- a/tests/unit/zai-web-models-discovery-7678.test.ts +++ b/tests/unit/zai-web-models-discovery-7678.test.ts @@ -17,13 +17,13 @@ const CURATED_ZAI_WEB_MODEL_IDS = ["glm-5.2", "GLM-5.1", "GLM-5-Turbo", "GLM-5v- async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("zai-web publishes the live reasoning and vision capabilities", () => { diff --git a/tests/unit/zcode-executor.test.ts b/tests/unit/zcode-executor.test.ts index db4a8586be..68e450490b 100644 --- a/tests/unit/zcode-executor.test.ts +++ b/tests/unit/zcode-executor.test.ts @@ -8,7 +8,9 @@ const fixture = join(process.cwd(), "tests/fixtures/fake-zcode-app-server.mjs"); const TEST_DATA_DIR = mkdtempSync(join(tmpdir(), "omniroute-zcode-")); process.env.DATA_DIR = TEST_DATA_DIR; -test.after(() => rmSync(TEST_DATA_DIR, { recursive: true, force: true })); +test.after(() => + rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }) +); async function loadZcodeExecutor() { return import("../../open-sse/executors/zcode.ts"); diff --git a/tests/unit/zed-hosted-models-discovery-route.test.ts b/tests/unit/zed-hosted-models-discovery-route.test.ts index 8d97931c48..2c8c543a66 100644 --- a/tests/unit/zed-hosted-models-discovery-route.test.ts +++ b/tests/unit/zed-hosted-models-discovery-route.test.ts @@ -36,7 +36,7 @@ async function resetStorage() { globalThis.fetch = originalFetch; zedAuth.clearZedCaches(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } @@ -67,7 +67,7 @@ test.after(async () => { globalThis.fetch = originalFetch; zedAuth.clearZedCaches(); core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); test("zed-hosted model discovery mints an LLM token and lists the live catalog", async () => { diff --git a/tests/unit/zenmux-models-fetch-4202.test.ts b/tests/unit/zenmux-models-fetch-4202.test.ts index 4a4f60585b..9258dd313c 100644 --- a/tests/unit/zenmux-models-fetch-4202.test.ts +++ b/tests/unit/zenmux-models-fetch-4202.test.ts @@ -29,13 +29,13 @@ const modelsRoute = await import("../../src/app/api/providers/[id]/models/route. async function resetStorage() { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } test.after(() => { core.resetDbInstance(); - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); interface ModelsBody { @@ -88,7 +88,10 @@ test("#4202 ZenMux import fetches the live /api/v1/models catalog (incl. the fre ids.includes("z-ai/glm-5.2-free"), `live free models missing from catalog: ${ids.join(",")}` ); - assert.ok(ids.includes("moonshotai/kimi-k2.7-code-free"), `live free models missing: ${ids.join(",")}`); + assert.ok( + ids.includes("moonshotai/kimi-k2.7-code-free"), + `live free models missing: ${ids.join(",")}` + ); // The stale hardcoded registry entry must not be what we serve. assert.ok( !ids.includes("mistralai/mistral-large-2512"),