mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:40:44 +00:00
test: slim provider registry mocks
This commit is contained in:
@@ -20,10 +20,20 @@ vi.mock("../../../../src/infra/net/fetch-guard.js", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/agents/model-auth.js", async () => {
|
||||
const { createModelAuthMockModule } =
|
||||
await import("../../../../src/test-utils/model-auth-mock.js");
|
||||
return createModelAuthMockModule();
|
||||
const { resolveApiKeyForProviderMock } = vi.hoisted(() => ({
|
||||
resolveApiKeyForProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/agents/model-auth.js", () => {
|
||||
return {
|
||||
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
|
||||
requireApiKey: (auth: { apiKey?: string; mode?: string }, provider: string) => {
|
||||
if (auth.apiKey) {
|
||||
return auth.apiKey;
|
||||
}
|
||||
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const createGeminiFetchMock = (embeddingValues = [1, 2, 3]) =>
|
||||
|
||||
@@ -22,10 +22,20 @@ vi.mock("../../../../src/infra/net/fetch-guard.js", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/agents/model-auth.js", async () => {
|
||||
const { createModelAuthMockModule } =
|
||||
await import("../../../../src/test-utils/model-auth-mock.js");
|
||||
return createModelAuthMockModule();
|
||||
const { resolveApiKeyForProviderMock } = vi.hoisted(() => ({
|
||||
resolveApiKeyForProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/agents/model-auth.js", () => {
|
||||
return {
|
||||
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
|
||||
requireApiKey: (auth: { apiKey?: string; mode?: string }, provider: string) => {
|
||||
if (auth.apiKey) {
|
||||
return auth.apiKey;
|
||||
}
|
||||
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const createFetchMock = () => {
|
||||
|
||||
@@ -4,10 +4,20 @@ import { createEmbeddingProvider, DEFAULT_LOCAL_MODEL } from "./embeddings.js";
|
||||
import * as nodeLlamaModule from "./node-llama.js";
|
||||
import { mockPublicPinnedHostname } from "./test-helpers/ssrf.js";
|
||||
|
||||
vi.mock("../../../../src/agents/model-auth.js", async () => {
|
||||
const { createModelAuthMockModule } =
|
||||
await import("../../../../src/test-utils/model-auth-mock.js");
|
||||
return createModelAuthMockModule();
|
||||
const { resolveApiKeyForProviderMock } = vi.hoisted(() => ({
|
||||
resolveApiKeyForProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/agents/model-auth.js", () => {
|
||||
return {
|
||||
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
|
||||
requireApiKey: (auth: { apiKey?: string; mode?: string }, provider: string) => {
|
||||
if (auth.apiKey) {
|
||||
return auth.apiKey;
|
||||
}
|
||||
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../../src/infra/net/fetch-guard.js", () => ({
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import type { ImageGenerationProviderPlugin } from "../plugins/types.js";
|
||||
|
||||
const { resolveRuntimePluginRegistryMock } = vi.hoisted(() => ({
|
||||
resolveRuntimePluginRegistryMock: vi.fn<
|
||||
(params?: unknown) => ReturnType<typeof createEmptyPluginRegistry> | undefined
|
||||
>(() => undefined),
|
||||
const { resolvePluginCapabilityProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginCapabilityProvidersMock: vi.fn<() => ImageGenerationProviderPlugin[]>(() => []),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/loader.js", () => ({
|
||||
resolveRuntimePluginRegistry: resolveRuntimePluginRegistryMock,
|
||||
vi.mock("../plugins/capability-provider-runtime.js", () => ({
|
||||
resolvePluginCapabilityProviders: resolvePluginCapabilityProvidersMock,
|
||||
}));
|
||||
|
||||
let getImageGenerationProvider: typeof import("./provider-registry.js").getImageGenerationProvider;
|
||||
let listImageGenerationProviders: typeof import("./provider-registry.js").listImageGenerationProviders;
|
||||
|
||||
function createProvider(
|
||||
params: Pick<ImageGenerationProviderPlugin, "id"> & Partial<ImageGenerationProviderPlugin>,
|
||||
): ImageGenerationProviderPlugin {
|
||||
return {
|
||||
label: params.id,
|
||||
capabilities: {
|
||||
generate: {},
|
||||
edit: { enabled: false },
|
||||
},
|
||||
generateImage: async () => ({
|
||||
images: [{ buffer: Buffer.from("image"), mimeType: "image/png" }],
|
||||
}),
|
||||
...params,
|
||||
};
|
||||
}
|
||||
|
||||
describe("image-generation provider registry", () => {
|
||||
beforeAll(async () => {
|
||||
({ getImageGenerationProvider, listImageGenerationProviders } =
|
||||
@@ -21,78 +35,35 @@ describe("image-generation provider registry", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(undefined);
|
||||
resolvePluginCapabilityProvidersMock.mockReset();
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([]);
|
||||
});
|
||||
|
||||
it("does not load plugins when listing without config", () => {
|
||||
it("delegates provider resolution to the capability provider boundary", () => {
|
||||
expect(listImageGenerationProviders()).toEqual([]);
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "imageGenerationProviders",
|
||||
cfg: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("uses active plugin providers without loading from disk", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.imageGenerationProviders.push({
|
||||
pluginId: "custom-image",
|
||||
pluginName: "Custom Image",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "custom-image",
|
||||
label: "Custom Image",
|
||||
capabilities: {
|
||||
generate: {},
|
||||
edit: { enabled: false },
|
||||
},
|
||||
generateImage: async () => ({
|
||||
images: [{ buffer: Buffer.from("image"), mimeType: "image/png" }],
|
||||
}),
|
||||
},
|
||||
});
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([createProvider({ id: "custom-image" })]);
|
||||
|
||||
const provider = getImageGenerationProvider("custom-image");
|
||||
|
||||
expect(provider?.id).toBe("custom-image");
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "imageGenerationProviders",
|
||||
cfg: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores prototype-like provider ids and aliases", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.imageGenerationProviders.push(
|
||||
{
|
||||
pluginId: "blocked-image",
|
||||
pluginName: "Blocked Image",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "__proto__",
|
||||
aliases: ["constructor", "prototype"],
|
||||
capabilities: {
|
||||
generate: {},
|
||||
edit: { enabled: false },
|
||||
},
|
||||
generateImage: async () => ({
|
||||
images: [{ buffer: Buffer.from("image"), mimeType: "image/png" }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
pluginId: "safe-image",
|
||||
pluginName: "Safe Image",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "safe-image",
|
||||
aliases: ["safe-alias", "constructor"],
|
||||
capabilities: {
|
||||
generate: {},
|
||||
edit: { enabled: false },
|
||||
},
|
||||
generateImage: async () => ({
|
||||
images: [{ buffer: Buffer.from("image"), mimeType: "image/png" }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([
|
||||
createProvider({ id: "__proto__", aliases: ["constructor", "prototype"] }),
|
||||
createProvider({ id: "safe-image", aliases: ["safe-alias", "constructor"] }),
|
||||
]);
|
||||
|
||||
expect(listImageGenerationProviders().map((provider) => provider.id)).toEqual(["safe-image"]);
|
||||
expect(getImageGenerationProvider("__proto__")).toBeUndefined();
|
||||
|
||||
@@ -20,9 +20,20 @@ import {
|
||||
type JsonFetchMock,
|
||||
} from "./embeddings-provider.test-support.js";
|
||||
|
||||
vi.mock("../../agents/model-auth.js", async () => {
|
||||
const { createModelAuthMockModule } = await import("../../test-utils/model-auth-mock.js");
|
||||
return createModelAuthMockModule();
|
||||
const { resolveApiKeyForProviderMock } = vi.hoisted(() => ({
|
||||
resolveApiKeyForProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/model-auth.js", () => {
|
||||
return {
|
||||
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
|
||||
requireApiKey: (auth: { apiKey?: string; mode?: string }, provider: string) => {
|
||||
if (auth.apiKey) {
|
||||
return auth.apiKey;
|
||||
}
|
||||
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -9,9 +9,20 @@ import {
|
||||
} 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");
|
||||
return createModelAuthMockModule();
|
||||
const { resolveApiKeyForProviderMock } = vi.hoisted(() => ({
|
||||
resolveApiKeyForProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/model-auth.js", () => {
|
||||
return {
|
||||
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
|
||||
requireApiKey: (auth: { apiKey?: string; mode?: string }, provider: string) => {
|
||||
if (auth.apiKey) {
|
||||
return auth.apiKey;
|
||||
}
|
||||
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
let createVoyageEmbeddingProvider: typeof import("./embeddings-voyage.js").createVoyageEmbeddingProvider;
|
||||
|
||||
@@ -17,6 +17,7 @@ const {
|
||||
bedrockSendMock,
|
||||
createOllamaEmbeddingProviderMock,
|
||||
defaultProviderMock,
|
||||
resolveApiKeyForProviderMock,
|
||||
resolveCredentialsMock,
|
||||
} = vi.hoisted(() => ({
|
||||
bedrockSendMock: vi.fn(),
|
||||
@@ -25,11 +26,19 @@ const {
|
||||
}),
|
||||
defaultProviderMock: vi.fn(),
|
||||
resolveCredentialsMock: vi.fn(),
|
||||
resolveApiKeyForProviderMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/model-auth.js", async () => {
|
||||
const { createModelAuthMockModule } = await import("../../test-utils/model-auth-mock.js");
|
||||
return createModelAuthMockModule();
|
||||
vi.mock("../../agents/model-auth.js", () => {
|
||||
return {
|
||||
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
|
||||
requireApiKey: (auth: { apiKey?: string; mode?: string }, provider: string) => {
|
||||
if (auth.apiKey) {
|
||||
return auth.apiKey;
|
||||
}
|
||||
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./embeddings-ollama.js", () => ({
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import type { VideoGenerationProviderPlugin } from "../plugins/types.js";
|
||||
|
||||
const { resolveRuntimePluginRegistryMock } = vi.hoisted(() => ({
|
||||
resolveRuntimePluginRegistryMock: vi.fn<
|
||||
(params?: unknown) => ReturnType<typeof createEmptyPluginRegistry> | undefined
|
||||
>(() => undefined),
|
||||
const { resolvePluginCapabilityProvidersMock } = vi.hoisted(() => ({
|
||||
resolvePluginCapabilityProvidersMock: vi.fn<() => VideoGenerationProviderPlugin[]>(() => []),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/loader.js", () => ({
|
||||
resolveRuntimePluginRegistry: resolveRuntimePluginRegistryMock,
|
||||
vi.mock("../plugins/capability-provider-runtime.js", () => ({
|
||||
resolvePluginCapabilityProviders: resolvePluginCapabilityProvidersMock,
|
||||
}));
|
||||
|
||||
let getVideoGenerationProvider: typeof import("./provider-registry.js").getVideoGenerationProvider;
|
||||
let listVideoGenerationProviders: typeof import("./provider-registry.js").listVideoGenerationProviders;
|
||||
|
||||
function createProvider(
|
||||
params: Pick<VideoGenerationProviderPlugin, "id"> & Partial<VideoGenerationProviderPlugin>,
|
||||
): VideoGenerationProviderPlugin {
|
||||
return {
|
||||
label: params.id,
|
||||
capabilities: {},
|
||||
generateVideo: async () => ({
|
||||
videos: [{ buffer: Buffer.from("video"), mimeType: "video/mp4" }],
|
||||
}),
|
||||
...params,
|
||||
};
|
||||
}
|
||||
|
||||
describe("video-generation provider registry", () => {
|
||||
beforeAll(async () => {
|
||||
({ getVideoGenerationProvider, listVideoGenerationProviders } =
|
||||
@@ -21,69 +32,35 @@ describe("video-generation provider registry", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(undefined);
|
||||
resolvePluginCapabilityProvidersMock.mockReset();
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([]);
|
||||
});
|
||||
|
||||
it("does not load plugins when listing without config", () => {
|
||||
it("delegates provider resolution to the capability provider boundary", () => {
|
||||
expect(listVideoGenerationProviders()).toEqual([]);
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "videoGenerationProviders",
|
||||
cfg: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("uses active plugin providers without loading from disk", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.videoGenerationProviders.push({
|
||||
pluginId: "custom-video",
|
||||
pluginName: "Custom Video",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "custom-video",
|
||||
label: "Custom Video",
|
||||
capabilities: {},
|
||||
generateVideo: async () => ({
|
||||
videos: [{ buffer: Buffer.from("video"), mimeType: "video/mp4" }],
|
||||
}),
|
||||
},
|
||||
});
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([createProvider({ id: "custom-video" })]);
|
||||
|
||||
const provider = getVideoGenerationProvider("custom-video");
|
||||
|
||||
expect(provider?.id).toBe("custom-video");
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "videoGenerationProviders",
|
||||
cfg: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores prototype-like provider ids and aliases", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.videoGenerationProviders.push(
|
||||
{
|
||||
pluginId: "blocked-video",
|
||||
pluginName: "Blocked Video",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "__proto__",
|
||||
aliases: ["constructor", "prototype"],
|
||||
capabilities: {},
|
||||
generateVideo: async () => ({
|
||||
videos: [{ buffer: Buffer.from("video"), mimeType: "video/mp4" }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
pluginId: "safe-video",
|
||||
pluginName: "Safe Video",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "safe-video",
|
||||
aliases: ["safe-alias", "constructor"],
|
||||
capabilities: {},
|
||||
generateVideo: async () => ({
|
||||
videos: [{ buffer: Buffer.from("video"), mimeType: "video/mp4" }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([
|
||||
createProvider({ id: "__proto__", aliases: ["constructor", "prototype"] }),
|
||||
createProvider({ id: "safe-video", aliases: ["safe-alias", "constructor"] }),
|
||||
]);
|
||||
|
||||
expect(listVideoGenerationProviders().map((provider) => provider.id)).toEqual(["safe-video"]);
|
||||
expect(getVideoGenerationProvider("__proto__")).toBeUndefined();
|
||||
|
||||
Reference in New Issue
Block a user