test: merge cron delivery-target thread coverage

This commit is contained in:
Shakker
2026-04-02 01:34:46 +01:00
committed by Peter Steinberger
parent 5ff72867bf
commit 6299a5fbfe
2 changed files with 57 additions and 184 deletions

View File

@@ -1,182 +0,0 @@
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { telegramMessagingForTest } from "../infra/outbound/targets.test-helpers.js";
const mockStore: Record<string, Record<string, unknown>> = {};
let resolveDeliveryTarget: typeof import("./isolated-agent/delivery-target.js").resolveDeliveryTarget;
beforeEach(async () => {
vi.resetModules();
vi.doMock("../config/sessions/main-session.js", () => ({
resolveAgentMainSessionKey: vi.fn(
({ agentId }: { agentId: string }) => `agent:${agentId}:main`,
),
}));
vi.doMock("../config/sessions/paths.js", () => ({
resolveStorePath: vi.fn((_store: unknown, _opts: unknown) => "/mock/store.json"),
}));
vi.doMock("../config/sessions/store-load.js", () => ({
loadSessionStore: vi.fn((storePath: string) => mockStore[storePath] ?? {}),
}));
vi.doMock("../infra/outbound/channel-selection.runtime.js", () => ({
resolveMessageChannelSelection: vi.fn(async () => ({ channel: "telegram" })),
}));
vi.doMock("../channels/plugins/index.js", () => ({
getChannelPlugin: vi.fn(() => ({
meta: { label: "Telegram" },
config: {},
messaging: telegramMessagingForTest,
outbound: {
resolveTarget: ({ to }: { to?: string }) =>
to ? { ok: true, to } : { ok: false, error: new Error("missing") },
},
})),
normalizeChannelId: vi.fn((id: string) => id),
}));
({ resolveDeliveryTarget } = await import("./isolated-agent/delivery-target.js"));
vi.clearAllMocks();
for (const key of Object.keys(mockStore)) {
delete mockStore[key];
}
});
afterAll(() => {
vi.restoreAllMocks();
vi.resetModules();
});
describe("resolveDeliveryTarget thread session lookup", () => {
const cfg: OpenClawConfig = {};
it("uses thread session entry when sessionKey is provided and entry exists", async () => {
mockStore["/mock/store.json"] = {
"agent:main:main": {
sessionId: "s1",
updatedAt: 1,
lastChannel: "telegram",
lastTo: "-100111",
},
"agent:main:main:thread:9999": {
sessionId: "s2",
updatedAt: 2,
lastChannel: "telegram",
lastTo: "-100111",
lastThreadId: 9999,
},
};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "last",
sessionKey: "agent:main:main:thread:9999",
});
expect(result.to).toBe("-100111");
expect(result.threadId).toBe(9999);
expect(result.channel).toBe("telegram");
});
it("falls back to main session when sessionKey entry does not exist", async () => {
mockStore["/mock/store.json"] = {
"agent:main:main": {
sessionId: "s1",
updatedAt: 1,
lastChannel: "telegram",
lastTo: "-100222",
},
};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "last",
sessionKey: "agent:main:main:thread:nonexistent",
});
expect(result.to).toBe("-100222");
expect(result.threadId).toBeUndefined();
expect(result.channel).toBe("telegram");
});
it("falls back to main session when no sessionKey is provided", async () => {
mockStore["/mock/store.json"] = {
"agent:main:main": {
sessionId: "s1",
updatedAt: 1,
lastChannel: "telegram",
lastTo: "-100333",
},
};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "last",
});
expect(result.to).toBe("-100333");
expect(result.threadId).toBeUndefined();
});
it("preserves threadId from :topic: in delivery.to on first run (no session history)", async () => {
mockStore["/mock/store.json"] = {};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "telegram",
to: "63448508:topic:1008013",
});
expect(result.to).toBe("63448508");
expect(result.threadId).toBe(1008013);
expect(result.channel).toBe("telegram");
});
it("explicit accountId overrides session lastAccountId", async () => {
mockStore["/mock/store.json"] = {
"agent:main:main": {
sessionId: "s1",
updatedAt: 1,
lastChannel: "telegram",
lastTo: "-100444",
lastAccountId: "session-account",
},
};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "telegram",
to: "-100444",
accountId: "explicit-account",
});
expect(result.accountId).toBe("explicit-account");
expect(result.to).toBe("-100444");
});
it("preserves threadId from :topic: when lastTo differs", async () => {
mockStore["/mock/store.json"] = {
"agent:main:main": {
sessionId: "s1",
updatedAt: 1,
lastChannel: "telegram",
lastTo: "-100999",
},
};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "telegram",
to: "63448508:topic:1008013",
});
expect(result.to).toBe("63448508");
expect(result.threadId).toBe(1008013);
});
it("preserves explicit delivery.threadId on first run without topic syntax", async () => {
mockStore["/mock/store.json"] = {};
const result = await resolveDeliveryTarget(cfg, "main", {
channel: "telegram",
to: "63448508",
threadId: "1008013",
});
expect(result.to).toBe("63448508");
expect(result.threadId).toBe("1008013");
expect(result.channel).toBe("telegram");
});
});

