mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:30:45 +00:00
test: speed up provider and security tests
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
getProviderRegistryAllowlistMocks,
|
||||
installProviderRegistryAllowlistMockDefaults,
|
||||
primeBundledProviderAllowlistFallback,
|
||||
} from "../test-utils/provider-registry-allowlist.test-helpers.js";
|
||||
|
||||
let getImageGenerationProvider: typeof import("./provider-registry.js").getImageGenerationProvider;
|
||||
let listImageGenerationProviders: typeof import("./provider-registry.js").listImageGenerationProviders;
|
||||
const mocks = getProviderRegistryAllowlistMocks();
|
||||
installProviderRegistryAllowlistMockDefaults();
|
||||
|
||||
describe("image-generation provider registry allowlist fallback", () => {
|
||||
beforeAll(async () => {
|
||||
({ getImageGenerationProvider, listImageGenerationProviders } =
|
||||
await import("./provider-registry.js"));
|
||||
});
|
||||
|
||||
it("adds bundled capability plugin ids to plugins.allow before fallback registry load", () => {
|
||||
const { cfg, compatConfig } = primeBundledProviderAllowlistFallback({
|
||||
contractKey: "imageGenerationProviders",
|
||||
});
|
||||
|
||||
expect(listImageGenerationProviders(cfg as OpenClawConfig)).toEqual([]);
|
||||
expect(getImageGenerationProvider("openai", cfg as OpenClawConfig)).toBeUndefined();
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: compatConfig,
|
||||
activate: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import type { ImageGenerationProviderPlugin } from "../plugins/types.js";
|
||||
|
||||
const { resolvePluginCapabilityProvidersMock } = vi.hoisted(() => ({
|
||||
@@ -40,10 +41,12 @@ describe("image-generation provider registry", () => {
|
||||
});
|
||||
|
||||
it("delegates provider resolution to the capability provider boundary", () => {
|
||||
expect(listImageGenerationProviders()).toEqual([]);
|
||||
const cfg = {} as OpenClawConfig;
|
||||
|
||||
expect(listImageGenerationProviders(cfg)).toEqual([]);
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "imageGenerationProviders",
|
||||
cfg: undefined,
|
||||
cfg,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import {
|
||||
getProviderRegistryAllowlistMocks,
|
||||
installProviderRegistryAllowlistMockDefaults,
|
||||
primeBundledProviderAllowlistFallback,
|
||||
} from "../test-utils/provider-registry-allowlist.test-helpers.js";
|
||||
|
||||
let buildMediaUnderstandingRegistry: typeof import("./provider-registry.js").buildMediaUnderstandingRegistry;
|
||||
let getMediaUnderstandingProvider: typeof import("./provider-registry.js").getMediaUnderstandingProvider;
|
||||
const mocks = getProviderRegistryAllowlistMocks();
|
||||
installProviderRegistryAllowlistMockDefaults();
|
||||
|
||||
describe("media-understanding provider registry allowlist fallback", () => {
|
||||
beforeAll(async () => {
|
||||
({ buildMediaUnderstandingRegistry, getMediaUnderstandingProvider } =
|
||||
await import("./provider-registry.js"));
|
||||
});
|
||||
|
||||
it("adds bundled capability plugin ids to plugins.allow before fallback registry load", () => {
|
||||
const { cfg, compatConfig } = primeBundledProviderAllowlistFallback({
|
||||
contractKey: "mediaUnderstandingProviders",
|
||||
});
|
||||
|
||||
const registry = buildMediaUnderstandingRegistry(undefined, cfg as OpenClawConfig);
|
||||
|
||||
expect(getMediaUnderstandingProvider("openai", registry)).toBeUndefined();
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: compatConfig,
|
||||
activate: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,88 +1,53 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
buildMediaUnderstandingRegistry,
|
||||
getMediaUnderstandingProvider,
|
||||
} from "./provider-registry.js";
|
||||
import type { MediaUnderstandingProvider } from "./types.js";
|
||||
|
||||
vi.mock("../plugins/capability-provider-runtime.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../plugins/capability-provider-runtime.js")>(
|
||||
"../plugins/capability-provider-runtime.js",
|
||||
);
|
||||
const runtime =
|
||||
await vi.importActual<typeof import("../plugins/runtime.js")>("../plugins/runtime.js");
|
||||
return {
|
||||
...actual,
|
||||
resolvePluginCapabilityProviders: ({ key }: { key: string }) =>
|
||||
key !== "mediaUnderstandingProviders"
|
||||
? []
|
||||
: (() => {
|
||||
const activeProviders =
|
||||
runtime
|
||||
.getActivePluginRegistry()
|
||||
?.mediaUnderstandingProviders.map((entry) => entry.provider) ?? [];
|
||||
return activeProviders.length > 0
|
||||
? activeProviders
|
||||
: [
|
||||
{ id: "groq", capabilities: ["image", "audio"] },
|
||||
{ id: "deepgram", capabilities: ["audio"] },
|
||||
];
|
||||
})(),
|
||||
};
|
||||
});
|
||||
const resolvePluginCapabilityProvidersMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../plugins/capability-provider-runtime.js", () => ({
|
||||
resolvePluginCapabilityProviders: resolvePluginCapabilityProvidersMock,
|
||||
}));
|
||||
|
||||
function createMediaProvider(
|
||||
params: Pick<MediaUnderstandingProvider, "id" | "capabilities"> &
|
||||
Partial<MediaUnderstandingProvider>,
|
||||
): MediaUnderstandingProvider {
|
||||
return params;
|
||||
}
|
||||
|
||||
describe("media-understanding provider registry", () => {
|
||||
afterEach(() => {
|
||||
setActivePluginRegistry(createEmptyPluginRegistry());
|
||||
beforeEach(() => {
|
||||
resolvePluginCapabilityProvidersMock.mockReset();
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([]);
|
||||
});
|
||||
|
||||
it("loads bundled providers by default when no active registry is present", () => {
|
||||
it("loads media providers from the capability runtime", () => {
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([
|
||||
createMediaProvider({ id: "groq", capabilities: ["image", "audio"] }),
|
||||
createMediaProvider({ id: "deepgram", capabilities: ["audio"] }),
|
||||
]);
|
||||
|
||||
const registry = buildMediaUnderstandingRegistry();
|
||||
|
||||
expect(getMediaUnderstandingProvider("groq", registry)?.id).toBe("groq");
|
||||
expect(getMediaUnderstandingProvider("deepgram", registry)?.id).toBe("deepgram");
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "mediaUnderstandingProviders",
|
||||
cfg: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("merges plugin-registered media providers into the active registry", async () => {
|
||||
const pluginRegistry = createEmptyPluginRegistry();
|
||||
pluginRegistry.mediaUnderstandingProviders.push({
|
||||
pluginId: "google",
|
||||
pluginName: "Google Plugin",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "google",
|
||||
capabilities: ["image", "audio", "video"],
|
||||
describeImage: async () => ({ text: "plugin image" }),
|
||||
transcribeAudio: async () => ({ text: "plugin audio" }),
|
||||
describeVideo: async () => ({ text: "plugin video" }),
|
||||
},
|
||||
});
|
||||
setActivePluginRegistry(pluginRegistry);
|
||||
it("keeps provider id normalization behavior for capability providers", () => {
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([
|
||||
createMediaProvider({ id: "google", capabilities: ["image", "audio", "video"] }),
|
||||
]);
|
||||
|
||||
const registry = buildMediaUnderstandingRegistry();
|
||||
const provider = getMediaUnderstandingProvider("gemini", registry);
|
||||
|
||||
expect(provider?.id).toBe("google");
|
||||
expect(await provider?.describeVideo?.({} as never)).toEqual({ text: "plugin video" });
|
||||
});
|
||||
|
||||
it("keeps provider id normalization behavior for plugin-owned providers", () => {
|
||||
const pluginRegistry = createEmptyPluginRegistry();
|
||||
pluginRegistry.mediaUnderstandingProviders.push({
|
||||
pluginId: "google",
|
||||
pluginName: "Google Plugin",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "google",
|
||||
capabilities: ["image", "audio", "video"],
|
||||
},
|
||||
});
|
||||
setActivePluginRegistry(pluginRegistry);
|
||||
|
||||
const registry = buildMediaUnderstandingRegistry();
|
||||
const provider = getMediaUnderstandingProvider("gemini", registry);
|
||||
|
||||
expect(provider?.id).toBe("google");
|
||||
expect(getMediaUnderstandingProvider("gemini", registry)?.id).toBe("google");
|
||||
});
|
||||
|
||||
it("auto-registers media-understanding for config providers with image-capable models (#51392)", () => {
|
||||
@@ -109,21 +74,15 @@ describe("media-understanding provider registry", () => {
|
||||
expect(textOnlyProvider).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not override plugin-registered providers when config also has image-capable models", async () => {
|
||||
const pluginRegistry = createEmptyPluginRegistry();
|
||||
pluginRegistry.mediaUnderstandingProviders.push({
|
||||
pluginId: "google",
|
||||
pluginName: "Google Plugin",
|
||||
source: "test",
|
||||
provider: {
|
||||
it("does not override capability providers when config also has image-capable models", async () => {
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([
|
||||
createMediaProvider({
|
||||
id: "google",
|
||||
capabilities: ["image", "audio", "video"],
|
||||
describeImage: async () => ({ text: "plugin image" }),
|
||||
transcribeAudio: async () => ({ text: "plugin audio" }),
|
||||
},
|
||||
});
|
||||
setActivePluginRegistry(pluginRegistry);
|
||||
|
||||
}),
|
||||
]);
|
||||
const cfg = {
|
||||
models: {
|
||||
providers: {
|
||||
@@ -140,6 +99,10 @@ describe("media-understanding provider registry", () => {
|
||||
expect(provider?.capabilities).toEqual(["image", "audio", "video"]);
|
||||
expect(await provider?.describeImage?.({} as never)).toEqual({ text: "plugin image" });
|
||||
expect(await provider?.transcribeAudio?.({} as never)).toEqual({ text: "plugin audio" });
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "mediaUnderstandingProviders",
|
||||
cfg,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not auto-register providers with audio or video only inputs", () => {
|
||||
|
||||
@@ -68,6 +68,18 @@ vi.mock("./plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
}));
|
||||
|
||||
vi.mock("./secrets/channel-env-vars.js", () => ({
|
||||
getChannelEnvVars: (channelId: string) => {
|
||||
const varsByChannel: Record<string, string[]> = {
|
||||
discord: ["DISCORD_BOT_TOKEN"],
|
||||
irc: ["IRC_HOST", "IRC_NICK"],
|
||||
slack: ["SLACK_BOT_TOKEN"],
|
||||
telegram: ["TELEGRAM_BOT_TOKEN"],
|
||||
};
|
||||
return varsByChannel[channelId] ?? [];
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("./plugin-sdk/facade-loader.js", () => ({
|
||||
...facadeMockHelpers,
|
||||
listImportedBundledPluginFacadeIds: () => [],
|
||||
@@ -114,7 +126,6 @@ describe("plugin activation boundary", () => {
|
||||
});
|
||||
expect(loadBundledPluginPublicSurfaceModuleSync).not.toHaveBeenCalled();
|
||||
|
||||
expect(loadBundledPluginPublicSurfaceModuleSync).not.toHaveBeenCalled();
|
||||
expect(parseBrowserMajorVersion("Google Chrome 144.0.7534.0")).toBe(144);
|
||||
expect(
|
||||
loadBundledPluginPublicSurfaceModuleSync.mock.calls.map(
|
||||
|
||||
@@ -83,6 +83,24 @@ vi.mock("../plugins/config-state.js", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
createPluginRegistryIdNormalizer: () => (id: string) => id,
|
||||
loadPluginRegistrySnapshot: () => ({
|
||||
diagnostics: [],
|
||||
plugins: [{ pluginId: "discord" }],
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../config/commands.js", () => ({
|
||||
resolveNativeSkillsEnabled: ({
|
||||
globalSetting,
|
||||
providerSetting,
|
||||
}: {
|
||||
globalSetting?: boolean | "auto";
|
||||
providerSetting?: boolean | "auto";
|
||||
}) => providerSetting === true || (providerSetting === undefined && globalSetting === true),
|
||||
}));
|
||||
|
||||
vi.mock("../channels/plugins/read-only.js", () => ({
|
||||
listReadOnlyChannelPluginsForConfig: () => mockChannelPlugins,
|
||||
}));
|
||||
|
||||
@@ -2,12 +2,19 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectEnabledInsecureOrDangerousFlags } from "./dangerous-config-flags.js";
|
||||
|
||||
const { loadPluginManifestRegistryMock } = vi.hoisted(() => ({
|
||||
loadPluginManifestRegistryMock: vi.fn(),
|
||||
const { resolvePluginConfigContractsByIdMock } = vi.hoisted(() => ({
|
||||
resolvePluginConfigContractsByIdMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry: loadPluginManifestRegistryMock,
|
||||
vi.mock("../plugins/config-contracts.js", () => ({
|
||||
collectPluginConfigContractMatches: ({
|
||||
pathPattern,
|
||||
root,
|
||||
}: {
|
||||
pathPattern: string;
|
||||
root: Record<string, unknown>;
|
||||
}) => (Object.hasOwn(root, pathPattern) ? [{ path: pathPattern, value: root[pathPattern] }] : []),
|
||||
resolvePluginConfigContractsById: resolvePluginConfigContractsByIdMock,
|
||||
}));
|
||||
|
||||
function asConfig(value: unknown): OpenClawConfig {
|
||||
@@ -16,21 +23,23 @@ function asConfig(value: unknown): OpenClawConfig {
|
||||
|
||||
describe("collectEnabledInsecureOrDangerousFlags", () => {
|
||||
beforeEach(() => {
|
||||
loadPluginManifestRegistryMock.mockReset();
|
||||
resolvePluginConfigContractsByIdMock.mockReset();
|
||||
resolvePluginConfigContractsByIdMock.mockReturnValue(new Map());
|
||||
});
|
||||
|
||||
it("collects manifest-declared dangerous plugin config values", () => {
|
||||
loadPluginManifestRegistryMock.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "acpx",
|
||||
configContracts: {
|
||||
dangerousFlags: [{ path: "permissionMode", equals: "approve-all" }],
|
||||
resolvePluginConfigContractsByIdMock.mockReturnValue(
|
||||
new Map([
|
||||
[
|
||||
"acpx",
|
||||
{
|
||||
configContracts: {
|
||||
dangerousFlags: [{ path: "permissionMode", equals: "approve-all" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
expect(
|
||||
collectEnabledInsecureOrDangerousFlags(
|
||||
@@ -50,17 +59,18 @@ describe("collectEnabledInsecureOrDangerousFlags", () => {
|
||||
});
|
||||
|
||||
it("ignores plugin config values that are not declared as dangerous", () => {
|
||||
loadPluginManifestRegistryMock.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "other",
|
||||
configContracts: {
|
||||
dangerousFlags: [{ path: "mode", equals: "danger" }],
|
||||
resolvePluginConfigContractsByIdMock.mockReturnValue(
|
||||
new Map([
|
||||
[
|
||||
"other",
|
||||
{
|
||||
configContracts: {
|
||||
dangerousFlags: [{ path: "mode", equals: "danger" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
expect(
|
||||
collectEnabledInsecureOrDangerousFlags(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { beforeEach, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
|
||||
|
||||
const providerRegistryAllowlistMocks = vi.hoisted(() => ({
|
||||
resolveRuntimePluginRegistry: vi.fn<
|
||||
|
||||
@@ -18,8 +18,8 @@ vi.mock("../infra/os-summary.js", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginManifestRegistryForPluginRegistry: loadPluginManifestRegistry,
|
||||
}));
|
||||
|
||||
import { buildTrajectoryArtifacts, buildTrajectoryRunMetadata } from "./metadata.js";
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
|
||||
import type { SpeechProviderPlugin } from "../plugins/types.js";
|
||||
|
||||
const resolveRuntimePluginRegistryMock = vi.fn();
|
||||
const loadPluginManifestRegistryMock = vi.fn(() => ({
|
||||
plugins: [
|
||||
{ id: "elevenlabs", origin: "bundled", contracts: { speechProviders: [{}] } },
|
||||
{ id: "microsoft", origin: "bundled", contracts: { speechProviders: [{}] } },
|
||||
{ id: "openai", origin: "bundled", contracts: { speechProviders: [{}] } },
|
||||
{ id: "tts-local-cli", origin: "bundled", contracts: { speechProviders: [{}] } },
|
||||
],
|
||||
}));
|
||||
const resolvePluginCapabilityProviderMock = vi.hoisted(() => vi.fn());
|
||||
const resolvePluginCapabilityProvidersMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../plugins/loader.js", () => ({
|
||||
resolveRuntimePluginRegistry: (...args: Parameters<typeof resolveRuntimePluginRegistryMock>) =>
|
||||
resolveRuntimePluginRegistryMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry: (...args: Parameters<typeof loadPluginManifestRegistryMock>) =>
|
||||
loadPluginManifestRegistryMock(...args),
|
||||
vi.mock("../plugins/capability-provider-runtime.js", () => ({
|
||||
resolvePluginCapabilityProvider: resolvePluginCapabilityProviderMock,
|
||||
resolvePluginCapabilityProviders: resolvePluginCapabilityProvidersMock,
|
||||
}));
|
||||
|
||||
let getSpeechProvider: typeof import("./provider-registry.js").getSpeechProvider;
|
||||
@@ -54,100 +41,48 @@ describe("speech provider registry", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue(undefined);
|
||||
loadPluginManifestRegistryMock.mockClear();
|
||||
});
|
||||
it("uses active plugin speech providers without reloading plugins", () => {
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue({
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
pluginId: "test-demo-speech",
|
||||
source: "test",
|
||||
provider: createSpeechProvider("demo-speech"),
|
||||
},
|
||||
],
|
||||
});
|
||||
const providers = listSpeechProviders();
|
||||
|
||||
expect(providers.map((provider) => provider.id)).toEqual(["demo-speech"]);
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
resolvePluginCapabilityProviderMock.mockReset();
|
||||
resolvePluginCapabilityProviderMock.mockReturnValue(undefined);
|
||||
resolvePluginCapabilityProvidersMock.mockReset();
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([]);
|
||||
});
|
||||
|
||||
it("uses active plugin speech providers even when config is provided", () => {
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue({
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
pluginId: "test-microsoft",
|
||||
source: "test",
|
||||
provider: createSpeechProvider("microsoft", ["edge"]),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
it("lists providers from the speech capability runtime", () => {
|
||||
const cfg = {} as OpenClawConfig;
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([createSpeechProvider("demo-speech")]);
|
||||
|
||||
expect(listSpeechProviders(cfg).map((provider) => provider.id)).toEqual(["microsoft"]);
|
||||
expect(getSpeechProvider("edge", cfg)?.id).toBe("microsoft");
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
expect(listSpeechProviders(cfg).map((provider) => provider.id)).toEqual(["demo-speech"]);
|
||||
expect(resolvePluginCapabilityProvidersMock).toHaveBeenCalledWith({
|
||||
key: "speechProviders",
|
||||
cfg,
|
||||
});
|
||||
});
|
||||
|
||||
it("loads speech providers from plugins when config is provided and no active providers exist", () => {
|
||||
resolveRuntimePluginRegistryMock.mockImplementation((params?: unknown) =>
|
||||
params === undefined
|
||||
? createEmptyPluginRegistry()
|
||||
: {
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
pluginId: "test-microsoft",
|
||||
source: "test",
|
||||
provider: createSpeechProvider("microsoft", ["edge"]),
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
it("gets providers by normalized id through the capability runtime", () => {
|
||||
const cfg = {} as OpenClawConfig;
|
||||
const provider = createSpeechProvider("microsoft", ["edge"]);
|
||||
resolvePluginCapabilityProviderMock.mockReturnValue(provider);
|
||||
|
||||
expect(listSpeechProviders(cfg).map((provider) => provider.id)).toEqual(["microsoft"]);
|
||||
expect(getSpeechProvider("edge", cfg)?.id).toBe("microsoft");
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith({
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
elevenlabs: { enabled: true },
|
||||
microsoft: { enabled: true },
|
||||
openai: { enabled: true },
|
||||
"tts-local-cli": { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
activate: false,
|
||||
expect(getSpeechProvider(" MICROSOFT ", cfg)).toBe(provider);
|
||||
expect(resolvePluginCapabilityProviderMock).toHaveBeenCalledWith({
|
||||
key: "speechProviders",
|
||||
providerId: "microsoft",
|
||||
cfg,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns no providers when neither plugins nor active registry provide speech support", () => {
|
||||
expect(listSpeechProviders()).toEqual([]);
|
||||
expect(getSpeechProvider("demo-speech")).toBeUndefined();
|
||||
expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it("canonicalizes the legacy edge alias to microsoft", () => {
|
||||
resolveRuntimePluginRegistryMock.mockReturnValue({
|
||||
...createEmptyPluginRegistry(),
|
||||
speechProviders: [
|
||||
{
|
||||
pluginId: "test-microsoft",
|
||||
source: "test",
|
||||
provider: createSpeechProvider("microsoft", ["edge"]),
|
||||
},
|
||||
],
|
||||
});
|
||||
it("canonicalizes aliases from listed providers when direct lookup misses", () => {
|
||||
resolvePluginCapabilityProvidersMock.mockReturnValue([
|
||||
createSpeechProvider("microsoft", ["edge"]),
|
||||
]);
|
||||
|
||||
expect(normalizeSpeechProviderId("edge")).toBe("edge");
|
||||
expect(canonicalizeSpeechProviderId("edge")).toBe("microsoft");
|
||||
});
|
||||
|
||||
it("returns empty results when the capability runtime has no speech providers", () => {
|
||||
expect(listSpeechProviders()).toEqual([]);
|
||||
expect(getSpeechProvider("demo-speech")).toBeUndefined();
|
||||
expect(canonicalizeSpeechProviderId("demo-speech")).toBe("demo-speech");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user