1+ import pytest
2+
3+ from unittest .mock import Mock
4+ from databricks .sdk .credentials_provider import external_browser
5+
6+ def test_external_browser_refresh_success (mocker ):
7+ """Tests successful refresh of existing credentials."""
8+
9+ # 1. Mock Config
10+ mock_cfg = Mock ()
11+ mock_cfg .auth_type = 'external-browser'
12+ mock_cfg .host = 'test-host'
13+ mock_cfg .oidc_endpoints = {'token_endpoint' : 'test-token-endpoint' }
14+ mock_cfg .client_id = 'test-client-id' # Or use azure_client_id
15+ mock_cfg .client_secret = 'test-client-secret' # Or use azure_client_secret
16+
17+ # 2. Mock TokenCache
18+ mock_token_cache = Mock ()
19+ mock_session_credentials = Mock ()
20+ mock_session_credentials .token .return_value = "valid_token" # Simulate successful refresh
21+ mock_token_cache .load .return_value = mock_session_credentials
22+
23+ mock_credentials_provider = Mock ()
24+ mock_session_credentials .return_value = mock_credentials_provider
25+
26+ # 3. Patch TokenCache (no need to mock OAuthClient in this case)
27+ mocker .patch ('databricks.sdk.credentials_provider.TokenCache' , return_value = mock_token_cache )
28+
29+ # 4. Call the function
30+ result = external_browser (mock_cfg )
31+
32+ # 5. Assertions
33+ mock_token_cache .load .assert_called_once ()
34+ mock_session_credentials .token .assert_called_once () # Verify token refresh was attempted
35+ assert result == mock_credentials_provider
36+
37+
38+ def test_external_browser_refresh_failure_new_oauth_flow (mocker ):
39+ """Tests failed refresh, triggering a new OAuth flow."""
40+
41+ # 1. Mock Config
42+ mock_cfg = Mock ()
43+ mock_cfg .auth_type = 'external-browser'
44+ mock_cfg .host = 'test-host'
45+ mock_cfg .oidc_endpoints = {'token_endpoint' : 'test-token-endpoint' }
46+ mock_cfg .client_id = 'test-client-id'
47+ mock_cfg .client_secret = 'test-client-secret'
48+
49+ # 2. Mock TokenCache
50+ mock_token_cache = Mock ()
51+ mock_session_credentials = Mock ()
52+ mock_session_credentials .token .side_effect = Exception ("Simulated refresh error" ) # Simulate a failed refresh
53+ mock_token_cache .load .return_value = mock_session_credentials
54+
55+ mock_credentials_provider = Mock ()
56+ mock_session_credentials .return_value = mock_credentials_provider
57+
58+ # 3. Mock OAuthClient
59+ mock_oauth_client = Mock ()
60+ mock_consent = Mock ()
61+ mock_consent .launch_external_browser .return_value = mock_session_credentials # Simulate successful OAuth flow
62+ mock_oauth_client .initiate_consent .return_value = mock_consent
63+
64+ # 4. Patch TokenCache and OAuthClient
65+ mocker .patch ('databricks.sdk.credentials_provider.TokenCache' , return_value = mock_token_cache )
66+ mocker .patch ('databricks.sdk.credentials_provider.OAuthClient' , return_value = mock_oauth_client )
67+
68+ # 5. Call the function
69+ result = external_browser (mock_cfg )
70+
71+ # 6. Assertions
72+ mock_token_cache .load .assert_called_once ()
73+ mock_session_credentials .token .assert_called_once () # Refresh attempt
74+ mock_oauth_client .initiate_consent .assert_called_once ()
75+ mock_consent .launch_external_browser .assert_called_once ()
76+ mock_token_cache .save .assert_called_once_with (mock_session_credentials )
77+ assert result == mock_credentials_provider
78+
79+
80+ def test_external_browser_no_cached_credentials (mocker ):
81+ """Tests the case where there are no cached credentials, initiating a new OAuth flow."""
82+
83+ # 1. Mock Config
84+ mock_cfg = Mock ()
85+ mock_cfg .auth_type = 'external-browser'
86+ mock_cfg .host = 'test-host'
87+ mock_cfg .oidc_endpoints = {'token_endpoint' : 'test-token-endpoint' }
88+ mock_cfg .client_id = 'test-client-id'
89+ mock_cfg .client_secret = 'test-client-secret'
90+
91+ # 2. Mock TokenCache
92+ mock_token_cache = Mock ()
93+ mock_token_cache .load .return_value = None # No cached credentials
94+
95+ mock_session_credentials = lambda c : "new_credentials"
96+
97+ # 3. Mock OAuthClient
98+ mock_consent = Mock ()
99+ mock_consent .launch_external_browser .return_value = mock_session_credentials
100+ mock_oauth_client = Mock ()
101+ mock_oauth_client .initiate_consent .return_value = mock_consent
102+
103+ # 4. Patch TokenCache and OAuthClient
104+ mocker .patch ('databricks.sdk.credentials_provider.TokenCache' , return_value = mock_token_cache )
105+ mocker .patch ('databricks.sdk.credentials_provider.OAuthClient' , return_value = mock_oauth_client )
106+
107+ # 5. Call the function
108+ result = external_browser (mock_cfg )
109+
110+ # 6. Assertions
111+ mock_token_cache .load .assert_called_once ()
112+ mock_oauth_client .initiate_consent .assert_called_once ()
113+ mock_consent .launch_external_browser .assert_called_once ()
114+ mock_token_cache .save .assert_called_once_with (mock_session_credentials )
115+ assert result == "new_credentials"
116+
117+
118+ def test_external_browser_consent_fails (mocker ):
119+ """Tests the case where OAuth consent initiation fails."""
120+
121+ # 1. Mock Config
122+ mock_cfg = Mock ()
123+ mock_cfg .auth_type = 'external-browser'
124+ mock_cfg .host = 'test-host'
125+ mock_cfg .oidc_endpoints = {'token_endpoint' : 'test-token-endpoint' }
126+ mock_cfg .client_id = 'test-client-id'
127+ mock_cfg .client_secret = 'test-client-secret'
128+
129+ # 2. Mock TokenCache
130+ mock_token_cache = Mock ()
131+ mock_token_cache .load .return_value = None # No cached credentials
132+
133+ # 3. Mock OAuthClient
134+ mock_oauth_client = Mock ()
135+ mock_oauth_client .initiate_consent .return_value = None # Simulate consent failure
136+
137+ # 4. Patch TokenCache and OAuthClient
138+ mocker .patch ('databricks.sdk.credentials_provider.TokenCache' , return_value = mock_token_cache )
139+ mocker .patch ('databricks.sdk.credentials_provider.OAuthClient' , return_value = mock_oauth_client )
140+
141+ # 5. Call the function
142+ result = external_browser (mock_cfg )
143+
144+ # 6. Assertions
145+ mock_token_cache .load .assert_called_once ()
146+ mock_oauth_client .initiate_consent .assert_called_once ()
147+ assert result is None
0 commit comments