1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ from unittest .mock import ANY , AsyncMock , MagicMock , patch
16+
1517import pytest
16- from unittest . mock import MagicMock , patch , ANY , AsyncMock
18+
1719from toolbox_adk .client import ToolboxClient
1820from toolbox_adk .credentials import CredentialStrategy
1921
22+
2023class TestToolboxClient :
21-
24+
2225 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
2326 def test_init_no_auth (self , mock_core_client ):
2427 creds = CredentialStrategy .TOOLBOX_IDENTITY ()
2528 client = ToolboxClient ("http://server" , credentials = creds )
26-
29+
2730 mock_core_client .assert_called_with (
28- server_url = "http://server" ,
29- client_headers = {}
31+ server_url = "http://server" , client_headers = {}
3032 )
3133
3234 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
3335 def test_init_manual_token (self , mock_core_client ):
3436 creds = CredentialStrategy .MANUAL_TOKEN ("abc" )
3537 client = ToolboxClient ("http://server" , credentials = creds )
36-
38+
3739 mock_core_client .assert_called_with (
38- server_url = "http://server" ,
39- client_headers = {"Authorization" : "Bearer abc" }
40+ server_url = "http://server" , client_headers = {"Authorization" : "Bearer abc" }
4041 )
4142
4243 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
4344 def test_init_additional_headers (self , mock_core_client ):
4445 creds = CredentialStrategy .TOOLBOX_IDENTITY ()
4546 headers = {"X-Custom" : "Val" }
4647 client = ToolboxClient (
47- "http://server" ,
48- credentials = creds ,
49- additional_headers = headers
48+ "http://server" , credentials = creds , additional_headers = headers
5049 )
51-
50+
5251 mock_core_client .assert_called_with (
53- server_url = "http://server" ,
54- client_headers = {"X-Custom" : "Val" }
52+ server_url = "http://server" , client_headers = {"X-Custom" : "Val" }
5553 )
5654
5755 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
5856 @patch ("toolbox_adk.client.id_token.fetch_id_token" )
5957 def test_adc_auth_flow_success (self , mock_fetch_token , mock_core_client ):
6058 mock_fetch_token .return_value = "id_token_123"
61-
59+
6260 creds = CredentialStrategy .APPLICATION_DEFAULT_CREDENTIALS ("http://aud" )
6361 client = ToolboxClient ("http://server" , credentials = creds )
64-
62+
6563 # Verify a callable was passed
6664 args , kwargs = mock_core_client .call_args
6765 assert "Authorization" in kwargs ["client_headers" ]
6866 token_getter = kwargs ["client_headers" ]["Authorization" ]
6967 assert callable (token_getter )
70-
68+
7169 # Verify callable behavior
7270 token = token_getter ()
7371 assert token == "Bearer id_token_123"
@@ -76,36 +74,38 @@ def test_adc_auth_flow_success(self, mock_fetch_token, mock_core_client):
7674 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
7775 @patch ("toolbox_adk.client.id_token.fetch_id_token" )
7876 @patch ("toolbox_adk.client.google.auth.default" )
79- def test_adc_auth_flow_fallback (self , mock_default , mock_fetch_token , mock_core_client ):
77+ def test_adc_auth_flow_fallback (
78+ self , mock_default , mock_fetch_token , mock_core_client
79+ ):
8080 # unexpected error on fetch_id_token
8181 mock_fetch_token .side_effect = Exception ("No metadata" )
82-
82+
8383 mock_creds = MagicMock ()
8484 mock_creds .valid = False
8585 mock_creds .id_token = "fallback_id_token"
8686 mock_default .return_value = (mock_creds , "proj" )
87-
87+
8888 creds = CredentialStrategy .APPLICATION_DEFAULT_CREDENTIALS ("http://aud" )
8989 client = ToolboxClient ("http://server" , credentials = creds )
90-
90+
9191 token_getter = mock_core_client .call_args [1 ]["client_headers" ]["Authorization" ]
9292 token = token_getter ()
93-
93+
9494 assert token == "Bearer fallback_id_token"
9595 mock_creds .refresh .assert_called ()
96-
96+
9797 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
9898 def test_manual_creds (self , mock_core_client ):
9999 mock_g_creds = MagicMock ()
100100 mock_g_creds .valid = False
101101 mock_g_creds .token = "oauth_token"
102-
102+
103103 creds = CredentialStrategy .MANUAL_CREDS (mock_g_creds )
104104 client = ToolboxClient ("http://server" , credentials = creds )
105-
105+
106106 token_getter = mock_core_client .call_args [1 ]["client_headers" ]["Authorization" ]
107107 token = token_getter ()
108-
108+
109109 assert token == "Bearer oauth_token"
110110 assert token == "Bearer oauth_token"
111111 mock_g_creds .refresh .assert_called ()
@@ -115,36 +115,41 @@ def test_init_validation_errors(self, mock_core_client):
115115 # ADC missing audience
116116 with pytest .raises (ValueError , match = "target_audience is required" ):
117117 # Fix: only pass target_audience as keyword arg OR positional, not both mixed in a way that causes overlap if defined so
118- # Actually simpler: just pass raw None
119- ToolboxClient ("url" , credentials = CredentialStrategy .APPLICATION_DEFAULT_CREDENTIALS (None ))
120-
118+ # Actually simpler: just pass raw None
119+ ToolboxClient (
120+ "url" ,
121+ credentials = CredentialStrategy .APPLICATION_DEFAULT_CREDENTIALS (None ),
122+ )
123+
121124 # Manual token missing token
122125 with pytest .raises (ValueError , match = "token is required" ):
123126 ToolboxClient ("url" , credentials = CredentialStrategy .MANUAL_TOKEN (None ))
124-
127+
125128 # Manual creds missing credentials
126129 with pytest .raises (ValueError , match = "credentials object is required" ):
127130 ToolboxClient ("url" , credentials = CredentialStrategy .MANUAL_CREDS (None ))
128131
129132 @patch ("toolbox_adk.client.toolbox_core.ToolboxClient" )
130133 @patch ("toolbox_adk.client.id_token.fetch_id_token" )
131134 @patch ("toolbox_adk.client.google.auth.default" )
132- def test_adc_auth_flow_fallback_access_token (self , mock_default , mock_fetch_token , mock_core_client ):
135+ def test_adc_auth_flow_fallback_access_token (
136+ self , mock_default , mock_fetch_token , mock_core_client
137+ ):
133138 # fetch_id_token fails
134139 mock_fetch_token .side_effect = Exception ("No metadata" )
135-
140+
136141 mock_creds = MagicMock ()
137142 mock_creds .valid = False
138- mock_creds .id_token = None # No ID token
143+ mock_creds .id_token = None # No ID token
139144 mock_creds .token = "access_token_123"
140145 mock_default .return_value = (mock_creds , "proj" )
141-
146+
142147 creds = CredentialStrategy .APPLICATION_DEFAULT_CREDENTIALS ("http://aud" )
143148 client = ToolboxClient ("http://server" , credentials = creds )
144-
149+
145150 token_getter = mock_core_client .call_args [1 ]["client_headers" ]["Authorization" ]
146151 token = token_getter ()
147-
152+
148153 assert token == "Bearer access_token_123"
149154 mock_creds .refresh .assert_called ()
150155
@@ -154,12 +159,12 @@ async def test_delegation(self, mock_core_client):
154159 mock_instance = mock_core_client .return_value
155160 mock_instance .load_toolset = AsyncMock (return_value = ["t1" ])
156161 mock_instance .close = AsyncMock ()
157-
162+
158163 client = ToolboxClient ("http://server" )
159164 tools = await client .load_toolset ("my-set" , extra = "arg" )
160-
165+
161166 mock_instance .load_toolset .assert_awaited_with ("my-set" , extra = "arg" )
162167 assert tools == ["t1" ]
163-
168+
164169 await client .close ()
165170 mock_instance .close .assert_awaited ()
0 commit comments