


























@@ -0,0 +1,117 @@
1+import { beforeEach, describe, expect, it, vi } from "vitest";
2+import type { CliDeps } from "../cli/deps.types.js";
3+import type { OpenClawConfig } from "../config/types.openclaw.js";
4+import type { CronServiceContract } from "../cron/service-contract.js";
5+import type { GatewayCronState } from "./server-cron.js";
6+7+const hoisted = vi.hoisted(() => {
8+let state: unknown;
9+return {
10+buildGatewayCronService: vi.fn(() => state),
11+setState(nextState: unknown) {
12+state = nextState;
13+},
14+};
15+});
16+17+vi.mock("./server-cron.js", () => ({
18+buildGatewayCronService: hoisted.buildGatewayCronService,
19+}));
20+21+const { createLazyGatewayCronState } = await import("./server-cron-lazy.js");
22+23+describe("createLazyGatewayCronState", () => {
24+beforeEach(() => {
25+vi.unstubAllEnvs();
26+hoisted.buildGatewayCronService.mockClear();
27+});
28+29+it("does not build the heavy cron service until an async cron operation needs it", async () => {
30+const cron = createCronService();
31+const state = createCronState(cron);
32+hoisted.setState(state);
33+34+const lazy = createLazyGatewayCronState(createParams());
35+36+expect(hoisted.buildGatewayCronService).not.toHaveBeenCalled();
37+expect(lazy.cron.getJob("demo")).toBeUndefined();
38+expect(lazy.cron.getDefaultAgentId()).toBeUndefined();
39+40+await lazy.cron.status();
41+42+expect(hoisted.buildGatewayCronService).toHaveBeenCalledTimes(1);
43+expect(cron.status).toHaveBeenCalledTimes(1);
44+});
45+46+it("starts the loaded cron service once", async () => {
47+const cron = createCronService();
48+hoisted.setState(createCronState(cron));
49+50+const lazy = createLazyGatewayCronState(createParams());
51+52+await lazy.cron.start();
53+await lazy.cron.start();
54+55+expect(hoisted.buildGatewayCronService).toHaveBeenCalledTimes(1);
56+expect(cron.start).toHaveBeenCalledTimes(1);
57+});
58+59+it("keeps synchronous wake non-blocking before the cron service is loaded", async () => {
60+const cron = createCronService();
61+hoisted.setState(createCronState(cron));
62+63+const lazy = createLazyGatewayCronState(createParams());
64+65+expect(lazy.cron.wake({ mode: "now", text: "ping" })).toEqual({ ok: false });
66+67+await vi.waitFor(() => {
68+expect(hoisted.buildGatewayCronService).toHaveBeenCalledTimes(1);
69+});
70+expect(cron.wake).not.toHaveBeenCalled();
71+});
72+73+it("preserves the startup cron enabled flag without loading cron runtime", () => {
74+vi.stubEnv("OPENCLAW_SKIP_CRON", "1");
75+76+const lazy = createLazyGatewayCronState(createParams());
77+78+expect(lazy.cronEnabled).toBe(false);
79+expect(hoisted.buildGatewayCronService).not.toHaveBeenCalled();
80+});
81+});
82+83+function createParams(overrides: Partial<OpenClawConfig> = {}) {
84+return {
85+cfg: {
86+ ...overrides,
87+} as OpenClawConfig,
88+deps: {} as CliDeps,
89+broadcast: vi.fn(),
90+};
91+}
92+93+function createCronState(cron: CronServiceContract): GatewayCronState {
94+return {
95+ cron,
96+storePath: "/tmp/openclaw-cron.json",
97+cronEnabled: true,
98+} as GatewayCronState;
99+}
100+101+function createCronService(): CronServiceContract {
102+return {
103+start: vi.fn(async () => undefined),
104+stop: vi.fn(),
105+status: vi.fn(async () => ({ enabled: true }) as never),
106+list: vi.fn(async () => [] as never),
107+listPage: vi.fn(async () => ({ items: [], total: 0 }) as never),
108+add: vi.fn(async () => ({ ok: true }) as never),
109+update: vi.fn(async () => ({ ok: true }) as never),
110+remove: vi.fn(async () => ({ ok: true }) as never),
111+run: vi.fn(async () => ({ ok: true, ran: false, reason: "invalid-spec" }) as never),
112+enqueueRun: vi.fn(async () => ({ ok: true, ran: false, reason: "invalid-spec" }) as never),
113+getJob: vi.fn(() => undefined),
114+getDefaultAgentId: vi.fn(() => "default"),
115+wake: vi.fn(() => ({ ok: true })),
116+};
117+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。