mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
refactor: consolidate free-port test helpers (#99771)
This commit is contained in:
@@ -1,26 +1,10 @@
|
||||
// Chutes OAuth tests cover OAuth endpoints, local callback handling, and fetch preconnect behavior.
|
||||
import net from "node:net";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { CHUTES_TOKEN_ENDPOINT, CHUTES_USERINFO_ENDPOINT } from "../agents/chutes-oauth.js";
|
||||
import { withFetchPreconnect } from "../test-utils/fetch-mock.js";
|
||||
import { getFreePort } from "../test-utils/ports.js";
|
||||
import { loginChutes } from "./chutes-oauth.js";
|
||||
|
||||
async function getFreePort(): Promise<number> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const address = server.address();
|
||||
if (!address || typeof address === "string") {
|
||||
server.close(() => reject(new Error("No TCP address")));
|
||||
return;
|
||||
}
|
||||
const port = address.port;
|
||||
server.close((err) => (err ? reject(err) : resolve(port)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const urlToString = (url: Request | URL | string): string => {
|
||||
if (typeof url === "string") {
|
||||
return url;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { randomBytes, randomUUID } from "node:crypto";
|
||||
import { writeSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import { createServer } from "node:net";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import {
|
||||
@@ -60,6 +59,7 @@ import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
|
||||
import { stripAssistantInternalScaffolding } from "../shared/text/assistant-visible-text.js";
|
||||
import { findFinalTagMatches, stripFinalTags } from "../shared/text/final-tags.js";
|
||||
import { deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
|
||||
import { getFreePort, isPortFree } from "../test-utils/ports.js";
|
||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
||||
import { GatewayClient } from "./client.js";
|
||||
import {
|
||||
@@ -1948,42 +1948,6 @@ function editDistance(a: string, b: string): number {
|
||||
|
||||
return prev[bLen] ?? Number.POSITIVE_INFINITY;
|
||||
}
|
||||
async function getFreePort(): Promise<number> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const srv = createServer();
|
||||
srv.on("error", reject);
|
||||
srv.listen(0, "127.0.0.1", () => {
|
||||
const addr = srv.address();
|
||||
if (!addr || typeof addr === "string") {
|
||||
srv.close();
|
||||
reject(new Error("failed to acquire free port"));
|
||||
return;
|
||||
}
|
||||
const port = addr.port;
|
||||
srv.close((err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(port);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function isPortFree(port: number): Promise<boolean> {
|
||||
if (!Number.isFinite(port) || port <= 0 || port > 65535) {
|
||||
return false;
|
||||
}
|
||||
return await new Promise((resolve) => {
|
||||
const srv = createServer();
|
||||
srv.once("error", () => resolve(false));
|
||||
srv.listen(port, "127.0.0.1", () => {
|
||||
srv.close(() => resolve(true));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function getFreeGatewayPort(): Promise<number> {
|
||||
// Gateway uses derived ports (browser/canvas). Avoid flaky collisions by
|
||||
// ensuring the common derived offsets are free too.
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
// Provider auth runtime tests cover OAuth callback handling and provider auth flow helpers.
|
||||
import fs from "node:fs/promises";
|
||||
import { createServer } from "node:net";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { saveAuthProfileStore } from "../agents/auth-profiles/store.js";
|
||||
import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js";
|
||||
import { getFreePort } from "../test-utils/ports.js";
|
||||
import * as providerAuthRuntime from "./provider-auth-runtime.js";
|
||||
|
||||
async function getFreePort(): Promise<number> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const server = createServer();
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const address = server.address();
|
||||
if (!address || typeof address === "string") {
|
||||
server.close(() => reject(new Error("Failed to allocate a local port")));
|
||||
return;
|
||||
}
|
||||
const { port } = address;
|
||||
server.close((err) => (err ? reject(err) : resolve(port)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("plugin-sdk provider-auth-runtime", () => {
|
||||
it("exports the runtime-ready auth helper", () => {
|
||||
expect(providerAuthRuntime.getRuntimeAuthForModel).toBeTypeOf("function");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { createServer } from "node:net";
|
||||
import { isMainThread, threadId } from "node:worker_threads";
|
||||
|
||||
async function isPortFree(port: number): Promise<boolean> {
|
||||
export async function isPortFree(port: number): Promise<boolean> {
|
||||
if (!Number.isFinite(port) || port <= 0 || port > 65535) {
|
||||
return false;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ async function isPortFree(port: number): Promise<boolean> {
|
||||
});
|
||||
}
|
||||
|
||||
async function getOsFreePort(): Promise<number> {
|
||||
export async function getFreePort(): Promise<number> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const server = createServer();
|
||||
server.once("error", reject);
|
||||
@@ -80,7 +80,7 @@ export async function getDeterministicFreePortBlock(params?: {
|
||||
|
||||
// Fallback: let the OS pick a port block (best effort).
|
||||
for (let attempt = 0; attempt < 25; attempt += 1) {
|
||||
const port = await getOsFreePort();
|
||||
const port = await getFreePort();
|
||||
const ok = (await Promise.all(offsets.map((offset) => isPortFree(port + offset)))).every(
|
||||
Boolean,
|
||||
);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
import { type ChildProcess, spawn, spawnSync } from "node:child_process";
|
||||
import { once } from "node:events";
|
||||
import { mkdtemp, rm } from "node:fs/promises";
|
||||
import net from "node:net";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { setTimeout as delay } from "node:timers/promises";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { getFreePort } from "../../src/test-utils/ports.js";
|
||||
|
||||
const mockOpenAiPath = "scripts/e2e/mock-openai-server.mjs";
|
||||
const webSearchMockPath = "scripts/e2e/lib/openai-web-search-minimal/mock-server.mjs";
|
||||
@@ -44,22 +44,6 @@ function runScript(scriptPath: string, env: Record<string, string>) {
|
||||
});
|
||||
}
|
||||
|
||||
async function freePort() {
|
||||
const server = net.createServer();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", resolve);
|
||||
});
|
||||
const address = server.address();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.close((error) => (error ? reject(error) : resolve()));
|
||||
});
|
||||
if (!address || typeof address === "string") {
|
||||
throw new Error("failed to allocate a local port");
|
||||
}
|
||||
return address.port;
|
||||
}
|
||||
|
||||
async function waitForListening(child: ChildProcess, port: number, output: () => string) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
let settled = false;
|
||||
@@ -127,7 +111,7 @@ async function withMockServer(
|
||||
},
|
||||
) => Promise<void>,
|
||||
) {
|
||||
const port = await freePort();
|
||||
const port = await getFreePort();
|
||||
let stderr = "";
|
||||
let stdout = "";
|
||||
const child = spawn(process.execPath, [scriptPath], {
|
||||
|
||||
Reference in New Issue
Block a user