mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
test: stop re-evaluating plugin module graphs for every test case (#131522)
The doctor contract registry suites called vi.resetModules() plus a dynamic
re-import in beforeEach, so all 54 cases re-evaluated the whole doctor owner
graph: setup policy, migration adapters, config normalization, loader state,
and native/SDK alias resolution. Load once in beforeAll instead and keep the
per-case mock resets, loader injection, cache clearing, and temp-dir cleanup
where they were. setup-registry.test.ts already used this shape.
doctor-contract-registry.test.ts: 29.7s -> 18.2s (-39%), import 508ms -> 136ms.
Also narrow imports that pulled broad graphs in for static work:
seven files reached createEmptyPluginRegistry through registry.js (the whole
registry construction graph) instead of its real owner registry-empty.js;
three provider tests imported api.js, paying for transport streaming,
provider auth, and image-generation SDK graphs to test string normalization;
and provider-utils.test.ts used importActual() to spread a runtime whose only
used export it immediately replaced.
Neither provider barrel suite actually asserted the narrowed exports, so add
explicit re-export assertions in extensions/{google,xai}/api.test.ts rather
than let that coverage lapse.
Unrelated flake fixed in passing: hooks.correlation.test.ts spawns a tsx
subprocess under a 3s deadline, which is killed under load and reports
status null. It failed 3/3 on unmodified code and passes 4/4 at 30s. No
assertion changed.
Test-only change: zero production LOC.
This commit is contained in:
committed by
GitHub
parent
cd7b282ed8
commit
153a6f59bf
@@ -1,11 +1,15 @@
|
||||
// Google tests cover api plugin behavior.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
applyGoogleGeminiModelDefault,
|
||||
GOOGLE_GEMINI_DEFAULT_MODEL,
|
||||
isGoogleGenerativeAiApi,
|
||||
isGoogleVertexBaseUrl,
|
||||
isGoogleVertexHostname,
|
||||
normalizeAntigravityModelId,
|
||||
normalizeGoogleApiBaseUrl,
|
||||
normalizeGoogleGenerativeAiBaseUrl,
|
||||
normalizeGoogleModelId,
|
||||
normalizeGoogleProviderConfig,
|
||||
parseGeminiAuth,
|
||||
resolveGoogleGenerativeAiHttpRequestConfig,
|
||||
@@ -13,8 +17,23 @@ import {
|
||||
resolveGoogleGenerativeAiTransport,
|
||||
shouldNormalizeGoogleGenerativeAiProviderConfig,
|
||||
} from "./api.js";
|
||||
import {
|
||||
normalizeAntigravityModelId as normalizeAntigravityModelIdDirect,
|
||||
normalizeGoogleModelId as normalizeGoogleModelIdDirect,
|
||||
} from "./model-id.js";
|
||||
import {
|
||||
applyGoogleGeminiModelDefault as applyGoogleGeminiModelDefaultDirect,
|
||||
GOOGLE_GEMINI_DEFAULT_MODEL as GOOGLE_GEMINI_DEFAULT_MODEL_DIRECT,
|
||||
} from "./onboard.js";
|
||||
|
||||
describe("google generative ai helpers", () => {
|
||||
it("re-exports model normalization and default helpers", () => {
|
||||
expect(normalizeAntigravityModelId).toBe(normalizeAntigravityModelIdDirect);
|
||||
expect(normalizeGoogleModelId).toBe(normalizeGoogleModelIdDirect);
|
||||
expect(applyGoogleGeminiModelDefault).toBe(applyGoogleGeminiModelDefaultDirect);
|
||||
expect(GOOGLE_GEMINI_DEFAULT_MODEL).toBe(GOOGLE_GEMINI_DEFAULT_MODEL_DIRECT);
|
||||
});
|
||||
|
||||
it("detects the Google Generative AI transport id", () => {
|
||||
expect(isGoogleGenerativeAiApi("google-generative-ai")).toBe(true);
|
||||
expect(isGoogleGenerativeAiApi("google-gemini-cli")).toBe(false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Google tests cover default model plugin behavior.
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyGoogleGeminiModelDefault, GOOGLE_GEMINI_DEFAULT_MODEL } from "./api.js";
|
||||
import { applyGoogleGeminiModelDefault, GOOGLE_GEMINI_DEFAULT_MODEL } from "./onboard.js";
|
||||
|
||||
describe("google default model", () => {
|
||||
it("sets defaults when model is unset", () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Google tests cover model id plugin behavior.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeAntigravityModelId, normalizeGoogleModelId } from "./api.js";
|
||||
import { normalizeAntigravityModelId, normalizeGoogleModelId } from "./model-id.js";
|
||||
|
||||
describe("google model id helpers", () => {
|
||||
it.each(["gemini-3-pro", "gemini-3.1-pro", "gemini-3-1-pro"])(
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
// Xai tests cover api plugin behavior.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveXaiForwardCompatModel, resolveXaiTransport, XAI_BASE_URL } from "./api.js";
|
||||
import {
|
||||
normalizeXaiModelId,
|
||||
resolveXaiForwardCompatModel,
|
||||
resolveXaiTransport,
|
||||
XAI_BASE_URL,
|
||||
} from "./api.js";
|
||||
import { normalizeXaiModelId as normalizeXaiModelIdDirect } from "./model-id.js";
|
||||
|
||||
describe("xai api helpers", () => {
|
||||
it("re-exports the model normalizer", () => {
|
||||
expect(normalizeXaiModelId).toBe(normalizeXaiModelIdDirect);
|
||||
});
|
||||
|
||||
it("uses shared endpoint classification for native xAI transports", () => {
|
||||
expect(
|
||||
resolveXaiTransport({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Xai tests cover model id plugin behavior.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeXaiModelId } from "./api.js";
|
||||
import { normalizeXaiModelId } from "./model-id.js";
|
||||
|
||||
describe("normalizeXaiModelId", () => {
|
||||
it("normalizes family-specific aliases but preserves the global alias", () => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { createWebhookInFlightLimiter } from "./webhook-request-guards.js";
|
||||
import {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Covers plugin doctor state-migration registry behavior.
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
|
||||
import {
|
||||
getRegistryJitiMocks,
|
||||
@@ -39,9 +39,7 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("doctor-contract-registry state migrations", () => {
|
||||
beforeEach(async () => {
|
||||
resetRegistryJitiMocks();
|
||||
doctorContractWarnMock.mockReset();
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ listPluginDoctorLegacyConfigRules, listPluginDoctorStateMigrationEntries } =
|
||||
await import("./doctor-contract-registry.js"));
|
||||
@@ -49,6 +47,17 @@ describe("doctor-contract-registry state migrations", () => {
|
||||
clearPluginDoctorContractRegistryCache,
|
||||
setPluginDoctorContractRegistryModuleLoaderFactoryForTest,
|
||||
} = await import("./doctor-contract-registry.test-fixtures.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resetRegistryJitiMocks();
|
||||
doctorContractWarnMock.mockReset();
|
||||
// Loaded once in beforeAll; afterEach guards the same binding optionally because it
|
||||
// can fire when that import never completed. Fail loudly here instead of silently
|
||||
// running a case against the real module loader.
|
||||
if (!setPluginDoctorContractRegistryModuleLoaderFactoryForTest) {
|
||||
throw new Error("doctor contract registry test fixtures were not loaded");
|
||||
}
|
||||
setPluginDoctorContractRegistryModuleLoaderFactoryForTest(mocks.createJiti);
|
||||
clearPluginDoctorContractRegistryCache();
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withMockedPlatform } from "../test-utils/vitest-spies.js";
|
||||
import { resolvePluginDoctorContractArtifactPath } from "./doctor-contract-artifact.js";
|
||||
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
|
||||
@@ -54,10 +54,7 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("doctor-contract-registry module loader", () => {
|
||||
beforeEach(async () => {
|
||||
resetRegistryJitiMocks();
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue({ plugins: [], diagnostics: [] });
|
||||
doctorContractWarnMock.mockReset();
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({
|
||||
applyPluginDoctorCompatibilityMigrations,
|
||||
@@ -71,6 +68,18 @@ describe("doctor-contract-registry module loader", () => {
|
||||
clearPluginDoctorContractRegistryCache,
|
||||
setPluginDoctorContractRegistryModuleLoaderFactoryForTest,
|
||||
} = await import("./doctor-contract-registry.test-fixtures.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resetRegistryJitiMocks();
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue({ plugins: [], diagnostics: [] });
|
||||
doctorContractWarnMock.mockReset();
|
||||
// Loaded once in beforeAll; afterEach guards the same binding optionally because it
|
||||
// can fire when that import never completed. Fail loudly here instead of silently
|
||||
// running a case against the real module loader.
|
||||
if (!setPluginDoctorContractRegistryModuleLoaderFactoryForTest) {
|
||||
throw new Error("doctor contract registry test fixtures were not loaded");
|
||||
}
|
||||
setPluginDoctorContractRegistryModuleLoaderFactoryForTest(mocks.createJiti);
|
||||
clearPluginDoctorContractRegistryCache();
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createHookRunner } from "./hooks.js";
|
||||
import { addStaticTestHooks, addTestHook } from "./hooks.test-fixtures.js";
|
||||
import { createEmptyPluginRegistry } from "./registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import type { PluginHookResolveExecEnvContext } from "./types.js";
|
||||
|
||||
const ctx: PluginHookResolveExecEnvContext = {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createHookRunner } from "./hooks.js";
|
||||
import { addTestHook } from "./hooks.test-fixtures.js";
|
||||
import { createEmptyPluginRegistry, type PluginRegistry } from "./registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import type {
|
||||
PluginHookBeforeInstallContext,
|
||||
PluginHookBeforeInstallEvent,
|
||||
|
||||
@@ -6,7 +6,8 @@ import { configureRuntimeActionDecisionSink } from "../audit/runtime-action-deci
|
||||
import { createHookRunner } from "./hooks.js";
|
||||
import { addStaticTestHooks } from "./hooks.test-fixtures.js";
|
||||
import { addTestHook } from "./hooks.test-helpers.js";
|
||||
import { createEmptyPluginRegistry, type PluginRegistry } from "./registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import type {
|
||||
PluginHookBeforeToolCallEvent,
|
||||
PluginHookBeforeToolCallResult,
|
||||
|
||||
@@ -4,7 +4,8 @@ import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coerci
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createHookRunner } from "./hooks.js";
|
||||
import { addTestHook, TEST_PLUGIN_AGENT_CTX } from "./hooks.test-fixtures.js";
|
||||
import { createEmptyPluginRegistry, type PluginRegistry } from "./registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import type { PluginHookRegistration } from "./types.js";
|
||||
|
||||
describe("hook correlation fields", () => {
|
||||
@@ -116,7 +117,10 @@ describe("hook correlation fields", () => {
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
timeout: 3_000,
|
||||
// Boots tsx in a child process, so the deadline must cover compile time on a
|
||||
// loaded machine. A tight bound kills the probe (status null) and fails the
|
||||
// assertions below for a reason unrelated to the hook timeout under test.
|
||||
timeout: 30_000,
|
||||
},
|
||||
);
|
||||
oneShotAgentEndProbe = {
|
||||
|
||||
@@ -4,7 +4,8 @@ import { applyEmbeddedAttemptToolsAllow } from "../agents/embedded-agent-runner/
|
||||
import { readToolAllowlistIntersection } from "../agents/tool-policy.js";
|
||||
import { createHookRunner } from "./hooks.js";
|
||||
import { addStaticTestHooks } from "./hooks.test-fixtures.js";
|
||||
import { createEmptyPluginRegistry, type PluginRegistry } from "./registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import type {
|
||||
PluginHookBeforeModelResolveResult,
|
||||
PluginHookBeforePromptBuildResult,
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createHookRunner } from "./hooks.js";
|
||||
import { addStaticTestHooks } from "./hooks.test-fixtures.js";
|
||||
import { createEmptyPluginRegistry, type PluginRegistry } from "./registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import type { PluginHookBeforeToolCallResult, PluginHookMessageSendingResult } from "./types.js";
|
||||
|
||||
const toolEvent = { toolName: "bash", params: { command: "echo hello" } };
|
||||
|
||||
@@ -5,15 +5,9 @@ const { resolveProviderReasoningOutputModeWithPluginMock } = vi.hoisted(() => ({
|
||||
resolveProviderReasoningOutputModeWithPluginMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/provider-runtime.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../plugins/provider-runtime.js")>(
|
||||
"../plugins/provider-runtime.js",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
resolveProviderReasoningOutputModeWithPlugin: resolveProviderReasoningOutputModeWithPluginMock,
|
||||
};
|
||||
});
|
||||
vi.mock("../plugins/provider-runtime.js", () => ({
|
||||
resolveProviderReasoningOutputModeWithPlugin: resolveProviderReasoningOutputModeWithPluginMock,
|
||||
}));
|
||||
|
||||
import { isReasoningTagProvider } from "./provider-utils.js";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user