mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-17 16:51:15 -07:00
test: fix Windows CI execution and resolve exposed platform failures (#24476)
This commit is contained in:
@@ -6,10 +6,20 @@
|
||||
|
||||
import { describe, it, expect, afterEach, vi } from 'vitest';
|
||||
import { ApiKeyAuthProvider } from './api-key-provider.js';
|
||||
import * as resolver from './value-resolver.js';
|
||||
|
||||
vi.mock('./value-resolver.js', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('./value-resolver.js')>();
|
||||
return {
|
||||
...actual,
|
||||
resolveAuthValue: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ApiKeyAuthProvider', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
@@ -26,6 +36,7 @@ describe('ApiKeyAuthProvider', () => {
|
||||
|
||||
it('should resolve API key from environment variable', async () => {
|
||||
vi.stubEnv('TEST_API_KEY', 'env-api-key');
|
||||
vi.mocked(resolver.resolveAuthValue).mockResolvedValue('env-api-key');
|
||||
|
||||
const provider = new ApiKeyAuthProvider({
|
||||
type: 'apiKey',
|
||||
@@ -38,6 +49,10 @@ describe('ApiKeyAuthProvider', () => {
|
||||
});
|
||||
|
||||
it('should throw if environment variable is not set', async () => {
|
||||
vi.mocked(resolver.resolveAuthValue).mockRejectedValue(
|
||||
new Error("Environment variable 'MISSING_KEY_12345' is not set"),
|
||||
);
|
||||
|
||||
const provider = new ApiKeyAuthProvider({
|
||||
type: 'apiKey',
|
||||
key: '$MISSING_KEY_12345',
|
||||
@@ -114,6 +129,8 @@ describe('ApiKeyAuthProvider', () => {
|
||||
|
||||
it('should return undefined for env-var keys on 403', async () => {
|
||||
vi.stubEnv('RETRY_TEST_KEY', 'some-key');
|
||||
vi.mocked(resolver.resolveAuthValue).mockResolvedValue('some-key');
|
||||
|
||||
const provider = new ApiKeyAuthProvider({
|
||||
type: 'apiKey',
|
||||
key: '$RETRY_TEST_KEY',
|
||||
@@ -128,9 +145,13 @@ describe('ApiKeyAuthProvider', () => {
|
||||
});
|
||||
|
||||
it('should re-resolve and return headers for command keys on 401', async () => {
|
||||
vi.mocked(resolver.resolveAuthValue)
|
||||
.mockResolvedValueOnce('initial-key')
|
||||
.mockResolvedValueOnce('refreshed-key');
|
||||
|
||||
const provider = new ApiKeyAuthProvider({
|
||||
type: 'apiKey',
|
||||
key: '!echo refreshed-key',
|
||||
key: '!some command',
|
||||
});
|
||||
await provider.initialize();
|
||||
|
||||
@@ -142,9 +163,11 @@ describe('ApiKeyAuthProvider', () => {
|
||||
});
|
||||
|
||||
it('should stop retrying after MAX_AUTH_RETRIES', async () => {
|
||||
vi.mocked(resolver.resolveAuthValue).mockResolvedValue('rotating-key');
|
||||
|
||||
const provider = new ApiKeyAuthProvider({
|
||||
type: 'apiKey',
|
||||
key: '!echo rotating-key',
|
||||
key: '!some command',
|
||||
});
|
||||
await provider.initialize();
|
||||
|
||||
|
||||
@@ -10,6 +10,16 @@ import {
|
||||
needsResolution,
|
||||
maskSensitiveValue,
|
||||
} from './value-resolver.js';
|
||||
import * as shellUtils from '../../utils/shell-utils.js';
|
||||
|
||||
vi.mock('../../utils/shell-utils.js', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('../../utils/shell-utils.js')>();
|
||||
return {
|
||||
...actual,
|
||||
spawnAsync: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('value-resolver', () => {
|
||||
describe('resolveAuthValue', () => {
|
||||
@@ -39,12 +49,24 @@ describe('value-resolver', () => {
|
||||
});
|
||||
|
||||
describe('shell commands', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should execute shell command with ! prefix', async () => {
|
||||
vi.mocked(shellUtils.spawnAsync).mockResolvedValue({
|
||||
stdout: 'hello\n',
|
||||
stderr: '',
|
||||
});
|
||||
const result = await resolveAuthValue('!echo hello');
|
||||
expect(result).toBe('hello');
|
||||
});
|
||||
|
||||
it('should trim whitespace from command output', async () => {
|
||||
vi.mocked(shellUtils.spawnAsync).mockResolvedValue({
|
||||
stdout: ' hello \n',
|
||||
stderr: '',
|
||||
});
|
||||
const result = await resolveAuthValue('!echo " hello "');
|
||||
expect(result).toBe('hello');
|
||||
});
|
||||
@@ -56,16 +78,32 @@ describe('value-resolver', () => {
|
||||
});
|
||||
|
||||
it('should throw error for command that returns empty output', async () => {
|
||||
vi.mocked(shellUtils.spawnAsync).mockResolvedValue({
|
||||
stdout: '',
|
||||
stderr: '',
|
||||
});
|
||||
await expect(resolveAuthValue('!echo -n ""')).rejects.toThrow(
|
||||
'returned empty output',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error for failed command', async () => {
|
||||
vi.mocked(shellUtils.spawnAsync).mockRejectedValue(
|
||||
new Error('Command failed'),
|
||||
);
|
||||
await expect(
|
||||
resolveAuthValue('!nonexistent-command-12345'),
|
||||
).rejects.toThrow(/Command.*failed/);
|
||||
});
|
||||
|
||||
it('should throw error for timeout', async () => {
|
||||
const timeoutError = new Error('AbortError');
|
||||
timeoutError.name = 'AbortError';
|
||||
vi.mocked(shellUtils.spawnAsync).mockRejectedValue(timeoutError);
|
||||
await expect(resolveAuthValue('!sleep 100')).rejects.toThrow(
|
||||
/timed out after/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('literal values', () => {
|
||||
|
||||
@@ -159,7 +159,9 @@ describe('BrowserManager', () => {
|
||||
expect.objectContaining({
|
||||
command: 'node',
|
||||
args: expect.arrayContaining([
|
||||
expect.stringMatching(/bundled\/chrome-devtools-mcp\.mjs$/),
|
||||
expect.stringMatching(
|
||||
/(dist[\\/])?bundled[\\/]chrome-devtools-mcp\.mjs$/,
|
||||
),
|
||||
]),
|
||||
}),
|
||||
);
|
||||
@@ -175,7 +177,7 @@ describe('BrowserManager', () => {
|
||||
command: 'node',
|
||||
args: expect.arrayContaining([
|
||||
expect.stringMatching(
|
||||
/(dist\/)?bundled\/chrome-devtools-mcp\.mjs$/,
|
||||
/(dist[\\/])?bundled[\\/]chrome-devtools-mcp\.mjs$/,
|
||||
),
|
||||
]),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user