View File

@@ -1,6 +1,7 @@
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { ChannelOutboundAdapter } from "../../channels/plugins/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import { telegramMessagingForTest } from "../../infra/outbound/targets.test-helpers.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../../plugins/runtime.js";
import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
@@ -104,6 +105,7 @@ beforeEach(() => {
plugin: createOutboundTestPlugin({
id: "telegram",
outbound: createStubOutbound("Telegram"),
messaging: telegramMessagingForTest,
}),
source: "test",
},
@@ -158,9 +160,13 @@ const DEFAULT_TARGET = {
type SessionStore = ReturnType<typeof loadSessionStore>;
function setSessionStore(store: SessionStore) {
vi.mocked(loadSessionStore).mockReturnValue(store);
}
function setMainSessionEntry(entry?: SessionStore[string]) {
const store = entry ? ({ "agent:test:main": entry } as SessionStore) : ({} as SessionStore);
vi.mocked(loadSessionStore).mockReturnValue(store);
setSessionStore(store);
}
function setLastSessionEntry(params: {
@@ -423,7 +429,7 @@ describe("resolveDeliveryTarget", () => {
});
it("uses sessionKey thread entry before main session entry", async () => {
vi.mocked(loadSessionStore).mockReturnValue({
setSessionStore({
"agent:test:main": {
sessionId: "main-session",
updatedAt: 1000,
@@ -435,6 +441,7 @@ describe("resolveDeliveryTarget", () => {
updatedAt: 2000,
lastChannel: "telegram",
lastTo: "thread-chat",
lastThreadId: 42,
},
} as SessionStore);
@@ -446,6 +453,27 @@ describe("resolveDeliveryTarget", () => {
expect(result.channel).toBe("telegram");
expect(result.to).toBe("thread-chat");
expect(result.threadId).toBe(42);
});
it("falls back to the main session entry when the requested sessionKey is missing", async () => {
setSessionStore({
"agent:test:main": {
sessionId: "main-session",
updatedAt: 1000,
lastChannel: "telegram",
lastTo: "main-chat",
},
} as SessionStore);
const result = await resolveDeliveryTarget(makeCfg({ bindings: [] }), AGENT_ID, {
channel: "last",
sessionKey: "agent:test:thread:missing",
to: undefined,
});
expect(result.channel).toBe("telegram");
expect(result.to).toBe("main-chat");
});
it("uses main session channel when channel=last and session route exists", async () => {
@@ -462,6 +490,33 @@ describe("resolveDeliveryTarget", () => {
expect(result.ok).toBe(true);
});
it("parses explicit telegram topic targets into delivery threadId", async () => {
setMainSessionEntry(undefined);
const result = await resolveDeliveryTarget(makeCfg({ bindings: [] }), AGENT_ID, {
channel: "telegram",
to: "63448508:topic:1008013",
});
expect(result.ok).toBe(true);
expect(result.to).toBe("63448508");
expect(result.threadId).toBe(1008013);
});
it("keeps explicit delivery threadId on first run without session history", async () => {
setMainSessionEntry(undefined);
const result = await resolveDeliveryTarget(makeCfg({ bindings: [] }), AGENT_ID, {
channel: "telegram",
to: "63448508",
threadId: "1008013",
});
expect(result.ok).toBe(true);
expect(result.to).toBe("63448508");
expect(result.threadId).toBe("1008013");
});
it("explicit delivery.accountId overrides session-derived accountId", async () => {
setLastSessionEntry({
sessionId: "sess-5",