mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 17:38:27 +00:00
Cron: guard missing expr in schedule parsing
This commit is contained in:
@@ -13,6 +13,18 @@ describe("cron schedule", () => {
|
||||
expect(next).toBe(Date.parse("2025-12-17T17:00:00.000Z"));
|
||||
});
|
||||
|
||||
it("throws a clear error when cron expr is missing at runtime", () => {
|
||||
const nowMs = Date.parse("2025-12-13T00:00:00.000Z");
|
||||
expect(() =>
|
||||
computeNextRunAtMs(
|
||||
{
|
||||
kind: "cron",
|
||||
} as unknown as { kind: "cron"; expr: string; tz?: string },
|
||||
nowMs,
|
||||
),
|
||||
).toThrow("invalid cron schedule: expr is required");
|
||||
});
|
||||
|
||||
it("computes next run for every schedule", () => {
|
||||
const anchor = Date.parse("2025-12-13T00:00:00.000Z");
|
||||
const now = anchor + 10_000;
|
||||
|
||||
@@ -41,7 +41,11 @@ export function computeNextRunAtMs(schedule: CronSchedule, nowMs: number): numbe
|
||||
return anchor + steps * everyMs;
|
||||
}
|
||||
|
||||
const expr = schedule.expr.trim();
|
||||
const exprSource = (schedule as { expr?: unknown }).expr;
|
||||
if (typeof exprSource !== "string") {
|
||||
throw new Error("invalid cron schedule: expr is required");
|
||||
}
|
||||
const expr = exprSource.trim();
|
||||
if (!expr) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -186,4 +186,19 @@ describe("cron schedule error isolation", () => {
|
||||
expect(badJob.state.lastError).toMatch(/^schedule error:/);
|
||||
expect(badJob.state.lastError).toBeTruthy();
|
||||
});
|
||||
|
||||
it("records a clear schedule error when cron expr is missing", () => {
|
||||
const badJob = createJob({
|
||||
id: "missing-expr",
|
||||
name: "Missing Expr",
|
||||
schedule: { kind: "cron" } as unknown as CronJob["schedule"],
|
||||
});
|
||||
const state = createMockState([badJob]);
|
||||
|
||||
recomputeNextRuns(state);
|
||||
|
||||
expect(badJob.state.lastError).toContain("invalid cron schedule: expr is required");
|
||||
expect(badJob.state.lastError).not.toContain("Cannot read properties of undefined");
|
||||
expect(badJob.state.scheduleErrorCount).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,4 +33,13 @@ describe("cron stagger helpers", () => {
|
||||
expect(resolveCronStaggerMs({ kind: "cron", expr: "0 * * * *", staggerMs: 0 })).toBe(0);
|
||||
expect(resolveCronStaggerMs({ kind: "cron", expr: "15 * * * *" })).toBe(0);
|
||||
});
|
||||
|
||||
it("handles missing runtime expr values without throwing", () => {
|
||||
expect(() =>
|
||||
resolveCronStaggerMs({ kind: "cron" } as unknown as { kind: "cron"; expr: string }),
|
||||
).not.toThrow();
|
||||
expect(
|
||||
resolveCronStaggerMs({ kind: "cron" } as unknown as { kind: "cron"; expr: string }),
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,5 +41,7 @@ export function resolveCronStaggerMs(schedule: Extract<CronSchedule, { kind: "cr
|
||||
if (explicit !== undefined) {
|
||||
return explicit;
|
||||
}
|
||||
return resolveDefaultCronStaggerMs(schedule.expr) ?? 0;
|
||||
const expr = (schedule as { expr?: unknown }).expr;
|
||||
const cronExpr = typeof expr === "string" ? expr : "";
|
||||
return resolveDefaultCronStaggerMs(cronExpr) ?? 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user