From 7fc0859a01f6f7d2934cfc6cf2c6340c2439a8a3 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 29 Apr 2026 21:21:34 +0100 Subject: [PATCH] perf(tests): split plugin state runtime imports --- .../plugin-state-store.runtime.test.ts | 92 +++++++++++++++++++ src/plugin-state/plugin-state-store.test.ts | 84 ----------------- ...it-channel-readonly-setup-fallback.test.ts | 19 +++- 3 files changed, 106 insertions(+), 89 deletions(-) create mode 100644 src/plugin-state/plugin-state-store.runtime.test.ts diff --git a/src/plugin-state/plugin-state-store.runtime.test.ts b/src/plugin-state/plugin-state-store.runtime.test.ts new file mode 100644 index 00000000000..851cf6bf0ac --- /dev/null +++ b/src/plugin-state/plugin-state-store.runtime.test.ts @@ -0,0 +1,92 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import type { PluginRecord } from "../plugins/registry-types.js"; +import { createPluginRegistry } from "../plugins/registry.js"; +import { createPluginRuntime } from "../plugins/runtime/index.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"): PluginRecord { + return { + id, + name: id, + source: `/plugins/${id}/index.ts`, + origin, + enabled: true, + status: "loaded", + toolNames: [], + hookNames: [], + channelIds: [], + cliBackendIds: [], + providerIds: [], + speechProviderIds: [], + realtimeTranscriptionProviderIds: [], + realtimeVoiceProviderIds: [], + mediaUnderstandingProviderIds: [], + imageGenerationProviderIds: [], + videoGenerationProviderIds: [], + musicGenerationProviderIds: [], + webFetchProviderIds: [], + webSearchProviderIds: [], + migrationProviderIds: [], + memoryEmbeddingProviderIds: [], + agentHarnessIds: [], + gatewayMethods: [], + 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: createPluginRuntime(), + }); +} + +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 store.register("k", { plugin: "discord" }); + + 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("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 bundled plugins"); + }); +}); diff --git a/src/plugin-state/plugin-state-store.test.ts b/src/plugin-state/plugin-state-store.test.ts index 03fe8fc849e..a0232b38e29 100644 --- a/src/plugin-state/plugin-state-store.test.ts +++ b/src/plugin-state/plugin-state-store.test.ts @@ -1,9 +1,6 @@ import { mkdirSync, statSync } from "node:fs"; import { afterEach, describe, expect, it, vi } from "vitest"; import { requireNodeSqlite } from "../infra/node-sqlite.js"; -import type { PluginRecord } from "../plugins/registry-types.js"; -import { createPluginRegistry } from "../plugins/registry.js"; -import { createPluginRuntime } from "../plugins/runtime/index.js"; import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js"; import { closePluginStateSqliteStore, @@ -16,42 +13,6 @@ import { } from "./plugin-state-store.js"; import { resolvePluginStateDir, resolvePluginStateSqlitePath } from "./plugin-state-store.paths.js"; -function createPluginRecord(id: string, origin: PluginRecord["origin"] = "bundled"): PluginRecord { - return { - id, - name: id, - source: `/plugins/${id}/index.ts`, - origin, - enabled: true, - status: "loaded", - toolNames: [], - hookNames: [], - channelIds: [], - cliBackendIds: [], - providerIds: [], - speechProviderIds: [], - realtimeTranscriptionProviderIds: [], - realtimeVoiceProviderIds: [], - mediaUnderstandingProviderIds: [], - imageGenerationProviderIds: [], - videoGenerationProviderIds: [], - musicGenerationProviderIds: [], - webFetchProviderIds: [], - webSearchProviderIds: [], - migrationProviderIds: [], - memoryEmbeddingProviderIds: [], - agentHarnessIds: [], - gatewayMethods: [], - cliCommands: [], - services: [], - gatewayDiscoveryServiceIds: [], - commands: [], - httpRoutes: 0, - hookCount: 0, - configSchema: false, - } as PluginRecord; -} - afterEach(() => { vi.useRealTimers(); resetPluginStateStoreForTests(); @@ -332,48 +293,3 @@ describe("plugin state keyed store", () => { }); }); }); - -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 = createPluginRegistry({ - logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }, - runtime: createPluginRuntime(), - }); - 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 store.register("k", { plugin: "discord" }); - - 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("rejects external plugins in this release", () => { - const registry = createPluginRegistry({ - logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }, - runtime: createPluginRuntime(), - }); - 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 bundled plugins"); - }); -}); diff --git a/src/security/audit-channel-readonly-setup-fallback.test.ts b/src/security/audit-channel-readonly-setup-fallback.test.ts index 71f6cf08cbb..a891eba6897 100644 --- a/src/security/audit-channel-readonly-setup-fallback.test.ts +++ b/src/security/audit-channel-readonly-setup-fallback.test.ts @@ -2,11 +2,20 @@ import { describe, expect, it, vi } from "vitest"; import type { ChannelPlugin } from "../channels/plugins/types.plugin.js"; import type { OpenClawConfig } from "../config/config.js"; -const { listReadOnlyChannelPluginsForConfigMock, hasConfiguredChannelsForReadOnlyScopeMock } = - vi.hoisted(() => ({ - listReadOnlyChannelPluginsForConfigMock: vi.fn(), - hasConfiguredChannelsForReadOnlyScopeMock: vi.fn(), - })); +const { + collectEnabledInsecureOrDangerousFlagsMock, + listReadOnlyChannelPluginsForConfigMock, + hasConfiguredChannelsForReadOnlyScopeMock, +} = vi.hoisted(() => ({ + collectEnabledInsecureOrDangerousFlagsMock: vi.fn((_config: OpenClawConfig): string[] => []), + listReadOnlyChannelPluginsForConfigMock: vi.fn(), + hasConfiguredChannelsForReadOnlyScopeMock: vi.fn(), +})); + +vi.mock("./dangerous-config-flags.js", () => ({ + collectEnabledInsecureOrDangerousFlags: (config: OpenClawConfig) => + collectEnabledInsecureOrDangerousFlagsMock(config), +})); vi.mock("../channels/plugins/read-only.js", () => ({ listReadOnlyChannelPluginsForConfig: (...args: unknown[]) =>