mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-13 14:20:35 +00:00
refactor(agent): dedupe harness and command workflows
This commit is contained in:
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { CronEvent } from "./service.js";
|
||||
import { CronService } from "./service.js";
|
||||
import { createStartedCronServiceWithFinishedBarrier } from "./service.test-harness.js";
|
||||
|
||||
const noopLogger = {
|
||||
debug: vi.fn(),
|
||||
@@ -22,25 +22,20 @@ async function makeStorePath() {
|
||||
return { storePath };
|
||||
}
|
||||
|
||||
function createFinishedBarrier() {
|
||||
const resolvers = new Map<string, (evt: CronEvent) => void>();
|
||||
return {
|
||||
waitForOk: (jobId: string) =>
|
||||
new Promise<CronEvent>((resolve) => {
|
||||
resolvers.set(jobId, resolve);
|
||||
}),
|
||||
onEvent: (evt: CronEvent) => {
|
||||
if (evt.action !== "finished" || evt.status !== "ok") {
|
||||
return;
|
||||
}
|
||||
const resolve = resolvers.get(evt.jobId);
|
||||
if (!resolve) {
|
||||
return;
|
||||
}
|
||||
resolvers.delete(evt.jobId);
|
||||
resolve(evt);
|
||||
},
|
||||
};
|
||||
async function writeJobsStore(storePath: string, jobs: unknown[]) {
|
||||
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
||||
await fs.writeFile(storePath, JSON.stringify({ version: 1, jobs }, null, 2), "utf-8");
|
||||
}
|
||||
|
||||
function createCronFromStorePath(storePath: string) {
|
||||
return new CronService({
|
||||
storePath,
|
||||
cronEnabled: true,
|
||||
log: noopLogger,
|
||||
enqueueSystemEvent: vi.fn(),
|
||||
requestHeartbeatNow: vi.fn(),
|
||||
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" })),
|
||||
});
|
||||
}
|
||||
|
||||
describe("#16156: cron.list() must not silently advance past-due recurring jobs", () => {
|
||||
@@ -69,18 +64,9 @@ describe("#16156: cron.list() must not silently advance past-due recurring jobs"
|
||||
|
||||
it("does not skip a cron job when list() is called while the job is past-due", async () => {
|
||||
const store = await makeStorePath();
|
||||
const enqueueSystemEvent = vi.fn();
|
||||
const requestHeartbeatNow = vi.fn();
|
||||
const finished = createFinishedBarrier();
|
||||
|
||||
const cron = new CronService({
|
||||
const { cron, enqueueSystemEvent, finished } = createStartedCronServiceWithFinishedBarrier({
|
||||
storePath: store.storePath,
|
||||
cronEnabled: true,
|
||||
log: noopLogger,
|
||||
enqueueSystemEvent,
|
||||
requestHeartbeatNow,
|
||||
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" })),
|
||||
onEvent: finished.onEvent,
|
||||
logger: noopLogger,
|
||||
});
|
||||
|
||||
await cron.start();
|
||||
@@ -133,18 +119,9 @@ describe("#16156: cron.list() must not silently advance past-due recurring jobs"
|
||||
|
||||
it("does not skip a cron job when status() is called while the job is past-due", async () => {
|
||||
const store = await makeStorePath();
|
||||
const enqueueSystemEvent = vi.fn();
|
||||
const requestHeartbeatNow = vi.fn();
|
||||
const finished = createFinishedBarrier();
|
||||
|
||||
const cron = new CronService({
|
||||
const { cron, enqueueSystemEvent, finished } = createStartedCronServiceWithFinishedBarrier({
|
||||
storePath: store.storePath,
|
||||
cronEnabled: true,
|
||||
log: noopLogger,
|
||||
enqueueSystemEvent,
|
||||
requestHeartbeatNow,
|
||||
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" })),
|
||||
onEvent: finished.onEvent,
|
||||
logger: noopLogger,
|
||||
});
|
||||
|
||||
await cron.start();
|
||||
@@ -188,41 +165,22 @@ describe("#16156: cron.list() must not silently advance past-due recurring jobs"
|
||||
const nowMs = Date.parse("2025-12-13T00:00:00.000Z");
|
||||
|
||||
// Write a store file with a cron job that has no nextRunAtMs.
|
||||
await fs.mkdir(path.dirname(store.storePath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
store.storePath,
|
||||
JSON.stringify(
|
||||
{
|
||||
version: 1,
|
||||
jobs: [
|
||||
{
|
||||
id: "missing-next",
|
||||
name: "missing next",
|
||||
enabled: true,
|
||||
createdAtMs: nowMs,
|
||||
updatedAtMs: nowMs,
|
||||
schedule: { kind: "cron", expr: "* * * * *", tz: "UTC" },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "systemEvent", text: "fill-me" },
|
||||
state: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
"utf-8",
|
||||
);
|
||||
await writeJobsStore(store.storePath, [
|
||||
{
|
||||
id: "missing-next",
|
||||
name: "missing next",
|
||||
enabled: true,
|
||||
createdAtMs: nowMs,
|
||||
updatedAtMs: nowMs,
|
||||
schedule: { kind: "cron", expr: "* * * * *", tz: "UTC" },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "systemEvent", text: "fill-me" },
|
||||
state: {},
|
||||
},
|
||||
]);
|
||||
|
||||
const cron = new CronService({
|
||||
storePath: store.storePath,
|
||||
cronEnabled: true,
|
||||
log: noopLogger,
|
||||
enqueueSystemEvent: vi.fn(),
|
||||
requestHeartbeatNow: vi.fn(),
|
||||
runIsolatedAgentJob: vi.fn(async () => ({ status: "ok" })),
|
||||
});
|
||||
const cron = createCronFromStorePath(store.storePath);
|
||||
|
||||
await cron.start();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user