Add a goosed over HTTP integration test, and test the developer tool PATH (#7178)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Integration test setup for testing the goosed binary via the TypeScript API client.
|
||||
*
|
||||
* This test suite spawns a real goosed process and issues requests via the
|
||||
* auto-generated API client.
|
||||
*/
|
||||
|
||||
import type { ChildProcess } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import type { Client } from '../../src/api/client';
|
||||
import { startGoosed as startGoosedBase, checkServerStatus, type Logger } from '../../src/goosed';
|
||||
import { expect } from 'vitest';
|
||||
|
||||
function stringifyResponse(response: Response) {
|
||||
const details = {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
url: response.url,
|
||||
headers: response.headers ? Object.fromEntries(response.headers) : undefined,
|
||||
};
|
||||
return JSON.stringify(details, null, 2);
|
||||
}
|
||||
|
||||
expect.extend({
|
||||
toBeOkResponse(response) {
|
||||
const pass = response.ok === true;
|
||||
return {
|
||||
pass,
|
||||
message: () =>
|
||||
pass
|
||||
? 'expected response not to be ok'
|
||||
: `expected response to be ok, got: ${stringifyResponse(response)}`,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const TEST_SECRET_KEY = 'test';
|
||||
|
||||
export interface GoosedTestContext {
|
||||
client: Client;
|
||||
baseUrl: string;
|
||||
secretKey: string;
|
||||
process: ChildProcess | null;
|
||||
cleanup: () => Promise<void>;
|
||||
}
|
||||
|
||||
export async function setupGoosed({
|
||||
pathOverride,
|
||||
configYaml,
|
||||
}: {
|
||||
pathOverride?: string;
|
||||
configYaml?: string;
|
||||
}): Promise<GoosedTestContext> {
|
||||
const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'goose-app-root-'));
|
||||
|
||||
if (configYaml) {
|
||||
await fs.promises.mkdir(path.join(tempDir, 'config'), { recursive: true });
|
||||
await fs.promises.writeFile(path.join(tempDir, 'config', 'config.yaml'), configYaml);
|
||||
}
|
||||
|
||||
const testLogger: Logger = {
|
||||
info: (...args) => {
|
||||
if (process.env.DEBUG) {
|
||||
console.log('[goosed]', ...args);
|
||||
}
|
||||
},
|
||||
error: (...args) => console.error('[goosed]', ...args),
|
||||
};
|
||||
|
||||
const additionalEnv: Record<string, string> = {
|
||||
GOOSE_PATH_ROOT: tempDir,
|
||||
};
|
||||
|
||||
if (pathOverride) {
|
||||
additionalEnv.PATH = pathOverride;
|
||||
}
|
||||
|
||||
const {
|
||||
baseUrl,
|
||||
process: goosedProcess,
|
||||
client,
|
||||
cleanup: baseCleanup,
|
||||
errorLog,
|
||||
} = await startGoosedBase({
|
||||
serverSecret: TEST_SECRET_KEY,
|
||||
env: additionalEnv,
|
||||
logger: testLogger,
|
||||
});
|
||||
|
||||
if (!goosedProcess) {
|
||||
throw new Error('Expected goosed process to be started, but got external backend');
|
||||
}
|
||||
|
||||
const cleanup = async (): Promise<void> => {
|
||||
// dump server logs to test logs, visible if there are test failures
|
||||
try {
|
||||
const logsPath = path.join(tempDir, 'state', 'logs', 'server');
|
||||
if (fs.existsSync(logsPath)) {
|
||||
const logDirs = await fs.promises.readdir(logsPath);
|
||||
for (const logDir of logDirs) {
|
||||
const logFiles = await fs.promises.readdir(path.join(logsPath, logDir));
|
||||
for (const logFile of logFiles) {
|
||||
const logPath = path.join(logsPath, logDir, logFile);
|
||||
const logContent = await fs.promises.readFile(logPath, 'utf8');
|
||||
console.log(logContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Logs may not exist
|
||||
}
|
||||
|
||||
await baseCleanup();
|
||||
await fs.promises.rm(tempDir, { recursive: true, force: true });
|
||||
};
|
||||
|
||||
const serverReady = await checkServerStatus(client, errorLog);
|
||||
if (!serverReady) {
|
||||
await cleanup();
|
||||
console.error('Server stderr:', errorLog.join('\n'));
|
||||
throw new Error('Failed to start goosed');
|
||||
}
|
||||
|
||||
return {
|
||||
client,
|
||||
baseUrl,
|
||||
secretKey: TEST_SECRET_KEY,
|
||||
process: goosedProcess,
|
||||
cleanup,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user