diff --git a/packages/core/src/scheduler/tool-executor.test.ts b/packages/core/src/scheduler/tool-executor.test.ts index 141f2bef80..452bc051a2 100644 --- a/packages/core/src/scheduler/tool-executor.test.ts +++ b/packages/core/src/scheduler/tool-executor.test.ts @@ -607,6 +607,8 @@ describe('ToolExecutor', () => { it('should preserve temporary file when fullOutputFilePath is provided but output is not truncated', async () => { // 1. Setup Config for Truncation vi.spyOn(config, 'getTruncateToolOutputThreshold').mockReturnValue(100); + vi.spyOn(config.storage, 'getProjectTempDir').mockReturnValue('/tmp'); + vi.spyOn(config, 'getSessionId').mockReturnValue('test-session-id'); const unlinkSpy = vi .spyOn(fsPromises, 'unlink') .mockResolvedValue(undefined); @@ -652,7 +654,7 @@ describe('ToolExecutor', () => { SHELL_TOOL_NAME, 'call-short-full', expect.any(String), - expect.any(String), + 'test-session-id', ); expect(unlinkSpy).not.toHaveBeenCalled(); expect(fileUtils.formatTruncatedToolOutput).not.toHaveBeenCalled(); diff --git a/packages/core/src/services/shellExecutionService.test.ts b/packages/core/src/services/shellExecutionService.test.ts index 869df2689c..a06ae10b41 100644 --- a/packages/core/src/services/shellExecutionService.test.ts +++ b/packages/core/src/services/shellExecutionService.test.ts @@ -1327,7 +1327,7 @@ describe('ShellExecutionService child_process fallback', () => { const { result, handle } = await simulateExecution('ls -l', (cp) => { cp.stdout?.emit('data', Buffer.from('file1.txt\n')); cp.stderr?.emit('data', Buffer.from('a warning')); - cp.emit('exit', 0, null); + cp.emit('close', 0, null); cp.emit('close', 0, null); }); @@ -1364,7 +1364,7 @@ describe('ShellExecutionService child_process fallback', () => { it('should strip ANSI color codes from output', async () => { const { result } = await simulateExecution('ls --color=auto', (cp) => { cp.stdout?.emit('data', Buffer.from('a\u001b[31mred\u001b[0mword')); - cp.emit('exit', 0, null); + cp.emit('close', 0, null); cp.emit('close', 0, null); }); @@ -1385,7 +1385,7 @@ describe('ShellExecutionService child_process fallback', () => { const multiByteChar = Buffer.from('你好', 'utf-8'); cp.stdout?.emit('data', multiByteChar.slice(0, 2)); cp.stdout?.emit('data', multiByteChar.slice(2)); - cp.emit('exit', 0, null); + cp.emit('close', 0, null); cp.emit('close', 0, null); }); expect(result.output.trim()).toBe('你好'); @@ -1393,7 +1393,7 @@ describe('ShellExecutionService child_process fallback', () => { it('should handle commands with no output', async () => { const { result } = await simulateExecution('touch file', (cp) => { - cp.emit('exit', 0, null); + cp.emit('close', 0, null); cp.emit('close', 0, null); }); @@ -1415,7 +1415,7 @@ describe('ShellExecutionService child_process fallback', () => { cp.stdout?.emit('data', Buffer.from(chunk1)); cp.stdout?.emit('data', Buffer.from(chunk2)); cp.stdout?.emit('data', Buffer.from(chunk3)); - cp.emit('exit', 0, null); + cp.emit('close', 0, null); }); const truncationMessage = @@ -1440,7 +1440,7 @@ describe('ShellExecutionService child_process fallback', () => { it('should capture a non-zero exit code and format output correctly', async () => { const { result } = await simulateExecution('a-bad-command', (cp) => { cp.stderr?.emit('data', Buffer.from('command not found')); - cp.emit('exit', 127, null); + cp.emit('close', 127, null); cp.emit('close', 127, null); }); @@ -1451,7 +1451,7 @@ describe('ShellExecutionService child_process fallback', () => { it('should capture a termination signal', async () => { const { result } = await simulateExecution('long-process', (cp) => { - cp.emit('exit', null, 'SIGTERM'); + cp.emit('close', null, 'SIGTERM'); cp.emit('close', null, 'SIGTERM'); }); @@ -1463,7 +1463,7 @@ describe('ShellExecutionService child_process fallback', () => { const spawnError = new Error('spawn EACCES'); const { result } = await simulateExecution('protected-cmd', (cp) => { cp.emit('error', spawnError); - cp.emit('exit', 1, null); + cp.emit('close', 1, null); cp.emit('close', 1, null); }); @@ -1506,11 +1506,11 @@ describe('ShellExecutionService child_process fallback', () => { (cp, abortController) => { abortController.abort(); if (expectedExit.signal) { - cp.emit('exit', null, expectedExit.signal); + cp.emit('close', null, expectedExit.signal); cp.emit('close', null, expectedExit.signal); } if (typeof expectedExit.code === 'number') { - cp.emit('exit', expectedExit.code, null); + cp.emit('close', expectedExit.code, null); cp.emit('close', expectedExit.code, null); } }, @@ -1575,7 +1575,7 @@ describe('ShellExecutionService child_process fallback', () => { ); // Finally, simulate the process exiting and await the result - mockChildProcess.emit('exit', null, 'SIGKILL'); + mockChildProcess.emit('close', null, 'SIGKILL'); mockChildProcess.emit('close', null, 'SIGKILL'); const result = await handle.result; @@ -1595,7 +1595,7 @@ describe('ShellExecutionService child_process fallback', () => { await simulateExecution('cat image.png', (cp) => { cp.stdout?.emit('data', binaryChunk1); cp.stdout?.emit('data', binaryChunk2); - cp.emit('exit', 0, null); + cp.emit('close', 0, null); }); // We don't check result here because result is not available in the test body as written @@ -1625,7 +1625,6 @@ describe('ShellExecutionService child_process fallback', () => { await simulateExecution('cat mixed_file', (cp) => { cp.stdout?.emit('data', Buffer.from([0x00, 0x01, 0x02])); cp.stdout?.emit('data', Buffer.from('more text')); - cp.emit('exit', 0, null); cp.emit('close', 0, null); }); @@ -1645,7 +1644,7 @@ describe('ShellExecutionService child_process fallback', () => { it('should use powershell.exe on Windows', async () => { mockPlatform.mockReturnValue('win32'); await simulateExecution('dir "foo bar"', (cp) => { - cp.emit('exit', 0, null); + cp.emit('close', 0, null); }); expect(mockCpSpawn).toHaveBeenCalledWith( @@ -1662,7 +1661,7 @@ describe('ShellExecutionService child_process fallback', () => { it('should use bash and detached process group on Linux', async () => { mockPlatform.mockReturnValue('linux'); await simulateExecution('ls "foo bar"', (cp) => { - cp.emit('exit', 0, null); + cp.emit('close', 0, null); }); expect(mockCpSpawn).toHaveBeenCalledWith( @@ -1772,7 +1771,7 @@ describe('ShellExecutionService execution method selection', () => { ); // Simulate exit to allow promise to resolve - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); const result = await handle.result; expect(mockGetPty).not.toHaveBeenCalled(); @@ -1795,7 +1794,7 @@ describe('ShellExecutionService execution method selection', () => { ); // Simulate exit to allow promise to resolve - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); const result = await handle.result; expect(mockGetPty).toHaveBeenCalled(); @@ -1859,10 +1858,6 @@ describe('ShellExecutionService environment variables', () => { // Small delay to allow async ops to complete setTimeout(() => mockPtyProcess.emit('exit', { exitCode, signal }), 0); }); - mockChildProcess.on('exit', (code, signal) => { - // Small delay to allow async ops to complete - setTimeout(() => mockChildProcess.emit('close', code, signal), 0); - }); }); afterEach(() => { @@ -1925,7 +1920,7 @@ describe('ShellExecutionService environment variables', () => { expect(cpEnv).toHaveProperty('GEMINI_CLI_TEST_VAR', 'test-value'); // Ensure child_process exits - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); mockChildProcess.emit('close', 0, null); await new Promise(process.nextTick); }); @@ -1985,7 +1980,7 @@ describe('ShellExecutionService environment variables', () => { expect(cpEnv).toHaveProperty('GEMINI_CLI_TEST_VAR', 'test-value'); // Ensure child_process exits - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); mockChildProcess.emit('close', 0, null); await new Promise(process.nextTick); }); @@ -2033,7 +2028,7 @@ describe('ShellExecutionService environment variables', () => { expect(cpEnv).toHaveProperty('GEMINI_CLI', '1'); // Ensure child_process exits - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); mockChildProcess.emit('close', 0, null); await new Promise(process.nextTick); }); @@ -2090,7 +2085,7 @@ describe('ShellExecutionService environment variables', () => { ); // Clean up - mockChild.emit('exit', 0, null); + mockChild.emit('close', 0, null); mockChild.emit('close', 0, null); await handle.result; }); @@ -2139,7 +2134,7 @@ describe('ShellExecutionService environment variables', () => { expect(cpEnv).toHaveProperty('GIT_CONFIG_VALUE_2', ''); // Ensure child_process exits - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); mockChildProcess.emit('close', 0, null); await new Promise(process.nextTick); @@ -2179,7 +2174,7 @@ describe('ShellExecutionService environment variables', () => { expect(cpEnv).not.toHaveProperty('GIT_CONFIG_COUNT'); // Ensure child_process exits - mockChildProcess.emit('exit', 0, null); + mockChildProcess.emit('close', 0, null); mockChildProcess.emit('close', 0, null); await new Promise(process.nextTick);