mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
test(ci): isolate flaky shared-worker suites (#107780)
* test(ci): isolate flaky shared-worker suites * test(ci): route isolated agent targets
This commit is contained in:
committed by
GitHub
parent
890f20be06
commit
86085563be
@@ -1,5 +1,6 @@
|
||||
// Builds CI node/Vitest shard plans from the full suite configuration.
|
||||
import { relative } from "node:path";
|
||||
import { agentsCoreIsolatedTestFiles } from "../../test/vitest/vitest.agents-paths.mjs";
|
||||
import { commandsLightTestFiles } from "../../test/vitest/vitest.commands-light-paths.mjs";
|
||||
import { fullSuiteVitestShards } from "../../test/vitest/vitest.test-shards.mjs";
|
||||
import { toolingIsolatedTestFiles } from "../../test/vitest/vitest.tooling-isolated-paths.mjs";
|
||||
@@ -280,17 +281,18 @@ function resolveAgentCoreShardName(file) {
|
||||
}
|
||||
|
||||
function createAgentCoreSplitShards() {
|
||||
const isolatedTests = new Set(agentsCoreIsolatedTestFiles);
|
||||
const groups = new Map();
|
||||
for (const file of listTestFiles("src/agents")) {
|
||||
const name = relative("src/agents", file).replaceAll("\\", "/");
|
||||
if (name.includes("/")) {
|
||||
if (name.includes("/") || isolatedTests.has(file)) {
|
||||
continue;
|
||||
}
|
||||
const shardName = resolveAgentCoreShardName(file);
|
||||
groups.set(shardName, [...(groups.get(shardName) ?? []), file]);
|
||||
}
|
||||
|
||||
return [
|
||||
const sharedShards = [
|
||||
"agentic-agents-core-auth",
|
||||
"agentic-agents-core-models",
|
||||
"agentic-agents-core-tools",
|
||||
@@ -305,6 +307,16 @@ function createAgentCoreSplitShards() {
|
||||
shardName,
|
||||
}))
|
||||
.filter((shard) => shard.includePatterns.length > 0);
|
||||
|
||||
return [
|
||||
...sharedShards,
|
||||
{
|
||||
configs: ["test/vitest/vitest.agents-core-isolated.config.ts"],
|
||||
includePatterns: agentsCoreIsolatedTestFiles,
|
||||
requiresDist: false,
|
||||
shardName: "agentic-agents-core-isolated",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const GATEWAY_SERVER_BACKED_HTTP_TESTS = new Set([
|
||||
|
||||
@@ -6,6 +6,10 @@ import { randomUUID } from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import {
|
||||
agentsCoreIsolatedTestFiles,
|
||||
isAgentsCoreIsolatedTestFile,
|
||||
} from "../test/vitest/vitest.agents-paths.mjs";
|
||||
import { isChannelSurfaceTestFile } from "../test/vitest/vitest.channel-paths.mjs";
|
||||
import {
|
||||
commandsLightTestFiles,
|
||||
@@ -70,6 +74,7 @@ import {
|
||||
} from "./run-vitest.mjs";
|
||||
|
||||
const DEFAULT_VITEST_CONFIG = "test/vitest/vitest.unit.config.ts";
|
||||
const AGENTS_CORE_ISOLATED_VITEST_CONFIG = "test/vitest/vitest.agents-core-isolated.config.ts";
|
||||
const AGENTS_CORE_VITEST_CONFIG = "test/vitest/vitest.agents-core.config.ts";
|
||||
const AGENTS_EMBEDDED_AGENT_VITEST_CONFIG = "test/vitest/vitest.agents-embedded-agent.config.ts";
|
||||
const AGENTS_SUPPORT_VITEST_CONFIG = "test/vitest/vitest.agents-support.config.ts";
|
||||
@@ -314,6 +319,7 @@ const VITEST_CONFIG_BY_KIND = {
|
||||
agentSupport: AGENTS_SUPPORT_VITEST_CONFIG,
|
||||
agentTools: AGENTS_TOOLS_VITEST_CONFIG,
|
||||
agent: AGENTS_VITEST_CONFIG,
|
||||
agentsCoreIsolated: AGENTS_CORE_ISOLATED_VITEST_CONFIG,
|
||||
agentsCore: AGENTS_CORE_VITEST_CONFIG,
|
||||
agentsSupport: AGENTS_SUPPORT_VITEST_CONFIG,
|
||||
agentsTools: AGENTS_TOOLS_VITEST_CONFIG,
|
||||
@@ -2563,6 +2569,7 @@ function listUnitFastFullSuiteTestTargets() {
|
||||
}
|
||||
|
||||
function listAgentsCoreFullSuiteTestTargets(cwd) {
|
||||
const isolatedTests = new Set(agentsCoreIsolatedTestFiles);
|
||||
const agentsDir = path.join(cwd, "src/agents");
|
||||
if (!fs.existsSync(agentsDir)) {
|
||||
return [];
|
||||
@@ -2571,6 +2578,7 @@ function listAgentsCoreFullSuiteTestTargets(cwd) {
|
||||
.readdirSync(agentsDir, { withFileTypes: true })
|
||||
.filter((entry) => entry.isFile() && entry.name.endsWith(".test.ts"))
|
||||
.map((entry) => `src/agents/${entry.name}`)
|
||||
.filter((file) => !isolatedTests.has(file))
|
||||
.toSorted((left, right) => left.localeCompare(right));
|
||||
}
|
||||
|
||||
@@ -3758,6 +3766,9 @@ function classifyTarget(arg, cwd) {
|
||||
if (configTargetKind) {
|
||||
return configTargetKind;
|
||||
}
|
||||
if (isAgentsCoreIsolatedTestFile(relative)) {
|
||||
return "agentsCoreIsolated";
|
||||
}
|
||||
if (isControlUiE2eTarget(relative)) {
|
||||
return "uiE2e";
|
||||
}
|
||||
@@ -4205,6 +4216,7 @@ export function buildVitestRunPlans(
|
||||
"agentSupport",
|
||||
"agentTools",
|
||||
"agent",
|
||||
"agentsCoreIsolated",
|
||||
"agentsCore",
|
||||
"agentsSupport",
|
||||
"agentsTools",
|
||||
|
||||
@@ -184,8 +184,8 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
|
||||
compact: true,
|
||||
});
|
||||
|
||||
expect(compact).toHaveLength(15);
|
||||
expect(compact.filter((shard) => !shard.requiresDist)).toHaveLength(14);
|
||||
expect(compact).toHaveLength(16);
|
||||
expect(compact.filter((shard) => !shard.requiresDist)).toHaveLength(15);
|
||||
expect(compact.every((shard) => Array.isArray(shard.groups))).toBe(true);
|
||||
expect(compact.some((shard) => shard.requiresDist)).toBe(true);
|
||||
expect(
|
||||
@@ -874,6 +874,14 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
|
||||
runner: DEFAULT_NODE_TEST_RUNNER,
|
||||
shardName: "agentic-agents-core-runtime",
|
||||
},
|
||||
{
|
||||
checkName: "checks-node-agentic-agents-core-isolated",
|
||||
configs: ["test/vitest/vitest.agents-core-isolated.config.ts"],
|
||||
includePatterns: agentShards[6]?.includePatterns,
|
||||
requiresDist: false,
|
||||
runner: DEFAULT_NODE_TEST_RUNNER,
|
||||
shardName: "agentic-agents-core-isolated",
|
||||
},
|
||||
{
|
||||
checkName: "checks-node-agentic-agents-embedded",
|
||||
configs: ["test/vitest/vitest.agents-embedded-agent.config.ts"],
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from "../../scripts/test-projects.test-support.mjs";
|
||||
import { captureReaddirSyncCallsDuring } from "../../src/test-utils/fs-scan-assertions.js";
|
||||
import { toRepoPath } from "../../src/test-utils/repo-files.js";
|
||||
import { agentsCoreIsolatedTestFiles } from "../vitest/vitest.agents-paths.mjs";
|
||||
import {
|
||||
channelConfigContractPatterns,
|
||||
channelRegistryContractPatterns,
|
||||
@@ -2466,6 +2467,34 @@ describe("scripts/test-projects changed-target routing", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
"test/scripts/check-extension-package-tsc-boundary.test.ts",
|
||||
"test/scripts/control-ui-i18n.test.ts",
|
||||
])("routes process-group test %s to the isolated tooling shard", (testFile) => {
|
||||
expect(buildVitestRunPlans([testFile])).toEqual([
|
||||
{
|
||||
config: "test/vitest/vitest.tooling-isolated.config.ts",
|
||||
forwardedArgs: [],
|
||||
includePatterns: [testFile],
|
||||
watchMode: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it.each(agentsCoreIsolatedTestFiles)(
|
||||
"routes isolated agent test %s to the isolated agents-core shard",
|
||||
(testFile) => {
|
||||
expect(buildVitestRunPlans([testFile])).toEqual([
|
||||
{
|
||||
config: "test/vitest/vitest.agents-core-isolated.config.ts",
|
||||
forwardedArgs: [],
|
||||
includePatterns: [testFile],
|
||||
watchMode: false,
|
||||
},
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it("routes Docker E2E script targets to their owner tooling tests", () => {
|
||||
const targets = [
|
||||
"scripts/e2e/kitchen-sink-plugin-docker.sh",
|
||||
@@ -2693,7 +2722,11 @@ describe("scripts/test-projects changed-target routing", () => {
|
||||
{
|
||||
config: "test/vitest/vitest.tooling-isolated.config.ts",
|
||||
forwardedArgs: [],
|
||||
includePatterns: ["test/scripts/openclaw-e2e-instance.test.ts"],
|
||||
includePatterns: [
|
||||
"test/scripts/check-extension-package-tsc-boundary.test.ts",
|
||||
"test/scripts/control-ui-i18n.test.ts",
|
||||
"test/scripts/openclaw-e2e-instance.test.ts",
|
||||
],
|
||||
watchMode: false,
|
||||
},
|
||||
]);
|
||||
@@ -2837,7 +2870,11 @@ describe("scripts/test-projects changed-target routing", () => {
|
||||
{
|
||||
config: "test/vitest/vitest.tooling-isolated.config.ts",
|
||||
forwardedArgs: [],
|
||||
includePatterns: ["test/scripts/openclaw-e2e-instance.test.ts"],
|
||||
includePatterns: [
|
||||
"test/scripts/check-extension-package-tsc-boundary.test.ts",
|
||||
"test/scripts/control-ui-i18n.test.ts",
|
||||
"test/scripts/openclaw-e2e-instance.test.ts",
|
||||
],
|
||||
watchMode: false,
|
||||
},
|
||||
]);
|
||||
@@ -3404,7 +3441,7 @@ describe("scripts/test-projects changed-target routing", () => {
|
||||
]),
|
||||
).toEqual([
|
||||
{
|
||||
config: "test/vitest/vitest.tooling.config.ts",
|
||||
config: "test/vitest/vitest.tooling-isolated.config.ts",
|
||||
forwardedArgs: [],
|
||||
includePatterns: ["test/scripts/control-ui-i18n.test.ts"],
|
||||
watchMode: false,
|
||||
@@ -4461,6 +4498,7 @@ describe("scripts/test-projects full-suite sharding", () => {
|
||||
"test/vitest/vitest.cli.config.ts",
|
||||
"test/vitest/vitest.commands-light.config.ts",
|
||||
"test/vitest/vitest.commands.config.ts",
|
||||
"test/vitest/vitest.agents-core-isolated.config.ts",
|
||||
...agentsCorePlans.map(() => agentsCoreConfig),
|
||||
"test/vitest/vitest.agents-embedded-agent.config.ts",
|
||||
"test/vitest/vitest.agents-support.config.ts",
|
||||
|
||||
@@ -7,6 +7,9 @@ import { describe, expect, it } from "vitest";
|
||||
import { cleanupTempDirs, makeTempDir } from "./helpers/temp-dir.js";
|
||||
import { normalizeConfigPath, normalizeConfigPaths } from "./helpers/vitest-config-paths.js";
|
||||
import { createAcpVitestConfig } from "./vitest/vitest.acp.config.ts";
|
||||
import { createAgentsCoreIsolatedVitestConfig } from "./vitest/vitest.agents-core-isolated.config.ts";
|
||||
import { createAgentsCoreVitestConfig } from "./vitest/vitest.agents-core.config.ts";
|
||||
import { agentsCoreIsolatedTestFiles } from "./vitest/vitest.agents-paths.mjs";
|
||||
import { createAgentsVitestConfig } from "./vitest/vitest.agents.config.ts";
|
||||
import { createAutoReplyCoreVitestConfig } from "./vitest/vitest.auto-reply-core.config.ts";
|
||||
import { createAutoReplyReplyVitestConfig } from "./vitest/vitest.auto-reply-reply.config.ts";
|
||||
@@ -566,6 +569,8 @@ describe("scoped vitest configs", () => {
|
||||
const defaultAutoReplyTopLevelConfig = createAutoReplyTopLevelVitestConfig({});
|
||||
const defaultAutoReplyReplyConfig = createAutoReplyReplyVitestConfig({});
|
||||
const defaultAgentsConfig = createAgentsVitestConfig({});
|
||||
const defaultAgentsCoreConfig = createAgentsCoreVitestConfig({});
|
||||
const defaultAgentsCoreIsolatedConfig = createAgentsCoreIsolatedVitestConfig({});
|
||||
const defaultPluginsConfig = createPluginsVitestConfig({});
|
||||
const defaultProcessConfig = createProcessVitestConfig({});
|
||||
const defaultToolingDockerConfig = createToolingDockerVitestConfig({});
|
||||
@@ -638,6 +643,19 @@ describe("scoped vitest configs", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("isolates media task status suites from conflicting task-runtime mocks", () => {
|
||||
const sharedConfig = requireTestConfig(defaultAgentsCoreConfig);
|
||||
const isolatedConfig = requireTestConfig(defaultAgentsCoreIsolatedConfig);
|
||||
|
||||
const scopedIsolatedFiles = agentsCoreIsolatedTestFiles.map((file) =>
|
||||
file.replace("src/agents/", ""),
|
||||
);
|
||||
expect(sharedConfig.exclude).toEqual(expect.arrayContaining(scopedIsolatedFiles));
|
||||
expect(isolatedConfig.include).toEqual(scopedIsolatedFiles);
|
||||
expect(isolatedConfig.isolate).toBe(true);
|
||||
expect(isolatedConfig.runner).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps selected plugin-sdk and commands light lanes off the openclaw runtime setup", () => {
|
||||
expect(normalizeConfigPaths(requireTestConfig(defaultPluginSdkLightConfig).setupFiles)).toEqual(
|
||||
["test/setup.ts"],
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Vitest agents core isolated config separates suites with conflicting module mocks.
|
||||
import { agentsCoreIsolatedTestFiles } from "./vitest.agents-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createAgentsCoreIsolatedVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(agentsCoreIsolatedTestFiles, {
|
||||
dir: "src/agents",
|
||||
env,
|
||||
isolate: true,
|
||||
name: "agents-core-isolated",
|
||||
passWithNoTests: true,
|
||||
useNonIsolatedRunner: false,
|
||||
});
|
||||
}
|
||||
|
||||
export default createAgentsCoreIsolatedVitestConfig();
|
||||
@@ -1,11 +1,12 @@
|
||||
// Vitest agents core config wires the agents core test shard.
|
||||
import { agentsCoreTestPatterns } from "./vitest.agents-paths.mjs";
|
||||
import { agentsCoreIsolatedTestFiles, agentsCoreTestPatterns } from "./vitest.agents-paths.mjs";
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
|
||||
export function createAgentsCoreVitestConfig(env?: Record<string, string | undefined>) {
|
||||
return createScopedVitestConfig(agentsCoreTestPatterns, {
|
||||
dir: "src/agents",
|
||||
env,
|
||||
exclude: agentsCoreIsolatedTestFiles,
|
||||
fileParallelism: false,
|
||||
name: "agents-core",
|
||||
});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export const agentsAllTestPatterns: string[];
|
||||
export const agentsCoreIsolatedTestFiles: string[];
|
||||
export function isAgentsCoreIsolatedTestFile(file: string): boolean;
|
||||
export const agentsCoreTestPatterns: string[];
|
||||
export const agentsEmbeddedTestPatterns: string[];
|
||||
export const agentsToolsTestPatterns: string[];
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
// Test routing globs for agent core, embedded-agent, tool, and support suites.
|
||||
export const agentsAllTestPatterns = ["src/agents/**/*.test.ts"];
|
||||
|
||||
// These suites install different mocks for the same task-runtime module. Keep
|
||||
// their module graphs separate from the shared agents-core worker.
|
||||
export const agentsCoreIsolatedTestFiles = [
|
||||
"src/agents/image-generation-task-status.test.ts",
|
||||
"src/agents/media-generation-task-status-shared.test.ts",
|
||||
"src/agents/video-generation-task-status.test.ts",
|
||||
];
|
||||
|
||||
const agentsCoreIsolatedTestFileSet = new Set(agentsCoreIsolatedTestFiles);
|
||||
|
||||
export function isAgentsCoreIsolatedTestFile(value) {
|
||||
return agentsCoreIsolatedTestFileSet.has(value.replaceAll("\\", "/"));
|
||||
}
|
||||
|
||||
export const agentsCoreTestPatterns = ["src/agents/*.test.ts"];
|
||||
|
||||
export const agentsEmbeddedTestPatterns = ["src/agents/embedded-agent-runner/**/*.test.ts"];
|
||||
|
||||
@@ -32,6 +32,7 @@ export const rootVitestProjects = [
|
||||
"test/vitest/vitest.commands-light.config.ts",
|
||||
"test/vitest/vitest.commands.config.ts",
|
||||
"test/vitest/vitest.auto-reply.config.ts",
|
||||
"test/vitest/vitest.agents-core-isolated.config.ts",
|
||||
"test/vitest/vitest.agents-core.config.ts",
|
||||
"test/vitest/vitest.agents-embedded-agent.config.ts",
|
||||
"test/vitest/vitest.agents-support.config.ts",
|
||||
|
||||
@@ -98,6 +98,7 @@ export const fullSuiteVitestShards = [
|
||||
"test/vitest/vitest.cli.config.ts",
|
||||
"test/vitest/vitest.commands-light.config.ts",
|
||||
"test/vitest/vitest.commands.config.ts",
|
||||
"test/vitest/vitest.agents-core-isolated.config.ts",
|
||||
"test/vitest/vitest.agents-core.config.ts",
|
||||
"test/vitest/vitest.agents-embedded-agent.config.ts",
|
||||
"test/vitest/vitest.agents-support.config.ts",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Tooling tests that need fresh module or process state instead of the shared serial worker.
|
||||
export const toolingIsolatedTestFiles = [
|
||||
"test/plugins/bundled-provider-auth-literal-parity.test.ts",
|
||||
"test/scripts/check-extension-package-tsc-boundary.test.ts",
|
||||
"test/scripts/control-ui-i18n.test.ts",
|
||||
"test/scripts/openclaw-e2e-instance.test.ts",
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user