mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
test(signal): isolate tool-result harness lifecycle (#110720)
This commit is contained in:
committed by
GitHub
parent
e8566596e0
commit
3f976a949a
@@ -8,6 +8,7 @@ import {
|
||||
createChannelIngressQueueForTests,
|
||||
} from "openclaw/plugin-sdk/plugin-state-test-runtime";
|
||||
import type { MockFn } from "openclaw/plugin-sdk/plugin-test-runtime";
|
||||
import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing";
|
||||
import { afterEach, beforeEach, vi } from "vitest";
|
||||
import type { SignalDaemonHandle } from "./daemon.js";
|
||||
import { setSignalRuntime } from "./runtime.js";
|
||||
@@ -40,9 +41,7 @@ const streamMock = vi.hoisted(() => vi.fn()) as unknown as MockFn;
|
||||
const signalCheckMock = vi.hoisted(() => vi.fn()) as unknown as MockFn;
|
||||
const signalRpcRequestMock = vi.hoisted(() => vi.fn()) as unknown as MockFn;
|
||||
const spawnSignalDaemonMock = vi.hoisted(() => vi.fn()) as unknown as MockFn;
|
||||
const signalToolResultSessionStorePath = vi.hoisted(
|
||||
() => `/tmp/openclaw-signal-tool-result-sessions-${process.pid}.json`,
|
||||
);
|
||||
const signalToolResultSessionStore = vi.hoisted(() => ({ path: "" }));
|
||||
let signalToolResultStateDir: string | undefined;
|
||||
let signalToolResultIngressQueue: ReturnType<typeof createChannelIngressQueueForTests> | undefined;
|
||||
|
||||
@@ -149,7 +148,7 @@ vi.mock("openclaw/plugin-sdk/session-store-runtime", async () => {
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
resolveStorePath: vi.fn(() => signalToolResultSessionStorePath),
|
||||
resolveStorePath: vi.fn(() => signalToolResultSessionStore.path),
|
||||
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
|
||||
readSessionUpdatedAt: vi.fn(() => undefined),
|
||||
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -175,7 +174,10 @@ vi.mock("openclaw/plugin-sdk/channel-inbound", async () => {
|
||||
}
|
||||
return {
|
||||
...resolved,
|
||||
replyResolver: (...replyArgs: unknown[]) => replyMock(...replyArgs),
|
||||
replyResolver: async (...replyArgs: unknown[]) => {
|
||||
await resolved.replyOptions?.turnAdoptionLifecycle?.onAdopted();
|
||||
return await replyMock(...replyArgs);
|
||||
},
|
||||
} as typeof resolved;
|
||||
},
|
||||
},
|
||||
@@ -264,6 +266,7 @@ export function installSignalToolResultTestHooks() {
|
||||
);
|
||||
const stateDir = await fs.realpath(createdStateDir);
|
||||
signalToolResultStateDir = stateDir;
|
||||
signalToolResultSessionStore.path = path.join(stateDir, "sessions.json");
|
||||
signalToolResultIngressQueue = undefined;
|
||||
setSignalRuntime({
|
||||
logging: {
|
||||
@@ -294,7 +297,7 @@ export function installSignalToolResultTestHooks() {
|
||||
} as unknown as PluginRuntime);
|
||||
config = {
|
||||
messages: { responsePrefix: "PFX" },
|
||||
session: { store: signalToolResultSessionStorePath },
|
||||
session: { store: signalToolResultSessionStore.path },
|
||||
channels: {
|
||||
signal: { autoStart: false, dmPolicy: "open", allowFrom: ["*"] },
|
||||
},
|
||||
@@ -318,10 +321,12 @@ export function installSignalToolResultTestHooks() {
|
||||
afterEach(async () => {
|
||||
clearSignalRuntimeForTest();
|
||||
signalToolResultIngressQueue = undefined;
|
||||
closeOpenClawAgentDatabasesForTest();
|
||||
closeOpenClawStateDatabaseForTest();
|
||||
if (signalToolResultStateDir) {
|
||||
await fs.rm(signalToolResultStateDir, { recursive: true, force: true });
|
||||
signalToolResultStateDir = undefined;
|
||||
}
|
||||
signalToolResultSessionStore.path = "";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const getLoadedChannelPluginForRead = vi.hoisted(() => vi.fn());
|
||||
const getChannelPlugin = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("./index.js", () => ({
|
||||
getChannelPlugin,
|
||||
normalizeChannelId: (raw?: string | null) => raw?.trim().toLowerCase() || null,
|
||||
}));
|
||||
|
||||
vi.mock("./registry-loaded.js", () => ({
|
||||
getLoadedChannelPluginForRead,
|
||||
}));
|
||||
|
||||
import { resolveExplicitDeliveryTargetCompat } from "./target-parsing-loaded.js";
|
||||
|
||||
describe("resolveExplicitDeliveryTargetCompat", () => {
|
||||
beforeEach(() => {
|
||||
getLoadedChannelPluginForRead.mockReset();
|
||||
getChannelPlugin.mockReset();
|
||||
});
|
||||
|
||||
it("keeps unloaded channels on generic parsing without activating a plugin", () => {
|
||||
getLoadedChannelPluginForRead.mockReturnValue(undefined);
|
||||
|
||||
expect(
|
||||
resolveExplicitDeliveryTargetCompat({
|
||||
channel: " LegacyChat ",
|
||||
rawTarget: " room-a ",
|
||||
fallbackThreadId: "77",
|
||||
}),
|
||||
).toEqual({
|
||||
channel: "legacychat",
|
||||
rawTo: "room-a",
|
||||
to: "room-a",
|
||||
threadId: "77",
|
||||
chatType: undefined,
|
||||
});
|
||||
expect(getLoadedChannelPluginForRead).toHaveBeenCalledWith("legacychat");
|
||||
expect(getChannelPlugin).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("preserves the deprecated parser contract for an already-loaded plugin", () => {
|
||||
const parseExplicitTarget = vi.fn(() => ({
|
||||
to: "room-a",
|
||||
threadId: 42,
|
||||
chatType: "group" as const,
|
||||
}));
|
||||
getLoadedChannelPluginForRead.mockReturnValue({
|
||||
messaging: { parseExplicitTarget },
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveExplicitDeliveryTargetCompat({
|
||||
channel: "legacychat",
|
||||
rawTarget: "room-a:topic:42",
|
||||
}),
|
||||
).toEqual({
|
||||
channel: "legacychat",
|
||||
rawTo: "room-a:topic:42",
|
||||
to: "room-a",
|
||||
threadId: 42,
|
||||
chatType: "group",
|
||||
});
|
||||
expect(parseExplicitTarget).toHaveBeenCalledWith({ raw: "room-a:topic:42" });
|
||||
expect(getChannelPlugin).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
normalizeOptionalThreadValue,
|
||||
} from "@openclaw/normalization-core/string-coerce";
|
||||
import type { ChannelRouteParsedTarget } from "../../plugin-sdk/channel-route.js";
|
||||
import { getChannelPlugin, normalizeChannelId } from "./index.js";
|
||||
import { normalizeChannelId } from "./index.js";
|
||||
import { getLoadedChannelPluginForRead } from "./registry-loaded.js";
|
||||
|
||||
/** Preserves the shipped `parseExplicitTarget` SDK contract until its deprecation window ends. */
|
||||
@@ -19,13 +19,10 @@ export function resolveExplicitDeliveryTargetCompat(params: {
|
||||
return null;
|
||||
}
|
||||
const normalizedChannel = normalizeChannelId(channel) ?? channel;
|
||||
const parsed =
|
||||
getLoadedChannelPluginForRead(normalizedChannel)?.messaging?.parseExplicitTarget?.({
|
||||
raw: rawTo,
|
||||
}) ??
|
||||
getChannelPlugin(normalizedChannel)?.messaging?.parseExplicitTarget?.({
|
||||
raw: rawTo,
|
||||
});
|
||||
// This deprecated hook belongs to the active plugin. Source-loading a bundled
|
||||
// plugin here turns every target parse into broad runtime discovery.
|
||||
const plugin = getLoadedChannelPluginForRead(normalizedChannel);
|
||||
const parsed = plugin?.messaging?.parseExplicitTarget?.({ raw: rawTo });
|
||||
return {
|
||||
channel,
|
||||
rawTo,
|
||||
|
||||
Reference in New Issue
Block a user