From 800a33bbfef6e5f6531320ac4d28f372f9709d46 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 2 May 2026 10:22:32 +0100 Subject: [PATCH] test: harden release live probes --- src/gateway/gateway-acp-bind.live.test.ts | 48 +++++++++++++++------- test/image-generation.runtime.live.test.ts | 17 +++++++- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/gateway/gateway-acp-bind.live.test.ts b/src/gateway/gateway-acp-bind.live.test.ts index 0f620b05ad0..14e9d7822ff 100644 --- a/src/gateway/gateway-acp-bind.live.test.ts +++ b/src/gateway/gateway-acp-bind.live.test.ts @@ -951,14 +951,17 @@ describeLive("gateway live (ACP bind)", () => { logLiveStep("bound session classified the probe image"); } - const cronProbe = createLiveCronProbeSpec({ - agentId: liveAgent, - sessionKey: spawnedSessionKey, - }); const requireCronMcpProbe = shouldRequireCronMcpProbe(); let cronJobId: string | undefined; let lastCronAssistantText = ""; + let lastCronProbeName = ""; + let lastCronMismatch = ""; for (let attempt = 0; attempt < ACP_CRON_MCP_PROBE_MAX_ATTEMPTS; attempt += 1) { + const cronProbe = createLiveCronProbeSpec({ + agentId: liveAgent, + sessionKey: spawnedSessionKey, + }); + lastCronProbeName = cronProbe.name; await sendChatAndWait({ client, sessionKey: originalSessionKey, @@ -998,13 +1001,26 @@ describeLive("gateway live (ACP bind)", () => { }); const createdJob = verifyResult.job; if (createdJob) { - assertCronJobMatches({ - job: createdJob, - expectedName: cronProbe.name, - expectedMessage: cronProbe.message, - expectedSessionKey: spawnedSessionKey, - expectedAgentId: liveAgent, - }); + try { + assertCronJobMatches({ + job: createdJob, + expectedName: cronProbe.name, + expectedMessage: cronProbe.message, + expectedSessionKey: spawnedSessionKey, + expectedAgentId: liveAgent, + }); + } catch (error) { + lastCronMismatch = error instanceof Error ? error.message : String(error); + logLiveStep( + `cron mcp job ${cronProbe.name} mismatch after attempt ${String( + attempt + 1, + )}: ${lastCronMismatch}`, + ); + if (attempt === ACP_CRON_MCP_PROBE_MAX_ATTEMPTS - 1 && requireCronMcpProbe) { + throw error; + } + continue; + } cronJobId = createdJob.id; if (cronHistory) { expect(cronHistory.lastAssistantText.trim().length).toBeGreaterThan(0); @@ -1019,14 +1035,16 @@ describeLive("gateway live (ACP bind)", () => { if (attempt === ACP_CRON_MCP_PROBE_MAX_ATTEMPTS - 1) { if (!requireCronMcpProbe) { logLiveStep( - `cron mcp job ${cronProbe.name} not observed; continuing after bind/image verification`, + `cron mcp job ${lastCronProbeName} not observed; continuing after bind/image verification${ + lastCronMismatch ? `; last mismatch=${lastCronMismatch}` : "" + }`, ); break; } throw new Error( - `acp cron cli verify could not find job ${cronProbe.name}: reply=${JSON.stringify( + `acp cron cli verify could not find job ${lastCronProbeName}: reply=${JSON.stringify( lastCronAssistantText, - )}`, + )}${lastCronMismatch ? ` mismatch=${lastCronMismatch}` : ""}`, ); } } @@ -1034,7 +1052,7 @@ describeLive("gateway live (ACP bind)", () => { if (!requireCronMcpProbe) { return; } - throw new Error(`acp cron cli verify did not create job ${cronProbe.name}`); + throw new Error(`acp cron cli verify did not create job ${lastCronProbeName}`); } await runOpenClawCliJson( ["cron", "rm", cronJobId, "--json", "--url", `ws://127.0.0.1:${port}`, "--token", token], diff --git a/test/image-generation.runtime.live.test.ts b/test/image-generation.runtime.live.test.ts index 0352e60cd5f..b134ed7f568 100644 --- a/test/image-generation.runtime.live.test.ts +++ b/test/image-generation.runtime.live.test.ts @@ -31,6 +31,11 @@ const describeLive = LIVE ? describe : describe.skip; const providerFilter = parseCsvFilter(process.env.OPENCLAW_LIVE_IMAGE_GENERATION_PROVIDERS); const caseFilter = parseCaseFilter(process.env.OPENCLAW_LIVE_IMAGE_GENERATION_CASES); const envModelMap = parseProviderModelMap(process.env.OPENCLAW_LIVE_IMAGE_GENERATION_MODELS); +const DEFAULT_LIVE_IMAGE_GENERATION_TIMEOUT_MS = 120_000; +const LIVE_IMAGE_GENERATION_TIMEOUT_MS = resolvePositiveIntegerEnv( + process.env.OPENCLAW_LIVE_IMAGE_GENERATION_TIMEOUT_MS, + DEFAULT_LIVE_IMAGE_GENERATION_TIMEOUT_MS, +); type LiveProviderCase = { pluginId: string; @@ -48,6 +53,14 @@ type LiveImageCase = { inputImages?: Array<{ buffer: Buffer; mimeType: string; fileName?: string }>; }; +function resolvePositiveIntegerEnv(raw: string | undefined, fallback: number): number { + if (!raw) { + return fallback; + } + const parsed = Number(raw); + return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback; +} + function loadBundledProviderPlugin( pluginId: string, ): ReturnType { @@ -255,7 +268,7 @@ describeLive("image generation live (provider sweep)", () => { size: testCase.size, resolution: testCase.resolution, inputImages: testCase.inputImages, - timeoutMs: 60_000, + timeoutMs: LIVE_IMAGE_GENERATION_TIMEOUT_MS, }); expect(result.images.length).toBeGreaterThan(0); @@ -293,6 +306,6 @@ describeLive("image generation live (provider sweep)", () => { } expect(failures).toEqual([]); }, - 10 * 60_000, + 15 * 60_000, ); });