chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// Unset NO_COLOR environment variable to ensure consistent theme behavior between local and CI test runs
|
||||
if (process.env['NO_COLOR'] !== undefined) {
|
||||
delete process.env['NO_COLOR'];
|
||||
}
|
||||
|
||||
import { mkdir, readdir, rm, readFile } from 'node:fs/promises';
|
||||
import { join, dirname, extname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { resolveRipgrepPath } from '../packages/core/src/tools/ripGrep.js';
|
||||
import { disableMouseTracking } from '@google/gemini-cli-core';
|
||||
import { isolateTestEnv } from '../packages/test-utils/src/env-setup.js';
|
||||
import { createServer, type Server } from 'node:http';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = join(__dirname, '..');
|
||||
const integrationTestsDir = join(rootDir, '.integration-tests');
|
||||
let runDir = ''; // Make runDir accessible in teardown
|
||||
let fixtureServer: Server | undefined;
|
||||
|
||||
const FIXTURE_PORT = 18923;
|
||||
const FIXTURE_DIR = join(__dirname, 'test-fixtures');
|
||||
|
||||
const MIME_TYPES: Record<string, string> = {
|
||||
'.html': 'text/html',
|
||||
'.css': 'text/css',
|
||||
'.js': 'application/javascript',
|
||||
'.json': 'application/json',
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.svg': 'image/svg+xml',
|
||||
};
|
||||
|
||||
async function startFixtureServer(): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = createServer(async (req, res) => {
|
||||
const urlPath = req.url?.split('?')[0] || '/';
|
||||
const relativePath = urlPath === '/' ? 'index.html' : urlPath;
|
||||
const filePath = join(FIXTURE_DIR, relativePath);
|
||||
|
||||
if (!filePath.startsWith(FIXTURE_DIR)) {
|
||||
res.writeHead(403, { 'Content-Type': 'text/html' });
|
||||
res.end('<h1>403 Forbidden</h1>');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = await readFile(filePath);
|
||||
const ext = extname(filePath);
|
||||
res.writeHead(200, {
|
||||
'Content-Type': MIME_TYPES[ext] || 'application/octet-stream',
|
||||
});
|
||||
res.end(content);
|
||||
} catch {
|
||||
res.writeHead(404, { 'Content-Type': 'text/html' });
|
||||
res.end('<h1>404 Not Found</h1>');
|
||||
}
|
||||
});
|
||||
|
||||
server.on('error', (err: NodeJS.ErrnoException) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
console.warn(
|
||||
`Port ${FIXTURE_PORT} in use, trying ${FIXTURE_PORT + 1}...`,
|
||||
);
|
||||
server.listen(FIXTURE_PORT + 1, '127.0.0.1');
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
server.on('listening', () => {
|
||||
const addr = server.address();
|
||||
const port = typeof addr === 'object' && addr ? addr.port : FIXTURE_PORT;
|
||||
fixtureServer = server;
|
||||
console.log(`Test fixture server listening on http://127.0.0.1:${port}`);
|
||||
resolve(port);
|
||||
});
|
||||
|
||||
server.listen(FIXTURE_PORT, '127.0.0.1');
|
||||
});
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
runDir = join(integrationTestsDir, `${Date.now()}`);
|
||||
await mkdir(runDir, { recursive: true });
|
||||
|
||||
// Isolate environment variables
|
||||
isolateTestEnv(runDir);
|
||||
|
||||
// Download ripgrep to avoid race conditions in parallel tests
|
||||
const available = await resolveRipgrepPath();
|
||||
if (!available) {
|
||||
throw new Error('Failed to download ripgrep binary');
|
||||
}
|
||||
|
||||
// Start the test fixture server
|
||||
const port = await startFixtureServer();
|
||||
process.env['TEST_FIXTURE_PORT'] = String(port);
|
||||
|
||||
// Clean up old test runs, but keep the latest few for debugging
|
||||
try {
|
||||
const testRuns = await readdir(integrationTestsDir);
|
||||
if (testRuns.length > 5) {
|
||||
const oldRuns = testRuns.sort().slice(0, testRuns.length - 5);
|
||||
await Promise.all(
|
||||
oldRuns.map((oldRun) =>
|
||||
rm(join(integrationTestsDir, oldRun), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error cleaning up old test runs:', e);
|
||||
}
|
||||
|
||||
process.env['INTEGRATION_TEST_FILE_DIR'] = runDir;
|
||||
|
||||
if (process.env['KEEP_OUTPUT']) {
|
||||
console.log(`Keeping output for test run in: ${runDir}`);
|
||||
}
|
||||
process.env['VERBOSE'] = process.env['VERBOSE'] ?? 'false';
|
||||
|
||||
console.log(`\nIntegration test output directory: ${runDir}`);
|
||||
}
|
||||
|
||||
export async function teardown() {
|
||||
// Stop the fixture server
|
||||
if (fixtureServer) {
|
||||
await new Promise<void>((resolve) => {
|
||||
fixtureServer!.close(() => resolve());
|
||||
});
|
||||
fixtureServer = undefined;
|
||||
}
|
||||
|
||||
// Disable mouse tracking
|
||||
if (process.stdout.isTTY) {
|
||||
disableMouseTracking();
|
||||
}
|
||||
|
||||
// Cleanup the test run directory unless KEEP_OUTPUT is set
|
||||
if (process.env['KEEP_OUTPUT'] !== 'true' && runDir) {
|
||||
try {
|
||||
await rm(runDir, { recursive: true, force: true });
|
||||
} catch (e) {
|
||||
console.warn('Failed to clean up test run directory:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user