
















@@ -20,6 +20,7 @@ const hoisted = vi.hoisted(() => {
2020const scheduleSubagentOrphanRecovery = vi.fn();
2121const shouldWakeFromRestartSentinel = vi.fn(() => false);
2222const scheduleRestartSentinelWake = vi.fn();
23+const getAcpRuntimeBackend = vi.fn<(id?: string) => unknown>(() => null);
2324const reconcilePendingSessionIdentities = vi.fn(async () => ({
2425checked: 0,
2526resolved: 0,
@@ -41,6 +42,7 @@ const hoisted = vi.hoisted(() => {
4142 scheduleSubagentOrphanRecovery,
4243 shouldWakeFromRestartSentinel,
4344 scheduleRestartSentinelWake,
45+ getAcpRuntimeBackend,
4446 reconcilePendingSessionIdentities,
4547};
4648});
@@ -97,6 +99,10 @@ vi.mock("../acp/control-plane/manager.js", () => ({
9799})),
98100}));
99101102+vi.mock("../acp/runtime/registry.js", () => ({
103+getAcpRuntimeBackend: hoisted.getAcpRuntimeBackend,
104+}));
105+100106vi.mock("./server-restart-sentinel.js", () => ({
101107scheduleRestartSentinelWake: hoisted.scheduleRestartSentinelWake,
102108shouldWakeFromRestartSentinel: hoisted.shouldWakeFromRestartSentinel,
@@ -143,6 +149,8 @@ describe("startGatewayPostAttachRuntime", () => {
143149hoisted.scheduleSubagentOrphanRecovery.mockClear();
144150hoisted.shouldWakeFromRestartSentinel.mockReturnValue(false);
145151hoisted.scheduleRestartSentinelWake.mockClear();
152+hoisted.getAcpRuntimeBackend.mockReset();
153+hoisted.getAcpRuntimeBackend.mockReturnValue(null);
146154hoisted.reconcilePendingSessionIdentities.mockClear();
147155});
148156@@ -294,6 +302,46 @@ describe("startGatewayPostAttachRuntime", () => {
294302}
295303});
296304305+it("waits for a healthy ACP runtime backend before startup identity reconcile", async () => {
306+let healthy = false;
307+hoisted.getAcpRuntimeBackend.mockImplementation((id?: string) => ({
308+id: id ?? "acpx",
309+runtime: {},
310+healthy: () => healthy,
311+}));
312+313+await startGatewaySidecars({
314+cfg: {
315+hooks: { internal: { enabled: false } },
316+acp: { enabled: true, backend: "acpx" },
317+} as never,
318+pluginRegistry: createPostAttachParams().pluginRegistry,
319+defaultWorkspaceDir: "/tmp/openclaw-workspace",
320+deps: {} as never,
321+startChannels: vi.fn(async () => undefined),
322+log: { warn: vi.fn() },
323+logHooks: {
324+info: vi.fn(),
325+warn: vi.fn(),
326+error: vi.fn(),
327+},
328+logChannels: {
329+info: vi.fn(),
330+error: vi.fn(),
331+},
332+});
333+334+await vi.waitFor(() => {
335+expect(hoisted.getAcpRuntimeBackend).toHaveBeenCalledWith("acpx");
336+});
337+expect(hoisted.reconcilePendingSessionIdentities).not.toHaveBeenCalled();
338+339+healthy = true;
340+await vi.waitFor(() => {
341+expect(hoisted.reconcilePendingSessionIdentities).toHaveBeenCalledTimes(1);
342+});
343+});
344+297345it("passes typed gateway_start context with config, workspace dir, and a live cron getter", async () => {
298346const runGatewayStart = vi.fn<
299347(event: PluginHookGatewayStartEvent, ctx: PluginHookGatewayContext) => Promise<void>
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。