Files
gemini-cli/packages/cli/src/utils/sandboxUtils.test.ts
Tommaso Sciortino 00705b14bd Fix tests (#14458)
2025-12-03 19:07:23 +00:00

153 lines
4.8 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
import os from 'node:os';
import fs from 'node:fs';
import { readFile } from 'node:fs/promises';
import {
getContainerPath,
parseImageName,
ports,
entrypoint,
shouldUseCurrentUserInSandbox,
} from './sandboxUtils.js';
vi.mock('node:os');
vi.mock('node:fs');
vi.mock('node:fs/promises');
vi.mock('@google/gemini-cli-core', () => ({
debugLogger: {
log: vi.fn(),
warn: vi.fn(),
},
GEMINI_DIR: '.gemini',
}));
describe('sandboxUtils', () => {
const originalEnv = process.env;
beforeEach(() => {
vi.clearAllMocks();
process.env = { ...originalEnv };
// Clean up these env vars that might affect tests
delete process.env['NODE_ENV'];
delete process.env['DEBUG'];
});
afterEach(() => {
process.env = originalEnv;
});
describe('getContainerPath', () => {
it('should return same path on non-Windows', () => {
vi.mocked(os.platform).mockReturnValue('linux');
expect(getContainerPath('/home/user')).toBe('/home/user');
});
it('should convert Windows path to container path', () => {
vi.mocked(os.platform).mockReturnValue('win32');
expect(getContainerPath('C:\\Users\\user')).toBe('/c/Users/user');
});
it('should handle Windows path without drive letter', () => {
vi.mocked(os.platform).mockReturnValue('win32');
expect(getContainerPath('\\Users\\user')).toBe('/Users/user');
});
});
describe('parseImageName', () => {
it('should parse image name with tag', () => {
expect(parseImageName('my-image:latest')).toBe('my-image-latest');
});
it('should parse image name without tag', () => {
expect(parseImageName('my-image')).toBe('my-image');
});
it('should handle registry path', () => {
expect(parseImageName('gcr.io/my-project/my-image:v1')).toBe(
'my-image-v1',
);
});
});
describe('ports', () => {
it('should return empty array if SANDBOX_PORTS is not set', () => {
delete process.env['SANDBOX_PORTS'];
expect(ports()).toEqual([]);
});
it('should parse comma-separated ports', () => {
process.env['SANDBOX_PORTS'] = '8080, 3000 , 9000';
expect(ports()).toEqual(['8080', '3000', '9000']);
});
});
describe('entrypoint', () => {
beforeEach(() => {
vi.mocked(os.platform).mockReturnValue('linux');
vi.mocked(fs.existsSync).mockReturnValue(false);
});
it('should generate default entrypoint', () => {
const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
expect(args).toEqual(['bash', '-c', 'gemini arg1']);
});
it('should include PATH and PYTHONPATH if set', () => {
process.env['PATH'] = '/work/bin:/usr/bin';
process.env['PYTHONPATH'] = '/work/lib';
const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
expect(args[2]).toContain('export PATH="$PATH:/work/bin"');
expect(args[2]).toContain('export PYTHONPATH="$PYTHONPATH:/work/lib"');
});
it('should source sandbox.bashrc if exists', () => {
vi.mocked(fs.existsSync).mockReturnValue(true);
const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
expect(args[2]).toContain('source .gemini/sandbox.bashrc');
});
it('should include socat commands for ports', () => {
process.env['SANDBOX_PORTS'] = '8080';
const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
expect(args[2]).toContain('socat TCP4-LISTEN:8080');
});
it('should use development command if NODE_ENV is development', () => {
process.env['NODE_ENV'] = 'development';
const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
expect(args[2]).toContain('npm rebuild && npm run start --');
});
});
describe('shouldUseCurrentUserInSandbox', () => {
it('should return true if SANDBOX_SET_UID_GID is 1', async () => {
process.env['SANDBOX_SET_UID_GID'] = '1';
expect(await shouldUseCurrentUserInSandbox()).toBe(true);
});
it('should return false if SANDBOX_SET_UID_GID is 0', async () => {
process.env['SANDBOX_SET_UID_GID'] = '0';
expect(await shouldUseCurrentUserInSandbox()).toBe(false);
});
it('should return true on Debian Linux', async () => {
delete process.env['SANDBOX_SET_UID_GID'];
vi.mocked(os.platform).mockReturnValue('linux');
vi.mocked(readFile).mockResolvedValue('ID=debian\n');
expect(await shouldUseCurrentUserInSandbox()).toBe(true);
});
it('should return false on non-Linux', async () => {
delete process.env['SANDBOX_SET_UID_GID'];
vi.mocked(os.platform).mockReturnValue('darwin');
expect(await shouldUseCurrentUserInSandbox()).toBe(false);
});
});
});