Files
OmniRoute/tests/unit/codex-catalog-revalidation.test.ts
Diego Rodrigues de Sa e Souza 3d4f3e4960 test(infra): retry recursive temp-dir removal instead of failing a shard on ENOTEMPTY (#11966) (#11968)
* test(infra): retry recursive temp-dir removal instead of failing a shard on ENOTEMPTY (#11966)

Two shards on release/v3.8.51 went red in one day with the same signature —
"ENOTEMPTY, Directory not empty: /tmp/omniroute-<test>-XXXXXX" — from
combo-same-provider-cascade (Unit Tests fast-path 4/4, on a PR that touches only
.github/) and auth-policy-embeddings-webfetch-7785 (the 20k-test TIA step). Both pass
alone and on re-run: the cleanup races something still writing into the directory
(SQLite WAL/-shm checkpoint, a worker, the backup) and under a loaded hosted runner
the window opens. 1154 test files do their own cleanup with
fs.rmSync(dir, { recursive: true, force: true }); 57 already asked for retries.

One-shot codemod (scripts/ad-hoc/codemod-rm-maxretries.mjs, kept for the record):
every rm / rmSync / rmdirSync option object with `recursive: true` and no
`maxRetries` gains `maxRetries: 5, retryDelay: 100` — Node itself then retries
ENOTEMPTY/EBUSY/EPERM for up to ~0.5 s before giving up. 2243 call sites in 1292
files under tests/, the shared tests/_setup/isolateDataDir.ts exit hook included.
Only the option object changes: no call site, assertion or import is touched.

Validation: prettier and ESLint (with the frozen suppressions) clean on all 1292
files; a random 20-file sample runs green (quota-redis-store hangs identically on
the untouched tree — it needs a Redis on localhost, an environment matter). The
four unit shards on this PR are the full run.

* fix(quality): let check-forgotten-sibling-tests read a 1,000-file diff

The gate shells out to `git diff` through execFileSync with Node's default 1 MB
maxBuffer; the 1,292-file codemod in this PR is the first diff large enough to
overflow it, and the gate died with `spawnSync git ENOBUFS` before comparing
anything. 64 MB is far above any real PR and costs nothing when unused.
2026-08-29 01:17:40 -03:00

258 lines
8.1 KiB
TypeScript

import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import type { SyncedAvailableModel } from "../../src/lib/db/models.ts";
import {
createCodexCatalogRevalidationCoordinator,
executeCodexCatalogRevalidation,
resolveBootRevalidationReason,
resolveCodexCatalogAppVersion,
scrubSyncedModelsWithCodexDenylist,
} from "../../src/shared/services/codexCatalogRevalidation.ts";
test("Codex revalidation avoids top-level createRequire in packaged Next modules", () => {
const source = fs.readFileSync(
path.join(process.cwd(), "src/shared/services/codexCatalogRevalidation.ts"),
"utf8"
);
assert.doesNotMatch(source, /^const\s+\w+\s*=\s*createRequire\s*\(/m);
});
test("scrubSyncedModelsWithCodexDenylist drops the GPT-5.4 family and keeps others", () => {
const input = [
{ id: "gpt-5.6-sol", name: "Sol", source: "imported" },
{ id: "gpt-5.4", name: "Retired", source: "imported" },
{ id: "gpt-5.4-mini", name: "Retired Mini", source: "imported" },
{ id: "future-codex-experimental", name: "Future", source: "imported" },
] satisfies SyncedAvailableModel[];
const { kept, removedIds } = scrubSyncedModelsWithCodexDenylist(input);
assert.deepEqual(
kept.map((m) => m.id),
["gpt-5.6-sol", "future-codex-experimental"]
);
assert.deepEqual(removedIds.sort(), ["gpt-5.4", "gpt-5.4-mini"]);
});
test("scrubSyncedModelsWithCodexDenylist is a no-op when nothing is denylisted", () => {
const input = [
{ id: "gpt-5.6-sol", name: "Sol", source: "imported" },
{ id: "gpt-5.5-low", name: "5.5 Low", source: "imported" },
] satisfies SyncedAvailableModel[];
const { kept, removedIds } = scrubSyncedModelsWithCodexDenylist(input);
assert.equal(removedIds.length, 0);
assert.equal(kept.length, 2);
});
test("resolveCodexCatalogAppVersion uses stable, source-qualified identities", () => {
const runtimeRoot = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-version-identity-"));
assert.equal(
resolveCodexCatalogAppVersion(
{
OMNIROUTE_BUILD_SHA: "abc123",
npm_package_version: "9.9.9",
},
{ runtimeRoot }
),
"build:abc123"
);
assert.equal(
resolveCodexCatalogAppVersion(
{
npm_package_version: "3.8.47",
},
{ runtimeRoot }
),
"pkg:3.8.47"
);
try {
fs.writeFileSync(path.join(runtimeRoot, "BUILD_SHA"), "sentinel-sha\n");
assert.equal(
resolveCodexCatalogAppVersion({}, { runtimeRoot, packageVersion: "3.8.47" }),
"build:sentinel-sha"
);
fs.rmSync(path.join(runtimeRoot, "BUILD_SHA"));
fs.writeFileSync(path.join(runtimeRoot, "package.json"), '{"version":"9.8.7"}\n');
assert.equal(resolveCodexCatalogAppVersion({}, { runtimeRoot }), "pkg:9.8.7");
assert.equal(
resolveCodexCatalogAppVersion({}, { runtimeRoot, packageVersion: "3.8.47" }),
"pkg:3.8.47"
);
assert.equal(resolveCodexCatalogAppVersion({}, { runtimeRoot, packageVersion: null }), null);
} finally {
fs.rmSync(runtimeRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
}
});
test("resolveBootRevalidationReason only fires on first-start or upgrade", () => {
assert.equal(resolveBootRevalidationReason(null, "v2"), "first-start");
assert.equal(resolveBootRevalidationReason("", "v2"), "first-start");
assert.equal(resolveBootRevalidationReason("v1", "v2"), "upgrade");
assert.equal(resolveBootRevalidationReason("v2", "v2"), null);
});
test("executeCodexCatalogRevalidation records completion only after a full live sync", async () => {
const events: string[] = [];
const failed = await executeCodexCatalogRevalidation({
appVersion: "build:audit",
scrub: async () => {
events.push("scrub");
},
waitForReady: async () => {
events.push("ready");
},
liveResync: async () => {
events.push("sync");
return { attempted: 2, succeeded: 1 };
},
writeMarker: async () => {
events.push("marker");
return true;
},
logSuccess: () => {
events.push("log");
},
});
assert.equal(failed.complete, false);
assert.deepEqual(events, ["scrub", "ready", "sync"]);
events.length = 0;
const complete = await executeCodexCatalogRevalidation({
appVersion: "build:audit",
scrub: async () => {
events.push("scrub");
},
waitForReady: async () => {
events.push("ready");
},
liveResync: async () => {
events.push("sync");
return { attempted: 2, succeeded: 2 };
},
writeMarker: async () => {
events.push("marker");
return true;
},
logSuccess: () => {
events.push("log");
},
});
assert.equal(complete.complete, true);
assert.deepEqual(events, ["scrub", "ready", "sync", "marker", "log"]);
});
test("executeCodexCatalogRevalidation leaves an unknown-version run incomplete and unlogged", async () => {
const events: string[] = [];
const result = await executeCodexCatalogRevalidation({
appVersion: null,
scrub: async () => undefined,
waitForReady: async () => undefined,
liveResync: async () => ({ attempted: 0, succeeded: 0 }),
writeMarker: async () => {
events.push("marker");
return true;
},
logSuccess: () => {
events.push("log");
},
});
assert.equal(result.complete, false);
assert.deepEqual(events, []);
});
test("executeCodexCatalogRevalidation does not complete after readiness or marker failure", async () => {
let liveCalls = 0;
let markerCalls = 0;
let successLogs = 0;
const notReady = await executeCodexCatalogRevalidation({
appVersion: "build:audit",
scrub: async () => undefined,
waitForReady: async () => {
throw new Error("not ready");
},
liveResync: async () => {
liveCalls += 1;
return { attempted: 1, succeeded: 1 };
},
writeMarker: async () => {
markerCalls += 1;
return true;
},
logSuccess: () => {
successLogs += 1;
},
});
assert.equal(notReady.complete, false);
assert.equal(liveCalls, 0);
assert.equal(markerCalls, 0);
assert.equal(successLogs, 0);
const markerFailed = await executeCodexCatalogRevalidation({
appVersion: "build:audit",
scrub: async () => undefined,
waitForReady: async () => undefined,
liveResync: async () => ({ attempted: 1, succeeded: 1 }),
writeMarker: async () => false,
logSuccess: () => {
successLogs += 1;
},
});
assert.equal(markerFailed.complete, false);
assert.equal(successLogs, 0);
});
test("Codex revalidation coordinator coalesces startup and queues one init rerun", async () => {
let releaseFirst: (() => void) | undefined;
const firstGate = new Promise<void>((resolve) => {
releaseFirst = resolve;
});
const reasons: string[] = [];
let active = 0;
let maxActive = 0;
const request = createCodexCatalogRevalidationCoordinator(async (options) => {
reasons.push(options.reason);
active += 1;
maxActive = Math.max(maxActive, active);
if (reasons.length === 1) await firstGate;
active -= 1;
});
const startupA = request({ reason: "upgrade" });
const startupB = request({ reason: "upgrade" });
const initA = request({ reason: "init" });
const initB = request({ reason: "init" });
releaseFirst?.();
await Promise.all([startupA, startupB, initA, initB]);
assert.deepEqual(reasons, ["upgrade", "init"]);
assert.equal(maxActive, 1);
});
test("Codex revalidation coordinator does not lose init during active-run settlement", async () => {
let releaseFirst: (() => void) | undefined;
const firstGate = new Promise<void>((resolve) => {
releaseFirst = resolve;
});
const reasons: string[] = [];
const request = createCodexCatalogRevalidationCoordinator(async ({ reason }) => {
reasons.push(reason);
if (reasons.length === 1) await firstGate;
});
const activeRun = request({ reason: "upgrade" });
const settlementInit = firstGate.then(() =>
Promise.resolve().then(() => request({ reason: "init" }))
);
releaseFirst?.();
await Promise.all([activeRun, settlementInit]);
assert.deepEqual(reasons, ["upgrade", "init"]);
});