From 05f5f35d4478f4af3201260b865e9f088468a4f0 Mon Sep 17 00:00:00 2001 From: ttbombadil Date: Mon, 12 Oct 2026 11:46:20 +0200 Subject: [PATCH] test: bind route test servers to the loopback address they request Seven test files listened on the wildcard address (app.listen(0) -> ::) but sent requests to 127.0.0.1. On macOS an ephemeral wildcard listen can be handed a port that another Vitest worker already holds on 127.0.0.1, and connections to 127.0.0.1: then reach that other server. Under the full parallel suite this produced 401 instead of 400 in tutor.routes.test.ts (a dev or gateway server answered) and a 30 s timeout in examples.routes.test.ts (a server without HTTP handler answered). Binding to 127.0.0.1 makes the kernel reject that port. Assertions and timeouts are unchanged. Co-Authored-By: Claude Opus 5.5 --- tests/server/routes/compiler.routes.test.ts | 2 +- tests/server/routes/examples.routes.test.ts | 2 +- tests/server/routes/routes-core.test.ts | 2 +- tests/server/routes/server-status.test.ts | 2 +- tests/server/routes/test-reset.routes.test.ts | 2 +- tests/server/routes/tutor.routes.test.ts | 2 +- tests/server/services/protocol-version.test.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/server/routes/compiler.routes.test.ts b/tests/server/routes/compiler.routes.test.ts index f28b12713..fb2942acb 100644 --- a/tests/server/routes/compiler.routes.test.ts +++ b/tests/server/routes/compiler.routes.test.ts @@ -35,7 +35,7 @@ function createApp() { /** Start the express app on a random port and return base URL + close fn */ function listen(app: express.Express): Promise<{ baseUrl: string; server: http.Server }> { return new Promise((resolve) => { - const server = app.listen(0, () => { + const server = app.listen(0, "127.0.0.1", () => { const addr = server.address() as { port: number }; resolve({ baseUrl: `http://127.0.0.1:${addr.port}`, server }); }); diff --git a/tests/server/routes/examples.routes.test.ts b/tests/server/routes/examples.routes.test.ts index cafa2b1a5..59dee0f37 100644 --- a/tests/server/routes/examples.routes.test.ts +++ b/tests/server/routes/examples.routes.test.ts @@ -60,7 +60,7 @@ describe("request-scoped examples routes", () => { validateRateLimiter: new IdentityRateLimiter("test validate", { maxRequests: validateMax, windowMs: 60_000, blockDurationMs: 60_000 }), overrideRateLimiter: new IdentityRateLimiter("test override", { maxRequests: overrideMax, windowMs: 60_000, blockDurationMs: 30_000 }), }); - server = app.listen(0); + server = app.listen(0, "127.0.0.1"); await new Promise((resolve) => server!.once("listening", resolve)); const address = server.address() as { port: number }; return { baseUrl: `http://127.0.0.1:${address.port}`, validate, getCatalog, getExample }; diff --git a/tests/server/routes/routes-core.test.ts b/tests/server/routes/routes-core.test.ts index cfa58f93d..e3f2073c0 100644 --- a/tests/server/routes/routes-core.test.ts +++ b/tests/server/routes/routes-core.test.ts @@ -65,7 +65,7 @@ vi.mock("../../../server/services/examples/examples-repository", () => ({ function listen(app: express.Express): Promise<{ baseUrl: string; server: http.Server }> { return new Promise((resolve) => { - const server = app.listen(0, () => { + const server = app.listen(0, "127.0.0.1", () => { const address = server.address() as { port: number }; resolve({ baseUrl: `http://127.0.0.1:${address.port}`, server }); }); diff --git a/tests/server/routes/server-status.test.ts b/tests/server/routes/server-status.test.ts index a37a06604..a49ba3976 100644 --- a/tests/server/routes/server-status.test.ts +++ b/tests/server/routes/server-status.test.ts @@ -48,7 +48,7 @@ vi.mock("../../../server/services/sandbox/docker-compile-semaphore", () => ({ function listen(app: express.Express): Promise<{ baseUrl: string; server: http.Server }> { return new Promise((resolve) => { - const server = app.listen(0, () => { + const server = app.listen(0, "127.0.0.1", () => { const addr = server.address() as { port: number }; resolve({ baseUrl: `http://127.0.0.1:${addr.port}`, server }); }); diff --git a/tests/server/routes/test-reset.routes.test.ts b/tests/server/routes/test-reset.routes.test.ts index d457cc2c1..d0da99ec8 100644 --- a/tests/server/routes/test-reset.routes.test.ts +++ b/tests/server/routes/test-reset.routes.test.ts @@ -32,7 +32,7 @@ async function postToReset(isTest: boolean, enabled: boolean) { }); const server = await new Promise((resolve) => { - const listeningServer = app.listen(0, () => resolve(listeningServer)); + const listeningServer = app.listen(0, "127.0.0.1", () => resolve(listeningServer)); }); servers.push(server); const address = server.address(); diff --git a/tests/server/routes/tutor.routes.test.ts b/tests/server/routes/tutor.routes.test.ts index 5513d4d54..5feee63e6 100644 --- a/tests/server/routes/tutor.routes.test.ts +++ b/tests/server/routes/tutor.routes.test.ts @@ -10,7 +10,7 @@ import { TutorService } from "../../../server/services/tutor/tutor-service"; function listen(app: express.Express): Promise<{ url: string; server: http.Server }> { return new Promise((resolve) => { - const server = app.listen(0, () => { + const server = app.listen(0, "127.0.0.1", () => { const address = server.address() as { port: number }; resolve({ url: `http://127.0.0.1:${address.port}`, server }); }); diff --git a/tests/server/services/protocol-version.test.ts b/tests/server/services/protocol-version.test.ts index 32acc8cad..26113896a 100644 --- a/tests/server/services/protocol-version.test.ts +++ b/tests/server/services/protocol-version.test.ts @@ -27,7 +27,7 @@ describe("protocol version contract", () => { app.use("/api", apiVersionMiddleware); app.get("/api/status", (_req, res) => res.json({ status: "ok" })); const server = createServer(app); - await new Promise((resolve) => server.listen(0, resolve)); + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const address = server.address(); const port = typeof address === "object" && address ? address.port : 0; const response = await fetch(`http://127.0.0.1:${port}/api/status`, {