mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-14 16:10:59 -07:00
Change flag name to flag id for existing flags (#13073)
# Conflicts: # packages/core/src/code_assist/experiments/experiments.test.ts
This commit is contained in:
committed by
gemini-cli-robot
parent
2c6d3eb512
commit
9f6d8173a9
115
packages/core/src/code_assist/experiments/experiments.test.ts
Normal file
115
packages/core/src/code_assist/experiments/experiments.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import type { CodeAssistServer } from '../server.js';
|
||||
import { getClientMetadata } from './client_metadata.js';
|
||||
import type { ListExperimentsResponse, Flag } from './types.js';
|
||||
|
||||
// Mock dependencies before importing the module under test
|
||||
vi.mock('../server.js');
|
||||
vi.mock('./client_metadata.js');
|
||||
|
||||
describe('experiments', () => {
|
||||
let mockServer: CodeAssistServer;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset modules to clear the cached `experimentsPromise`
|
||||
vi.resetModules();
|
||||
|
||||
// Mock the dependencies that `getExperiments` relies on
|
||||
vi.mocked(getClientMetadata).mockResolvedValue({
|
||||
ideName: 'GEMINI_CLI',
|
||||
ideVersion: '1.0.0',
|
||||
platform: 'LINUX_AMD64',
|
||||
updateChannel: 'stable',
|
||||
});
|
||||
|
||||
// Create a mock instance of the server for each test
|
||||
mockServer = {
|
||||
listExperiments: vi.fn(),
|
||||
} as unknown as CodeAssistServer;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fetch and parse experiments from the server', async () => {
|
||||
const { getExperiments } = await import('./experiments.js');
|
||||
const mockApiResponse: ListExperimentsResponse = {
|
||||
flags: [
|
||||
{ flagId: 234, boolValue: true },
|
||||
{ flagId: 345, stringValue: 'value' },
|
||||
],
|
||||
experimentIds: [123, 456],
|
||||
};
|
||||
vi.mocked(mockServer.listExperiments).mockResolvedValue(mockApiResponse);
|
||||
|
||||
const experiments = await getExperiments(mockServer);
|
||||
|
||||
// Verify that the dependencies were called
|
||||
expect(getClientMetadata).toHaveBeenCalled();
|
||||
expect(mockServer.listExperiments).toHaveBeenCalledWith(
|
||||
await getClientMetadata(),
|
||||
);
|
||||
|
||||
// Verify that the response was parsed correctly
|
||||
expect(experiments.flags[234]).toEqual({
|
||||
flagId: 234,
|
||||
boolValue: true,
|
||||
});
|
||||
expect(experiments.flags[345]).toEqual({
|
||||
flagId: 345,
|
||||
stringValue: 'value',
|
||||
});
|
||||
expect(experiments.experimentIds).toEqual([123, 456]);
|
||||
});
|
||||
|
||||
it('should handle an empty or partial response from the server', async () => {
|
||||
const { getExperiments } = await import('./experiments.js');
|
||||
const mockApiResponse: ListExperimentsResponse = {}; // No flags or experimentIds
|
||||
vi.mocked(mockServer.listExperiments).mockResolvedValue(mockApiResponse);
|
||||
|
||||
const experiments = await getExperiments(mockServer);
|
||||
|
||||
expect(experiments.flags).toEqual({});
|
||||
expect(experiments.experimentIds).toEqual([]);
|
||||
});
|
||||
|
||||
it('should ignore flags that are missing a name', async () => {
|
||||
const { getExperiments } = await import('./experiments.js');
|
||||
const mockApiResponse: ListExperimentsResponse = {
|
||||
flags: [
|
||||
{ boolValue: true } as Flag, // No name
|
||||
{ flagId: 256, stringValue: 'value' },
|
||||
],
|
||||
};
|
||||
vi.mocked(mockServer.listExperiments).mockResolvedValue(mockApiResponse);
|
||||
|
||||
const experiments = await getExperiments(mockServer);
|
||||
|
||||
expect(Object.keys(experiments.flags)).toHaveLength(1);
|
||||
expect(experiments.flags[256]).toBeDefined();
|
||||
expect(experiments.flags['undefined']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should cache the experiments promise to avoid multiple fetches', async () => {
|
||||
const { getExperiments } = await import('./experiments.js');
|
||||
const mockApiResponse: ListExperimentsResponse = {
|
||||
experimentIds: [1, 2, 3],
|
||||
};
|
||||
vi.mocked(mockServer.listExperiments).mockResolvedValue(mockApiResponse);
|
||||
|
||||
const firstCall = await getExperiments(mockServer);
|
||||
const secondCall = await getExperiments(mockServer);
|
||||
|
||||
expect(firstCall).toBe(secondCall); // Should be the exact same promise object
|
||||
// Verify the underlying functions were only called once
|
||||
expect(getClientMetadata).toHaveBeenCalledTimes(1);
|
||||
expect(mockServer.listExperiments).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -38,8 +38,8 @@ export async function getExperiments(
|
||||
function parseExperiments(response: ListExperimentsResponse): Experiments {
|
||||
const flags: Record<string, Flag> = {};
|
||||
for (const flag of response.flags ?? []) {
|
||||
if (flag.name) {
|
||||
flags[flag.name] = flag;
|
||||
if (flag.flagId) {
|
||||
flags[flag.flagId] = flag;
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
*/
|
||||
|
||||
export const ExperimentFlags = {
|
||||
CONTEXT_COMPRESSION_THRESHOLD:
|
||||
'GeminiCLIContextCompression__threshold_fraction',
|
||||
USER_CACHING: 'GcliUserCaching__user_caching',
|
||||
CONTEXT_COMPRESSION_THRESHOLD: 45740197,
|
||||
USER_CACHING: 45740198,
|
||||
} as const;
|
||||
|
||||
export type ExperimentFlagName =
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface ListExperimentsResponse {
|
||||
}
|
||||
|
||||
export interface Flag {
|
||||
name?: string;
|
||||
flagId?: number;
|
||||
boolValue?: boolean;
|
||||
floatValue?: number;
|
||||
intValue?: string; // int64
|
||||
|
||||
@@ -1455,8 +1455,8 @@ export class Config {
|
||||
this.experiments = experiments;
|
||||
const flagSummaries = Object.entries(experiments.flags ?? {})
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.map(([name, flag]) => {
|
||||
const summary: Record<string, unknown> = { name };
|
||||
.map(([flagId, flag]) => {
|
||||
const summary: Record<string, unknown> = { flagId };
|
||||
if (flag.boolValue !== undefined) {
|
||||
summary['boolValue'] = flag.boolValue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user