File size: 4,322 Bytes
84aa3bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { performInitialAuth } from './auth.js';
import {
  type Config,
  ValidationRequiredError,
  ProjectIdRequiredError,
  AuthType,
} from '@google/gemini-cli-core';

vi.mock('@google/gemini-cli-core', async (importOriginal) => {
  const actual =
    await importOriginal<typeof import('@google/gemini-cli-core')>();
  return {
    ...actual,
  };
});

describe('auth', () => {
  let mockConfig: Config;

  beforeEach(() => {
    mockConfig = {
      refreshAuth: vi.fn(),
    } as unknown as Config;
  });

  it('should return null if authType is undefined', async () => {
    const result = await performInitialAuth(mockConfig, undefined);
    expect(result).toEqual({ authError: null, accountSuspensionInfo: null });
    expect(mockConfig.refreshAuth).not.toHaveBeenCalled();
  });

  it('should return null on successful auth', async () => {
    const result = await performInitialAuth(
      mockConfig,
      AuthType.LOGIN_WITH_GOOGLE,
    );
    expect(result).toEqual({ authError: null, accountSuspensionInfo: null });
    expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
      AuthType.LOGIN_WITH_GOOGLE,
    );
  });

  it('should return error message on failed auth', async () => {
    const error = new Error('Authentication failed');
    vi.mocked(mockConfig.refreshAuth).mockRejectedValue(error);
    const result = await performInitialAuth(
      mockConfig,
      AuthType.LOGIN_WITH_GOOGLE,
    );
    expect(result).toEqual({
      authError: 'Failed to sign in. Message: Authentication failed',
      accountSuspensionInfo: null,
    });
    expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
      AuthType.LOGIN_WITH_GOOGLE,
    );
  });

  it('should return null if refreshAuth throws ValidationRequiredError', async () => {
    vi.mocked(mockConfig.refreshAuth).mockRejectedValue(
      new ValidationRequiredError('Validation required'),
    );
    const result = await performInitialAuth(
      mockConfig,
      AuthType.LOGIN_WITH_GOOGLE,
    );
    expect(result).toEqual({ authError: null, accountSuspensionInfo: null });
    expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
      AuthType.LOGIN_WITH_GOOGLE,
    );
  });

  it('should return accountSuspensionInfo for 403 TOS_VIOLATION error', async () => {
    vi.mocked(mockConfig.refreshAuth).mockRejectedValue({
      response: {
        data: {
          error: {
            code: 403,
            message:
              'This service has been disabled for violation of Terms of Service.',
            details: [
              {
                '@type': 'type.googleapis.com/google.rpc.ErrorInfo',
                reason: 'TOS_VIOLATION',
                domain: 'example.googleapis.com',
                metadata: {
                  appeal_url: 'https://example.com/appeal',
                  appeal_url_link_text: 'Appeal Here',
                },
              },
            ],
          },
        },
      },
    });
    const result = await performInitialAuth(
      mockConfig,
      AuthType.LOGIN_WITH_GOOGLE,
    );
    expect(result).toEqual({
      authError: null,
      accountSuspensionInfo: {
        message:
          'This service has been disabled for violation of Terms of Service.',
        appealUrl: 'https://example.com/appeal',
        appealLinkText: 'Appeal Here',
      },
    });
    expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
      AuthType.LOGIN_WITH_GOOGLE,
    );
  });

  it('should return ProjectIdRequiredError message without "Failed to login" prefix', async () => {
    const projectIdError = new ProjectIdRequiredError();
    vi.mocked(mockConfig.refreshAuth).mockRejectedValue(projectIdError);
    const result = await performInitialAuth(
      mockConfig,
      AuthType.LOGIN_WITH_GOOGLE,
    );
    expect(result).toEqual({
      authError:
        'This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID env var. See https://goo.gle/gemini-cli-auth-docs#workspace-gca',
      accountSuspensionInfo: null,
    });
    expect(result.authError).not.toContain('Failed to login');
    expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
      AuthType.LOGIN_WITH_GOOGLE,
    );
  });
});