diff --git a/packages/core/src/code_assist/oauth-credential-storage.test.ts b/packages/core/src/code_assist/oauth-credential-storage.test.ts index c555b923e6..f588742495 100644 --- a/packages/core/src/code_assist/oauth-credential-storage.test.ts +++ b/packages/core/src/code_assist/oauth-credential-storage.test.ts @@ -8,6 +8,7 @@ import { type Credentials } from 'google-auth-library'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { OAuthCredentialStorage } from './oauth-credential-storage.js'; import type { OAuthCredentials } from '../mcp/token-storage/types.js'; +import { coreEvents } from '@google/gemini-cli-core'; import * as path from 'node:path'; import * as os from 'node:os'; @@ -30,6 +31,11 @@ vi.mock('node:fs', () => ({ })); vi.mock('node:os'); vi.mock('node:path'); +vi.mock('@google/gemini-cli-core', () => ({ + coreEvents: { + emitFeedback: vi.fn(), + }, +})); describe('OAuthCredentialStorage', () => { const mockCredentials: Credentials = { @@ -119,26 +125,36 @@ describe('OAuthCredentialStorage', () => { }); it('should throw an error if loading fails', async () => { + const mockError = new Error('HybridTokenStorage error'); vi.spyOn(mockHybridTokenStorage, 'getCredentials').mockRejectedValue( - new Error('Loading error'), + mockError, ); await expect(OAuthCredentialStorage.loadCredentials()).rejects.toThrow( 'Failed to load OAuth credentials', ); + expect(coreEvents.emitFeedback).toHaveBeenCalledWith( + 'error', + 'Failed to load OAuth credentials', + mockError, + ); }); it('should throw an error if read file fails', async () => { + const mockError = new Error('Permission denied'); vi.spyOn(mockHybridTokenStorage, 'getCredentials').mockResolvedValue( null, ); - vi.spyOn(fs, 'readFile').mockRejectedValue( - new Error('Permission denied'), - ); + vi.spyOn(fs, 'readFile').mockRejectedValue(mockError); await expect(OAuthCredentialStorage.loadCredentials()).rejects.toThrow( 'Failed to load OAuth credentials', ); + expect(coreEvents.emitFeedback).toHaveBeenCalledWith( + 'error', + 'Failed to load OAuth credentials', + mockError, + ); }); it('should not throw error if migration file removal failed', async () => { @@ -205,13 +221,19 @@ describe('OAuthCredentialStorage', () => { }); it('should throw an error if clearing from HybridTokenStorage fails', async () => { + const mockError = new Error('Deletion error'); vi.spyOn(mockHybridTokenStorage, 'deleteCredentials').mockRejectedValue( - new Error('Deletion error'), + mockError, ); await expect(OAuthCredentialStorage.clearCredentials()).rejects.toThrow( 'Failed to clear OAuth credentials', ); + expect(coreEvents.emitFeedback).toHaveBeenCalledWith( + 'error', + 'Failed to clear OAuth credentials', + mockError, + ); }); }); }); diff --git a/packages/core/src/code_assist/oauth-credential-storage.ts b/packages/core/src/code_assist/oauth-credential-storage.ts index b1ed9b0e82..0165a5647e 100644 --- a/packages/core/src/code_assist/oauth-credential-storage.ts +++ b/packages/core/src/code_assist/oauth-credential-storage.ts @@ -12,6 +12,7 @@ import * as path from 'node:path'; import * as os from 'node:os'; import { promises as fs } from 'node:fs'; import { GEMINI_DIR } from '../utils/paths.js'; +import { coreEvents } from '@google/gemini-cli-core'; const KEYCHAIN_SERVICE_NAME = 'gemini-cli-oauth'; const MAIN_ACCOUNT_KEY = 'main-account'; @@ -49,8 +50,12 @@ export class OAuthCredentialStorage { // Fallback: Try to migrate from old file-based storage return await this.migrateFromFileStorage(); } catch (error: unknown) { - console.error(error); - throw new Error('Failed to load OAuth credentials'); + coreEvents.emitFeedback( + 'error', + 'Failed to load OAuth credentials', + error, + ); + throw new Error('Failed to load OAuth credentials', { cause: error }); } } @@ -89,8 +94,12 @@ export class OAuthCredentialStorage { const oldFilePath = path.join(os.homedir(), GEMINI_DIR, OAUTH_FILE); await fs.rm(oldFilePath, { force: true }).catch(() => {}); } catch (error: unknown) { - console.error(error); - throw new Error('Failed to clear OAuth credentials'); + coreEvents.emitFeedback( + 'error', + 'Failed to clear OAuth credentials', + error, + ); + throw new Error('Failed to clear OAuth credentials', { cause: error }); } }