mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
140 lines
3.8 KiB
TypeScript
140 lines
3.8 KiB
TypeScript
/**
|
|
* 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),
|
|
};
|
|
|
|
// Accept self-signed TLS certs from the local goosed server.
|
|
// In Electron this is handled by setCertificateVerifyProc, but integration
|
|
// tests run in plain Node.js where fetch rejects self-signed certs.
|
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
|
|
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,
|
|
};
|
|
}
|