From ca78e8e5f3e44b4b673c8dae5d8fd8525b533b16 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Fri, 24 Apr 2026 20:52:29 +0200 Subject: [PATCH] Use internal API route for edge E2E in CI --- scripts/edge-gateway-e2e.mjs | 65 +++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/scripts/edge-gateway-e2e.mjs b/scripts/edge-gateway-e2e.mjs index e5e3322e..f656cdd5 100644 --- a/scripts/edge-gateway-e2e.mjs +++ b/scripts/edge-gateway-e2e.mjs @@ -84,6 +84,29 @@ function baseUrlWithHost(baseUrl, host, port = null) { return normalizeBaseUrl(url.toString()); } +function directCaddyBaseUrl(baseUrl) { + const url = new URL(normalizeBaseUrl(baseUrl)); + url.hostname = "caddy"; + url.port = ""; + if (url.pathname === "/api" || url.pathname === "/api/") { + url.pathname = "/"; + } + return normalizeBaseUrl(url.toString()); +} + +function resolveBrokerWebSocketUrl(rawUrl, apiBaseUrl) { + const websocketUrl = new URL(String(rawUrl)); + const apiUrl = new URL(normalizeBaseUrl(apiBaseUrl)); + + if (apiUrl.hostname === "caddy" && websocketUrl.hostname === "caddy") { + websocketUrl.hostname = "edge-broker"; + websocketUrl.port = "4300"; + websocketUrl.pathname = websocketUrl.pathname.replace(/^\/edge-broker(?=\/|$)/, "") || "/"; + } + + return websocketUrl.toString(); +} + async function readDefaultGatewayHost() { if (process.platform === "win32") { return null; @@ -185,6 +208,18 @@ async function connectCurrentContainerToComposeNetwork(rootDir, composeProject) return false; } +async function disconnectCurrentContainerFromComposeNetwork(rootDir, composeProject) { + const containerRef = await readCurrentContainerRef(); + if (!containerRef) { + return; + } + + await runCommand("docker", ["network", "disconnect", composeNetworkName(composeProject), containerRef], { + cwd: rootDir, + allowFailure: true, + }); +} + async function readComposeServiceHost(rootDir, composeProject, serviceName) { const ps = await runCommand("docker", composeArgs(composeProject, ["ps", "-q", serviceName]), { cwd: rootDir, @@ -216,15 +251,17 @@ async function readComposeServiceHost(rootDir, composeProject, serviceName) { return null; } -async function candidateApiBaseUrls(baseUrl, rootDir, composeProject) { +async function candidateApiBaseUrls(baseUrl, rootDir, composeProject, useComposeNetwork = false) { const normalized = normalizeBaseUrl(baseUrl); const candidates = [normalized]; const url = new URL(normalized); if (["localhost", "127.0.0.1", "::1"].includes(url.hostname)) { if (rootDir && composeProject) { - await connectCurrentContainerToComposeNetwork(rootDir, composeProject); - candidates.push(baseUrlWithHost(normalized, "traefik", "")); + if (useComposeNetwork) { + candidates.push(directCaddyBaseUrl(normalized)); + candidates.push(baseUrlWithHost(normalized, "traefik", "")); + } const traefikHost = await readComposeServiceHost(rootDir, composeProject, "traefik"); if (traefikHost) { @@ -264,8 +301,8 @@ async function ensureComposeServices(rootDir, composeProject) { }); } -async function waitForApiReady(baseUrl, rootDir, composeProject, attempts = 60) { - const candidates = await candidateApiBaseUrls(baseUrl, rootDir, composeProject); +async function waitForApiReady(baseUrl, rootDir, composeProject, useComposeNetwork = false, attempts = 60) { + const candidates = await candidateApiBaseUrls(baseUrl, rootDir, composeProject, useComposeNetwork); let lastError = "API never responded"; for (let attempt = 0; attempt < attempts; attempt += 1) { @@ -526,10 +563,12 @@ async function main() { let gatewayId = null; let streamSocket = null; let shellSocket = null; + let runnerNetworkAttached = false; try { await ensureComposeServices(rootDir, composeProject); - baseUrl = await waitForApiReady(baseUrl, rootDir, composeProject); + runnerNetworkAttached = await connectCurrentContainerToComposeNetwork(rootDir, composeProject); + baseUrl = await waitForApiReady(baseUrl, rootDir, composeProject, runnerNetworkAttached); process.stdout.write(`Using API base URL ${baseUrl}\n`); fixture = await runPhpFixture(rootDir, composeProject, "create"); @@ -643,7 +682,10 @@ async function main() { scopes: ["overview", "tasks", "logs", "statistics"], }, }); - const streamWsUrl = buildSocketUrl(String(streamSession?.data?.ws_url || ""), String(streamSession?.data?.token || "")); + const streamWsUrl = buildSocketUrl( + resolveBrokerWebSocketUrl(String(streamSession?.data?.ws_url || ""), baseUrl), + String(streamSession?.data?.token || "") + ); streamSocket = new WebSocketImpl(streamWsUrl); const streamMessages = collectSocketMessages(streamSocket); @@ -771,7 +813,10 @@ async function main() { rows: 40, }, }); - const shellWsUrl = buildSocketUrl(String(shellSession?.data?.ws_url || ""), String(shellSession?.data?.token || "")); + const shellWsUrl = buildSocketUrl( + resolveBrokerWebSocketUrl(String(shellSession?.data?.ws_url || ""), baseUrl), + String(shellSession?.data?.token || "") + ); shellSocket = new WebSocketImpl(shellWsUrl); const shellMessages = collectSocketMessages(shellSocket); @@ -843,6 +888,10 @@ async function main() { } await fs.rm(configDir, { recursive: true, force: true }).catch(() => {}); + + if (runnerNetworkAttached) { + await disconnectCurrentContainerFromComposeNetwork(rootDir, composeProject).catch(() => {}); + } } }