test: stabilize faster unit lanes

This commit is contained in:
Peter Steinberger
2026-04-28 04:09:36 +01:00
parent e11eb03182
commit b1a36226b1
11 changed files with 157 additions and 158 deletions

View File

@@ -1,53 +1,34 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({
fetchWithSsrFGuardMock: vi.fn(),
shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false),
}));
vi.mock("../../../../src/infra/net/fetch-guard.js", async () => {
const actual = await vi.importActual<typeof import("../../../../src/infra/net/fetch-guard.js")>(
"../../../../src/infra/net/fetch-guard.js",
);
return {
...actual,
fetchWithSsrFGuard: fetchWithSsrFGuardMock,
};
});
vi.mock("../../../../src/infra/net/proxy-env.js", async () => {
const actual = await vi.importActual<typeof import("../../../../src/infra/net/proxy-env.js")>(
"../../../../src/infra/net/proxy-env.js",
);
return {
...actual,
shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock,
};
});
import { describe, expect, it } from "vitest";
import { GUARDED_FETCH_MODE } from "../../../../src/infra/net/fetch-guard.js";
import { withRemoteHttpResponse } from "./remote-http.js";
describe("package withRemoteHttpResponse", () => {
beforeEach(() => {
vi.clearAllMocks();
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
fetchWithSsrFGuardMock.mockResolvedValue({
response: new Response("ok", { status: 200 }),
finalUrl: "https://memory.example/v1",
release: vi.fn(async () => {}),
});
});
function makeFetchDeps({ useEnvProxy = false }: { useEnvProxy?: boolean } = {}) {
const calls: unknown[] = [];
return {
calls,
fetchWithSsrFGuardImpl: async (params: unknown) => {
calls.push(params);
return {
response: new Response("ok", { status: 200 }),
finalUrl: "https://memory.example/v1",
release: async () => {},
};
},
shouldUseEnvHttpProxyForUrlImpl: () => useEnvProxy,
};
}
it("uses trusted env proxy mode when the target will use EnvHttpProxyAgent", async () => {
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
const deps = makeFetchDeps({ useEnvProxy: true });
await withRemoteHttpResponse({
url: "https://memory.example/v1/embeddings",
onResponse: async () => undefined,
...deps,
});
expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith(
expect(deps.calls[0]).toEqual(
expect.objectContaining({
url: "https://memory.example/v1/embeddings",
mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY,
@@ -56,13 +37,15 @@ describe("package withRemoteHttpResponse", () => {
});
it("keeps strict guarded fetch mode when proxy env would not proxy the target", async () => {
const deps = makeFetchDeps();
await withRemoteHttpResponse({
url: "https://internal.corp.example/v1/embeddings",
onResponse: async () => undefined,
...deps,
});
const call = fetchWithSsrFGuardMock.mock.calls[0]?.[0];
expect(call).toBeDefined();
expect(call).not.toHaveProperty("mode");
expect(deps.calls[0]).toBeDefined();
expect(deps.calls[0]).not.toHaveProperty("mode");
});
});

View File

@@ -24,17 +24,19 @@ export async function withRemoteHttpResponse<T>(params: {
url: string;
init?: RequestInit;
ssrfPolicy?: SsrFPolicy;
fetchWithSsrFGuardImpl?: typeof fetchWithSsrFGuard;
shouldUseEnvHttpProxyForUrlImpl?: typeof shouldUseEnvHttpProxyForUrl;
auditContext?: string;
onResponse: (response: Response) => Promise<T>;
}): Promise<T> {
const { response, release } = await fetchWithSsrFGuard({
const guardedFetch = params.fetchWithSsrFGuardImpl ?? fetchWithSsrFGuard;
const shouldUseEnvProxy = params.shouldUseEnvHttpProxyForUrlImpl ?? shouldUseEnvHttpProxyForUrl;
const { response, release } = await guardedFetch({
url: params.url,
init: params.init,
policy: params.ssrfPolicy,
auditContext: params.auditContext ?? "memory-remote",
...(shouldUseEnvHttpProxyForUrl(params.url)
? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY }
: {}),
...(shouldUseEnvProxy(params.url) ? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY } : {}),
});
try {
return await params.onResponse(response);

View File

@@ -18,7 +18,6 @@ export const RELEASE_LIVE_TEST_SHARDS = Object.freeze([
"native-live-extensions-o-z-other",
"native-live-extensions-xai",
"native-live-extensions-media-audio",
"native-live-extensions-media-music",
"native-live-extensions-media-music-google",
"native-live-extensions-media-music-minimax",
"native-live-extensions-media-video",
@@ -28,6 +27,7 @@ export const LIVE_TEST_SHARDS = Object.freeze([
...RELEASE_LIVE_TEST_SHARDS,
"native-live-extensions-o-z",
"native-live-extensions-media",
"native-live-extensions-media-music",
]);
function walkFiles(rootDir) {

View File

@@ -1,22 +1,14 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { describe, expect, it } from "vitest";
import type { ConfigFileSnapshot, OpenClawConfig } from "../config/config.js";
import {
formatCrestodianOverview,
formatCrestodianStartupMessage,
loadCrestodianOverview,
} from "./overview.js";
vi.mock("./probes.js", () => ({
probeLocalCommand: vi.fn(async (command: string) => ({
command,
found: command === "codex",
version: command === "codex" ? "codex 1.0.0" : undefined,
})),
probeGatewayUrl: vi.fn(async (url: string) => ({ reachable: false, url, error: "offline" })),
}));
vi.mock("../config/config.js", () => ({
readConfigFileSnapshot: vi.fn(async () => ({
path: "/tmp/openclaw.json",
exists: true,
valid: true,
issues: [],
hash: "test-hash",
runtimeConfig: {
describe("loadCrestodianOverview", () => {
it("summarizes config, agents, model, tools, and gateway", async () => {
const runtimeConfig: OpenClawConfig = {
agents: {
defaults: { model: { primary: "openai/gpt-5.2" } },
list: [
@@ -25,37 +17,40 @@ vi.mock("../config/config.js", () => ({
],
},
gateway: { port: 19001 },
},
sourceConfig: undefined,
})),
resolveConfigPath: vi.fn(() => "/tmp/openclaw.json"),
resolveGatewayPort: vi.fn((cfg: { gateway?: { port?: number } }) => cfg.gateway?.port ?? 8765),
}));
vi.mock("../gateway/call.js", () => ({
buildGatewayConnectionDetails: vi.fn((input: { config: { gateway?: { port?: number } } }) => ({
url: `ws://127.0.0.1:${input.config.gateway?.port ?? 8765}`,
urlSource: "local loopback",
})),
}));
describe("loadCrestodianOverview", () => {
const previousTestFast = process.env.OPENCLAW_TEST_FAST;
afterEach(() => {
if (previousTestFast === undefined) {
delete process.env.OPENCLAW_TEST_FAST;
} else {
process.env.OPENCLAW_TEST_FAST = previousTestFast;
}
});
it("summarizes config, agents, model, tools, and gateway", async () => {
vi.stubEnv("OPENCLAW_TEST_FAST", "1");
const { formatCrestodianOverview, formatCrestodianStartupMessage, loadCrestodianOverview } =
await import("./overview.js");
const overview = await loadCrestodianOverview();
};
const snapshot: ConfigFileSnapshot = {
path: "/tmp/openclaw.json",
exists: true,
raw: "{}",
parsed: runtimeConfig,
sourceConfig: runtimeConfig,
resolved: runtimeConfig,
valid: true,
runtimeConfig,
config: runtimeConfig,
hash: "test-hash",
issues: [],
warnings: [],
legacyIssues: [],
};
const overview = await loadCrestodianOverview({
env: { OPENCLAW_TEST_FAST: "1" },
deps: {
readConfigFileSnapshot: async () => snapshot,
resolveConfigPath: () => "/tmp/openclaw.json",
resolveGatewayPort: (cfg) => cfg?.gateway?.port ?? 8765,
buildGatewayConnectionDetails: (input) => ({
url: `ws://127.0.0.1:${input.config.gateway?.port ?? 8765}`,
urlSource: "local loopback",
}),
probeLocalCommand: async (command) => ({
command,
found: command === "codex",
version: command === "codex" ? "codex 1.0.0" : undefined,
}),
probeGatewayUrl: async (url) => ({ reachable: false, url, error: "offline" }),
},
});
expect(overview.config).toMatchObject({
exists: true,

View File

@@ -62,6 +62,25 @@ export type CrestodianOverview = {
type OpenClawReferencePaths = Awaited<ReturnType<typeof resolveOpenClawReferencePaths>>;
type GatewayConnectionDetails = {
url: string;
urlSource: string;
remoteFallbackNote?: string;
};
type CrestodianOverviewDependencies = {
readConfigFileSnapshot?: typeof readConfigFileSnapshot;
resolveConfigPath?: typeof resolveConfigPath;
resolveGatewayPort?: typeof resolveGatewayPort;
buildGatewayConnectionDetails?: (input: {
config: OpenClawConfig;
configPath: string;
}) => GatewayConnectionDetails;
probeLocalCommand?: typeof probeLocalCommand;
probeGatewayUrl?: typeof probeGatewayUrl;
resolveOpenClawReferencePaths?: typeof resolveOpenClawReferencePaths;
};
function issueMessages(snapshot: ConfigFileSnapshot): string[] {
return snapshot.issues.map((issue) => {
const path = issue.path ? `${issue.path}: ` : "";
@@ -120,21 +139,25 @@ function resolveFastTestReferences(env: NodeJS.ProcessEnv): OpenClawReferencePat
}
export async function loadCrestodianOverview(
opts: { env?: NodeJS.ProcessEnv } = {},
opts: { env?: NodeJS.ProcessEnv; deps?: CrestodianOverviewDependencies } = {},
): Promise<CrestodianOverview> {
const env = opts.env ?? process.env;
const snapshot = await readConfigFileSnapshot();
const deps = opts.deps ?? {};
const readSnapshot = deps.readConfigFileSnapshot ?? readConfigFileSnapshot;
const snapshot = await readSnapshot();
const cfg = snapshot.runtimeConfig ?? snapshot.sourceConfig ?? {};
const defaultAgentId = resolveDefaultAgentId(cfg);
const defaultModel =
resolveAgentEffectiveModelPrimary(cfg, defaultAgentId) ??
resolveAgentModelPrimaryValue(cfg.agents?.defaults?.model);
const configPath = snapshot.path || resolveConfigPath(env);
let gatewayUrl = `ws://127.0.0.1:${resolveGatewayPort(cfg, env)}`;
const configPath = snapshot.path || (deps.resolveConfigPath ?? resolveConfigPath)(env);
let gatewayUrl = `ws://127.0.0.1:${(deps.resolveGatewayPort ?? resolveGatewayPort)(cfg, env)}`;
let gatewaySource = "local loopback";
let gatewayError: string | undefined;
try {
const { buildGatewayConnectionDetails } = await import("../gateway/call.js");
const buildGatewayConnectionDetails =
deps.buildGatewayConnectionDetails ??
(await import("../gateway/call.js")).buildGatewayConnectionDetails;
const details = buildGatewayConnectionDetails({ config: cfg, configPath });
gatewayUrl = details.url;
gatewaySource = details.urlSource;
@@ -142,12 +165,14 @@ export async function loadCrestodianOverview(
} catch (err) {
gatewayError = err instanceof Error ? err.message : String(err);
}
const resolveReferences = deps.resolveOpenClawReferencePaths ?? resolveOpenClawReferencePaths;
const commandProbe = deps.probeLocalCommand ?? probeLocalCommand;
const [codex, claude, gateway, references] = await Promise.all([
probeLocalCommand("codex"),
probeLocalCommand("claude"),
probeGatewayUrl(gatewayUrl),
commandProbe("codex"),
commandProbe("claude"),
(deps.probeGatewayUrl ?? probeGatewayUrl)(gatewayUrl),
resolveFastTestReferences(env) ??
resolveOpenClawReferencePaths({
resolveReferences({
argv1: process.argv[1],
cwd: process.cwd(),
moduleUrl: import.meta.url,

View File

@@ -1,53 +1,34 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({
fetchWithSsrFGuardMock: vi.fn(),
shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false),
}));
vi.mock("../../infra/net/fetch-guard.js", async () => {
const actual = await vi.importActual<typeof import("../../infra/net/fetch-guard.js")>(
"../../infra/net/fetch-guard.js",
);
return {
...actual,
fetchWithSsrFGuard: fetchWithSsrFGuardMock,
};
});
vi.mock("../../infra/net/proxy-env.js", async () => {
const actual = await vi.importActual<typeof import("../../infra/net/proxy-env.js")>(
"../../infra/net/proxy-env.js",
);
return {
...actual,
shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock,
};
});
import { describe, expect, it } from "vitest";
import { GUARDED_FETCH_MODE } from "../../infra/net/fetch-guard.js";
import { withRemoteHttpResponse } from "./remote-http.js";
describe("withRemoteHttpResponse", () => {
beforeEach(() => {
vi.clearAllMocks();
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
fetchWithSsrFGuardMock.mockResolvedValue({
response: new Response("ok", { status: 200 }),
finalUrl: "https://memory.example/v1",
release: vi.fn(async () => {}),
});
});
function makeFetchDeps({ useEnvProxy = false }: { useEnvProxy?: boolean } = {}) {
const calls: unknown[] = [];
return {
calls,
fetchWithSsrFGuardImpl: async (params: unknown) => {
calls.push(params);
return {
response: new Response("ok", { status: 200 }),
finalUrl: "https://memory.example/v1",
release: async () => {},
};
},
shouldUseEnvHttpProxyForUrlImpl: () => useEnvProxy,
};
}
it("uses trusted env proxy mode when the target will use EnvHttpProxyAgent", async () => {
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
const deps = makeFetchDeps({ useEnvProxy: true });
await withRemoteHttpResponse({
url: "https://memory.example/v1/embeddings",
onResponse: async () => undefined,
...deps,
});
expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith(
expect(deps.calls[0]).toEqual(
expect.objectContaining({
url: "https://memory.example/v1/embeddings",
mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY,
@@ -56,13 +37,15 @@ describe("withRemoteHttpResponse", () => {
});
it("keeps strict guarded fetch mode when proxy env would not proxy the target", async () => {
const deps = makeFetchDeps();
await withRemoteHttpResponse({
url: "https://internal.corp.example/v1/embeddings",
onResponse: async () => undefined,
...deps,
});
const call = fetchWithSsrFGuardMock.mock.calls[0]?.[0];
expect(call).toBeDefined();
expect(call).not.toHaveProperty("mode");
expect(deps.calls[0]).toBeDefined();
expect(deps.calls[0]).not.toHaveProperty("mode");
});
});

View File

@@ -9,18 +9,20 @@ export async function withRemoteHttpResponse<T>(params: {
init?: RequestInit;
ssrfPolicy?: SsrFPolicy;
fetchImpl?: typeof fetch;
fetchWithSsrFGuardImpl?: typeof fetchWithSsrFGuard;
shouldUseEnvHttpProxyForUrlImpl?: typeof shouldUseEnvHttpProxyForUrl;
auditContext?: string;
onResponse: (response: Response) => Promise<T>;
}): Promise<T> {
const { response, release } = await fetchWithSsrFGuard({
const guardedFetch = params.fetchWithSsrFGuardImpl ?? fetchWithSsrFGuard;
const shouldUseEnvProxy = params.shouldUseEnvHttpProxyForUrlImpl ?? shouldUseEnvHttpProxyForUrl;
const { response, release } = await guardedFetch({
url: params.url,
fetchImpl: params.fetchImpl,
init: params.init,
policy: params.ssrfPolicy,
auditContext: params.auditContext ?? "memory-remote",
...(shouldUseEnvHttpProxyForUrl(params.url)
? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY }
: {}),
...(shouldUseEnvProxy(params.url) ? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY } : {}),
});
try {
return await params.onResponse(response);

View File

@@ -9,15 +9,26 @@ import {
describe("scripts/test-live-shard", () => {
const allFiles = collectAllLiveTestFiles();
it("partitions every native live test into exactly one release shard", () => {
it("covers every native live test and tracks provider-filtered release fanout", () => {
const selected = RELEASE_LIVE_TEST_SHARDS.flatMap((shard) =>
selectLiveShardFiles(shard, allFiles).map((file) => ({ file, shard })),
);
const selectedFiles = selected.map(({ file }) => file);
const duplicateFiles = selectedFiles.filter(
(file, index) => selectedFiles.indexOf(file) !== index,
);
const musicProviderFanout = selected
.filter(({ file }) => file === "extensions/music-generation-providers.live.test.ts")
.map(({ shard }) => shard)
.toSorted();
expect(allFiles.length).toBeGreaterThan(0);
expect(selectedFiles.toSorted()).toEqual(allFiles);
expect(new Set(selectedFiles).size).toBe(selectedFiles.length);
expect([...new Set(selectedFiles)].toSorted()).toEqual(allFiles);
expect(duplicateFiles).toEqual(["extensions/music-generation-providers.live.test.ts"]);
expect(musicProviderFanout).toEqual([
"native-live-extensions-media-music-google",
"native-live-extensions-media-music-minimax",
]);
});
it("keeps aggregate shard aliases available outside the release partition", () => {

View File

@@ -65,7 +65,6 @@ export const forcedUnitFastTestFiles = [
"src/acp/translator.prompt-prefix.test.ts",
"src/acp/translator.cancel-scoping.test.ts",
"src/acp/translator.stop-reason.test.ts",
"src/acp/persistent-bindings.lifecycle.test.ts",
"src/acp/persistent-bindings.test.ts",
"src/acp/server.startup.test.ts",
"src/acp/translator.session-rate-limit.test.ts",
@@ -87,7 +86,6 @@ export const forcedUnitFastTestFiles = [
"src/dockerfile.test.ts",
"src/entry.compile-cache.test.ts",
"src/entry.test.ts",
"src/image-generation/runtime.test.ts",
"src/i18n/registry.test.ts",
"src/install-sh-version.test.ts",
"src/logger.test.ts",
@@ -106,10 +104,10 @@ export const forcedUnitFastTestFiles = [
"src/pairing/setup-code.test.ts",
"src/plugin-activation-boundary.test.ts",
"src/plugin-sdk/memory-host-events.test.ts",
"src/proxy-capture/runtime.test.ts",
"src/proxy-capture/store.sqlite.test.ts",
"src/security/audit-exec-surface.test.ts",
"src/security/audit-extra.async.test.ts",
"src/security/audit-trust-model.test.ts",
"src/security/dm-policy-shared.test.ts",
"src/security/audit-plugins-trust.test.ts",
"src/security/audit-workspace-skill-escape.test.ts",
@@ -118,7 +116,6 @@ export const forcedUnitFastTestFiles = [
"src/security/scan-paths.test.ts",
"src/security/skill-scanner.test.ts",
"src/security/audit-config-include-perms.test.ts",
"src/security/windows-acl.test.ts",
"src/realtime-transcription/websocket-session.test.ts",
"src/routing/resolve-route.test.ts",
"src/trajectory/cleanup.test.ts",
@@ -135,7 +132,6 @@ export const forcedUnitFastTestFiles = [
"src/test-utils/env.test.ts",
"src/test-utils/temp-home.test.ts",
"src/utils.test.ts",
"src/video-generation/runtime.test.ts",
"src/version.test.ts",
];
const forcedUnitFastTestFileSet = new Set(forcedUnitFastTestFiles);

View File

@@ -3,4 +3,5 @@ import { createUnitVitestConfigWithOptions } from "./vitest.unit.config.ts";
export default createUnitVitestConfigWithOptions(process.env, {
name: "unit-support",
includePatterns: ["packages/**/*.test.ts"],
passWithNoTests: true,
});

View File

@@ -35,6 +35,7 @@ export function createUnitVitestConfigWithOptions(
extraExcludePatterns?: string[];
name?: string;
argv?: string[];
passWithNoTests?: boolean;
} = {},
) {
const isolate = resolveVitestIsolation(env);
@@ -85,7 +86,7 @@ export function createUnitVitestConfigWithOptions(
]),
],
},
...(cliIncludePatterns !== null ? { passWithNoTests: true } : {}),
...(options.passWithNoTests || cliIncludePatterns !== null ? { passWithNoTests: true } : {}),
},
});
}