ci: split remaining slow test shards

This commit is contained in:
Peter Steinberger
2026-04-20 19:15:31 +01:00
parent 9a71595d97
commit 7aebac697e
5 changed files with 84 additions and 44 deletions

View File

@@ -51,7 +51,7 @@ Local changed-lane logic lives in `scripts/changed-lanes.mjs` and is executed by
On pushes, the `checks` matrix adds the push-only `compat-node22` lane. On pull requests, that lane is skipped and the matrix stays focused on the normal test/channel lanes.
The slowest Node test families are split into include-file shards so each job stays small: channel contracts split registry/core/extension coverage into focused shards, and auto-reply reply tests split each large prefix group into two include-pattern shards. `check-additional` also separates package-boundary compile/canary work from runtime topology gateway/architecture work.
The slowest Node test families are split into include-file shards so each job stays small: channel contracts split registry and core coverage into four balanced shards each, auto-reply reply command tests split into four include-pattern shards, and the other large auto-reply reply prefix groups split into two shards each. `check-additional` also separates package-boundary compile/canary work from runtime topology gateway/architecture work.
## Runners

View File

@@ -14,31 +14,27 @@ function listContractTestFiles(rootDir = "src/channels/plugins/contracts") {
export function createChannelContractTestShards() {
const rootDir = "src/channels/plugins/contracts";
const groups = {
"checks-fast-contracts-channels-registry-a": [],
"checks-fast-contracts-channels-registry-b": [],
"checks-fast-contracts-channels-core-a": [],
"checks-fast-contracts-channels-core-b": [],
const suffixes = ["a", "b", "c", "d"];
const groups = Object.fromEntries(
["registry", "core"].flatMap((family) =>
suffixes.map((suffix) => [`checks-fast-contracts-channels-${family}-${suffix}`, []]),
),
);
const groupKeys = {
core: suffixes.map((suffix) => `checks-fast-contracts-channels-core-${suffix}`),
registry: suffixes.map((suffix) => `checks-fast-contracts-channels-registry-${suffix}`),
};
const pushBalanced = (firstKey, secondKey, file) => {
const target = groups[firstKey].length <= groups[secondKey].length ? firstKey : secondKey;
const pushBalanced = (keys, file) => {
const target = keys.toSorted((a, b) => groups[a].length - groups[b].length)[0];
groups[target].push(file);
};
for (const file of listContractTestFiles(rootDir)) {
const name = relative(rootDir, file).replaceAll("\\", "/");
if (name.startsWith("plugins-core.") || name.startsWith("plugin.")) {
pushBalanced(
"checks-fast-contracts-channels-core-a",
"checks-fast-contracts-channels-core-b",
file,
);
pushBalanced(groupKeys.core, file);
} else {
pushBalanced(
"checks-fast-contracts-channels-registry-a",
"checks-fast-contracts-channels-registry-b",
file,
);
pushBalanced(groupKeys.registry, file);
}
}

View File

@@ -66,21 +66,13 @@ function createAutoReplyReplySplitShards() {
}
return Object.entries(groups).flatMap(([groupName, includePatterns]) => {
const midpoint = Math.ceil(includePatterns.length / 2);
return [
{
shardName: `${groupName}-a`,
configs: ["test/vitest/vitest.auto-reply-reply.config.ts"],
includePatterns: includePatterns.slice(0, midpoint),
requiresDist: false,
},
{
shardName: `${groupName}-b`,
configs: ["test/vitest/vitest.auto-reply-reply.config.ts"],
includePatterns: includePatterns.slice(midpoint),
requiresDist: false,
},
].filter((shard) => shard.includePatterns.length > 0);
const shardCount = groupName === "auto-reply-reply-commands" ? 4 : 2;
return Array.from({ length: shardCount }, (_, index) => ({
shardName: `${groupName}-${String.fromCharCode(97 + index)}`,
configs: ["test/vitest/vitest.auto-reply-reply.config.ts"],
includePatterns: includePatterns.filter((_, fileIndex) => fileIndex % shardCount === index),
requiresDist: false,
})).filter((shard) => shard.includePatterns.length > 0);
});
}
@@ -164,13 +156,21 @@ const SPLIT_NODE_SHARDS = new Map([
requiresDist: false,
},
{
shardName: "agentic-agents-plugins",
shardName: "agentic-agents",
configs: ["test/vitest/vitest.agents.config.ts"],
requiresDist: false,
},
{
shardName: "agentic-plugin-sdk",
configs: [
"test/vitest/vitest.agents.config.ts",
"test/vitest/vitest.plugin-sdk-light.config.ts",
"test/vitest/vitest.plugin-sdk.config.ts",
"test/vitest/vitest.plugins.config.ts",
],
requiresDist: false,
},
{
shardName: "agentic-plugins",
configs: ["test/vitest/vitest.plugins.config.ts"],
requiresDist: true,
},
],

View File

@@ -33,6 +33,16 @@ describe("scripts/lib/channel-contract-test-plan.mjs", () => {
runtime: "node",
task: "contracts-channels",
},
{
checkName: "checks-fast-contracts-channels-registry-c",
runtime: "node",
task: "contracts-channels",
},
{
checkName: "checks-fast-contracts-channels-registry-d",
runtime: "node",
task: "contracts-channels",
},
{
checkName: "checks-fast-contracts-channels-core-a",
runtime: "node",
@@ -43,6 +53,16 @@ describe("scripts/lib/channel-contract-test-plan.mjs", () => {
runtime: "node",
task: "contracts-channels",
},
{
checkName: "checks-fast-contracts-channels-core-c",
runtime: "node",
task: "contracts-channels",
},
{
checkName: "checks-fast-contracts-channels-core-d",
runtime: "node",
task: "contracts-channels",
},
]);
});

View File

@@ -58,7 +58,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
"core-runtime-infra",
"core-runtime-media-ui",
"core-runtime-shared",
"agentic-agents-plugins",
"agentic-plugins",
]);
});
@@ -109,11 +109,13 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
]);
});
it("splits the agentic lane into control-plane, commands, and agent/plugin shards", () => {
it("splits the agentic lane into control-plane, commands, agent, SDK, and plugin shards", () => {
const shards = createNodeTestShards();
const controlPlaneShard = shards.find((shard) => shard.shardName === "agentic-control-plane");
const commandsShard = shards.find((shard) => shard.shardName === "agentic-commands");
const agentPluginShard = shards.find((shard) => shard.shardName === "agentic-agents-plugins");
const agentShard = shards.find((shard) => shard.shardName === "agentic-agents");
const pluginSdkShard = shards.find((shard) => shard.shardName === "agentic-plugin-sdk");
const pluginsShard = shards.find((shard) => shard.shardName === "agentic-plugins");
expect(controlPlaneShard).toEqual({
checkName: "checks-node-agentic-control-plane",
@@ -137,15 +139,25 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
],
requiresDist: false,
});
expect(agentPluginShard).toEqual({
checkName: "checks-node-agentic-agents-plugins",
shardName: "agentic-agents-plugins",
expect(agentShard).toEqual({
checkName: "checks-node-agentic-agents",
shardName: "agentic-agents",
configs: ["test/vitest/vitest.agents.config.ts"],
requiresDist: false,
});
expect(pluginSdkShard).toEqual({
checkName: "checks-node-agentic-plugin-sdk",
shardName: "agentic-plugin-sdk",
configs: [
"test/vitest/vitest.agents.config.ts",
"test/vitest/vitest.plugin-sdk-light.config.ts",
"test/vitest/vitest.plugin-sdk.config.ts",
"test/vitest/vitest.plugins.config.ts",
],
requiresDist: false,
});
expect(pluginsShard).toEqual({
checkName: "checks-node-agentic-plugins",
shardName: "agentic-plugins",
configs: ["test/vitest/vitest.plugins.config.ts"],
requiresDist: true,
});
});
@@ -198,6 +210,18 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
requiresDist: false,
shardName: "auto-reply-reply-commands-b",
},
{
checkName: "checks-node-auto-reply-reply-commands-c",
configs: ["test/vitest/vitest.auto-reply-reply.config.ts"],
requiresDist: false,
shardName: "auto-reply-reply-commands-c",
},
{
checkName: "checks-node-auto-reply-reply-commands-d",
configs: ["test/vitest/vitest.auto-reply-reply.config.ts"],
requiresDist: false,
shardName: "auto-reply-reply-commands-d",
},
{
checkName: "checks-node-auto-reply-reply-dispatch-a",
configs: ["test/vitest/vitest.auto-reply-reply.config.ts"],