openclaw/src/cron/delivery.test.ts
Mariano d4e59a3666
Cron: enforce cron-owned delivery contract (#40998)
Merged via squash.

Prepared head SHA: 5877389e33d5b3a518925b5793a6f6294cb3fb3d
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-03-09 20:12:37 +01:00

221 lines
5.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { resolveCronDeliveryPlan, resolveFailureDestination } from "./delivery.js";
import type { CronJob } from "./types.js";
function makeJob(overrides: Partial<CronJob>): CronJob {
const now = Date.now();
return {
id: "job-1",
name: "test",
enabled: true,
createdAtMs: now,
updatedAtMs: now,
schedule: { kind: "every", everyMs: 60_000 },
sessionTarget: "isolated",
wakeMode: "next-heartbeat",
payload: { kind: "agentTurn", message: "hello" },
state: {},
...overrides,
};
}
describe("resolveCronDeliveryPlan", () => {
it("defaults to announce when delivery object has no mode", () => {
const plan = resolveCronDeliveryPlan(
makeJob({
delivery: { channel: "telegram", to: "123", mode: undefined as never },
}),
);
expect(plan.mode).toBe("announce");
expect(plan.requested).toBe(true);
expect(plan.channel).toBe("telegram");
expect(plan.to).toBe("123");
});
it("respects legacy payload deliver=false", () => {
const plan = resolveCronDeliveryPlan(
makeJob({
delivery: undefined,
payload: { kind: "agentTurn", message: "hello", deliver: false },
}),
);
expect(plan.mode).toBe("none");
expect(plan.requested).toBe(false);
});
it("resolves mode=none with requested=false and no channel (#21808)", () => {
const plan = resolveCronDeliveryPlan(
makeJob({
delivery: { mode: "none", to: "telegram:123" },
}),
);
expect(plan.mode).toBe("none");
expect(plan.requested).toBe(false);
expect(plan.channel).toBeUndefined();
expect(plan.to).toBe("telegram:123");
});
it("resolves webhook mode without channel routing", () => {
const plan = resolveCronDeliveryPlan(
makeJob({
delivery: { mode: "webhook", to: "https://example.invalid/cron" },
}),
);
expect(plan.mode).toBe("webhook");
expect(plan.requested).toBe(false);
expect(plan.channel).toBeUndefined();
expect(plan.to).toBe("https://example.invalid/cron");
});
it("threads delivery.accountId when explicitly configured", () => {
const plan = resolveCronDeliveryPlan(
makeJob({
delivery: {
mode: "announce",
channel: "telegram",
to: "123",
accountId: " bot-a ",
},
}),
);
expect(plan.mode).toBe("announce");
expect(plan.requested).toBe(true);
expect(plan.channel).toBe("telegram");
expect(plan.to).toBe("123");
expect(plan.accountId).toBe("bot-a");
});
});
describe("resolveFailureDestination", () => {
it("merges global defaults with job-level overrides", () => {
const plan = resolveFailureDestination(
makeJob({
delivery: {
mode: "announce",
channel: "telegram",
to: "111",
failureDestination: { channel: "signal", mode: "announce" },
},
}),
{
channel: "telegram",
to: "222",
mode: "announce",
accountId: "global-account",
},
);
expect(plan).toEqual({
mode: "announce",
channel: "signal",
to: "222",
accountId: "global-account",
});
});
it("returns null for webhook mode without destination URL", () => {
const plan = resolveFailureDestination(
makeJob({
delivery: {
mode: "announce",
channel: "telegram",
to: "111",
failureDestination: { mode: "webhook" },
},
}),
undefined,
);
expect(plan).toBeNull();
});
it("returns null when failure destination matches primary delivery target", () => {
const plan = resolveFailureDestination(
makeJob({
delivery: {
mode: "announce",
channel: "telegram",
to: "111",
accountId: "bot-a",
failureDestination: {
mode: "announce",
channel: "telegram",
to: "111",
accountId: "bot-a",
},
},
}),
undefined,
);
expect(plan).toBeNull();
});
it("returns null when webhook failure destination matches the primary webhook target", () => {
const plan = resolveFailureDestination(
makeJob({
sessionTarget: "main",
payload: { kind: "systemEvent", text: "tick" },
delivery: {
mode: "webhook",
to: "https://example.invalid/cron",
failureDestination: {
mode: "webhook",
to: "https://example.invalid/cron",
},
},
}),
undefined,
);
expect(plan).toBeNull();
});
it("does not reuse inherited announce recipient when switching failure destination to webhook", () => {
const plan = resolveFailureDestination(
makeJob({
delivery: {
mode: "announce",
channel: "telegram",
to: "111",
failureDestination: {
mode: "webhook",
},
},
}),
{
channel: "signal",
to: "group-abc",
mode: "announce",
},
);
expect(plan).toBeNull();
});
it("allows job-level failure destination fields to clear inherited global values", () => {
const plan = resolveFailureDestination(
makeJob({
delivery: {
mode: "announce",
channel: "telegram",
to: "111",
failureDestination: {
mode: "announce",
channel: undefined as never,
to: undefined as never,
accountId: undefined as never,
},
},
}),
{
channel: "signal",
to: "group-abc",
accountId: "global-account",
mode: "announce",
},
);
expect(plan).toEqual({
mode: "announce",
channel: "last",
to: undefined,
accountId: undefined,
});
});
});