diff --git a/packages/cli/src/__tests__/hetzner-cov.test.ts b/packages/cli/src/__tests__/hetzner-cov.test.ts index ed1c050f1..bd82098fb 100644 --- a/packages/cli/src/__tests__/hetzner-cov.test.ts +++ b/packages/cli/src/__tests__/hetzner-cov.test.ts @@ -1,4 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test"; +import { isString } from "@openrouter/spawn-shared"; import { mockBunSpawn, mockClackPrompts } from "./test-helpers"; mockClackPrompts(); @@ -585,21 +586,14 @@ describe("hetzner/createServer", () => { }, }, }; + let createAttempts = 0; let callCount = 0; - global.fetch = mock(() => { + const mockFetch = mock((url: string | URL | Request, init?: RequestInit) => { callCount++; - if (callCount <= 1) { - // Token validation - return Promise.resolve( - new Response( - JSON.stringify({ - servers: [], - }), - ), - ); - } - if (callCount <= 2) { - // SSH keys + const urlStr = isString(url) ? url : url instanceof URL ? url.href : url.url; + const method = init?.method ?? "GET"; + // SSH keys lookup + if (urlStr.includes("/ssh_keys")) { return Promise.resolve( new Response( JSON.stringify({ @@ -608,24 +602,16 @@ describe("hetzner/createServer", () => { ), ); } - if (callCount <= 3) { - // First create attempt — resource_limit_exceeded (HTTP 403) + // Delete orphaned IP (DELETE /primary_ips/NNN — must come before list check) + if (urlStr.includes("/primary_ips/") && method === "DELETE") { return Promise.resolve( - new Response( - JSON.stringify({ - error: { - code: "resource_limit_exceeded", - message: "primary_ip_limit", - }, - }), - { - status: 403, - }, - ), + new Response("", { + status: 204, + }), ); } - if (callCount <= 4) { - // List primary IPs for cleanup + // List primary IPs for cleanup + if (urlStr.includes("/primary_ips")) { return Promise.resolve( new Response( JSON.stringify({ @@ -645,22 +631,47 @@ describe("hetzner/createServer", () => { ), ); } - if (callCount <= 5) { - // Delete orphaned IP 100 + // Create server (POST /servers) + if (urlStr.includes("/servers") && method === "POST") { + createAttempts++; + if (createAttempts <= 1) { + // First create attempt — resource_limit_exceeded (HTTP 403) + return Promise.resolve( + new Response( + JSON.stringify({ + error: { + code: "resource_limit_exceeded", + message: "primary_ip_limit", + }, + }), + { + status: 403, + }, + ), + ); + } + // Retry create — success + return Promise.resolve(new Response(JSON.stringify(serverResp))); + } + // Token validation — GET /servers (and any other GET) + if (urlStr.includes("/servers")) { return Promise.resolve( - new Response("", { - status: 204, - }), + new Response( + JSON.stringify({ + servers: [], + }), + ), ); } - // Retry create — success - return Promise.resolve(new Response(JSON.stringify(serverResp))); + // Fallback + return Promise.resolve(new Response(JSON.stringify({}))); }); + global.fetch = mockFetch; const { ensureHcloudToken, createServer } = await import("../hetzner/hetzner"); await ensureHcloudToken(); const conn = await createServer("test-retry", "cx23", "fsn1"); expect(conn.ip).toBe("10.0.0.5"); - // Should have called: token(1), ssh_keys(2), create-fail(3), list-ips(4), delete-ip(5), create-ok(6) + // Should have called: token, ssh_keys, create-fail, list-ips, delete-ip, create-ok expect(callCount).toBeGreaterThanOrEqual(6); });