From 89654b2a90f646a0b9d2624d3b60d04fc1523e91 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 12 Jun 2026 04:19:42 -0700 Subject: [PATCH] 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 --- .../core/src/__test-utils__/vitest-setup.ts | 20 ++++++--- .../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(-) create mode 100644 plugins/fusion-plugin-compound-engineering/src/__tests__/setup-invariant.test.ts diff --git a/packages/core/src/__test-utils__/vitest-setup.ts b/packages/core/src/__test-utils__/vitest-setup.ts index 57665958ac..c9f461a1fe 100644 --- a/packages/core/src/__test-utils__/vitest-setup.ts +++ b/packages/core/src/__test-utils__/vitest-setup.ts @@ -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 { diff --git a/packages/core/src/__test-utils__/vitest-teardown.ts b/packages/core/src/__test-utils__/vitest-teardown.ts index f09bb12cab..55ba855b83 100644 --- a/packages/core/src/__test-utils__/vitest-teardown.ts +++ b/packages/core/src/__test-utils__/vitest-teardown.ts @@ -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 { - // 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. + } }; } diff --git a/plugins/fusion-plugin-compound-engineering/src/__tests__/_harness.ts b/plugins/fusion-plugin-compound-engineering/src/__tests__/_harness.ts index 0aacbd045e..7f05475934 100644 --- a/plugins/fusion-plugin-compound-engineering/src/__tests__/_harness.ts +++ b/plugins/fusion-plugin-compound-engineering/src/__tests__/_harness.ts @@ -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 }); + }, }; } diff --git a/plugins/fusion-plugin-compound-engineering/src/__tests__/setup-invariant.test.ts b/plugins/fusion-plugin-compound-engineering/src/__tests__/setup-invariant.test.ts new file mode 100644 index 0000000000..cc0f84d386 --- /dev/null +++ b/plugins/fusion-plugin-compound-engineering/src/__tests__/setup-invariant.test.ts @@ -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); + }); +});