mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-11 06:31:01 -07:00
88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { TestRig } from './test-helper.js';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
describe('Background Shell Output Logging', () => {
|
|
let rig: TestRig;
|
|
|
|
beforeEach(() => {
|
|
rig = new TestRig();
|
|
});
|
|
|
|
afterEach(async () => await rig.cleanup());
|
|
|
|
it('should log background process output to a file', async () => {
|
|
await rig.setup('should log background process output to a file', {
|
|
settings: { tools: { core: ['run_shell_command'] } },
|
|
});
|
|
|
|
// We use a command that outputs something, then backgrounds, then outputs more.
|
|
// Since we're in the test rig, we have to be careful with how we background.
|
|
// The run_shell_command tool backgrounds if is_background: true is passed.
|
|
|
|
const prompt = `Please run the command "echo start; sleep 1; echo end" in the background and tell me the PID.`;
|
|
|
|
const result = await rig.run({
|
|
args: [prompt],
|
|
// approvalMode: 'yolo' is needed to avoid interactive prompt in tests
|
|
approvalMode: 'yolo',
|
|
});
|
|
|
|
// Extract PID from result
|
|
const cleanResult = result.replace(
|
|
// eslint-disable-next-line no-control-regex
|
|
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
|
|
'',
|
|
);
|
|
const pidMatch = cleanResult.match(/PID.*?\s*(\d+)/i);
|
|
expect(pidMatch, `Expected PID in output: ${cleanResult}`).toBeTruthy();
|
|
const pid = parseInt(pidMatch![1], 10);
|
|
|
|
const logDir = path.join(
|
|
rig.homeDir!,
|
|
'.gemini',
|
|
'tmp',
|
|
'background-processes',
|
|
);
|
|
const logFilePath = path.join(logDir, `background-${pid}.log`);
|
|
|
|
// Wait for the process to finish and log output
|
|
// We'll poll the log file
|
|
let logContent = '';
|
|
const maxRetries = 40;
|
|
let retries = 0;
|
|
|
|
while (retries < maxRetries) {
|
|
if (fs.existsSync(logFilePath)) {
|
|
logContent = fs.readFileSync(logFilePath, 'utf8');
|
|
if (logContent.includes('end')) {
|
|
break;
|
|
}
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
retries++;
|
|
}
|
|
|
|
expect(logContent).toContain('start');
|
|
expect(logContent).toContain('end');
|
|
|
|
// Verify no ANSI escape codes are present (starting with \x1b[ or \u001b[)
|
|
const ansiRegex =
|
|
// eslint-disable-next-line no-control-regex
|
|
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
expect(logContent).not.toMatch(ansiRegex);
|
|
|
|
// Cleanup the log file after test
|
|
if (fs.existsSync(logFilePath)) {
|
|
fs.unlinkSync(logFilePath);
|
|
}
|
|
});
|
|
});
|