test(cron): dedupe delivery target tests and add coverage

This commit is contained in:
Peter Steinberger
2026-02-18 12:04:09 +00:00
parent 36a34e5959
commit 3356aae704

View File

@@ -1,4 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import { DEFAULT_CHAT_CHANNEL } from "../../channels/registry.js";
import type { OpenClawConfig } from "../../config/config.js";
vi.mock("../../config/sessions.js", () => ({
@@ -12,6 +13,7 @@ vi.mock("../../infra/outbound/channel-selection.js", () => ({
}));
import { loadSessionStore } from "../../config/sessions.js";
import { resolveMessageChannelSelection } from "../../infra/outbound/channel-selection.js";
import { resolveDeliveryTarget } from "./delivery-target.js";
function makeCfg(overrides?: Partial<OpenClawConfig>): OpenClawConfig {
@@ -22,9 +24,34 @@ function makeCfg(overrides?: Partial<OpenClawConfig>): OpenClawConfig {
} as OpenClawConfig;
}
const AGENT_ID = "agent-b";
const DEFAULT_TARGET = {
channel: "telegram" as const,
to: "123456",
};
type SessionStore = ReturnType<typeof loadSessionStore>;
function setMainSessionEntry(entry?: SessionStore[string]) {
const store = entry ? ({ "agent:test:main": entry } as SessionStore) : ({} as SessionStore);
vi.mocked(loadSessionStore).mockReturnValue(store);
}
async function resolveForAgent(params: {
cfg: OpenClawConfig;
target?: { channel?: "last" | "telegram"; to?: string };
}) {
const channel = params.target ? params.target.channel : DEFAULT_TARGET.channel;
const to = params.target && "to" in params.target ? params.target.to : DEFAULT_TARGET.to;
return resolveDeliveryTarget(params.cfg, AGENT_ID, {
channel,
to,
});
}
describe("resolveDeliveryTarget", () => {
it("falls back to bound accountId when session has no lastAccountId", async () => {
vi.mocked(loadSessionStore).mockReturnValue({});
setMainSessionEntry(undefined);
const cfg = makeCfg({
bindings: [
@@ -35,23 +62,18 @@ describe("resolveDeliveryTarget", () => {
],
});
const result = await resolveDeliveryTarget(cfg, "agent-b", {
channel: "telegram",
to: "123456",
});
const result = await resolveForAgent({ cfg });
expect(result.accountId).toBe("account-b");
});
it("preserves session lastAccountId when present", async () => {
vi.mocked(loadSessionStore).mockReturnValue({
"agent:test:main": {
sessionId: "sess-1",
updatedAt: 1000,
lastChannel: "telegram",
lastTo: "123456",
lastAccountId: "session-account",
},
setMainSessionEntry({
sessionId: "sess-1",
updatedAt: 1000,
lastChannel: "telegram",
lastTo: "123456",
lastAccountId: "session-account",
});
const cfg = makeCfg({
@@ -63,30 +85,24 @@ describe("resolveDeliveryTarget", () => {
],
});
const result = await resolveDeliveryTarget(cfg, "agent-b", {
channel: "telegram",
to: "123456",
});
const result = await resolveForAgent({ cfg });
// Session-derived accountId should take precedence over binding
expect(result.accountId).toBe("session-account");
});
it("returns undefined accountId when no binding and no session", async () => {
vi.mocked(loadSessionStore).mockReturnValue({});
setMainSessionEntry(undefined);
const cfg = makeCfg({ bindings: [] });
const result = await resolveDeliveryTarget(cfg, "agent-b", {
channel: "telegram",
to: "123456",
});
const result = await resolveForAgent({ cfg });
expect(result.accountId).toBeUndefined();
});
it("selects correct binding when multiple agents have bindings", async () => {
vi.mocked(loadSessionStore).mockReturnValue({});
setMainSessionEntry(undefined);
const cfg = makeCfg({
bindings: [
@@ -101,16 +117,13 @@ describe("resolveDeliveryTarget", () => {
],
});
const result = await resolveDeliveryTarget(cfg, "agent-b", {
channel: "telegram",
to: "123456",
});
const result = await resolveForAgent({ cfg });
expect(result.accountId).toBe("account-b");
});
it("ignores bindings for different channels", async () => {
vi.mocked(loadSessionStore).mockReturnValue({});
setMainSessionEntry(undefined);
const cfg = makeCfg({
bindings: [
@@ -121,11 +134,46 @@ describe("resolveDeliveryTarget", () => {
],
});
const result = await resolveDeliveryTarget(cfg, "agent-b", {
channel: "telegram",
to: "123456",
});
const result = await resolveForAgent({ cfg });
expect(result.accountId).toBeUndefined();
});
it("drops session threadId when destination does not match the previous recipient", async () => {
setMainSessionEntry({
sessionId: "sess-2",
updatedAt: 1000,
lastChannel: "telegram",
lastTo: "999999",
lastThreadId: "thread-1",
});
const result = await resolveForAgent({ cfg: makeCfg({ bindings: [] }) });
expect(result.threadId).toBeUndefined();
});
it("keeps session threadId when destination matches the previous recipient", async () => {
setMainSessionEntry({
sessionId: "sess-3",
updatedAt: 1000,
lastChannel: "telegram",
lastTo: "123456",
lastThreadId: "thread-2",
});
const result = await resolveForAgent({ cfg: makeCfg({ bindings: [] }) });
expect(result.threadId).toBe("thread-2");
});
it("falls back to default channel when selection probe fails", async () => {
setMainSessionEntry(undefined);
vi.mocked(resolveMessageChannelSelection).mockRejectedValueOnce(new Error("no selection"));
const result = await resolveForAgent({
cfg: makeCfg({ bindings: [] }),
target: { channel: "last", to: undefined },
});
expect(result.channel).toBe(DEFAULT_CHAT_CHANNEL);
expect(result.to).toBeUndefined();
});
});