Skip to content

Commit 619711a

Browse files
stainless-emRobertCraigie
authored andcommitted
chore(internal): add proxy ecosystem tests
1 parent 157248a commit 619711a

File tree

4 files changed

+173
-95
lines changed

4 files changed

+173
-95
lines changed

ecosystem-tests/bun/openai.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ test(`basic request works`, async function () {
4343
expectSimilar(completion.choices[0]?.message?.content, 'This is a test', 10);
4444
});
4545

46+
test(`proxied request works`, async function () {
47+
const client = new OpenAI({
48+
fetch(url, init) {
49+
return fetch(url, { ...init, proxy: process.env['ECOSYSTEM_TESTS_PROXY'] });
50+
},
51+
});
52+
53+
const completion = await client.chat.completions.create({
54+
model: 'gpt-4',
55+
messages: [{ role: 'user', content: 'Say this is a test' }],
56+
});
57+
expectSimilar(completion.choices[0]?.message?.content, 'This is a test', 10);
58+
});
59+
4660
test(`raw response`, async function () {
4761
const response = await client.chat.completions
4862
.create({

ecosystem-tests/cli.ts

Lines changed: 131 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import execa from 'execa';
33
import yargs from 'yargs';
44
import assert from 'assert';
55
import path from 'path';
6+
import { createServer } from 'http';
7+
import { connect } from 'net';
68

79
const TAR_NAME = 'openai.tgz';
810
const PACK_FOLDER = '.pack';
@@ -109,6 +111,35 @@ const projectRunners = {
109111
let projectNames = Object.keys(projectRunners) as Array<keyof typeof projectRunners>;
110112
const projectNamesSet = new Set(projectNames);
111113

114+
async function startProxy() {
115+
const proxy = createServer((_req, res) => {
116+
res.end();
117+
});
118+
119+
proxy.on('connect', (req, clientSocket, head) => {
120+
console.log('got proxied connection');
121+
const serverSocket = connect(443, 'api.openai.com', () => {
122+
clientSocket.write(
123+
'HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + '\r\n',
124+
);
125+
serverSocket.write(head);
126+
serverSocket.pipe(clientSocket);
127+
clientSocket.pipe(serverSocket);
128+
});
129+
});
130+
131+
await new Promise<void>((resolve) => proxy.listen(0, '127.0.0.1', resolve));
132+
133+
const address = proxy.address();
134+
assert(address && typeof address !== 'string');
135+
process.env['ECOSYSTEM_TESTS_PROXY'] = 'http://127.0.0.1:' + address.port;
136+
137+
return () => {
138+
delete process.env['ECOSYSTEM_TESTS_PROXY'];
139+
proxy.close();
140+
};
141+
}
142+
112143
function parseArgs() {
113144
return yargs(process.argv.slice(2))
114145
.scriptName('ecosystem-tests')
@@ -287,112 +318,118 @@ async function main() {
287318
await fileCache.cacheFiles(tmpFolderPath);
288319
}
289320

290-
if (jobs > 1) {
291-
const queue = [...projectsToRun];
292-
const runningProjects = new Set();
293-
294-
const cursorLeft = '\x1B[G';
295-
const eraseLine = '\x1B[2K';
296-
297-
let progressDisplayed = false;
298-
function clearProgress() {
299-
if (progressDisplayed) {
300-
process.stderr.write(cursorLeft + eraseLine);
301-
progressDisplayed = false;
321+
const stopProxy = await startProxy();
322+
try {
323+
if (jobs > 1) {
324+
const queue = [...projectsToRun];
325+
const runningProjects = new Set();
326+
327+
const cursorLeft = '\x1B[G';
328+
const eraseLine = '\x1B[2K';
329+
330+
let progressDisplayed = false;
331+
function clearProgress() {
332+
if (progressDisplayed) {
333+
process.stderr.write(cursorLeft + eraseLine);
334+
progressDisplayed = false;
335+
}
336+
}
337+
const spinner = ['|', '/', '-', '\\'];
338+
339+
function showProgress() {
340+
clearProgress();
341+
progressDisplayed = true;
342+
const spin = spinner[Math.floor(Date.now() / 500) % spinner.length];
343+
process.stderr.write(
344+
`${spin} Running ${[...runningProjects].join(', ')}`.substring(0, process.stdout.columns - 3) +
345+
'...',
346+
);
302347
}
303-
}
304-
const spinner = ['|', '/', '-', '\\'];
305348

306-
function showProgress() {
307-
clearProgress();
308-
progressDisplayed = true;
309-
const spin = spinner[Math.floor(Date.now() / 500) % spinner.length];
310-
process.stderr.write(
311-
`${spin} Running ${[...runningProjects].join(', ')}`.substring(0, process.stdout.columns - 3) + '...',
312-
);
313-
}
349+
const progressInterval = setInterval(showProgress, process.stdout.isTTY ? 500 : 5000);
350+
showProgress();
351+
352+
await Promise.all(
353+
[...Array(jobs).keys()].map(async () => {
354+
while (queue.length) {
355+
const project = queue.shift();
356+
if (!project) {
357+
break;
358+
}
314359

315-
const progressInterval = setInterval(showProgress, process.stdout.isTTY ? 500 : 5000);
316-
showProgress();
360+
// preserve interleaved ordering of writes to stdout/stderr
361+
const chunks: { dest: 'stdout' | 'stderr'; data: string | Buffer }[] = [];
362+
try {
363+
runningProjects.add(project);
364+
const child = execa(
365+
'yarn',
366+
[
367+
'tsn',
368+
__filename,
369+
project,
370+
'--skip-pack',
371+
'--noCleanup',
372+
`--retry=${args.retry}`,
373+
...(args.live ? ['--live'] : []),
374+
...(args.verbose ? ['--verbose'] : []),
375+
...(args.deploy ? ['--deploy'] : []),
376+
...(args.fromNpm ? ['--from-npm'] : []),
377+
],
378+
{ stdio: 'pipe', encoding: 'utf8', maxBuffer: 100 * 1024 * 1024 },
379+
);
380+
child.stdout?.on('data', (data) => chunks.push({ dest: 'stdout', data }));
381+
child.stderr?.on('data', (data) => chunks.push({ dest: 'stderr', data }));
382+
383+
await child;
384+
} catch (error) {
385+
failed.push(project);
386+
} finally {
387+
runningProjects.delete(project);
388+
}
317389

318-
await Promise.all(
319-
[...Array(jobs).keys()].map(async () => {
320-
while (queue.length) {
321-
const project = queue.shift();
322-
if (!project) {
323-
break;
324-
}
390+
if (IS_CI) {
391+
console.log(`::group::${failed.includes(project) ? '❌' : '✅'} ${project}`);
392+
}
325393

326-
// preserve interleaved ordering of writes to stdout/stderr
327-
const chunks: { dest: 'stdout' | 'stderr'; data: string | Buffer }[] = [];
328-
try {
329-
runningProjects.add(project);
330-
const child = execa(
331-
'yarn',
332-
[
333-
'tsn',
334-
__filename,
335-
project,
336-
'--skip-pack',
337-
'--noCleanup',
338-
`--retry=${args.retry}`,
339-
...(args.live ? ['--live'] : []),
340-
...(args.verbose ? ['--verbose'] : []),
341-
...(args.deploy ? ['--deploy'] : []),
342-
...(args.fromNpm ? ['--from-npm'] : []),
343-
],
344-
{ stdio: 'pipe', encoding: 'utf8', maxBuffer: 100 * 1024 * 1024 },
345-
);
346-
child.stdout?.on('data', (data) => chunks.push({ dest: 'stdout', data }));
347-
child.stderr?.on('data', (data) => chunks.push({ dest: 'stderr', data }));
348-
349-
await child;
350-
} catch (error) {
351-
failed.push(project);
352-
} finally {
353-
runningProjects.delete(project);
394+
for (const { data } of chunks) {
395+
process.stdout.write(data);
396+
}
397+
if (IS_CI) console.log('::endgroup::');
354398
}
399+
}),
400+
);
355401

356-
if (IS_CI) {
357-
console.log(`::group::${failed.includes(project) ? '❌' : '✅'} ${project}`);
358-
}
402+
clearInterval(progressInterval);
403+
clearProgress();
404+
} else {
405+
for (const project of projectsToRun) {
406+
const fn = projectRunners[project];
359407

360-
for (const { data } of chunks) {
361-
process.stdout.write(data);
362-
}
363-
if (IS_CI) console.log('::endgroup::');
364-
}
365-
}),
366-
);
367-
368-
clearInterval(progressInterval);
369-
clearProgress();
370-
} else {
371-
for (const project of projectsToRun) {
372-
const fn = projectRunners[project];
373-
374-
await withChdir(path.join(rootDir, 'ecosystem-tests', project), async () => {
375-
console.error('\n');
376-
console.error(banner(`▶️ ${project}`));
377-
console.error('\n');
378-
379-
try {
380-
await withRetry(fn, project, state.retry, state.retryDelay);
408+
await withChdir(path.join(rootDir, 'ecosystem-tests', project), async () => {
409+
console.error('\n');
410+
console.error(banner(`▶️ ${project}`));
381411
console.error('\n');
382-
console.error(`✅ ${project}`);
383-
} catch (err) {
384-
if (err && (err as any).shortMessage) {
385-
console.error((err as any).shortMessage);
386-
} else {
387-
console.error(err);
412+
413+
try {
414+
await withRetry(fn, project, state.retry, state.retryDelay);
415+
console.error('\n');
416+
console.error(`✅ ${project}`);
417+
} catch (err) {
418+
if (err && (err as any).shortMessage) {
419+
console.error((err as any).shortMessage);
420+
} else {
421+
console.error(err);
422+
}
423+
console.error('\n');
424+
console.error(`❌ ${project}`);
425+
failed.push(project);
388426
}
389427
console.error('\n');
390-
console.error(`❌ ${project}`);
391-
failed.push(project);
392-
}
393-
console.error('\n');
394-
});
428+
});
429+
}
395430
}
431+
} finally {
432+
stopProxy();
396433
}
397434

398435
if (!args.noCleanup) {

ecosystem-tests/node-ts-cjs/tests/test-node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import OpenAI, { toFile } from 'openai';
2-
import * as undici from 'undici';
32
import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions';
3+
import * as undici from 'undici';
44
import { File as FormDataFile, Blob as FormDataBlob } from 'formdata-node';
55
import * as fs from 'fs';
66
import { distance } from 'fastest-levenshtein';

ecosystem-tests/proxy.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { createServer } from 'http';
2+
import { connect } from 'net';
3+
4+
async function startProxy() {
5+
const proxy = createServer((_req, res) => {
6+
res.end();
7+
});
8+
9+
proxy.on('connect', (req, clientSocket, head) => {
10+
const serverSocket = connect(443, 'api.openai.com', () => {
11+
clientSocket.write(
12+
'HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + '\r\n',
13+
);
14+
serverSocket.write(head);
15+
serverSocket.pipe(clientSocket);
16+
clientSocket.pipe(serverSocket);
17+
});
18+
});
19+
20+
await new Promise<void>((resolve) => proxy.listen(0, '127.0.0.1', resolve));
21+
22+
console.log(proxy.address()!.toString())
23+
24+
return () => {
25+
proxy.close()
26+
}
27+
}

0 commit comments

Comments
 (0)