diff --git a/src/cron/service.issue-regressions.test.ts b/src/cron/service.issue-regressions.test.ts index 058b971943..1899f54fc8 100644 --- a/src/cron/service.issue-regressions.test.ts +++ b/src/cron/service.issue-regressions.test.ts @@ -5,6 +5,7 @@ import path from "node:path"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as schedule from "./schedule.js"; import { CronService } from "./service.js"; +import { createRunningCronServiceState } from "./service.test-harness.js"; import { computeJobNextRunAtMs } from "./service/jobs.js"; import { createCronServiceState, type CronEvent } from "./service/state.js"; import { onTimer } from "./service/timer.js"; @@ -410,20 +411,12 @@ describe("Cron issue regressions", () => { const timeoutSpy = vi.spyOn(globalThis, "setTimeout"); const store = await makeStorePath(); const now = Date.parse("2026-02-06T10:05:00.000Z"); - const state = createCronServiceState({ - cronEnabled: true, + const state = createRunningCronServiceState({ storePath: store.storePath, log: noopLogger, nowMs: () => now, - enqueueSystemEvent: vi.fn(), - requestHeartbeatNow: vi.fn(), - runIsolatedAgentJob: vi.fn().mockResolvedValue({ status: "ok", summary: "ok" }), - }); - state.running = true; - state.store = { - version: 1, jobs: [createDueIsolatedJob({ id: "due", nowMs: now, nextRunAtMs: now - 1 })], - }; + }); await onTimer(state); diff --git a/src/cron/service.rearm-timer-when-running.test.ts b/src/cron/service.rearm-timer-when-running.test.ts index 90f7d73533..6dfb0284a1 100644 --- a/src/cron/service.rearm-timer-when-running.test.ts +++ b/src/cron/service.rearm-timer-when-running.test.ts @@ -1,6 +1,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { createCronStoreHarness, createNoopLogger } from "./service.test-harness.js"; -import { createCronServiceState } from "./service/state.js"; +import { + createCronStoreHarness, + createNoopLogger, + createRunningCronServiceState, +} from "./service.test-harness.js"; import { onTimer } from "./service/timer.js"; import type { CronJob } from "./types.js"; @@ -45,20 +48,10 @@ describe("CronService - timer re-arm when running (#12025)", () => { const store = await makeStorePath(); const now = Date.parse("2026-02-06T10:05:00.000Z"); - const state = createCronServiceState({ - cronEnabled: true, + const state = createRunningCronServiceState({ storePath: store.storePath, log: noopLogger, nowMs: () => now, - enqueueSystemEvent: vi.fn(), - requestHeartbeatNow: vi.fn(), - runIsolatedAgentJob: vi.fn().mockResolvedValue({ status: "ok", summary: "ok" }), - }); - - // Simulate a job that is currently running. - state.running = true; - state.store = { - version: 1, jobs: [ createDueRecurringJob({ id: "recurring-job", @@ -66,7 +59,7 @@ describe("CronService - timer re-arm when running (#12025)", () => { nextRunAtMs: now + 5 * 60_000, }), ], - }; + }); // Before the fix in #12025, this would return without re-arming, // silently killing the scheduler. diff --git a/src/cron/service.test-harness.ts b/src/cron/service.test-harness.ts index 05db703d6c..641f8fd3a9 100644 --- a/src/cron/service.test-harness.ts +++ b/src/cron/service.test-harness.ts @@ -5,6 +5,8 @@ import { afterAll, afterEach, beforeAll, beforeEach, vi } from "vitest"; import type { MockFn } from "../test-utils/vitest-mock-fn.js"; import type { CronEvent } from "./service.js"; import { CronService } from "./service.js"; +import { createCronServiceState } from "./service/state.js"; +import type { CronJob } from "./types.js"; export type NoopLogger = { debug: MockFn; @@ -111,3 +113,26 @@ export function createStartedCronServiceWithFinishedBarrier(params: { }); return { cron, enqueueSystemEvent, requestHeartbeatNow, finished }; } + +export function createRunningCronServiceState(params: { + storePath: string; + log: ReturnType; + nowMs: () => number; + jobs: CronJob[]; +}) { + const state = createCronServiceState({ + cronEnabled: true, + storePath: params.storePath, + log: params.log, + nowMs: params.nowMs, + enqueueSystemEvent: vi.fn(), + requestHeartbeatNow: vi.fn(), + runIsolatedAgentJob: vi.fn().mockResolvedValue({ status: "ok", summary: "ok" }), + }); + state.running = true; + state.store = { + version: 1, + jobs: params.jobs, + }; + return state; +}