improve(ci): stripe giant compact test groups (#123142)

* ci: stripe media-ui, gateway-core, and security compact groups

* fix(ci): preserve compact stripe config ownership
This commit is contained in:
Peter Steinberger
2026-08-13 10:46:38 -07:00
committed by GitHub
parent 165a2e9ede
commit 2a70d849e8
3 changed files with 311 additions and 105 deletions
+151 -36
View File
@@ -17,10 +17,19 @@ import {
embeddedAgentVitestProjectOwners,
} from "../vitest/vitest.agents-paths.mjs";
import { commandsLightTestFiles } from "../vitest/vitest.commands-light-paths.mjs";
import { createGatewayClientVitestConfig } from "../vitest/vitest.gateway-client.config.ts";
import { createGatewayCoreVitestConfig } from "../vitest/vitest.gateway-core.config.ts";
import { isGatewayServerTestFile } from "../vitest/vitest.gateway-server-paths.mjs";
import { createGatewayServerVitestConfig } from "../vitest/vitest.gateway-server.config.ts";
import { createMediaUnderstandingVitestConfig } from "../vitest/vitest.media-understanding.config.ts";
import { createMediaVitestConfig } from "../vitest/vitest.media.config.ts";
import { createPluginsVitestConfig } from "../vitest/vitest.plugins.config.ts";
import { createToolingVitestConfig } from "../vitest/vitest.tooling.config.ts";
import { createTuiVitestConfig } from "../vitest/vitest.tui.config.ts";
import { createUiIsolatedVitestConfig } from "../vitest/vitest.ui-isolated.config.ts";
import { createUiVitestConfig } from "../vitest/vitest.ui.config.ts";
import { createUnitVitestConfigWithOptions } from "../vitest/vitest.unit.config.ts";
import { createWizardVitestConfig } from "../vitest/vitest.wizard.config.ts";
type VitestTestConfig = {
dir?: string;
@@ -268,7 +277,7 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
// Rebalancing may change ownership, but the compact plan stays within the
// CI workflow's 28-worker cap.
expect(compact).toHaveLength(25);
expect(compact).toHaveLength(28);
expect(compact.every((shard) => Array.isArray(shard.groups))).toBe(true);
expect(compact.every((shard) => shard.groups.length <= 10)).toBe(true);
expect(compact.some((shard) => shard.requiresDist)).toBe(true);
@@ -279,18 +288,18 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
),
),
).toBe(true);
// Runtime-balanced packing must keep the two heaviest measured groups in
// different jobs; regressing to per-file weights recombines them.
const jobOf = (name: string) =>
compact.findIndex((shard) => shard.groups.some((group) => group.shard_name === name));
expect(jobOf("agentic-agents-core-runner-embedded")).toBeGreaterThanOrEqual(0);
// The complete Control UI and model catalog both cold-load broad graphs;
// pairing them starves model visibility and repeatedly hits its timeout.
expect(jobOf("agentic-agents-core-models")).not.toBe(jobOf("core-runtime-media-ui"));
expect(jobOf("core-runtime-media-ui")).not.toBe(jobOf("core-unit-src-security"));
expect(
compact[jobOf("core-unit-src-security")]?.groups.map((group) => group.shard_name),
).toEqual(["core-unit-src-security"]);
for (const prefix of [
"agentic-gateway-core",
"core-runtime-media-ui",
"core-unit-src-security",
]) {
expect(jobOf(`${prefix}-1`)).toBeGreaterThanOrEqual(0);
expect(jobOf(`${prefix}-2`)).toBeGreaterThanOrEqual(0);
expect(jobOf(`${prefix}-1`)).not.toBe(jobOf(`${prefix}-2`));
}
// Cheap stripes may legally co-locate in one bin; only existence matters.
expect(jobOf("core-unit-fast-1")).toBeGreaterThanOrEqual(0);
expect(jobOf("core-unit-fast-2")).toBeGreaterThanOrEqual(0);
@@ -356,6 +365,20 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
).toEqual({
OPENCLAW_VITEST_MAX_WORKERS: "2",
});
for (const prefix of ["agentic-gateway-core", "core-runtime-media-ui"]) {
for (const suffix of ["1", "2"]) {
expect(
compact
.flatMap((shard) => shard.groups)
.find((group) => group.shard_name === `${prefix}-${suffix}`)?.env,
).toEqual({ OPENCLAW_VITEST_MAX_WORKERS: "2" });
}
}
expect(
compact
.flatMap((shard) => shard.groups)
.find((group) => group.shard_name === "core-runtime-media-ui-support")?.env,
).toEqual({ OPENCLAW_VITEST_MAX_WORKERS: "2" });
const startupCoreJob = compact.find((shard) =>
shard.groups.some((group) => group.shard_name === "agentic-control-plane-startup-core"),
);
@@ -377,13 +400,13 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
(shard) => !shard.requiresDist && shard.checkName.startsWith("checks-node-compact-small-"),
);
const distJobs = compact.filter((shard) => shard.requiresDist);
expect(largeJobs).toHaveLength(7);
expect(smallJobs).toHaveLength(16);
expect(largeJobs).toHaveLength(9);
expect(smallJobs).toHaveLength(17);
expect(distJobs).toHaveLength(2);
const regularSmallJobs = smallJobs.filter((shard) =>
shard.groups.every((group) => !exclusiveGroupRe.test(group.shard_name)),
);
expect(regularSmallJobs).toHaveLength(11);
expect(regularSmallJobs).toHaveLength(12);
const routed8VcpuCheckNames = [
"checks-node-compact-small-2",
"checks-node-compact-small-5",
@@ -402,12 +425,14 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
// The refreshed hosted estimates give every regular bin one known tail
// anchor. Stale hints paired two slow groups in each runner class.
const largeTailAnchors = [
"core-unit-src-security",
"agentic-gateway-core",
"core-runtime-media-ui",
"core-unit-src-security-1",
"core-unit-src-security-2",
"agentic-gateway-core-1",
"agentic-gateway-core-2",
"core-runtime-media-ui-1",
"core-runtime-media-ui-2",
"agentic-agents-support",
"agentic-gateway-methods",
"agentic-agents-core-runtime",
"core-unit-fast-isolated",
];
const smallTailAnchors = [
@@ -422,6 +447,7 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
"agentic-commands-doctor-config-state",
"core-runtime-shared",
"auto-reply-reply-state-routing",
"auto-reply-reply-agent-runner",
];
expect(
largeJobs.map(
@@ -531,12 +557,19 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
shardName: "core-unit-fast-isolated",
},
{
configs: [
"test/vitest/vitest.unit-src.config.ts",
"test/vitest/vitest.unit-security.config.ts",
],
configs: ["test/vitest/vitest.unit-src.config.ts"],
requiresDist: false,
shardName: "core-unit-src-security",
shardName: "core-unit-src-security-1",
},
{
configs: ["test/vitest/vitest.unit-src.config.ts"],
requiresDist: false,
shardName: "core-unit-src-security-2",
},
{
configs: ["test/vitest/vitest.unit-security.config.ts"],
requiresDist: false,
shardName: "core-unit-src-security-support",
},
{
configs: ["test/vitest/vitest.unit-support.config.ts"],
@@ -546,6 +579,71 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
]);
});
it("partitions each giant compact group across two deterministic stripes", () => {
const env = { ...process.env, OPENCLAW_VITEST_INCLUDE_FILE: undefined };
const cases = [
{
stripeConfigs: [createUiVitestConfig(env)],
supportConfigs: [
createMediaVitestConfig(env),
createMediaUnderstandingVitestConfig(env),
createTuiVitestConfig(env),
createUiIsolatedVitestConfig(env),
createWizardVitestConfig(env),
],
prefix: "core-runtime-media-ui",
},
{
stripeConfigs: [createGatewayCoreVitestConfig(env), createGatewayClientVitestConfig(env)],
supportConfigs: [],
prefix: "agentic-gateway-core",
},
{
stripeConfigs: [
createUnitVitestConfigWithOptions(env, {
name: "unit-src",
includePatterns: ["src/**/*.test.ts"],
extraExcludePatterns: ["src/acp/**", "src/security/**"],
}),
],
supportConfigs: [
createUnitVitestConfigWithOptions(env, {
name: "unit-security",
includePatterns: ["src/security/**/*.test.ts"],
passWithNoTests: true,
}),
],
prefix: "core-unit-src-security",
},
];
const shards = createNodeTestShards();
for (const { prefix, stripeConfigs, supportConfigs } of cases) {
const stripes = shards.filter(
(shard) => /^.+-\d+$/u.test(shard.shardName) && shard.shardName.startsWith(`${prefix}-`),
);
const actual = stripes
.flatMap((stripe) => stripe.includePatterns ?? [])
.toSorted((a, b) => a.localeCompare(b));
const expected = stripeConfigs
.flatMap((config) => listMatchedTestFiles(config))
.toSorted((a, b) => a.localeCompare(b));
expect(stripes.map((stripe) => stripe.shardName)).toEqual([`${prefix}-1`, `${prefix}-2`]);
expect(stripes.every((stripe) => (stripe.includePatterns?.length ?? 0) > 0)).toBe(true);
expect(new Set(actual).size).toBe(actual.length);
expect(actual).toEqual(expected);
const support = shards.find((shard) => shard.shardName === `${prefix}-support`);
if (supportConfigs.length === 0) {
expect(support).toBeUndefined();
} else {
expect(support?.includePatterns).toBeUndefined();
expect(support?.configs).toHaveLength(supportConfigs.length);
}
}
});
it("names the node shard checks as core test lanes", () => {
const shards = createNodeTestShards();
@@ -817,18 +915,29 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
runner: "blacksmith-4vcpu-ubuntu-2404",
shardName: "core-runtime-tui-pty",
},
{
configs: ["test/vitest/vitest.ui.config.ts"],
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
shardName: "core-runtime-media-ui-1",
},
{
configs: ["test/vitest/vitest.ui.config.ts"],
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
shardName: "core-runtime-media-ui-2",
},
{
configs: [
"test/vitest/vitest.media.config.ts",
"test/vitest/vitest.media-understanding.config.ts",
"test/vitest/vitest.tui.config.ts",
"test/vitest/vitest.ui.config.ts",
"test/vitest/vitest.ui-isolated.config.ts",
"test/vitest/vitest.wizard.config.ts",
],
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
shardName: "core-runtime-media-ui",
shardName: "core-runtime-media-ui-support",
},
{
configs: [
@@ -950,7 +1059,9 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
);
const commandShards = shards.filter((shard) => shard.shardName.startsWith("agentic-commands-"));
const agentShards = shards.filter((shard) => shard.shardName.startsWith("agentic-agents-"));
const gatewayCoreShard = shards.find((shard) => shard.shardName === "agentic-gateway-core");
const gatewayCoreShards = shards.filter((shard) =>
shard.shardName.startsWith("agentic-gateway-core-"),
);
const gatewayMethodsShard = shards.find(
(shard) => shard.shardName === "agentic-gateway-methods",
);
@@ -1200,16 +1311,19 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
});
expect(gatewayCoreShard).toEqual({
checkName: "checks-node-agentic-gateway-core",
shardName: "agentic-gateway-core",
configs: [
"test/vitest/vitest.gateway-core.config.ts",
"test/vitest/vitest.gateway-client.config.ts",
],
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
});
expect(gatewayCoreShards).toEqual(
[1, 2].map((stripe) => ({
checkName: `checks-node-agentic-gateway-core-${stripe}`,
shardName: `agentic-gateway-core-${stripe}`,
configs: [
"test/vitest/vitest.gateway-core.config.ts",
"test/vitest/vitest.gateway-client.config.ts",
],
includePatterns: gatewayCoreShards[stripe - 1]?.includePatterns,
requiresDist: false,
runner: DEFAULT_NODE_TEST_RUNNER,
})),
);
expect(gatewayMethodsShard).toEqual({
checkName: "checks-node-agentic-gateway-methods",
shardName: "agentic-gateway-methods",
@@ -1294,7 +1408,8 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
const shardNames = shards.map((shard) => shard.shardName);
expect(shardNames).not.toContain("agentic-plugins");
expect(shardNames).toContain("agentic-gateway-core");
expect(shardNames).toContain("agentic-gateway-core-1");
expect(shardNames).toContain("agentic-gateway-core-2");
expect(shardNames).toContain("agentic-gateway-methods");
expect(shardNames).toContain("agentic-plugin-sdk");
});