Files
openclaw/src/plugin-state/plugin-state-store.runtime.test.ts
Peter Steinberger cac0b2db18 refactor: move transcripts into core
Move meeting notes into core transcripts, remove the bundled meeting-notes plugin/API, and require explicit transcripts.enabled before exposing the recording-capable tool.
2026-05-26 14:51:11 +01:00

135 lines
4.9 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import { resolveStateDir } from "../config/paths.js";
import type { PluginRecord } from "../plugins/registry-types.js";
import { createPluginRegistry } from "../plugins/registry.js";
import type { PluginRuntime } from "../plugins/runtime/types.js";
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
import { resetPluginStateStoreForTests } from "./plugin-state-store.js";
function createPluginRecord(
id: string,
origin: PluginRecord["origin"] = "bundled",
opts: { trustedOfficialInstall?: boolean } = {},
): PluginRecord {
return {
id,
name: id,
source: `/plugins/${id}/index.ts`,
origin,
trustedOfficialInstall: opts.trustedOfficialInstall,
enabled: true,
status: "loaded",
toolNames: [],
hookNames: [],
channelIds: [],
cliBackendIds: [],
providerIds: [],
embeddingProviderIds: [],
speechProviderIds: [],
realtimeTranscriptionProviderIds: [],
realtimeVoiceProviderIds: [],
mediaUnderstandingProviderIds: [],
transcriptSourceProviderIds: [],
imageGenerationProviderIds: [],
videoGenerationProviderIds: [],
musicGenerationProviderIds: [],
webFetchProviderIds: [],
webSearchProviderIds: [],
migrationProviderIds: [],
memoryEmbeddingProviderIds: [],
agentHarnessIds: [],
cliCommands: [],
services: [],
gatewayDiscoveryServiceIds: [],
commands: [],
httpRoutes: 0,
hookCount: 0,
configSchema: false,
} as PluginRecord;
}
function createTestPluginRegistry() {
return createPluginRegistry({
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
runtime: {
state: {
resolveStateDir,
openKeyedStore: () => {
throw new Error("registry plugin runtime proxy should bind openKeyedStore");
},
},
} as unknown as PluginRuntime,
});
}
afterEach(() => {
resetPluginStateStoreForTests();
});
describe("plugin runtime state proxy", () => {
it("binds openKeyedStore to the bundled plugin id and keeps resolveStateDir", async () => {
await withOpenClawTestState({ label: "plugin-state-runtime" }, async (state) => {
const registry = createTestPluginRegistry();
const record = createPluginRecord("discord", "bundled");
registry.registry.plugins.push(record);
const api = registry.createApi(record, { config: {} });
expect(api.runtime.state.resolveStateDir()).toBe(state.stateDir);
const store = api.runtime.state.openKeyedStore<{ plugin: string }>({
namespace: "runtime",
maxEntries: 10,
});
await expect(store.registerIfAbsent("k", { plugin: "discord" })).resolves.toBe(true);
await expect(store.registerIfAbsent("k", { plugin: "duplicate" })).resolves.toBe(false);
const telegram = createPluginRecord("telegram", "bundled");
registry.registry.plugins.push(telegram);
const telegramApi = registry.createApi(telegram, { config: {} });
const telegramStore = telegramApi.runtime.state.openKeyedStore<{ plugin: string }>({
namespace: "runtime",
maxEntries: 10,
});
await expect(telegramStore.lookup("k")).resolves.toBeUndefined();
await expect(store.lookup("k")).resolves.toEqual({ plugin: "discord" });
});
});
it("allows trusted official global plugins to use keyed state", async () => {
await withOpenClawTestState({ label: "plugin-state-trusted-global" }, async () => {
const registry = createTestPluginRegistry();
const record = createPluginRecord("slack", "global", { trustedOfficialInstall: true });
registry.registry.plugins.push(record);
const api = registry.createApi(record, { config: {} });
const store = api.runtime.state.openKeyedStore<{ plugin: string }>({
namespace: "runtime",
maxEntries: 10,
});
await expect(store.register("thread", { plugin: "slack" })).resolves.toBeUndefined();
await expect(store.lookup("thread")).resolves.toEqual({ plugin: "slack" });
});
});
it("rejects external plugins in this release", () => {
const registry = createTestPluginRegistry();
const record = createPluginRecord("external-plugin", "workspace");
registry.registry.plugins.push(record);
const api = registry.createApi(record, { config: {} });
expect(() =>
api.runtime.state.openKeyedStore({ namespace: "runtime", maxEntries: 10 }),
).toThrow("openKeyedStore is only available for trusted plugins");
});
it("rejects untrusted global plugins", () => {
const registry = createTestPluginRegistry();
const record = createPluginRecord("external-plugin", "global");
registry.registry.plugins.push(record);
const api = registry.createApi(record, { config: {} });
expect(() =>
api.runtime.state.openKeyedStore({ namespace: "runtime", maxEntries: 10 }),
).toThrow("openKeyedStore is only available for trusted plugins");
});
});