test: tighten runtime setup and boundary guards

This commit is contained in:
Peter Steinberger
2026-04-03 18:50:45 +01:00
parent 3edfc494df
commit 7439479047
2 changed files with 74 additions and 5 deletions

View File

@@ -72,6 +72,15 @@ function findPluginSdkImports(source: string): string[] {
].map((match) => match[1]);
}
function findBundledPluginPublicSurfaceImports(source: string): string[] {
return [
...source.matchAll(/from\s+["'](?:\.\.\/)+test-utils\/bundled-plugin-public-surface\.js["']/g),
...source.matchAll(
/import\(\s*["'](?:\.\.\/)+test-utils\/bundled-plugin-public-surface\.js["']\s*\)/g,
),
].map((match) => match[0]);
}
function getImportBasename(importPath: string): string {
return importPath.split("/").at(-1) ?? importPath;
}
@@ -143,6 +152,24 @@ describe("non-extension test boundaries", () => {
expect(imports).toEqual([]);
});
it("keeps bundled plugin public-surface imports on an explicit core allowlist", () => {
const allowed = new Set([
"src/auto-reply/reply.triggers.trigger-handling.test-harness.ts",
"src/channels/plugins/contracts/slack-outbound-harness.ts",
"src/commands/channel-test-registry.ts",
"src/gateway/test-helpers.mocks.ts",
"src/plugin-sdk/testing.ts",
]);
const files = walkCode(path.join(repoRoot, "src"));
const offenders = files.filter((file) => {
const source = fs.readFileSync(path.join(repoRoot, file), "utf8");
return findBundledPluginPublicSurfaceImports(source).length > 0 && !allowed.has(file);
});
expect(offenders).toEqual([]);
});
it("keeps bundled plugin sync test-api loaders out of core tests", () => {
const files = [
...walkCode(path.join(repoRoot, "src")),

View File

@@ -1,5 +1,4 @@
import { afterAll, afterEach, beforeAll } from "vitest";
import { createTopLevelChannelReplyToModeResolver } from "../src/channels/plugins/threading-helpers.js";
import type {
ChannelId,
ChannelOutboundAdapter,
@@ -9,7 +8,6 @@ import type { OpenClawConfig } from "../src/config/config.js";
import type { OutboundSendDeps } from "../src/infra/outbound/deliver.js";
import type { PluginRegistry } from "../src/plugins/registry.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../src/plugins/runtime.js";
import { createTestRegistry } from "../src/test-utils/channel-plugins.js";
import { installSharedTestSetup } from "./setup.shared.js";
const testEnv = installSharedTestSetup();
@@ -30,6 +28,10 @@ type WorkerCleanupDeps = {
cleanupSessionStateForTest: typeof import("../src/test-utils/session-state-cleanup.js").cleanupSessionStateForTest;
};
type ReplyToModeResolver = NonNullable<
NonNullable<ChannelPlugin["threading"]>["resolveReplyToMode"]
>;
const workerRuntimeState = (() => {
const globalState = globalThis as typeof globalThis & {
[WORKER_RUNTIME_STATE]?: WorkerRuntimeState;
@@ -82,6 +84,46 @@ const pickSendFn = (id: ChannelId, deps?: OutboundSendDeps) => {
return deps?.[id] as ((...args: unknown[]) => Promise<unknown>) | undefined;
};
function createTopLevelChannelReplyToModeResolverForTest(channelId: string): ReplyToModeResolver {
return ({ cfg }) => {
const channelConfig = (
cfg.channels as Record<string, { replyToMode?: "off" | "first" | "all" }> | undefined
)?.[channelId];
return channelConfig?.replyToMode ?? "off";
};
}
function createTestRegistryForSetup(
channels: Array<{ pluginId: string; plugin: ChannelPlugin; source: string }> = [],
): PluginRegistry {
return {
plugins: [],
tools: [],
hooks: [],
typedHooks: [],
channels: channels as unknown as PluginRegistry["channels"],
channelSetups: channels.map((entry) => ({
pluginId: entry.pluginId,
plugin: entry.plugin,
source: entry.source,
enabled: true,
})),
providers: [],
speechProviders: [],
mediaUnderstandingProviders: [],
imageGenerationProviders: [],
webFetchProviders: [],
webSearchProviders: [],
gatewayHandlers: {},
httpRoutes: [],
cliRegistrars: [],
services: [],
commands: [],
conversationBindingResolvedHandlers: [],
diagnostics: [],
};
}
function resolveSlackStubReplyToMode(params: {
cfg: OpenClawConfig;
chatType?: string | null;
@@ -204,13 +246,13 @@ const createStubPlugin = (params: {
});
const createDefaultRegistry = () =>
createTestRegistry([
createTestRegistryForSetup([
{
pluginId: "discord",
plugin: createStubPlugin({
id: "discord",
label: "Discord",
resolveReplyToMode: createTopLevelChannelReplyToModeResolver("discord"),
resolveReplyToMode: createTopLevelChannelReplyToModeResolverForTest("discord"),
}),
source: "test",
},
@@ -229,7 +271,7 @@ const createDefaultRegistry = () =>
...createStubPlugin({
id: "telegram",
label: "Telegram",
resolveReplyToMode: createTopLevelChannelReplyToModeResolver("telegram"),
resolveReplyToMode: createTopLevelChannelReplyToModeResolverForTest("telegram"),
}),
status: {
buildChannelSummary: async () => ({