diff options
| author | christine betts <[email protected]> | 2025-08-14 18:09:19 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-14 18:09:19 +0000 |
| commit | af93a10a92423184b30c8ef0f5a8e9e70abff167 (patch) | |
| tree | 2b94b9d8ac40ba026b9d2c40685988f621f575dd /integration-tests | |
| parent | ec7b84191f539c1a3f890fc994dd62b68d3232fd (diff) | |
[ide-mode] Write port to file in ide-server (#5811)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Diffstat (limited to 'integration-tests')
| -rw-r--r-- | integration-tests/ide-client.test.ts | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/integration-tests/ide-client.test.ts b/integration-tests/ide-client.test.ts new file mode 100644 index 00000000..186320b3 --- /dev/null +++ b/integration-tests/ide-client.test.ts @@ -0,0 +1,139 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import * as net from 'node:net'; +import { IdeClient } from '../packages/core/src/ide/ide-client.js'; +import { getIdeProcessId } from '../packages/core/src/ide/process-utils.js'; +import { spawn, ChildProcess } from 'child_process'; + +describe('IdeClient', () => { + it('reads port from file and connects', async () => { + const port = 12345; + const pid = await getIdeProcessId(); + const portFile = path.join(os.tmpdir(), `gemini-ide-server-${pid}.json`); + fs.writeFileSync(portFile, JSON.stringify({ port })); + + const ideClient = IdeClient.getInstance(); + await ideClient.connect(); + + expect(ideClient.getConnectionStatus().status).not.toBe('disconnected'); + + fs.unlinkSync(portFile); + }); +}); + +const getFreePort = (): Promise<number> => { + return new Promise((resolve, reject) => { + const server = net.createServer(); + server.unref(); + server.on('error', reject); + server.listen(0, () => { + const port = (server.address() as net.AddressInfo).port; + server.close(() => { + resolve(port); + }); + }); + }); +}; + +describe('IdeClient fallback connection logic', () => { + let server: net.Server; + let envPort: number; + let pid: number; + let portFile: string; + + beforeEach(async () => { + pid = await getIdeProcessId(); + portFile = path.join(os.tmpdir(), `gemini-ide-server-${pid}.json`); + envPort = await getFreePort(); + server = net.createServer().listen(envPort); + process.env['GEMINI_CLI_IDE_SERVER_PORT'] = String(envPort); + process.env['GEMINI_CLI_IDE_WORKSPACE_PATH'] = process.cwd(); + // Reset instance + IdeClient.instance = undefined; + }); + + afterEach(() => { + server.close(); + delete process.env['GEMINI_CLI_IDE_SERVER_PORT']; + delete process.env['GEMINI_CLI_IDE_WORKSPACE_PATH']; + if (fs.existsSync(portFile)) { + fs.unlinkSync(portFile); + } + }); + + it('connects using env var when port file does not exist', async () => { + // Ensure port file doesn't exist + if (fs.existsSync(portFile)) { + fs.unlinkSync(portFile); + } + + const ideClient = IdeClient.getInstance(); + await ideClient.connect(); + + expect(ideClient.getConnectionStatus().status).toBe('connected'); + }); + + it('falls back to env var when connection with port from file fails', async () => { + const filePort = await getFreePort(); + // Write port file with a port that is not listening + fs.writeFileSync(portFile, JSON.stringify({ port: filePort })); + + const ideClient = IdeClient.getInstance(); + await ideClient.connect(); + + expect(ideClient.getConnectionStatus().status).toBe('connected'); + }); +}); + +describe('getIdeProcessId', () => { + let child: ChildProcess; + + afterEach(() => { + if (child) { + child.kill(); + } + }); + + it('should return the pid of the parent process', async () => { + // We need to spawn a child process that will run the test + // so that we can check that getIdeProcessId returns the pid of the parent + const parentPid = process.pid; + const output = await new Promise<string>((resolve, reject) => { + child = spawn( + 'node', + [ + '-e', + ` + const { getIdeProcessId } = require('../packages/core/src/ide/process-utils.js'); + getIdeProcessId().then(pid => console.log(pid)); + `, + ], + { + stdio: ['pipe', 'pipe', 'pipe'], + }, + ); + + let out = ''; + child.stdout?.on('data', (data) => { + out += data.toString(); + }); + + child.on('close', (code) => { + if (code === 0) { + resolve(out.trim()); + } else { + reject(new Error(`Child process exited with code ${code}`)); + } + }); + }); + + expect(parseInt(output, 10)).toBe(parentPid); + }, 10000); +}); |
