import http from "node:http"; // The offline suite must genuinely remove infrastructure, not simulate it. // Talking to the Docker Engine socket directly avoids installing a CLI into // the browser image and keeps every scenario inside one Playwright run. const SOCKET = "/var/run/docker.sock"; function engine(method, path) { return new Promise((resolve, reject) => { const request = http.request({ socketPath: SOCKET, method, path }, (response) => { let body = ""; response.on("data", (chunk) => (body += chunk)); response.on("end", () => resolve({ status: response.statusCode, body })); }); request.on("error", reject); request.end(); }); } const PROJECT = process.env.VERIFY_PROJECT || "announcements-p5b-verify"; export const CONTAINERS = { web: `${PROJECT}-web-1`, api: `${PROJECT}-api-1`, storage: `${PROJECT}-seaweedfs-1`, }; export async function stop(...names) { for (const name of names) await engine("POST", `/containers/${name}/stop?t=2`); } export async function start(...names) { for (const name of names) await engine("POST", `/containers/${name}/start`); } export async function isRunning(name) { const { status, body } = await engine("GET", `/containers/${name}/json`); if (status !== 200) return false; return Boolean(JSON.parse(body).State?.Running); } export async function waitUntilHealthy(baseUrl, timeoutMs = 120_000) { const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { try { const response = await fetch(`${baseUrl}/api/playback`, { signal: AbortSignal.timeout(2_000), }); if (response.ok) return true; } catch { // Still coming up. } await new Promise((resolve) => setTimeout(resolve, 500)); } throw new Error("stack did not become reachable in time"); } // With the API stopped but Nginx still running, the proxy answers 502. That is // a response, not a reachable API, so a gateway error counts as unreachable // just like a refused connection does. export async function waitUntilUnreachable(baseUrl, timeoutMs = 60_000) { const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { try { const response = await fetch(`${baseUrl}/api/playback`, { signal: AbortSignal.timeout(1_000), }); if (!response.ok) return true; } catch { return true; } await new Promise((resolve) => setTimeout(resolve, 250)); } throw new Error("stack stayed reachable"); }