fix(test): stabilize proxy integration server ports

This commit is contained in:
Tam Nhu Tran committed 2026-04-22 09:16:15 -04:00
1 parent 3e7ce1743b
commit e6ac91b9c7
3 files changed
+99 -39

No files matched your search

@@ -1,5 +1,4 @@
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import getPort from 'get-port';
import * as fs from 'fs'; import * as fs from 'fs';
import * as http from 'http'; import * as http from 'http';
import * as os from 'os'; import * as os from 'os';
@@ -16,6 +15,29 @@ let tempDir: string;
let originalTimeoutEnv: string | undefined; let originalTimeoutEnv: string | undefined;
let originalCcsHome: string | undefined; let originalCcsHome: string | undefined;
function resolveListeningPort(server: http.Server): number {
const address = server.address();
if (!address || typeof address === 'string') {
throw new Error('Failed to resolve server port');
}
return address.port;
}
async function waitForServerListening(server: http.Server): Promise<number> {
if (server.listening) {
return resolveListeningPort(server);
}
return new Promise<number>((resolve, reject) => {
const onError = (error: Error) => reject(error);
server.once('error', onError);
server.once('listening', () => {
server.off('error', onError);
resolve(resolveListeningPort(server));
});
});
}
async function startUpstream( async function startUpstream(
handler: (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void> | void handler: (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void> | void
): Promise<void> { ): Promise<void> {
@@ -28,9 +50,8 @@ async function startUpstream(
upstreamSockets.delete(socket); upstreamSockets.delete(socket);
}); });
}); });
await new Promise<void>((resolve) => upstreamServer.listen(0, '127.0.0.1');
upstreamServer.listen(upstreamPort, '127.0.0.1', () => resolve()) upstreamPort = await waitForServerListening(upstreamServer);
);
} }
async function requestProxy(payload: unknown, signal?: AbortSignal): Promise<Response> { async function requestProxy(payload: unknown, signal?: AbortSignal): Promise<Response> {
@@ -46,8 +67,6 @@ async function requestProxy(payload: unknown, signal?: AbortSignal): Promise<Res
} }
beforeEach(async () => { beforeEach(async () => {
upstreamPort = await getPort();
proxyPort = await getPort();
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-proxy-edge-')); tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-proxy-edge-'));
originalTimeoutEnv = process.env.CCS_OPENAI_PROXY_REQUEST_TIMEOUT_MS; originalTimeoutEnv = process.env.CCS_OPENAI_PROXY_REQUEST_TIMEOUT_MS;
originalCcsHome = process.env.CCS_HOME; originalCcsHome = process.env.CCS_HOME;
@@ -94,9 +113,10 @@ describe('openai proxy message edge cases', () => {
}; };
proxyServer = startOpenAICompatProxyServer({ proxyServer = startOpenAICompatProxyServer({
profile, profile,
port: proxyPort, port: 0,
authToken: 'test-proxy-token', authToken: 'test-proxy-token',
}); });
proxyPort = await waitForServerListening(proxyServer);
} }
it('preserves rate-limit errors from the upstream provider', async () => { it('preserves rate-limit errors from the upstream provider', async () => {
@@ -1,5 +1,4 @@
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import getPort from 'get-port';
import * as http from 'http'; import * as http from 'http';
import { startOpenAICompatProxyServer } from '../../../src/proxy/server/proxy-server'; import { startOpenAICompatProxyServer } from '../../../src/proxy/server/proxy-server';
import type { OpenAICompatProfileConfig } from '../../../src/proxy/profile-router'; import type { OpenAICompatProfileConfig } from '../../../src/proxy/profile-router';
@@ -10,8 +9,30 @@ let upstreamBody: unknown;
let upstreamPort: number; let upstreamPort: number;
let proxyPort: number; let proxyPort: number;
function startMockUpstream(): Promise<void> { function resolveListeningPort(server: http.Server): number {
return new Promise((resolve) => { const address = server.address();
if (!address || typeof address === 'string') {
throw new Error('Failed to resolve server port');
}
return address.port;
}
async function waitForServerListening(server: http.Server): Promise<number> {
if (server.listening) {
return resolveListeningPort(server);
}
return new Promise<number>((resolve, reject) => {
const onError = (error: Error) => reject(error);
server.once('error', onError);
server.once('listening', () => {
server.off('error', onError);
resolve(resolveListeningPort(server));
});
});
}
async function startMockUpstream(): Promise<void> {
upstreamServer = http.createServer(async (req, res) => { upstreamServer = http.createServer(async (req, res) => {
if (req.method !== 'POST' || req.url !== '/v1/chat/completions') { if (req.method !== 'POST' || req.url !== '/v1/chat/completions') {
res.writeHead(404).end(); res.writeHead(404).end();
@@ -25,7 +46,10 @@ function startMockUpstream(): Promise<void> {
upstreamBody = JSON.parse(body); upstreamBody = JSON.parse(body);
const parsed = upstreamBody as { const parsed = upstreamBody as {
stream?: boolean; stream?: boolean;
messages?: Array<{ role?: string; content?: string | Array<{ type?: string; text?: string }> }>; messages?: Array<{
role?: string;
content?: string | Array<{ type?: string; text?: string }>;
}>;
}; };
if (parsed.stream) { if (parsed.stream) {
@@ -81,8 +105,8 @@ function startMockUpstream(): Promise<void> {
); );
}); });
upstreamServer.listen(upstreamPort, '127.0.0.1', () => resolve()); upstreamServer.listen(0, '127.0.0.1');
}); upstreamPort = await waitForServerListening(upstreamServer);
} }
async function requestProxy(payload: unknown): Promise<Response> { async function requestProxy(payload: unknown): Promise<Response> {
@@ -98,8 +122,6 @@ async function requestProxy(payload: unknown): Promise<Response> {
} }
beforeEach(async () => { beforeEach(async () => {
upstreamPort = await getPort();
proxyPort = await getPort();
upstreamBody = undefined; upstreamBody = undefined;
await startMockUpstream(); await startMockUpstream();
const profile: OpenAICompatProfileConfig = { const profile: OpenAICompatProfileConfig = {
@@ -112,9 +134,10 @@ beforeEach(async () => {
}; };
proxyServer = startOpenAICompatProxyServer({ proxyServer = startOpenAICompatProxyServer({
profile, profile,
port: proxyPort, port: 0,
authToken: 'test-proxy-token', authToken: 'test-proxy-token',
}); });
proxyPort = await waitForServerListening(proxyServer);
}); });
afterEach(async () => { afterEach(async () => {
+40 -23
View File
@@ -1,5 +1,4 @@
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import getPort from 'get-port';
import * as fs from 'fs'; import * as fs from 'fs';
import * as http from 'http'; import * as http from 'http';
import * as os from 'os'; import * as os from 'os';
@@ -13,13 +12,34 @@ let proxyServer: http.Server;
let upstreamServers: http.Server[] = []; let upstreamServers: http.Server[] = [];
let proxyPort: number; let proxyPort: number;
function startMockUpstream( function resolveListeningPort(server: http.Server): number {
port: number, const address = server.address();
if (!address || typeof address === 'string') {
throw new Error('Failed to resolve server port');
}
return address.port;
}
async function waitForServerListening(server: http.Server): Promise<number> {
if (server.listening) {
return resolveListeningPort(server);
}
return new Promise<number>((resolve, reject) => {
const onError = (error: Error) => reject(error);
server.once('error', onError);
server.once('listening', () => {
server.off('error', onError);
resolve(resolveListeningPort(server));
});
});
}
async function startMockUpstream(
hitLabel: string, hitLabel: string,
hits: string[], hits: string[],
bodies: Array<{ label: string; body: unknown }> bodies: Array<{ label: string; body: unknown }>
): Promise<void> { ): Promise<number> {
return new Promise((resolve) => {
const server = http.createServer(async (req, res) => { const server = http.createServer(async (req, res) => {
let body = ''; let body = '';
for await (const chunk of req) { for await (const chunk of req) {
@@ -45,8 +65,8 @@ function startMockUpstream(
); );
}); });
upstreamServers.push(server); upstreamServers.push(server);
server.listen(port, '127.0.0.1', () => resolve()); server.listen(0, '127.0.0.1');
}); return waitForServerListening(server);
} }
function writeSettings(profileName: string, env: Record<string, string>): string { function writeSettings(profileName: string, env: Record<string, string>): string {
@@ -71,7 +91,7 @@ beforeEach(async () => {
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-proxy-routing-')); tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-proxy-routing-'));
fs.mkdirSync(path.join(tempDir, '.ccs'), { recursive: true }); fs.mkdirSync(path.join(tempDir, '.ccs'), { recursive: true });
process.env.CCS_HOME = tempDir; process.env.CCS_HOME = tempDir;
proxyPort = await getPort(); proxyPort = 0;
}); });
afterEach(async () => { afterEach(async () => {
@@ -97,12 +117,10 @@ afterEach(async () => {
describe('openai proxy request routing', () => { describe('openai proxy request routing', () => {
it('routes explicit profile:model selectors to the matching upstream profile', async () => { it('routes explicit profile:model selectors to the matching upstream profile', async () => {
const primaryPort = await getPort();
const secondaryPort = await getPort();
const hits: string[] = []; const hits: string[] = [];
const bodies: Array<{ label: string; body: unknown }> = []; const bodies: Array<{ label: string; body: unknown }> = [];
await startMockUpstream(primaryPort, 'primary', hits, bodies); const primaryPort = await startMockUpstream('primary', hits, bodies);
await startMockUpstream(secondaryPort, 'secondary', hits, bodies); const secondaryPort = await startMockUpstream('secondary', hits, bodies);
const primarySettings = writeSettings('hf', { const primarySettings = writeSettings('hf', {
ANTHROPIC_BASE_URL: `http://127.0.0.1:${primaryPort}`, ANTHROPIC_BASE_URL: `http://127.0.0.1:${primaryPort}`,
@@ -133,9 +151,10 @@ describe('openai proxy request routing', () => {
}; };
proxyServer = startOpenAICompatProxyServer({ proxyServer = startOpenAICompatProxyServer({
profile, profile,
port: proxyPort, port: 0,
authToken: 'test-proxy-token', authToken: 'test-proxy-token',
}); });
proxyPort = await waitForServerListening(proxyServer);
const response = await requestProxy({ const response = await requestProxy({
model: 'deepseek:deepseek-reasoner', model: 'deepseek:deepseek-reasoner',
@@ -150,12 +169,10 @@ describe('openai proxy request routing', () => {
}); });
it('routes thinking requests through the configured think scenario', async () => { it('routes thinking requests through the configured think scenario', async () => {
const primaryPort = await getPort();
const thinkPort = await getPort();
const hits: string[] = []; const hits: string[] = [];
const bodies: Array<{ label: string; body: unknown }> = []; const bodies: Array<{ label: string; body: unknown }> = [];
await startMockUpstream(primaryPort, 'primary', hits, bodies); const primaryPort = await startMockUpstream('primary', hits, bodies);
await startMockUpstream(thinkPort, 'thinker', hits, bodies); const thinkPort = await startMockUpstream('thinker', hits, bodies);
const primarySettings = writeSettings('hf', { const primarySettings = writeSettings('hf', {
ANTHROPIC_BASE_URL: `http://127.0.0.1:${primaryPort}`, ANTHROPIC_BASE_URL: `http://127.0.0.1:${primaryPort}`,
@@ -197,9 +214,10 @@ describe('openai proxy request routing', () => {
}; };
proxyServer = startOpenAICompatProxyServer({ proxyServer = startOpenAICompatProxyServer({
profile, profile,
port: proxyPort, port: 0,
authToken: 'test-proxy-token', authToken: 'test-proxy-token',
}); });
proxyPort = await waitForServerListening(proxyServer);
const response = await requestProxy({ const response = await requestProxy({
model: 'hf-default', model: 'hf-default',
@@ -216,12 +234,10 @@ describe('openai proxy request routing', () => {
}); });
it('routes adaptive thinking requests through the configured think scenario', async () => { it('routes adaptive thinking requests through the configured think scenario', async () => {
const primaryPort = await getPort();
const thinkPort = await getPort();
const hits: string[] = []; const hits: string[] = [];
const bodies: Array<{ label: string; body: unknown }> = []; const bodies: Array<{ label: string; body: unknown }> = [];
await startMockUpstream(primaryPort, 'primary', hits, bodies); const primaryPort = await startMockUpstream('primary', hits, bodies);
await startMockUpstream(thinkPort, 'thinker', hits, bodies); const thinkPort = await startMockUpstream('thinker', hits, bodies);
const primarySettings = writeSettings('hf', { const primarySettings = writeSettings('hf', {
ANTHROPIC_BASE_URL: `http://127.0.0.1:${primaryPort}`, ANTHROPIC_BASE_URL: `http://127.0.0.1:${primaryPort}`,
@@ -263,9 +279,10 @@ describe('openai proxy request routing', () => {
}; };
proxyServer = startOpenAICompatProxyServer({ proxyServer = startOpenAICompatProxyServer({
profile, profile,
port: proxyPort, port: 0,
authToken: 'test-proxy-token', authToken: 'test-proxy-token',
}); });
proxyPort = await waitForServerListening(proxyServer);
const response = await requestProxy({ const response = await requestProxy({
model: 'hf-default', model: 'hf-default',