FN-6282: isolate vitest worker temp roots
Use per-invocation Vitest worker roots to keep compound-engineering tests from timing out on stale temp fixtures. - Allocate a fresh FUSION_TEST_WORKER_ROOT during Vitest global setup and remove it during teardown. - Preserve per-worker fallback root creation when global setup is not available. - Clean compound-engineering harness project roots on close and cover the setup invariants with regression tests. Files changed: packages/core/src/__test-utils__/vitest-setup.ts | 20 +++++++--- .../core/src/__test-utils__/vitest-teardown.ts | 38 +++++++++++-------- .../src/__tests__/_harness.ts | 7 +++- .../src/__tests__/setup-invariant.test.ts | 43 ++++++++++++++++++++++ 4 files changed, 85 insertions(+), 23 deletions(-) Fusion-Task-Id: FN-6282 Fusion-Task-Lineage: 8b842dd0-4f51-44de-b2db-8e8bfa97239c
This commit is contained in:
@@ -164,11 +164,21 @@ if (!process.env.FUSION_MASTER_KEY_DISABLE_KEYCHAIN) {
|
||||
process.env.FUSION_MASTER_KEY_DISABLE_KEYCHAIN = "1";
|
||||
}
|
||||
|
||||
// Shared parent directory for all worker temp dirs in this run.
|
||||
// globalTeardown wipes this at the end of the suite.
|
||||
const WORKER_ROOT = join(tmpdir(), "fusion-test-workers");
|
||||
try { mkdirSync(WORKER_ROOT, { recursive: true }); } catch { /* ignore */ }
|
||||
process.env.FUSION_TEST_WORKER_ROOT = WORKER_ROOT;
|
||||
// Shared parent directory for all worker temp dirs in this Vitest invocation.
|
||||
// Keep this per-run (globalSetup seeds FUSION_TEST_WORKER_ROOT) instead of a
|
||||
// single long-lived tmpdir/fusion-test-workers directory: redirect setup does a
|
||||
// bounded one-level sweep of WORKER_ROOT, and a static root can accumulate enough
|
||||
// stale worker/home dirs after interrupted runs to make every mkdtempSync call
|
||||
// take seconds.
|
||||
const WORKER_ROOT = (() => {
|
||||
const fromEnv = process.env.FUSION_TEST_WORKER_ROOT;
|
||||
const root = fromEnv && fromEnv.trim().length > 0
|
||||
? resolve(fromEnv)
|
||||
: realpathSync(mkdtempSync(join(tmpdir(), "fusion-test-workers-")));
|
||||
try { mkdirSync(root, { recursive: true }); } catch { /* ignore */ }
|
||||
process.env.FUSION_TEST_WORKER_ROOT = root;
|
||||
return root;
|
||||
})();
|
||||
|
||||
const REAL_TMPDIR = (() => {
|
||||
try {
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
/**
|
||||
* Vitest globalSetup hook.
|
||||
*
|
||||
* We only publish the shared worker-root env var here. Teardown is intentionally
|
||||
* a no-op because deleting shared temp roots during teardown can race with
|
||||
* still-running suites in some Vitest pool modes and trigger uv_cwd failures.
|
||||
* Worker dirs are cleaned by vitest-setup.ts on process exit.
|
||||
* We publish a per-invocation worker-root env var. Teardown removes that private
|
||||
* root after the project finishes so workspace isolation checks do not report
|
||||
* the run-local worker/home directories as leaks.
|
||||
*/
|
||||
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
const WORKER_ROOT = join(tmpdir(), "fusion-test-workers");
|
||||
import { join, resolve } from "node:path";
|
||||
|
||||
export default function setup(): () => Promise<void> {
|
||||
// Set the env var here too so vitest-setup.ts workers pick it up even if
|
||||
// their own mkdir runs after globalSetup.
|
||||
process.env.FUSION_TEST_WORKER_ROOT = WORKER_ROOT;
|
||||
// Use a fresh root for each Vitest invocation. A static shared root makes the
|
||||
// setup-time redirect sweep proportional to stale directories left by every
|
||||
// prior interrupted run.
|
||||
const workerRoot = resolve(mkdtempSync(join(tmpdir(), "fusion-test-workers-")));
|
||||
process.env.FUSION_TEST_WORKER_ROOT = workerRoot;
|
||||
|
||||
return async function teardown() {
|
||||
// Intentionally no-op.
|
||||
//
|
||||
// Worker temp dirs are cleaned by vitest-setup.ts using process.on("exit")
|
||||
// after first chdir-ing out of the worker dir. Deleting shared temp roots
|
||||
// from global teardown is unsafe under some Vitest pool modes because it
|
||||
// can run while other suites are still active, causing ENOENT uv_cwd.
|
||||
try {
|
||||
process.chdir(tmpdir());
|
||||
} catch {
|
||||
// Ignore — cleanup below is best-effort and uses an absolute path.
|
||||
}
|
||||
try {
|
||||
rmSync(workerRoot, { recursive: true, force: true });
|
||||
} catch {
|
||||
// Ignore — interrupted or still-active workers may leave a per-run root
|
||||
// behind, but future runs no longer sweep it because every invocation gets
|
||||
// a fresh root.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdtempSync } from "node:fs";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { vi } from "vitest";
|
||||
@@ -50,7 +50,10 @@ export function makeHarness(): TestHarness {
|
||||
projectRoot,
|
||||
ctx,
|
||||
emitted,
|
||||
close: () => db.close(),
|
||||
close: () => {
|
||||
db.close();
|
||||
rmSync(projectRoot, { recursive: true, force: true });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { existsSync, mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, join, resolve, sep } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { makeHarness } from "./_harness.js";
|
||||
|
||||
function workerRoot(): string {
|
||||
const root = process.env.FUSION_TEST_WORKER_ROOT;
|
||||
if (!root) throw new Error("FUSION_TEST_WORKER_ROOT is not set");
|
||||
return resolve(root);
|
||||
}
|
||||
|
||||
describe("compound-engineering setup invariants", () => {
|
||||
it("uses a per-run worker temp root for redirected temp fixtures", () => {
|
||||
const root = workerRoot();
|
||||
|
||||
// Regression guard for FN-6282: this must not be the old static
|
||||
// tmpdir()/fusion-test-workers directory whose one-level redirect sweep made
|
||||
// setup proportional to stale directories from prior interrupted runs.
|
||||
expect(basename(root)).toMatch(/^fusion-test-workers-/);
|
||||
expect(root).not.toBe(resolve(tmpdir(), "fusion-test-workers"));
|
||||
|
||||
const tempFixture = mkdtempSync(join(tmpdir(), "ce-setup-guard-"));
|
||||
try {
|
||||
expect(resolve(tempFixture).startsWith(root + sep)).toBe(true);
|
||||
} finally {
|
||||
rmSync(tempFixture, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("closes the CE harness and removes its redirected project root", () => {
|
||||
const root = workerRoot();
|
||||
const harness = makeHarness();
|
||||
const projectRoot = resolve(harness.projectRoot);
|
||||
|
||||
expect(projectRoot.startsWith(root + sep)).toBe(true);
|
||||
expect(existsSync(projectRoot)).toBe(true);
|
||||
|
||||
harness.close();
|
||||
|
||||
expect(existsSync(projectRoot)).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user