test: narrow hotspot boundaries

This commit is contained in:
Peter Steinberger
2026-04-17 01:09:28 +01:00
parent 0dc4c4076c
commit 59b98334f6
5 changed files with 174 additions and 160 deletions

View File

@@ -4,9 +4,8 @@ const resolveAgentWorkspaceDir = vi.hoisted(() =>
vi.fn((_cfg?: unknown, _agentId?: unknown) => "/tmp/openclaw-workspace"),
);
const resolveDefaultAgentId = vi.hoisted(() => vi.fn((_cfg?: unknown) => "default"));
const listChannelPluginCatalogEntries = vi.hoisted(() => vi.fn((_opts?: unknown): unknown[] => []));
const getChannelPluginCatalogEntry = vi.hoisted(() =>
vi.fn((_id?: unknown, _opts?: unknown) => undefined),
const listTrustedChannelPluginCatalogEntries = vi.hoisted(() =>
vi.fn((_params?: unknown): unknown[] => []),
);
const getChannelSetupPlugin = vi.hoisted(() => vi.fn((_channel?: unknown) => undefined));
const listChannelSetupPlugins = vi.hoisted(() => vi.fn((): unknown[] => []));
@@ -30,12 +29,6 @@ vi.mock("../agents/agent-scope.js", () => ({
resolveDefaultAgentId: (cfg?: unknown) => resolveDefaultAgentId(cfg),
}));
vi.mock("../channels/plugins/catalog.js", () => ({
listChannelPluginCatalogEntries: (opts?: unknown) => listChannelPluginCatalogEntries(opts),
getChannelPluginCatalogEntry: (id?: unknown, opts?: unknown) =>
getChannelPluginCatalogEntry(id, opts),
}));
vi.mock("../channels/plugins/setup-registry.js", () => ({
getChannelSetupPlugin: (channel?: unknown) => getChannelSetupPlugin(channel),
listChannelSetupPlugins: () => listChannelSetupPlugins(),
@@ -63,6 +56,11 @@ vi.mock("../commands/channel-setup/registry.js", () => ({
resolveChannelSetupWizardAdapterForPlugin: () => undefined,
}));
vi.mock("../commands/channel-setup/trusted-catalog.js", () => ({
listTrustedChannelPluginCatalogEntries: (params?: unknown) =>
listTrustedChannelPluginCatalogEntries(params),
}));
vi.mock("../config/channel-configured.js", () => ({
isChannelConfigured: (cfg?: unknown, channel?: unknown) => isChannelConfigured(cfg, channel),
}));
@@ -90,10 +88,11 @@ describe("setupChannels workspace shadow exclusion", () => {
vi.clearAllMocks();
resolveAgentWorkspaceDir.mockReturnValue("/tmp/openclaw-workspace");
resolveDefaultAgentId.mockReturnValue("default");
listChannelPluginCatalogEntries.mockReturnValue([
listTrustedChannelPluginCatalogEntries.mockReturnValue([
{
id: "telegram",
pluginId: "@openclaw/telegram-plugin",
origin: "bundled",
},
]);
getChannelSetupPlugin.mockReturnValue(undefined);
@@ -112,13 +111,7 @@ describe("setupChannels workspace shadow exclusion", () => {
isChannelConfigured.mockReturnValue(true);
});
it("preloads configured external plugins from the bundled fallback for untrusted shadows", async () => {
listChannelPluginCatalogEntries.mockImplementation((opts?: unknown) =>
(opts as { excludeWorkspace?: boolean } | undefined)?.excludeWorkspace
? [{ id: "telegram", pluginId: "@openclaw/telegram-plugin", origin: "bundled" }]
: [{ id: "telegram", pluginId: "evil-telegram-shadow", origin: "workspace" }],
);
it("preloads configured external plugins from the trusted catalog boundary", async () => {
await setupChannels(
{} as never,
{} as never,
@@ -128,10 +121,12 @@ describe("setupChannels workspace shadow exclusion", () => {
} as never,
);
const fallbackCall = listChannelPluginCatalogEntries.mock.calls.find(
([opts]) => (opts as { excludeWorkspace?: boolean } | undefined)?.excludeWorkspace === true,
expect(listTrustedChannelPluginCatalogEntries).toHaveBeenCalledWith(
expect.objectContaining({
cfg: {},
workspaceDir: "/tmp/openclaw-workspace",
}),
);
expect(fallbackCall).toBeTruthy();
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
expect.objectContaining({
channel: "telegram",
@@ -142,7 +137,7 @@ describe("setupChannels workspace shadow exclusion", () => {
});
it("keeps trusted workspace overrides eligible during preload", async () => {
listChannelPluginCatalogEntries.mockReturnValue([
listTrustedChannelPluginCatalogEntries.mockReturnValue([
{ id: "telegram", pluginId: "trusted-telegram-shadow", origin: "workspace" },
]);

View File

@@ -12,14 +12,13 @@ import {
} from "./embeddings-gemini.js";
import {
createGeminiBatchFetchMock,
createGeminiFetchMock,
createJsonResponseFetchMock,
installFetchMock,
mockResolvedProviderKey,
parseFetchBody,
readFirstFetchRequest,
type JsonFetchMock,
} from "./embeddings-provider.test-support.js";
import { mockPublicPinnedHostname } from "./test-helpers/ssrf.js";
vi.mock("../../agents/model-auth.js", async () => {
const { createModelAuthMockModule } = await import("../../test-utils/model-auth-mock.js");
@@ -42,7 +41,6 @@ async function createProviderWithFetch(
options: Partial<Parameters<typeof createGeminiEmbeddingProvider>[0]> & { model: string },
) {
installFetchMock(fetchMock as unknown as typeof globalThis.fetch);
mockPublicPinnedHostname();
mockResolvedProviderKey(authModule.resolveApiKeyForProvider);
const { provider } = await createGeminiEmbeddingProvider({
config: {} as never,
@@ -169,55 +167,26 @@ describe("gemini embedding provider", () => {
expect(parseFetchBody(legacyFetch, 0)).not.toHaveProperty("outputDimensionality");
expect(parseFetchBody(legacyFetch, 1)).not.toHaveProperty("outputDimensionality");
const v2QueryFetch = createGeminiFetchMock([3, 4, Number.NaN]);
const v2QueryProvider = await createProviderWithFetch(v2QueryFetch, {
model: "gemini-embedding-2-preview",
const v2Fetch = createJsonResponseFetchMock((input) => {
const url = input instanceof URL ? input.href : typeof input === "string" ? input : input.url;
return url.endsWith(":batchEmbedContents")
? {
embeddings: Array.from({ length: 2 }, () => ({
values: [0, Number.POSITIVE_INFINITY, 5],
})),
}
: { embedding: { values: [3, 4, Number.NaN] } };
});
await expect(v2QueryProvider.embedQuery(" ")).resolves.toEqual([]);
await expect(v2QueryProvider.embedBatch([])).resolves.toEqual([]);
await expect(v2QueryProvider.embedQuery("test query")).resolves.toEqual([0.6, 0.8, 0]);
const v2BatchFetch = createGeminiBatchFetchMock(2, [0, Number.POSITIVE_INFINITY, 5]);
const v2BatchProvider = await createProviderWithFetch(v2BatchFetch, {
model: "gemini-embedding-2-preview",
});
const batch = await v2BatchProvider.embedBatch(["text1", "text2"]);
expect(batch).toEqual([
[0, 0, 1],
[0, 0, 1],
]);
expect(parseFetchBody(v2QueryFetch)).toMatchObject({
outputDimensionality: 3072,
taskType: "RETRIEVAL_QUERY",
content: { parts: [{ text: "test query" }] },
});
expect(parseFetchBody(v2BatchFetch).requests).toEqual([
{
model: "models/gemini-embedding-2-preview",
content: { parts: [{ text: "text1" }] },
taskType: "RETRIEVAL_DOCUMENT",
outputDimensionality: 3072,
},
{
model: "models/gemini-embedding-2-preview",
content: { parts: [{ text: "text2" }] },
taskType: "RETRIEVAL_DOCUMENT",
outputDimensionality: 3072,
},
]);
});
it("supports custom dimensions, task type, multimodal inputs, and endpoint URL", async () => {
const fetchMock = createGeminiBatchFetchMock(2);
const provider = await createProviderWithFetch(fetchMock, {
const v2Provider = await createProviderWithFetch(v2Fetch, {
model: "gemini-embedding-2-preview",
outputDimensionality: 768,
taskType: "SEMANTIC_SIMILARITY",
});
await expect(v2Provider.embedQuery(" ")).resolves.toEqual([]);
await expect(v2Provider.embedBatch([])).resolves.toEqual([]);
await expect(v2Provider.embedQuery("test query")).resolves.toEqual([0.6, 0.8, 0]);
await provider.embedQuery("test");
const structuredBatch = await provider.embedBatchInputs?.([
const structuredBatch = await v2Provider.embedBatchInputs?.([
{
text: "Image file: diagram.png",
parts: [
@@ -234,19 +203,20 @@ describe("gemini embedding provider", () => {
},
]);
expect(structuredBatch).toEqual([
[0.2672612419124244, 0.5345224838248488, 0.8017837257372732],
[0.2672612419124244, 0.5345224838248488, 0.8017837257372732],
[0, 0, 1],
[0, 0, 1],
]);
const { url } = readFirstFetchRequest(fetchMock);
const { url } = readFirstFetchRequest(v2Fetch);
expect(url).toBe(
"https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2-preview:embedContent",
);
expect(parseFetchBody(fetchMock, 0)).toMatchObject({
expect(parseFetchBody(v2Fetch, 0)).toMatchObject({
outputDimensionality: 768,
taskType: "SEMANTIC_SIMILARITY",
content: { parts: [{ text: "test query" }] },
});
expect(parseFetchBody(fetchMock, 1).requests).toEqual([
expect(parseFetchBody(v2Fetch, 1).requests).toEqual([
{
model: "models/gemini-embedding-2-preview",
content: {

View File

@@ -7,6 +7,48 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vites
import { resolveOAuthDir } from "../config/paths.js";
import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
import { withEnvAsync } from "../test-utils/env.js";
vi.mock("../channels/plugins/pairing.js", () => ({
getPairingAdapter: () => null,
}));
vi.mock("../infra/file-lock.js", () => ({
withFileLock: async (_path: string, _options: unknown, fn: () => unknown) => await fn(),
}));
vi.mock("../plugin-sdk/json-store.js", async () => {
const fs = await import("node:fs/promises");
const path = await import("node:path");
return {
readJsonFileWithFallback: async <T>(filePath: string, fallback: T) => {
let raw: string;
try {
raw = await fs.readFile(filePath, "utf8");
} catch (err) {
if ((err as { code?: string }).code === "ENOENT") {
return { value: fallback, exists: false };
}
return { value: fallback, exists: false };
}
try {
const parsed = JSON.parse(raw) as T;
return {
value: parsed ?? fallback,
exists: true,
};
} catch {
return { value: fallback, exists: true };
}
},
writeJsonFileAtomically: async (filePath: string, value: unknown) => {
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
},
};
});
import * as jsonStore from "../plugin-sdk/json-store.js";
import {
addChannelAllowFromStoreEntry,
clearPairingAllowFromReadCacheForTest,
@@ -552,7 +594,7 @@ describe("pairing store", () => {
await withTempStateDir(async (stateDir) => {
for (const variant of [
{
createReadSpy: () => vi.spyOn(fs, "readFile"),
createReadSpy: () => vi.spyOn(jsonStore, "readJsonFileWithFallback"),
readAllowFrom: () => readChannelAllowFromStore("telegram", process.env, "yy"),
},
{