mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
test(gateway): give module-mocking Gateway tests a private module graph
`server.sessions.compaction-read-errors` mocks `config/sessions/session-accessor.sqlite-read.js`, but production reaches `loadTranscriptEvents` through re-exports: `server-methods/sessions-compact.ts` imports it from the `session-accessor.js` barrel and `preflightSessionTranscriptForManualCompact` imports it from the leaf. The `gateway-server` project is `isolate: false`, so when a neighbour has already evaluated those importers they stay bound to the real implementation and the mock never fires -- the injected read error simply does not happen and all three tests fail with `expected true to be false`, reading like a product regression. Trigger:33744584f3added `server.chat-metadata-boundary.test.ts`, which boots a full non-minimal Gateway in `beforeAll` and lands immediately before this file in the shard. Main has gone red on it repeatedly since (32338154086, 32339521003, 32339928383, 32341300955, 32341946296);e294c154a6fixed only the sibling symptom where the factory had not run yet. Route the file to a new `gateway-server-isolated` project instead, mirroring `unit-fast-isolated` -- whose comment describes this exact hazard. A fresh graph per file makes both symptoms structurally impossible rather than order-dependent. The list is explicit so the reason travels with the file. Not reproducible on macOS: the exact 24-file stripe in CI's own order, and the triggering pair three times, are green locally every time.
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
import { commandsLightTestFiles } from "../../test/vitest/vitest.commands-light-paths.mjs";
|
||||
import {
|
||||
gatewayServerExcludedTestFiles,
|
||||
gatewayServerIsolatedTestFiles,
|
||||
isGatewayServerBackedHttpTestFile,
|
||||
isGatewayServerTestFile,
|
||||
} from "../../test/vitest/vitest.gateway-server-paths.mjs";
|
||||
@@ -264,6 +265,8 @@ const COMPACT_GROUP_SECONDS_HINTS = new Map<string, number>([
|
||||
["agentic-gateway-core-1", 99],
|
||||
["agentic-gateway-core-2", 99],
|
||||
["agentic-gateway-core-3", 99],
|
||||
// One small file that pays a full cold module graph because it runs isolated.
|
||||
["agentic-gateway-server-isolated", 30],
|
||||
["agentic-gateway-methods", 157],
|
||||
["agentic-plugin-sdk", 45],
|
||||
["auto-reply-core-top-level", 27],
|
||||
@@ -1637,7 +1640,10 @@ function createCoreRuntimeMediaUiSplitShards(): NodeTestSplitShard[] {
|
||||
|
||||
function createAgenticGatewayCoreSplitShards(): NodeTestSplitShard[] {
|
||||
const unitFastFiles = new Set(getUnitFastTestFiles());
|
||||
const excludedGatewayFiles = new Set(gatewayServerExcludedTestFiles);
|
||||
const excludedGatewayFiles = new Set([
|
||||
...gatewayServerExcludedTestFiles,
|
||||
...gatewayServerIsolatedTestFiles,
|
||||
]);
|
||||
const gatewayFiles = listTestFiles("src/gateway").filter(
|
||||
(file) =>
|
||||
isStripeEligibleTestFile(file, unitFastFiles) &&
|
||||
@@ -1747,6 +1753,11 @@ const SPLIT_NODE_SHARDS = new Map<string, NodeTestSplitShard[]>([
|
||||
"agentic",
|
||||
[
|
||||
...createGatewayServerSplitShards(),
|
||||
{
|
||||
shardName: "agentic-gateway-server-isolated",
|
||||
configs: ["test/vitest/vitest.gateway-server-isolated.config.ts"],
|
||||
requiresDist: false,
|
||||
},
|
||||
// Split per config: the combined pair owned a ~206s hosted wall that no
|
||||
// bin packing could shorten, while the halves fit normal lanes.
|
||||
{
|
||||
|
||||
@@ -318,27 +318,27 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
|
||||
name: "Blacksmith",
|
||||
pullRequest: pullRequestCompact,
|
||||
pullRequestJobs: 34,
|
||||
pullRequestMax: 204,
|
||||
pullRequestMax: 207,
|
||||
push: compact,
|
||||
pushJobs: 25,
|
||||
pushMax: 204,
|
||||
pushMax: 207,
|
||||
},
|
||||
{
|
||||
name: "GitHub-hosted",
|
||||
pullRequest: githubPullRequestCompact,
|
||||
pullRequestJobs: 79,
|
||||
pullRequestJobs: 80,
|
||||
pullRequestMax: 186,
|
||||
push: githubCompact,
|
||||
pushJobs: 70,
|
||||
pushJobs: 71,
|
||||
pushMax: 149,
|
||||
},
|
||||
{
|
||||
name: "hybrid",
|
||||
pullRequest: hybridPullRequestCompact,
|
||||
pullRequestJobs: 56,
|
||||
pullRequestJobs: 57,
|
||||
pullRequestMax: 140,
|
||||
push: hybridCompact,
|
||||
pushJobs: 48,
|
||||
pushJobs: 49,
|
||||
pushMax: 140,
|
||||
},
|
||||
]) {
|
||||
@@ -355,7 +355,7 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
|
||||
`${profile.name} pull-request max`,
|
||||
).toBe(profile.pullRequestMax);
|
||||
}
|
||||
expect(hybridCompact.filter((shard) => !shard.requiresDist)).toHaveLength(47);
|
||||
expect(hybridCompact.filter((shard) => !shard.requiresDist)).toHaveLength(48);
|
||||
expect(githubCompact.length - hybridCompact.length).toBeGreaterThanOrEqual(20);
|
||||
expect(githubPullRequestCompact.length).toBeLessThanOrEqual(96);
|
||||
// Nondist expanded-profile lanes stay under the 150-second body ceiling;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Vitest gateway server isolated config wires module-mocking Gateway tests out of
|
||||
// the shared module cache.
|
||||
import { defineConfig } from "vitest/config";
|
||||
import { gatewayServerIsolatedTestFiles } from "./vitest.gateway-server-paths.mjs";
|
||||
import { loadPatternListFromEnv, narrowIncludePatternsForCli } from "./vitest.pattern-file.ts";
|
||||
import { resolveRepoRootPath, sharedVitestConfig } from "./vitest.shared.config.ts";
|
||||
|
||||
export function createGatewayServerIsolatedVitestConfig(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
options: { argv?: string[] } = {},
|
||||
) {
|
||||
const sharedTest = sharedVitestConfig.test ?? {};
|
||||
const includeFromEnv = loadPatternListFromEnv("OPENCLAW_VITEST_INCLUDE_FILE", env);
|
||||
const cliInclude = narrowIncludePatternsForCli(gatewayServerIsolatedTestFiles, options.argv);
|
||||
|
||||
return defineConfig({
|
||||
...sharedVitestConfig,
|
||||
test: {
|
||||
...sharedTest,
|
||||
name: "gateway-server-isolated",
|
||||
// These files replace a module the Gateway reaches through re-exports, so a
|
||||
// neighbour that already bound the real implementation would defeat the mock.
|
||||
isolate: true,
|
||||
runner: undefined,
|
||||
setupFiles: [resolveRepoRootPath("test/setup.env.ts")],
|
||||
include: includeFromEnv ?? cliInclude ?? gatewayServerIsolatedTestFiles,
|
||||
exclude: sharedTest.exclude ?? [],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default createGatewayServerIsolatedVitestConfig();
|
||||
@@ -1,4 +1,5 @@
|
||||
export const gatewayServerBackedHttpTestFiles: string[];
|
||||
export const gatewayServerExcludedTestFiles: string[];
|
||||
export const gatewayServerIsolatedTestFiles: string[];
|
||||
export function isGatewayServerBackedHttpTestFile(file: string): boolean;
|
||||
export function isGatewayServerTestFile(file: string): boolean;
|
||||
|
||||
@@ -7,6 +7,15 @@ export const gatewayServerBackedHttpTestFiles = [
|
||||
"src/gateway/probe.auth.integration.test.ts",
|
||||
];
|
||||
|
||||
// Gateway server tests that replace a module the Gateway reaches only through
|
||||
// re-exports. `gateway-server` is `isolate: false`, so a neighbour that boots a
|
||||
// full Gateway leaves those importers bound to the real implementation and the
|
||||
// mock silently never fires. These run in `gateway-server-isolated` instead,
|
||||
// which gives each file a fresh module graph.
|
||||
export const gatewayServerIsolatedTestFiles = [
|
||||
"src/gateway/server.sessions.compaction-read-errors.test.ts",
|
||||
];
|
||||
|
||||
export const gatewayServerExcludedTestFiles = [
|
||||
"src/gateway/gateway.test.ts",
|
||||
"src/gateway/server.startup-matrix-migration.integration.test.ts",
|
||||
@@ -15,6 +24,7 @@ export const gatewayServerExcludedTestFiles = [
|
||||
|
||||
const gatewayServerBackedHttpTestFileSet = new Set(gatewayServerBackedHttpTestFiles);
|
||||
const gatewayServerExcludedTestFileSet = new Set(gatewayServerExcludedTestFiles);
|
||||
const gatewayServerIsolatedTestFileSet = new Set(gatewayServerIsolatedTestFiles);
|
||||
|
||||
export function isGatewayServerBackedHttpTestFile(file) {
|
||||
return gatewayServerBackedHttpTestFileSet.has(file.replaceAll("\\", "/"));
|
||||
@@ -24,6 +34,7 @@ export function isGatewayServerTestFile(file) {
|
||||
const normalized = file.replaceAll("\\", "/");
|
||||
if (
|
||||
gatewayServerExcludedTestFileSet.has(normalized) ||
|
||||
gatewayServerIsolatedTestFileSet.has(normalized) ||
|
||||
normalized.startsWith("src/gateway/server-methods/") ||
|
||||
normalized.endsWith(".e2e.test.ts")
|
||||
) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
gatewayServerBackedHttpTestFiles,
|
||||
gatewayServerExcludedTestFiles,
|
||||
gatewayServerIsolatedTestFiles,
|
||||
} from "./vitest.gateway-server-paths.mjs";
|
||||
// Vitest gateway server config wires the gateway server test shard.
|
||||
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
|
||||
@@ -11,7 +12,11 @@ export function createGatewayServerVitestConfig(env?: Record<string, string | un
|
||||
{
|
||||
dir: "src/gateway",
|
||||
env,
|
||||
exclude: ["src/gateway/server-methods/**/*.test.ts", ...gatewayServerExcludedTestFiles],
|
||||
exclude: [
|
||||
"src/gateway/server-methods/**/*.test.ts",
|
||||
...gatewayServerExcludedTestFiles,
|
||||
...gatewayServerIsolatedTestFiles,
|
||||
],
|
||||
fileParallelism: false,
|
||||
// Gateway child projects share one include file; preserve this project's ownership.
|
||||
intersectIncludeFile: true,
|
||||
|
||||
@@ -7,6 +7,7 @@ const gatewayProjectConfigs = [
|
||||
"test/vitest/vitest.gateway-client.config.ts",
|
||||
"test/vitest/vitest.gateway-methods.config.ts",
|
||||
"test/vitest/vitest.gateway-server.config.ts",
|
||||
"test/vitest/vitest.gateway-server-isolated.config.ts",
|
||||
] as const;
|
||||
|
||||
export function createGatewayVitestConfig(env?: Record<string, string | undefined>) {
|
||||
|
||||
@@ -99,6 +99,7 @@ export const fullSuiteVitestShards = [
|
||||
"test/vitest/vitest.gateway-client.config.ts",
|
||||
"test/vitest/vitest.gateway-methods.config.ts",
|
||||
"test/vitest/vitest.gateway-server.config.ts",
|
||||
"test/vitest/vitest.gateway-server-isolated.config.ts",
|
||||
"test/vitest/vitest.cli-process.config.ts",
|
||||
"test/vitest/vitest.cli.config.ts",
|
||||
"test/vitest/vitest.commands-light.config.ts",
|
||||
|
||||
Reference in New Issue
Block a user