fix(engine): use fork pool for engine-core Vitest gate (#1764)
## Summary - Switches the engine-core Vitest project from thread workers to fork workers to avoid the Node 24/macOS libuv kqueue SIGABRT while preserving real failure semantics. - Adds a small policy regression test covering the gate pool, warning behavior, and engine-core allow-list expectations. ## Test Plan - node --test scripts/__tests__/engine-vitest-gate-policy.test.mjs - corepack pnpm --filter @fusion/engine test:core <!-- stage-review-badge-begin --> --- <a href="https://stagereview.app/Runfusion/Fusion/pull/1764"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://stagereview.app/assets/gh-open-in-stage-dark.svg"> <img src="https://stagereview.app/assets/gh-open-in-stage-light.svg" alt="Open in Stage"> </picture> </a> <!-- stage-review-badge-end --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved reliability of the engine’s Vitest test execution on newer macOS/Node setups by scoping a safer worker strategy to the core merge-gate suite. * Prevented configuration and gate-script changes that could otherwise break consistent test behavior. * **Tests** * Added automated “gate policy” checks to validate Vitest configuration constraints and ensure core/test-gate scripts run with the expected command and allow-listed test patterns. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -19,6 +19,8 @@ export default defineConfig({
|
||||
resolve(__dirname, "../core/src/__test-utils__/vitest-setup.ts"),
|
||||
],
|
||||
globalSetup: [resolve(__dirname, "../core/src/__test-utils__/vitest-teardown.ts")],
|
||||
// Keep the broad engine lanes on worker threads; engine-core overrides this
|
||||
// below because only the curated merge gate has hit the Node/macOS abort.
|
||||
pool: "threads",
|
||||
maxWorkers,
|
||||
minWorkers: 1,
|
||||
@@ -52,6 +54,11 @@ export default defineConfig({
|
||||
extends: true,
|
||||
test: {
|
||||
name: "engine-core",
|
||||
/*
|
||||
FNXC:EngineTests 2026-06-25-11:11:
|
||||
The curated engine-core merge gate hits a Node 24.15.0/macOS libuv kqueue SIGABRT when Vitest thread workers close unmanaged file descriptors. Scope fork workers to this gate so the broad default engine suite keeps its explicit worker-thread behavior.
|
||||
*/
|
||||
pool: "forks",
|
||||
// The curated merge-gate suite (see docs/testing.md "Merge gate").
|
||||
// Membership is an explicit allow-list, NOT a glob: tests earn their
|
||||
// way in with evidence of value, and a flaky gate test is evicted by
|
||||
|
||||
83
scripts/__tests__/engine-vitest-gate-policy.test.mjs
Normal file
83
scripts/__tests__/engine-vitest-gate-policy.test.mjs
Normal file
@@ -0,0 +1,83 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const repoRoot = path.resolve(__dirname, "../..");
|
||||
|
||||
function read(relativePath) {
|
||||
return readFileSync(path.join(repoRoot, relativePath), "utf8");
|
||||
}
|
||||
|
||||
function readJson(relativePath) {
|
||||
return JSON.parse(read(relativePath));
|
||||
}
|
||||
|
||||
test("engine-core gate keeps a Node 24/macOS-safe Vitest pool without changing broad engine lanes", () => {
|
||||
const config = read("packages/engine/vitest.config.ts");
|
||||
const projectsIndex = config.indexOf("projects:");
|
||||
const rootTestConfig = projectsIndex === -1 ? config : config.slice(0, projectsIndex);
|
||||
const engineCoreBlock = config.match(/name:\s*"engine-core"[\s\S]*?include:\s*\[/)?.[0] ?? "";
|
||||
const engineDefaultBlock = config.match(/name:\s*"engine-default"[\s\S]*?include:\s*\[/)?.[0] ?? "";
|
||||
|
||||
assert.match(
|
||||
engineCoreBlock,
|
||||
/pool:\s*"forks"/,
|
||||
"engine-core must use fork workers; thread workers abort with Node 24/macOS libuv kqueue",
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
rootTestConfig,
|
||||
/pool:\s*"forks"/,
|
||||
"fork workers must not be configured at root scope because that slows the broad engine-default lane",
|
||||
);
|
||||
assert.match(
|
||||
rootTestConfig,
|
||||
/pool:\s*"threads"/,
|
||||
"root engine config must explicitly keep broad lanes on threads because Vitest 4 defaults to forks",
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
engineDefaultBlock,
|
||||
/pool:\s*"forks"/,
|
||||
"engine-default must keep inheriting Vitest's default thread pool for broad src/**/*.test.ts runs",
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
config,
|
||||
/NODE_NO_WARNINGS/,
|
||||
"the gate must not hide unmanaged-fd warnings by suppressing Node warnings",
|
||||
);
|
||||
assert.match(config, /maxWorkers,/, "worker budgeting must still flow through computeMaxWorkers");
|
||||
assert.match(config, /fileParallelism:\s*true/, "engine-core should preserve file-level parallelism");
|
||||
});
|
||||
|
||||
test("engine-core remains an explicit allow-listed merge gate", () => {
|
||||
const config = read("packages/engine/vitest.config.ts");
|
||||
const engineCoreBlock = config.match(/name:\s*"engine-core"[\s\S]*?exclude:\s*\[/)?.[0] ?? "";
|
||||
const includeEntries = [...engineCoreBlock.matchAll(/"src\/__tests__\/[^"\n]+\.test\.ts"/g)].map((match) => match[0]);
|
||||
|
||||
assert.equal(new Set(includeEntries).size, includeEntries.length, "engine-core allow-list must not contain duplicates");
|
||||
assert.ok(includeEntries.length >= 18, "engine-core allow-list must not be gutted to avoid the runtime abort");
|
||||
assert.ok(
|
||||
includeEntries.includes('"src/__tests__/workflow-graph-task-runner.test.ts"'),
|
||||
"engine-core must keep workflow graph gate coverage",
|
||||
);
|
||||
assert.ok(
|
||||
includeEntries.includes('"src/__tests__/heartbeat-monitor.test.ts"'),
|
||||
"engine-core must keep heartbeat monitor gate coverage while avoiding FN-779 scope changes",
|
||||
);
|
||||
});
|
||||
|
||||
test("root and package gate scripts still propagate real Vitest failures", () => {
|
||||
const root = readJson("package.json");
|
||||
const engine = readJson("packages/engine/package.json");
|
||||
|
||||
assert.equal(
|
||||
engine.scripts?.["test:core"],
|
||||
"vitest run --silent=passed-only --reporter=dot --project=engine-core",
|
||||
);
|
||||
assert.match(root.scripts?.["test:gate"] ?? "", /pnpm --filter @fusion\/engine test:core/);
|
||||
assert.doesNotMatch(root.scripts?.["test:gate"] ?? "", /NODE_NO_WARNINGS/);
|
||||
assert.doesNotMatch(root.scripts?.["test"] ?? "", /NODE_NO_WARNINGS/);
|
||||
});
|
||||
Reference in New Issue
Block a user