test: pair cron task state env

This commit is contained in:
Shakker
2026-06-05 16:50:22 +01:00
parent 2514980118
commit a16b6c02ce

View File

@@ -6,7 +6,7 @@ import { runOpenClawStateWriteTransaction } from "../../state/openclaw-state-db.
import * as detachedTaskRuntime from "../../tasks/detached-task-runtime.js"; import * as detachedTaskRuntime from "../../tasks/detached-task-runtime.js";
import { findTaskByRunId, resetTaskRegistryForTests } from "../../tasks/task-registry.js"; import { findTaskByRunId, resetTaskRegistryForTests } from "../../tasks/task-registry.js";
import { formatTaskStatusDetail } from "../../tasks/task-status.js"; import { formatTaskStatusDetail } from "../../tasks/task-status.js";
import { captureEnv } from "../../test-utils/env.js"; import { withEnvAsync } from "../../test-utils/env.js";
import { setupCronServiceSuite, writeCronStoreSnapshot } from "../service.test-harness.js"; import { setupCronServiceSuite, writeCronStoreSnapshot } from "../service.test-harness.js";
import { loadCronJobsStoreWithConfigJobs, loadCronStore } from "../store.js"; import { loadCronJobsStoreWithConfigJobs, loadCronStore } from "../store.js";
import type { CronJob } from "../types.js"; import type { CronJob } from "../types.js";
@@ -18,15 +18,17 @@ const { logger, makeStorePath } = setupCronServiceSuite({
prefix: "cron-service-ops-seam", prefix: "cron-service-ops-seam",
}); });
function withStateDirForStorePath(storePath: string) { async function withStateDirForStorePath<T>(
storePath: string,
runWithStateDir: () => Promise<T>,
): Promise<T> {
const stateRoot = path.dirname(path.dirname(storePath)); const stateRoot = path.dirname(path.dirname(storePath));
const envSnapshot = captureEnv(["OPENCLAW_STATE_DIR"]);
process.env.OPENCLAW_STATE_DIR = stateRoot;
resetTaskRegistryForTests(); resetTaskRegistryForTests();
return () => { try {
envSnapshot.restore(); return await withEnvAsync({ OPENCLAW_STATE_DIR: stateRoot }, runWithStateDir);
} finally {
resetTaskRegistryForTests(); resetTaskRegistryForTests();
}; }
} }
function createTimedOutIsolatedCronState(params: { storePath: string; now: number }) { function createTimedOutIsolatedCronState(params: { storePath: string; now: number }) {
@@ -413,9 +415,8 @@ describe("cron service ops seam coverage", () => {
it("keeps manual acknowledgement IDs separate from recoverable task run IDs", async () => { it("keeps manual acknowledgement IDs separate from recoverable task run IDs", async () => {
const { storePath } = await makeStorePath(); const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z"); const now = Date.parse("2026-03-23T12:00:00.000Z");
const restoreStateDir = withStateDirForStorePath(storePath);
try { await withStateDirForStorePath(storePath, async () => {
await writeDueIsolatedJobSnapshot(storePath, now); await writeDueIsolatedJobSnapshot(storePath, now);
const state = createOkIsolatedCronState({ storePath, now, summary: "done" }); const state = createOkIsolatedCronState({ storePath, now, summary: "done" });
@@ -436,17 +437,14 @@ describe("cron service ops seam coverage", () => {
progressSummary: "Running cron job.", progressSummary: "Running cron job.",
}); });
expect(findTaskByRunId(manualRunId)).toBeUndefined(); expect(findTaskByRunId(manualRunId)).toBeUndefined();
} finally { });
restoreStateDir();
}
}); });
it("records timed out manual runs as timed_out in the shared task registry", async () => { it("records timed out manual runs as timed_out in the shared task registry", async () => {
const { storePath } = await makeStorePath(); const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z"); const now = Date.parse("2026-03-23T12:00:00.000Z");
const restoreStateDir = withStateDirForStorePath(storePath);
try { await withStateDirForStorePath(storePath, async () => {
await writeDueIsolatedJobSnapshot(storePath, now); await writeDueIsolatedJobSnapshot(storePath, now);
const state = createTimedOutIsolatedCronState({ const state = createTimedOutIsolatedCronState({
@@ -462,9 +460,7 @@ describe("cron service ops seam coverage", () => {
status: "timed_out", status: "timed_out",
sourceId: "isolated-timeout", sourceId: "isolated-timeout",
}); });
} finally { });
restoreStateDir();
}
}); });
it("keeps manual cron runs progressing when task ledger creation fails", async () => { it("keeps manual cron runs progressing when task ledger creation fails", async () => {
@@ -495,9 +491,8 @@ describe("cron service ops seam coverage", () => {
it("keeps manual cron cleanup progressing when task ledger updates fail", async () => { it("keeps manual cron cleanup progressing when task ledger updates fail", async () => {
const { storePath } = await makeStorePath(); const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z"); const now = Date.parse("2026-03-23T12:00:00.000Z");
const restoreStateDir = withStateDirForStorePath(storePath);
try { await withStateDirForStorePath(storePath, async () => {
await writeDueIsolatedJobSnapshot(storePath, now); await writeDueIsolatedJobSnapshot(storePath, now);
const updateTaskRecordSpy = vi const updateTaskRecordSpy = vi
@@ -516,9 +511,7 @@ describe("cron service ops seam coverage", () => {
} finally { } finally {
updateTaskRecordSpy.mockRestore(); updateTaskRecordSpy.mockRestore();
} }
} finally { });
restoreStateDir();
}
}); });
it("non-schedule edit preserves nextRunAtMs (#63499)", async () => { it("non-schedule edit preserves nextRunAtMs (#63499)", async () => {
@@ -586,9 +579,8 @@ describe("cron service ops seam coverage", () => {
it("records startup catch-up timeouts as timed_out in the shared task registry", async () => { it("records startup catch-up timeouts as timed_out in the shared task registry", async () => {
const { storePath } = await makeStorePath(); const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z"); const now = Date.parse("2026-03-23T12:00:00.000Z");
const restoreStateDir = withStateDirForStorePath(storePath);
try { await withStateDirForStorePath(storePath, async () => {
await writeCronStoreSnapshot({ await writeCronStoreSnapshot({
storePath, storePath,
jobs: [createMissedIsolatedJob(now)], jobs: [createMissedIsolatedJob(now)],
@@ -608,17 +600,14 @@ describe("cron service ops seam coverage", () => {
sourceId: "startup-timeout", sourceId: "startup-timeout",
progressSummary: "Running cron job.", progressSummary: "Running cron job.",
}); });
} finally { });
restoreStateDir();
}
}); });
it("seeds active manual cron task progress for status surfaces", async () => { it("seeds active manual cron task progress for status surfaces", async () => {
const { storePath } = await makeStorePath(); const { storePath } = await makeStorePath();
const now = Date.parse("2026-03-23T12:00:00.000Z"); const now = Date.parse("2026-03-23T12:00:00.000Z");
const restoreStateDir = withStateDirForStorePath(storePath);
try { await withStateDirForStorePath(storePath, async () => {
await writeDueIsolatedJobSnapshot(storePath, now); await writeDueIsolatedJobSnapshot(storePath, now);
let resolveRun: ((value: { status: "ok"; summary: string }) => void) | undefined; let resolveRun: ((value: { status: "ok"; summary: string }) => void) | undefined;
const state = createCronServiceState({ const state = createCronServiceState({
@@ -651,8 +640,6 @@ describe("cron service ops seam coverage", () => {
resolveRun?.({ status: "ok", summary: "done" }); resolveRun?.({ status: "ok", summary: "done" });
await manualRun; await manualRun;
} finally { });
restoreStateDir();
}
}); });
}); });