2424
2525
2626class TestMTLS :
27- @mock .patch ("google.auth.aio.transport.mtls.path.expanduser" )
28- @mock .patch ("google.auth.aio.transport.mtls.path.exists" )
29- def test__check_config_path_exists (self , mock_exists , mock_expand ):
30- mock_expand .side_effect = lambda x : x .replace ("~" , "/home/user" )
31- mock_exists .return_value = True
32-
33- input_path = "~/config.json"
34- expected_path = "/home/user/config.json"
35- result = mtls ._check_config_path (input_path )
36-
37- assert result == expected_path
38- mock_exists .assert_called_with (expected_path )
39-
40- @mock .patch ("google.auth.aio.transport.mtls.path.exists" , return_value = False )
41- def test__check_config_path_not_found (self , mock_exists ):
42- result = mtls ._check_config_path ("nonexistent.json" )
43- assert result is None
44-
45- @mock .patch ("google.auth.aio.transport.mtls._check_config_path" )
46- @mock .patch ("google.auth.aio.transport.mtls.getenv" )
47- def test_has_default_client_cert_source_env_var (self , mock_getenv , mock_check ):
48- custom_path = "/custom/path.json"
49- mock_check .side_effect = lambda x : custom_path if x == custom_path else None
50- mock_getenv .return_value = custom_path
51-
52- assert mtls .has_default_client_cert_source () is True
53-
54- @mock .patch ("google.auth.aio.transport.mtls._check_config_path" )
55- @mock .patch ("google.auth.aio.transport.mtls.getenv" )
56- def test_has_default_client_cert_source_check_priority (
57- self , mock_getenv , mock_check
58- ):
59- mock_check .return_value = "/default/path.json"
60-
61- assert mtls .has_default_client_cert_source () is True
62- mock_getenv .assert_not_called ()
63-
27+ @pytest .mark .asyncio
6428 @mock .patch (
65- "google.auth.aio.transport.mtls.has_default_client_cert_source" ,
66- return_value = False ,
29+ "google.auth.transport.mtls.has_default_client_cert_source" , return_value = False
6730 )
68- def test_default_client_cert_source_none (self , mock_has_default ):
69- with pytest .raises (exceptions .MutualTLSChannelError ):
31+ async def test_default_client_cert_source_not_found (self , mock_has_default ):
32+ """Tests that a MutualTLSChannelError is raised if no cert source exists."""
33+ with pytest .raises (exceptions .MutualTLSChannelError , match = "doesn't exist" ):
7034 mtls .default_client_cert_source ()
7135
7236 @pytest .mark .asyncio
@@ -75,45 +39,35 @@ def test_default_client_cert_source_none(self, mock_has_default):
7539 new_callable = mock .AsyncMock ,
7640 )
7741 @mock .patch (
78- "google.auth.aio.transport.mtls.has_default_client_cert_source" ,
79- return_value = True ,
42+ "google.auth.transport.mtls.has_default_client_cert_source" , return_value = True
8043 )
8144 async def test_default_client_cert_source_success (
8245 self , mock_has_default , mock_get_cert_key
8346 ):
47+ """Tests the async callback returned by default_client_cert_source."""
8448 mock_get_cert_key .return_value = (True , CERT_DATA , KEY_DATA )
8549
86- # Note: default_client_cert_source is NOT async, but it returns an async callback
50+ # default_client_cert_source is a factory that returns an async callback
8751 callback = mtls .default_client_cert_source ()
8852 assert callable (callback )
8953
9054 cert , key = await callback ()
9155 assert cert == CERT_DATA
9256 assert key == KEY_DATA
9357
94- @pytest .mark .asyncio
95- @mock .patch (
96- "google.auth.aio.transport.mtls.has_default_client_cert_source" ,
97- return_value = False ,
98- )
99- async def test_default_client_cert_source_not_found (self , mock_has_default ):
100- with pytest .raises (exceptions .MutualTLSChannelError , match = "doesn't exist" ):
101- await mtls .default_client_cert_source ()
102-
10358 @pytest .mark .asyncio
10459 @mock .patch (
10560 "google.auth.aio.transport.mtls.get_client_cert_and_key" ,
10661 new_callable = mock .AsyncMock ,
10762 )
10863 @mock .patch (
109- "google.auth.aio.transport.mtls.has_default_client_cert_source" ,
110- return_value = True ,
64+ "google.auth.transport.mtls.has_default_client_cert_source" , return_value = True
11165 )
11266 async def test_default_client_cert_source_callback_wraps_exception (
11367 self , mock_has , mock_get
11468 ):
69+ """Tests that the callback wraps underlying errors into MutualTLSChannelError."""
11570 mock_get .side_effect = ValueError ("Format error" )
116-
11771 callback = mtls .default_client_cert_source ()
11872
11973 with pytest .raises (exceptions .MutualTLSChannelError ) as excinfo :
@@ -123,6 +77,7 @@ async def test_default_client_cert_source_callback_wraps_exception(
12377 @pytest .mark .asyncio
12478 @mock .patch ("google.auth.transport._mtls_helper._get_workload_cert_and_key" )
12579 async def test_get_client_ssl_credentials_success (self , mock_workload ):
80+ """Tests successful retrieval of workload credentials via the executor."""
12681 mock_workload .return_value = (CERT_DATA , KEY_DATA )
12782
12883 success , cert , key , passphrase = await mtls .get_client_ssl_credentials ()
@@ -135,6 +90,7 @@ async def test_get_client_ssl_credentials_success(self, mock_workload):
13590 @pytest .mark .asyncio
13691 @mock .patch ("google.auth.aio.transport.mtls.get_client_ssl_credentials" )
13792 async def test_get_client_cert_and_key_no_credentials_found (self , mock_get_ssl ):
93+ """Tests behavior when no credentials are found at the default location."""
13894 mock_get_ssl .return_value = (False , None , None , None )
13995
14096 success , cert , key = await mtls .get_client_cert_and_key (None )
@@ -145,7 +101,7 @@ async def test_get_client_cert_and_key_no_credentials_found(self, mock_get_ssl):
145101
146102 @pytest .mark .asyncio
147103 async def test_get_client_cert_and_key_callback_async (self ):
148- # Test with an actual coroutine/AsyncMock to satisfy the 'await' in your code
104+ """Tests that an async callback is correctly awaited."""
149105 callback = mock .AsyncMock (return_value = (CERT_DATA , KEY_DATA ))
150106
151107 success , cert , key = await mtls .get_client_cert_and_key (callback )
@@ -157,51 +113,24 @@ async def test_get_client_cert_and_key_callback_async(self):
157113
158114 @pytest .mark .asyncio
159115 async def test_get_client_cert_and_key_callback_sync (self ):
160- # Test the fallback logic: if it's a sync function, the TypeError is caught
116+ """Tests that a sync callback is handled via the TypeError fallback."""
161117 callback = mock .Mock (return_value = (CERT_DATA , KEY_DATA ))
162118
163119 success , cert , key = await mtls .get_client_cert_and_key (callback )
164120
165121 assert success is True
166122 assert cert == CERT_DATA
167- # In your current implementation, this might still show 2 calls if the
168- # first 'await' attempt triggers a call before failing.
169- # To strictly avoid 2 calls, the implementation would need to check inspect.iscoroutinefunction.
170- assert callback .call_count >= 1
171-
172- @pytest .mark .asyncio
173- @mock .patch (
174- "google.auth.aio.transport.mtls.get_client_ssl_credentials" ,
175- new_callable = mock .AsyncMock ,
176- )
177- async def test_get_client_cert_and_key_default (self , mock_get_credentials ):
178- mock_get_credentials .return_value = (True , CERT_DATA , KEY_DATA , None )
179-
180- success , cert , key = await mtls .get_client_cert_and_key (None )
181-
182- assert success is True
183- assert cert == CERT_DATA
184- assert key == KEY_DATA
185- mock_get_credentials .assert_called_once ()
123+ # Note: In the source, the first 'await' will call the function.
124+ # When it fails to await, the exception handler uses the result already obtained.
125+ assert callback .call_count == 1
186126
187127 @pytest .mark .asyncio
188128 @mock .patch ("google.auth.transport._mtls_helper._get_workload_cert_and_key" )
189129 async def test_get_client_ssl_credentials_error (self , mock_workload ):
130+ """Tests exception propagation from the workload helper."""
190131 mock_workload .side_effect = exceptions .ClientCertError (
191132 "Failed to read metadata"
192133 )
193134
194135 with pytest .raises (exceptions .ClientCertError , match = "Failed to read metadata" ):
195136 await mtls .get_client_ssl_credentials ()
196-
197- @pytest .mark .asyncio
198- @mock .patch ("google.auth.aio.transport.mtls.get_client_ssl_credentials" )
199- async def test_get_client_cert_and_key_exception_propagation (self , mock_get_ssl ):
200- mock_get_ssl .side_effect = exceptions .ClientCertError (
201- "Underlying credentials failed"
202- )
203-
204- with pytest .raises (
205- exceptions .ClientCertError , match = "Underlying credentials failed"
206- ):
207- await mtls .get_client_cert_and_key (client_cert_callback = None )
0 commit comments