




















@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
22import path from "node:path";
33import { describe, expect, it, vi } from "vitest";
44import { setupCronServiceSuite } from "../service.test-harness.js";
5+import { resolveCronQuarantinePath } from "../store.js";
56import { assertSupportedJobSpec, findJobOrThrow } from "./jobs.js";
67import { createCronServiceState } from "./state.js";
78import { ensureLoaded } from "./store.js";
@@ -16,7 +17,7 @@ async function writeSingleJobStore(storePath: string, job: Record<string, unknow
1617await writeJobStore(storePath, [job]);
1718}
181919-async function writeJobStore(storePath: string, jobs: Array<Record<string, unknown>>) {
20+async function writeJobStore(storePath: string, jobs: unknown[]) {
2021await fs.mkdir(path.dirname(storePath), { recursive: true });
2122await fs.writeFile(storePath, JSON.stringify({ version: 1, jobs }, null, 2), "utf8");
2223}
@@ -122,7 +123,7 @@ describe("cron service store load: missing sessionTarget", () => {
122123expect(() => assertSupportedJobSpec(bogus)).toThrow(/missing sessionTarget/);
123124});
124125125-it("skips malformed persisted schedule and payload shapes without rewriting the store", async () => {
126+it("quarantines malformed persisted schedule and payload shapes while sanitizing the store", async () => {
126127const { storePath } = await makeStorePath();
127128128129await writeJobStore(storePath, [
@@ -199,7 +200,6 @@ describe("cron service store load: missing sessionTarget", () => {
199200state: {},
200201},
201202]);
202-const beforeRaw = await fs.readFile(storePath, "utf-8");
203203const warnSpy = vi.spyOn(logger, "warn");
204204205205const state = createStoreTestState(storePath);
@@ -208,11 +208,24 @@ describe("cron service store load: missing sessionTarget", () => {
208208209209expect(state.store?.jobs.map((job) => job.id)).toEqual(["valid-job"]);
210210expect(findJobOrThrow(state, "valid-job").state.nextRunAtMs).toBe(STORE_TEST_NOW);
211-await expect(fs.readFile(storePath, "utf-8")).resolves.toBe(beforeRaw);
211+const sanitized = JSON.parse(await fs.readFile(storePath, "utf-8")) as {
212+jobs: Array<Record<string, unknown>>;
213+};
214+expect(sanitized.jobs.map((job) => job.id)).toEqual(["valid-job"]);
215+const quarantine = JSON.parse(
216+await fs.readFile(resolveCronQuarantinePath(storePath), "utf-8"),
217+) as { jobs: Array<{ job?: Record<string, unknown> }> };
218+expect(quarantine.jobs.map((entry) => entry.job?.id)).toEqual([
219+"bad-schedule",
220+"bad-payload",
221+"bad-cron-expr",
222+"bad-system-event-text",
223+"bad-agent-turn-message",
224+]);
212225213226const invalidShapeWarns = warnSpy.mock.calls.filter((call) => {
214227const msg = typeof call[1] === "string" ? call[1] : "";
215-return msg.includes("skipped invalid persisted job");
228+return msg.includes("quarantined invalid persisted job");
216229});
217230expect(invalidShapeWarns).toHaveLength(5);
218231expect(invalidShapeWarns.map((call) => (call[0] as { reason?: string }).reason)).toEqual([
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。