From ecac665bf3c7c6477771fdd71fba3873d21eb402 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 20 Jun 2026 18:13:58 +0200 Subject: [PATCH] fix(parallels): pace background launch probes --- scripts/e2e/parallels/guest-transports.ts | 9 +++++--- test/scripts/parallels-smoke-model.test.ts | 27 +++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/scripts/e2e/parallels/guest-transports.ts b/scripts/e2e/parallels/guest-transports.ts index af3aa7561bd3..ddc5e305729f 100644 --- a/scripts/e2e/parallels/guest-transports.ts +++ b/scripts/e2e/parallels/guest-transports.ts @@ -191,10 +191,11 @@ Write-OpenClawUtf8File $pidPath ([string]$process.Id) } lastLaunchStatus = launch.status; if (launch.status === 0 || launch.status === 124) { - const materialized = waitForWindowsBackgroundMaterialized({ + const materialized = await waitForWindowsBackgroundMaterialized({ append, deadline, pathsScript, + pollIntervalMs, runCommand, vmName: options.vmName, }); @@ -309,13 +310,14 @@ function hasControlLine(output: string, marker: string): boolean { return output.split(/\r?\n/u).some((entry) => entry.trimEnd() === marker); } -function waitForWindowsBackgroundMaterialized(params: { +async function waitForWindowsBackgroundMaterialized(params: { append?: (chunk: string | Uint8Array) => void; deadline: number; pathsScript: string; + pollIntervalMs: number; runCommand: typeof run; vmName: string; -}): boolean { +}): Promise { const materializeDeadline = Math.min(Date.now() + 45_000, params.deadline); while (Date.now() < materializeDeadline) { const result = params.runCommand( @@ -340,6 +342,7 @@ if ((Test-Path $logPath) -or (Test-Path $donePath)) { if (result.stdout.includes("materialized")) { return true; } + await sleep(Math.min(params.pollIntervalMs, Math.max(1, materializeDeadline - Date.now()))); } return false; } diff --git a/test/scripts/parallels-smoke-model.test.ts b/test/scripts/parallels-smoke-model.test.ts index 60f4fe0de41a..ca216b9e6feb 100644 --- a/test/scripts/parallels-smoke-model.test.ts +++ b/test/scripts/parallels-smoke-model.test.ts @@ -40,7 +40,11 @@ import { validateSnapshotRestoreMode, withProgressOnStderr, } from "../../scripts/e2e/parallels/common.ts"; -import { LinuxGuest, MacosGuest } from "../../scripts/e2e/parallels/guest-transports.ts"; +import { + LinuxGuest, + MacosGuest, + runWindowsBackgroundPowerShell, +} from "../../scripts/e2e/parallels/guest-transports.ts"; import { resolveHostCommandInvocation } from "../../scripts/e2e/parallels/host-command.ts"; import { testing as hostServerTesting } from "../../scripts/e2e/parallels/host-server.ts"; import { parseArgs as parseLinuxSmokeArgs } from "../../scripts/e2e/parallels/linux-smoke.ts"; @@ -1381,6 +1385,27 @@ if (isPrlctl) { expect(transports).toContain("waitForWindowsBackgroundMaterialized"); }); + it("paces ambiguous Windows background launch materialization probes", async () => { + let calls = 0; + const runCommand = vi.fn(() => { + calls++; + return { status: 0, stderr: "", stdout: "" }; + }); + + await expect( + runWindowsBackgroundPowerShell({ + label: "ambiguous launch", + pollIntervalMs: 20, + runCommand, + script: "Write-Output ok", + timeoutMs: 90, + vmName: "Windows 11", + }), + ).rejects.toThrow("ambiguous launch background launch failed"); + + expect(calls).toBeLessThan(20); + }); + it("returns timed-out host command status when check is disabled", () => { const result = run( process.execPath,