openclaw / src /cli /cron-cli /schedule-options.stream.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f778c12 verified
Raw History Blame Contribute Delete
3.62 kB
import { describe, expect, it } from "vitest";
import {
applyExistingStreamSchedulePatch,
resolveCronCreateScheduleFromArgs,
resolveCronEditScheduleRequest,
} from "./schedule-options.js";
describe("resolveCronCreateScheduleFromArgs --stream-command", () => {
it("builds an argv stream schedule with batching and match options", () => {
expect(
resolveCronCreateScheduleFromArgs({
streamCommand: '["node","events.mjs"]',
streamCwd: "/repo",
streamMode: "match",
streamMatch: "^ready:",
streamBatchMs: "100",
streamMaxBatchBytes: "2048",
}),
).toEqual({
kind: "stream",
command: ["node", "events.mjs"],
cwd: "/repo",
mode: "match",
match: "^ready:",
batchMs: 100,
maxBatchBytes: 2048,
});
});
it("requires a valid argv array and match expression when requested", () => {
expect(() => resolveCronCreateScheduleFromArgs({ streamCommand: "node events.mjs" })).toThrow(
"JSON array",
);
expect(() =>
resolveCronCreateScheduleFromArgs({
streamCommand: '["node","events.mjs"]',
streamMode: "match",
}),
).toThrow("--stream-match is required");
});
it("rejects stream-only options without a stream command", () => {
expect(() => resolveCronCreateScheduleFromArgs({ every: "1m", streamBatchMs: "250" })).toThrow(
"require --stream-command",
);
});
it("patches an existing stream back to line mode without restating argv", () => {
const request = resolveCronEditScheduleRequest({ streamMode: "line" });
expect(request.kind).toBe("patch-existing-stream");
if (request.kind !== "patch-existing-stream") {
throw new Error("expected stream patch");
}
expect(
applyExistingStreamSchedulePatch(
{
kind: "stream",
command: ["node", "events.mjs"],
mode: "match",
match: "^ready:",
batchMs: 100,
},
request,
),
).toEqual({
kind: "stream",
command: ["node", "events.mjs"],
mode: "line",
match: undefined,
batchMs: 100,
cwd: undefined,
maxBatchBytes: undefined,
});
});
it("defers command replacement metadata checks until existing match settings are merged", () => {
const commandAndMatch = resolveCronEditScheduleRequest({
streamCommand: '["node","replacement.mjs"]',
streamMatch: "^updated:",
});
expect(commandAndMatch.kind).toBe("direct");
const matchPatch = resolveCronEditScheduleRequest({ streamMatch: "^updated:" });
expect(matchPatch.kind).toBe("patch-existing-stream");
if (matchPatch.kind !== "patch-existing-stream") {
throw new Error("expected stream patch");
}
expect(
applyExistingStreamSchedulePatch(
{
kind: "stream",
command: ["node", "events.mjs"],
mode: "match",
match: "^ready:",
},
matchPatch,
),
).toMatchObject({ mode: "match", match: "^updated:" });
expect(() =>
resolveCronEditScheduleRequest({
streamCommand: '["node","replacement.mjs"]',
streamMode: "match",
}),
).not.toThrow();
});
it("rejects time-schedule modifiers mixed into stream metadata edits", () => {
expect(() => resolveCronEditScheduleRequest({ streamBatchMs: "100", tz: "UTC" })).toThrow(
"not valid with stream schedule edits",
);
expect(() => resolveCronEditScheduleRequest({ streamMode: "line", exact: true })).toThrow(
"not valid with stream schedule edits",
);
});
});