| import fs from "node:fs/promises"; |
| import path from "node:path"; |
| import { describe, expect, it, vi } from "vitest"; |
| import { writeCronStoreSnapshot } from "./service.issue-regressions.test-helpers.js"; |
| import { CronService } from "./service.js"; |
| import { createCronStoreHarness, createNoopLogger } from "./service.test-harness.js"; |
|
|
| const noopLogger = createNoopLogger(); |
| const { makeStorePath } = createCronStoreHarness({ prefix: "openclaw-cron-issue-35195-" }); |
|
|
| describe("cron backup timing for edit", () => { |
| it("keeps .bak as the pre-edit store even after later normalization persists", async () => { |
| const store = await makeStorePath(); |
| const base = Date.now(); |
|
|
| await fs.mkdir(path.dirname(store.storePath), { recursive: true }); |
| await writeCronStoreSnapshot(store.storePath, [ |
| { |
| id: "job-35195", |
| name: "job-35195", |
| enabled: true, |
| createdAtMs: base, |
| updatedAtMs: base, |
| schedule: { kind: "every", everyMs: 60_000, anchorMs: base }, |
| sessionTarget: "main", |
| wakeMode: "next-heartbeat", |
| payload: { kind: "systemEvent", text: "hello" }, |
| state: {}, |
| }, |
| ]); |
|
|
| const service = new CronService({ |
| storePath: store.storePath, |
| cronEnabled: true, |
| log: noopLogger, |
| enqueueSystemEvent: vi.fn(), |
| requestHeartbeatNow: vi.fn(), |
| runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })), |
| }); |
|
|
| await service.start(); |
|
|
| const beforeEditRaw = await fs.readFile(store.storePath, "utf-8"); |
|
|
| await service.update("job-35195", { |
| payload: { kind: "systemEvent", text: "edited" }, |
| }); |
|
|
| const backupRaw = await fs.readFile(`${store.storePath}.bak`, "utf-8"); |
| expect(JSON.parse(backupRaw)).toEqual(JSON.parse(beforeEditRaw)); |
|
|
| const diskAfterEdit = JSON.parse(await fs.readFile(store.storePath, "utf-8")); |
| const normalizedJob = { |
| ...diskAfterEdit.jobs[0], |
| payload: { |
| ...diskAfterEdit.jobs[0].payload, |
| channel: "telegram", |
| }, |
| }; |
|
|
| await writeCronStoreSnapshot(store.storePath, [normalizedJob]); |
|
|
| service.stop(); |
| const service2 = new CronService({ |
| storePath: store.storePath, |
| cronEnabled: true, |
| log: noopLogger, |
| enqueueSystemEvent: vi.fn(), |
| requestHeartbeatNow: vi.fn(), |
| runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" as const })), |
| }); |
|
|
| await service2.start(); |
|
|
| const backupAfterNormalize = await fs.readFile(`${store.storePath}.bak`, "utf-8"); |
| expect(JSON.parse(backupAfterNormalize)).toEqual(JSON.parse(beforeEditRaw)); |
|
|
| service2.stop(); |
| await store.cleanup(); |
| }); |
| }); |
|
|