From 755c9259648f4bdb5866f18d7269c6c652658310 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 15 Nov 2024 17:08:56 +0100 Subject: [PATCH 1/5] fix(site): e2e: wait until port is available) --- site/e2e/helpers.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index c5ac7f1abde65..7bf9d32419286 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -2,6 +2,7 @@ import { type ChildProcess, exec, spawn } from "node:child_process"; import { randomUUID } from "node:crypto"; import path from "node:path"; import { Duplex } from "node:stream"; +import net from "node:net"; import { type BrowserContext, type Page, expect, test } from "@playwright/test"; import { API } from "api/api"; import type { @@ -685,6 +686,8 @@ export class Awaiter { export const createServer = async ( port: number, ): Promise> => { + await waitForPort(port); // Wait until the port is available + const e = express(); // We need to specify the local IP address as the web server // tends to fail with IPv6 related error: @@ -693,6 +696,36 @@ export const createServer = async ( return e; }; +async function waitForPort(port: number, host = "0.0.0.0", timeout = 5000): Promise { + const start = Date.now(); + while (Date.now() - start < timeout) { + const available = await isPortAvailable(port, host); + if (available) { + return; + } + await new Promise((resolve) => setTimeout(resolve, 100)); // Wait 1 second before retrying + } + throw new Error(`Timeout: port ${port} is still in use after ${timeout / 1000} seconds.`); +} + +function isPortAvailable(port: number, host = "0.0.0.0"): Promise { + return new Promise((resolve) => { + const probe = net.createServer() + .once('error', (err: any) => { + if (err.code === 'EADDRINUSE') { + resolve(false); // port is in use + } else { + resolve(false); // some other error occurred + } + }) + .once('listening', () => { + probe.close(); + resolve(true); // port is available + }) + .listen(port, host); + }); +} + export const findSessionToken = async (page: Page): Promise => { const cookies = await page.context().cookies(); const sessionCookie = cookies.find((c) => c.name === "coder_session_token"); From 216af9c26514a0f5e0a1e661182bf5217ab7669f Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 15 Nov 2024 17:16:32 +0100 Subject: [PATCH 2/5] errno --- site/e2e/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 7bf9d32419286..fa5301d949ac1 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -1,8 +1,8 @@ import { type ChildProcess, exec, spawn } from "node:child_process"; import { randomUUID } from "node:crypto"; +import net from "node:net"; import path from "node:path"; import { Duplex } from "node:stream"; -import net from "node:net"; import { type BrowserContext, type Page, expect, test } from "@playwright/test"; import { API } from "api/api"; import type { @@ -711,7 +711,7 @@ async function waitForPort(port: number, host = "0.0.0.0", timeout = 5000): Prom function isPortAvailable(port: number, host = "0.0.0.0"): Promise { return new Promise((resolve) => { const probe = net.createServer() - .once('error', (err: any) => { + .once('error', (err: NodeJS.ErrnoException) => { if (err.code === 'EADDRINUSE') { resolve(false); // port is in use } else { From 0843a8f9fd759e1a1b854f10f29c166ecf3a63ca Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 15 Nov 2024 16:32:41 +0000 Subject: [PATCH 3/5] fmt --- site/e2e/helpers.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index fa5301d949ac1..18107602d8210 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -696,7 +696,11 @@ export const createServer = async ( return e; }; -async function waitForPort(port: number, host = "0.0.0.0", timeout = 5000): Promise { +async function waitForPort( + port: number, + host = "0.0.0.0", + timeout = 5000, +): Promise { const start = Date.now(); while (Date.now() - start < timeout) { const available = await isPortAvailable(port, host); @@ -705,20 +709,23 @@ async function waitForPort(port: number, host = "0.0.0.0", timeout = 5000): Prom } await new Promise((resolve) => setTimeout(resolve, 100)); // Wait 1 second before retrying } - throw new Error(`Timeout: port ${port} is still in use after ${timeout / 1000} seconds.`); + throw new Error( + `Timeout: port ${port} is still in use after ${timeout / 1000} seconds.`, + ); } function isPortAvailable(port: number, host = "0.0.0.0"): Promise { return new Promise((resolve) => { - const probe = net.createServer() - .once('error', (err: NodeJS.ErrnoException) => { - if (err.code === 'EADDRINUSE') { + const probe = net + .createServer() + .once("error", (err: NodeJS.ErrnoException) => { + if (err.code === "EADDRINUSE") { resolve(false); // port is in use } else { resolve(false); // some other error occurred } }) - .once('listening', () => { + .once("listening", () => { probe.close(); resolve(true); // port is available }) From 444baad2190806f51a440d44544cec78d3837e54 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 18 Nov 2024 11:12:51 +0100 Subject: [PATCH 4/5] Expanding timeout, fixing retry interval Signed-off-by: Danny Kopping --- site/e2e/helpers.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 18107602d8210..9f88b1f7a6333 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -699,7 +699,7 @@ export const createServer = async ( async function waitForPort( port: number, host = "0.0.0.0", - timeout = 5000, + timeout = 30000, ): Promise { const start = Date.now(); while (Date.now() - start < timeout) { @@ -707,7 +707,8 @@ async function waitForPort( if (available) { return; } - await new Promise((resolve) => setTimeout(resolve, 100)); // Wait 1 second before retrying + console.warn(`${host}:${port} is in use, checking again in 1s`) + await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second before retrying } throw new Error( `Timeout: port ${port} is still in use after ${timeout / 1000} seconds.`, From cdd9d8bc80ac4a8b998278288ea44e47fdc00adb Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 18 Nov 2024 11:19:49 +0100 Subject: [PATCH 5/5] make fmt Signed-off-by: Danny Kopping --- site/e2e/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 9f88b1f7a6333..f099d9ff39a5a 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -707,7 +707,7 @@ async function waitForPort( if (available) { return; } - console.warn(`${host}:${port} is in use, checking again in 1s`) + console.warn(`${host}:${port} is in use, checking again in 1s`); await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second before retrying } throw new Error(