diff --git a/scripts/e2e/parallels/windows-git.ts b/scripts/e2e/parallels/windows-git.ts index e2485d7fe98e..16e0cc72cb9c 100644 --- a/scripts/e2e/parallels/windows-git.ts +++ b/scripts/e2e/parallels/windows-git.ts @@ -82,17 +82,30 @@ print(best["browser_download_url"])`, } const zipPath = path.join(tgzDir, name); say(`Download ${name}`); - run("curl", [ - "--retry", - "5", - "--retry-delay", - "3", - "--retry-all-errors", - "-fsSL", - url, - "-o", - zipPath, - ]); + run( + "curl", + [ + "--retry", + "5", + "--retry-delay", + "3", + "--retry-all-errors", + "--connect-timeout", + "10", + "--max-time", + "120", + "--retry-max-time", + "120", + "-fsSL", + url, + "-o", + zipPath, + ], + { + // curl can start one final 120s transfer at the retry-window edge. + timeoutMs: 270_000, + }, + ); return zipPath; } diff --git a/test/scripts/parallels-windows-git.test.ts b/test/scripts/parallels-windows-git.test.ts new file mode 100644 index 000000000000..1e2ba06bb7a3 --- /dev/null +++ b/test/scripts/parallels-windows-git.test.ts @@ -0,0 +1,57 @@ +// Parallels Windows Git tests cover host-side MinGit preparation. +import path from "node:path"; +import { describe, expect, it, vi } from "vitest"; + +const { runMock } = vi.hoisted(() => ({ + runMock: vi.fn(), +})); + +vi.mock("../../scripts/e2e/parallels/host-command.ts", async (importOriginal) => { + const actual = + await importOriginal(); + return { + ...actual, + run: runMock, + say: vi.fn(), + }; +}); + +import { prepareMinGitZip } from "../../scripts/e2e/parallels/windows-git.ts"; + +describe("Parallels Windows MinGit preparation", () => { + it("bounds the host asset download across connections, transfers, and retries", async () => { + const assetName = "MinGit-2.53.0.2-64-bit.zip"; + const assetUrl = `https://example.test/${assetName}`; + const targetDir = path.join("tmp", "windows-smoke"); + const targetPath = path.join(targetDir, assetName); + runMock.mockImplementation((command: string) => ({ + status: 0, + stderr: "", + stdout: command === "python3" ? `${assetName}\n${assetUrl}\n` : "", + })); + + await expect(prepareMinGitZip(targetDir)).resolves.toBe(targetPath); + expect(runMock).toHaveBeenNthCalledWith( + 2, + "curl", + [ + "--retry", + "5", + "--retry-delay", + "3", + "--retry-all-errors", + "--connect-timeout", + "10", + "--max-time", + "120", + "--retry-max-time", + "120", + "-fsSL", + assetUrl, + "-o", + targetPath, + ], + { timeoutMs: 270_000 }, + ); + }); +});