mirror of https://github.com/openclaw/openclaw.git
test: default vitest root projects to threads
This commit is contained in:
parent
fb5066dfb1
commit
bb1cc84d50
|
|
@ -206,7 +206,7 @@
|
|||
- Agents MUST NOT modify baseline, inventory, ignore, snapshot, or expected-failure files to silence failing checks without explicit approval in this chat.
|
||||
- For targeted/local debugging, use the native root-project entrypoint: `pnpm test <path-or-filter> [vitest args...]` (for example `pnpm test src/commands/onboard-search.test.ts -t "shows registered plugin providers"`); do not default to raw `pnpm vitest run ...` because it bypasses the repo's default config/profile/pool routing.
|
||||
- Do not set test workers above 16; tried already.
|
||||
- Keep Vitest on `forks` only. Do not introduce or reintroduce any non-`forks` Vitest pool or alternate execution mode in configs, wrapper scripts, or default test commands without explicit approval in this chat. This includes `threads`, `vmThreads`, `vmForks`, and any future/nonstandard pool variant.
|
||||
- Vitest now defaults to native root-project `threads`, with hard `forks` exceptions for `gateway`, `agents`, and `commands`. Keep new pool changes explicit and justified; use `OPENCLAW_VITEST_POOL=forks` for full local fork debugging.
|
||||
- If local Vitest runs cause memory pressure, the default worker budget now derives from host capabilities (CPU, memory band, current load). For a conservative explicit override during land/gate runs, use `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`.
|
||||
- Live tests (real keys): `OPENCLAW_LIVE_TEST=1 pnpm test:live` (OpenClaw-only) or `LIVE=1 pnpm test:live` (includes provider live tests). Docker: `pnpm test:docker:live-models`, `pnpm test:docker:live-gateway`. Onboarding Docker E2E: `pnpm test:docker:onboard`.
|
||||
- `pnpm test:live` defaults quiet now. Keep `[live]` progress; suppress profile/gateway chatter. Full logs: `OPENCLAW_LIVE_TEST_QUIET=0 pnpm test:live`.
|
||||
|
|
|
|||
|
|
@ -71,13 +71,14 @@ Think of the suites as “increasing realism” (and increasing flakiness/cost):
|
|||
through the real `run.ts` / `compact.ts` paths; helper-only tests are not a
|
||||
sufficient substitute for those integration paths.
|
||||
- Pool note:
|
||||
- Base Vitest config still defaults to `forks`.
|
||||
- Unit and boundary projects stay on `forks`.
|
||||
- Channel, extension, and gateway configs also stay on `forks`.
|
||||
- Base Vitest config now defaults to `threads`.
|
||||
- Hard thread exceptions stay on `forks`: `gateway`, `agents`, and `commands`.
|
||||
- The root UI lane now mirrors the dedicated UI setup more closely: `jsdom`, isolated files, and the standard Vitest runner.
|
||||
- Unit, channel, and extension configs default to `isolate: false` for faster file startup.
|
||||
- `pnpm test` inherits the isolation defaults from the root `vitest.config.ts` projects config.
|
||||
- Opt back into unit-file isolation with `OPENCLAW_TEST_ISOLATE=1 pnpm test`.
|
||||
- `OPENCLAW_TEST_NO_ISOLATE=0` or `OPENCLAW_TEST_NO_ISOLATE=false` also force isolated runs.
|
||||
- `OPENCLAW_VITEST_POOL=forks` (or `OPENCLAW_TEST_POOL=forks`) forces a full local fork run when debugging thread-sensitive behavior.
|
||||
- Fast-local iteration note:
|
||||
- `pnpm test:changed` runs the native projects config with `--changed origin/main`.
|
||||
- `pnpm test:max` and `pnpm test:changed:max` keep the same native projects config, just with a higher worker cap.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ title: "Tests"
|
|||
- `pnpm test:coverage:changed`: Runs unit coverage only for files changed since `origin/main`.
|
||||
- `pnpm test:changed`: runs the native Vitest projects config with `--changed origin/main`. The base config treats the projects/config files as `forceRerunTriggers` so wiring changes still rerun broadly when needed.
|
||||
- `pnpm test`: runs the native Vitest root projects config directly. File filters work natively across the configured projects.
|
||||
- Unit, channel, and extension configs default to `pool: "forks"`.
|
||||
- Base Vitest config now defaults to `pool: "threads"`.
|
||||
- Hard thread exceptions stay on `pool: "forks"` for stability: `gateway`, `agents`, and `commands`.
|
||||
- Use `OPENCLAW_VITEST_POOL=forks pnpm test` (or `OPENCLAW_TEST_POOL=forks pnpm test`) when you want a full local fork run for debugging.
|
||||
- `pnpm test:channels` runs `vitest.channels.config.ts`.
|
||||
- `pnpm test:extensions` runs `vitest.extensions.config.ts`.
|
||||
- `pnpm test:extensions`: runs extension/plugin suites.
|
||||
|
|
@ -40,6 +42,7 @@ For local PR land/gate checks, run:
|
|||
If `pnpm test` flakes on a loaded host, rerun once before treating it as a regression, then isolate with `pnpm test <path/to/test>`. For memory-constrained hosts, use:
|
||||
|
||||
- `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`
|
||||
- `OPENCLAW_VITEST_POOL=forks OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`
|
||||
- `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-cache pnpm test:changed`
|
||||
|
||||
## Model latency bench (local keys)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import baseConfig, { resolveLocalVitestMaxWorkers } from "../../vitest.config.ts";
|
||||
import baseConfig, {
|
||||
resolveDefaultVitestPool,
|
||||
resolveLocalVitestMaxWorkers,
|
||||
} from "../../vitest.config.ts";
|
||||
|
||||
describe("resolveLocalVitestMaxWorkers", () => {
|
||||
it("uses a moderate local worker cap on larger hosts", () => {
|
||||
|
|
@ -89,6 +92,19 @@ describe("resolveLocalVitestMaxWorkers", () => {
|
|||
});
|
||||
|
||||
describe("base vitest config", () => {
|
||||
it("defaults the base pool to threads", () => {
|
||||
expect(resolveDefaultVitestPool()).toBe("threads");
|
||||
expect(baseConfig.test?.pool).toBe("threads");
|
||||
});
|
||||
|
||||
it("lets OPENCLAW_VITEST_POOL force forks for local debugging", () => {
|
||||
expect(
|
||||
resolveDefaultVitestPool({
|
||||
OPENCLAW_VITEST_POOL: "forks",
|
||||
}),
|
||||
).toBe("forks");
|
||||
});
|
||||
|
||||
it("excludes fixture trees from test collection", () => {
|
||||
expect(baseConfig.test?.exclude).toContain("test/fixtures/**");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -146,7 +146,9 @@ describe("scripts/test-extension.mjs", () => {
|
|||
resolveExtensionTestPlan({ cwd: process.cwd(), targetArg: extensionId }).hasTests,
|
||||
);
|
||||
|
||||
expect(uniqueAssigned.toSorted((left, right) => left.localeCompare(right))).toEqual(expected);
|
||||
expect(uniqueAssigned.toSorted((left, right) => left.localeCompare(right))).toEqual(
|
||||
expected.toSorted((left, right) => left.localeCompare(right)),
|
||||
);
|
||||
expect(assigned).toHaveLength(expected.length);
|
||||
|
||||
const totals = shards.map((shard) => shard.testFileCount);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,26 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { createAgentsVitestConfig } from "../vitest.agents.config.ts";
|
||||
import { createCommandsVitestConfig } from "../vitest.commands.config.ts";
|
||||
import baseConfig, { rootVitestProjects } from "../vitest.config.ts";
|
||||
import { createGatewayVitestConfig } from "../vitest.gateway.config.ts";
|
||||
import { createUiVitestConfig } from "../vitest.ui.config.ts";
|
||||
|
||||
describe("projects vitest config", () => {
|
||||
it("defines the native root project list for all non-live Vitest lanes", () => {
|
||||
expect(baseConfig.test?.projects).toEqual([...rootVitestProjects]);
|
||||
});
|
||||
|
||||
it("keeps hard thread exceptions on forks", () => {
|
||||
expect(createGatewayVitestConfig().test.pool).toBe("forks");
|
||||
expect(createAgentsVitestConfig().test.pool).toBe("forks");
|
||||
expect(createCommandsVitestConfig().test.pool).toBe("forks");
|
||||
});
|
||||
|
||||
it("keeps the root ui lane aligned with the jsdom ui project setup", () => {
|
||||
const config = createUiVitestConfig();
|
||||
expect(config.test.environment).toBe("jsdom");
|
||||
expect(config.test.isolate).toBe(true);
|
||||
expect(config.test.runner).toBeUndefined();
|
||||
expect(config.test.setupFiles).toContain("ui/src/test-helpers/lit-warnings.setup.ts");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export function createAgentsVitestConfig(env?: Record<string, string | undefined
|
|||
dir: "src/agents",
|
||||
env,
|
||||
name: "agents",
|
||||
pool: "forks",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export function createCommandsVitestConfig(env?: Record<string, string | undefin
|
|||
dir: "src/commands",
|
||||
env,
|
||||
name: "commands",
|
||||
pool: "forks",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import { resolveLocalVitestMaxWorkers, sharedVitestConfig } from "./vitest.shared.config.ts";
|
||||
import {
|
||||
resolveDefaultVitestPool,
|
||||
resolveLocalVitestMaxWorkers,
|
||||
sharedVitestConfig,
|
||||
} from "./vitest.shared.config.ts";
|
||||
|
||||
export { resolveLocalVitestMaxWorkers };
|
||||
export { resolveDefaultVitestPool, resolveLocalVitestMaxWorkers };
|
||||
|
||||
export const rootVitestProjects = [
|
||||
"vitest.unit.config.ts",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export function createGatewayVitestConfig(env?: Record<string, string | undefine
|
|||
dir: "src/gateway",
|
||||
env,
|
||||
name: "gateway",
|
||||
pool: "forks",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,11 +42,14 @@ export function createScopedVitestConfig(
|
|||
options?: {
|
||||
dir?: string;
|
||||
env?: Record<string, string | undefined>;
|
||||
environment?: string;
|
||||
exclude?: string[];
|
||||
isolate?: boolean;
|
||||
name?: string;
|
||||
pool?: "threads" | "forks";
|
||||
passWithNoTests?: boolean;
|
||||
setupFiles?: string[];
|
||||
useNonIsolatedRunner?: boolean;
|
||||
},
|
||||
) {
|
||||
const base = sharedVitestConfig as Record<string, unknown>;
|
||||
|
|
@ -56,16 +59,26 @@ export function createScopedVitestConfig(
|
|||
[...(baseTest.exclude ?? []), ...(options?.exclude ?? [])],
|
||||
scopedDir,
|
||||
);
|
||||
const isolate = resolveVitestIsolation(options?.env);
|
||||
const isolate = options?.isolate ?? resolveVitestIsolation(options?.env);
|
||||
const setupFiles = [
|
||||
...new Set([
|
||||
...(baseTest.setupFiles ?? []),
|
||||
...(options?.setupFiles ?? []),
|
||||
"test/setup-openclaw-runtime.ts",
|
||||
]),
|
||||
];
|
||||
|
||||
return defineConfig({
|
||||
...base,
|
||||
test: {
|
||||
...baseTest,
|
||||
...(options?.name ? { name: options.name } : {}),
|
||||
...(options?.environment ? { environment: options.environment } : {}),
|
||||
isolate,
|
||||
runner: "./test/non-isolated-runner.ts",
|
||||
setupFiles: [...new Set([...(baseTest.setupFiles ?? []), "test/setup-openclaw-runtime.ts"])],
|
||||
...(options?.useNonIsolatedRunner === false
|
||||
? {}
|
||||
: { runner: "./test/non-isolated-runner.ts" }),
|
||||
setupFiles,
|
||||
...(scopedDir ? { dir: scopedDir } : {}),
|
||||
include: relativizeScopedPatterns(include, scopedDir),
|
||||
exclude,
|
||||
|
|
@ -73,7 +86,6 @@ export function createScopedVitestConfig(
|
|||
...(options?.passWithNoTests !== undefined
|
||||
? { passWithNoTests: options.passWithNoTests }
|
||||
: {}),
|
||||
...(options?.setupFiles ? { setupFiles: options.setupFiles } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ type VitestHostInfo = {
|
|||
totalMemoryBytes?: number;
|
||||
};
|
||||
|
||||
export type OpenClawVitestPool = "threads" | "forks";
|
||||
|
||||
function detectVitestHostInfo(): Required<VitestHostInfo> {
|
||||
return {
|
||||
cpuCount:
|
||||
|
|
@ -68,11 +70,22 @@ export function resolveLocalVitestMaxWorkers(
|
|||
return clamp(inferred, 1, 16);
|
||||
}
|
||||
|
||||
export function resolveDefaultVitestPool(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): OpenClawVitestPool {
|
||||
const configuredPool = (env.OPENCLAW_VITEST_POOL ?? env.OPENCLAW_TEST_POOL)?.trim();
|
||||
if (configuredPool === "threads" || configuredPool === "forks") {
|
||||
return configuredPool;
|
||||
}
|
||||
return "threads";
|
||||
}
|
||||
|
||||
const repoRoot = path.dirname(fileURLToPath(import.meta.url));
|
||||
const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
|
||||
const isWindows = process.platform === "win32";
|
||||
const localWorkers = resolveLocalVitestMaxWorkers();
|
||||
const ciWorkers = isWindows ? 2 : 3;
|
||||
const defaultPool = resolveDefaultVitestPool();
|
||||
|
||||
export const sharedVitestConfig = {
|
||||
resolve: {
|
||||
|
|
@ -96,7 +109,7 @@ export const sharedVitestConfig = {
|
|||
hookTimeout: isWindows ? 180_000 : 120_000,
|
||||
unstubEnvs: true,
|
||||
unstubGlobals: true,
|
||||
pool: "forks" as const,
|
||||
pool: defaultPool,
|
||||
maxWorkers: isCI ? ciWorkers : localWorkers,
|
||||
forceRerunTriggers: [
|
||||
"package.json",
|
||||
|
|
|
|||
|
|
@ -3,8 +3,12 @@ import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
|||
export function createUiVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(["ui/src/ui/**/*.test.ts"], {
|
||||
dir: "ui/src/ui",
|
||||
environment: "jsdom",
|
||||
env,
|
||||
isolate: true,
|
||||
name: "ui",
|
||||
setupFiles: ["ui/src/test-helpers/lit-warnings.setup.ts"],
|
||||
useNonIsolatedRunner: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue