4fa4f13558
Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
105 lines
3.7 KiB
TypeScript
105 lines
3.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
filterCronJobsForAgent,
|
|
formatCronJobDisplay,
|
|
formatCronPayload,
|
|
formatCronSchedule,
|
|
resolveLatestCronJobForAgent,
|
|
} from "@/lib/cron/types";
|
|
import type { CronJobSummary } from "@/lib/cron/types";
|
|
|
|
const buildJob = (input: {
|
|
id: string;
|
|
agentId?: string;
|
|
updatedAtMs: number;
|
|
}): CronJobSummary => ({
|
|
id: input.id,
|
|
name: input.id,
|
|
enabled: true,
|
|
updatedAtMs: input.updatedAtMs,
|
|
schedule: { kind: "every", everyMs: 60_000 },
|
|
sessionTarget: "isolated",
|
|
wakeMode: "next-heartbeat",
|
|
payload: { kind: "agentTurn", message: "hello" },
|
|
state: {},
|
|
...(input.agentId ? { agentId: input.agentId } : {}),
|
|
});
|
|
|
|
describe("cron selectors", () => {
|
|
it("filters_jobs_to_selected_agent", () => {
|
|
const jobs = [
|
|
buildJob({ id: "one", agentId: "agent-1", updatedAtMs: 10 }),
|
|
buildJob({ id: "two", agentId: "agent-2", updatedAtMs: 20 }),
|
|
buildJob({ id: "three", updatedAtMs: 30 }),
|
|
];
|
|
|
|
expect(filterCronJobsForAgent(jobs, "agent-1").map((job) => job.id)).toEqual(["one"]);
|
|
expect(filterCronJobsForAgent(jobs, "agent-2").map((job) => job.id)).toEqual(["two"]);
|
|
expect(filterCronJobsForAgent(jobs, "missing")).toEqual([]);
|
|
});
|
|
|
|
it("resolves_latest_agent_job_by_updated_at", () => {
|
|
const jobs = [
|
|
buildJob({ id: "older", agentId: "agent-1", updatedAtMs: 10 }),
|
|
buildJob({ id: "newer", agentId: "agent-1", updatedAtMs: 30 }),
|
|
buildJob({ id: "other", agentId: "agent-2", updatedAtMs: 40 }),
|
|
];
|
|
|
|
expect(resolveLatestCronJobForAgent(jobs, "agent-1")?.id).toBe("newer");
|
|
expect(resolveLatestCronJobForAgent(jobs, "agent-2")?.id).toBe("other");
|
|
expect(resolveLatestCronJobForAgent(jobs, "missing")).toBeNull();
|
|
});
|
|
|
|
it("matches_agent_ids_after_trimming_whitespace", () => {
|
|
const jobs = [
|
|
buildJob({ id: "trimmed", agentId: "agent-1", updatedAtMs: 20 }),
|
|
buildJob({ id: "other", agentId: "agent-2", updatedAtMs: 30 }),
|
|
];
|
|
|
|
expect(filterCronJobsForAgent(jobs, " agent-1 ").map((job) => job.id)).toEqual(["trimmed"]);
|
|
expect(resolveLatestCronJobForAgent(jobs, " agent-1 ")?.id).toBe("trimmed");
|
|
});
|
|
});
|
|
|
|
describe("cron formatting", () => {
|
|
it("formats_every_schedule_with_h_m_s_ms_suffixes", () => {
|
|
expect(formatCronSchedule({ kind: "every", everyMs: 3_600_000 })).toBe("Every 1h");
|
|
expect(formatCronSchedule({ kind: "every", everyMs: 60_000 })).toBe("Every 1m");
|
|
expect(formatCronSchedule({ kind: "every", everyMs: 1_000 })).toBe("Every 1s");
|
|
expect(formatCronSchedule({ kind: "every", everyMs: 1_500 })).toBe("Every 1500ms");
|
|
});
|
|
|
|
it("formats_cron_schedule_with_optional_tz", () => {
|
|
expect(formatCronSchedule({ kind: "cron", expr: "0 0 * * *" })).toBe("Cron: 0 0 * * *");
|
|
expect(formatCronSchedule({ kind: "cron", expr: "0 0 * * *", tz: "UTC" })).toBe(
|
|
"Cron: 0 0 * * * (UTC)"
|
|
);
|
|
});
|
|
|
|
it("formats_at_schedule_as_raw_when_not_parseable", () => {
|
|
expect(formatCronSchedule({ kind: "at", at: "not-a-date" })).toBe("At: not-a-date");
|
|
});
|
|
|
|
it("formats_cron_payload_text", () => {
|
|
expect(formatCronPayload({ kind: "systemEvent", text: "hello" })).toBe("hello");
|
|
expect(formatCronPayload({ kind: "agentTurn", message: "hi" })).toBe("hi");
|
|
});
|
|
|
|
it("formats_cron_job_display_as_three_lines", () => {
|
|
const job: CronJobSummary = {
|
|
id: "job-1",
|
|
name: "Job name",
|
|
enabled: true,
|
|
updatedAtMs: 10,
|
|
schedule: { kind: "every", everyMs: 60_000 },
|
|
sessionTarget: "isolated",
|
|
wakeMode: "next-heartbeat",
|
|
payload: { kind: "agentTurn", message: "hi" },
|
|
state: {},
|
|
};
|
|
|
|
expect(formatCronJobDisplay(job)).toBe("Job name\nEvery 1m\nhi");
|
|
});
|
|
});
|