Skip to content

Commit ddcaee1

Browse files
committed
refactor(api-core): decouple client_utils helpers from client details and remove should_use_mtls_endpoint
1 parent c862011 commit ddcaee1

2 files changed

Lines changed: 52 additions & 154 deletions

File tree

packages/google-api-core/google/api_core/gapic_v1/client_utils.py

Lines changed: 12 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414
# limitations under the License.
1515
#
1616

17-
import os
18-
from typing import Callable, Optional, Tuple
17+
from typing import Optional
1918
from urllib.parse import urlparse, urlunparse
2019

21-
import google.auth.transport.mtls # type: ignore
2220
from google.auth.exceptions import MutualTLSChannelError # type: ignore
2321

2422

@@ -68,53 +66,25 @@ def get_default_mtls_endpoint(api_endpoint: Optional[str]) -> Optional[str]:
6866
return urlunparse(new_parsed)
6967

7068

71-
def should_use_mtls_endpoint(client_cert_available: bool) -> bool:
72-
"""Helper to determine whether to use mTLS endpoint.
73-
74-
Uses google.auth.transport.mtls.should_use_mtls_endpoint if available,
75-
otherwise falls back to evaluation of GOOGLE_API_USE_MTLS_ENDPOINT.
76-
"""
77-
if hasattr(google.auth.transport.mtls, "should_use_mtls_endpoint"):
78-
return google.auth.transport.mtls.should_use_mtls_endpoint(
79-
client_cert_available
80-
)
81-
82-
# Fallback logic for older google-auth versions
83-
use_mtls_endpoint = (
84-
os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").strip().lower()
85-
)
86-
if use_mtls_endpoint == "always":
87-
return True
88-
elif use_mtls_endpoint == "never":
89-
return False
90-
elif use_mtls_endpoint == "auto":
91-
return client_cert_available
92-
else:
93-
raise MutualTLSChannelError(
94-
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
95-
)
96-
97-
9869
def get_api_endpoint(
9970
api_override: Optional[str],
100-
client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]],
10171
universe_domain: str,
10272
default_universe: str,
10373
default_mtls_endpoint: Optional[str],
10474
default_endpoint_template: str,
75+
use_mtls: bool,
10576
) -> str:
10677
"""Return the API endpoint used by the client.
10778
10879
Args:
10980
api_override (Optional[str]): The API endpoint override. If specified,
11081
this is always returned.
111-
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): The client
112-
certificate source used by the client.
11382
universe_domain (str): The universe domain used by the client.
11483
default_universe (str): The default universe domain.
11584
default_mtls_endpoint (Optional[str]): The default mTLS endpoint.
11685
default_endpoint_template (str): The default endpoint template containing
11786
a placeholder `{UNIVERSE_DOMAIN}`.
87+
use_mtls (bool): Whether to use the mTLS endpoint.
11888
11989
Returns:
12090
str: The API endpoint to be used by the client.
@@ -127,8 +97,7 @@ def get_api_endpoint(
12797
if api_override is not None:
12898
return api_override
12999

130-
client_cert_available = client_cert_source is not None
131-
if should_use_mtls_endpoint(client_cert_available):
100+
if use_mtls:
132101
if universe_domain.lower() != default_universe.lower():
133102
raise MutualTLSChannelError(
134103
f"mTLS is not supported in any universe other than {default_universe}."
@@ -141,17 +110,13 @@ def get_api_endpoint(
141110

142111

143112
def get_universe_domain(
144-
client_universe_domain: Optional[str],
145-
universe_domain_env: Optional[str],
146-
default_universe: str,
113+
universe_domain: Optional[str],
114+
default_universe: str = "googleapis.com",
147115
) -> str:
148116
"""Return the universe domain used by the client.
149117
150118
Args:
151-
client_universe_domain (Optional[str]): The universe domain configured
152-
via client options.
153-
universe_domain_env (Optional[str]): The universe domain configured
154-
via environment variable.
119+
universe_domain (Optional[str]): The configured universe domain.
155120
default_universe (str): The default universe domain.
156121
157122
Returns:
@@ -160,13 +125,10 @@ def get_universe_domain(
160125
Raises:
161126
ValueError: If the resolved universe domain is an empty string.
162127
"""
163-
if client_universe_domain is not None:
164-
universe_domain = client_universe_domain.strip()
165-
elif universe_domain_env is not None:
166-
universe_domain = universe_domain_env.strip()
167-
else:
168-
universe_domain = default_universe
128+
resolved = (
129+
universe_domain.strip() if universe_domain is not None else default_universe
130+
)
169131

170-
if not universe_domain:
132+
if not resolved:
171133
raise ValueError("Universe Domain cannot be an empty string.")
172-
return universe_domain
134+
return resolved

packages/google-api-core/tests/unit/gapic/test_client_utils.py

Lines changed: 40 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
import os
17-
from unittest import mock
18-
1916
import pytest
2017
from google.auth.exceptions import MutualTLSChannelError
2118

@@ -26,12 +23,6 @@
2623
)
2724

2825

29-
class MockClient:
30-
_DEFAULT_UNIVERSE = "googleapis.com"
31-
DEFAULT_MTLS_ENDPOINT = "foo.mtls.googleapis.com"
32-
_DEFAULT_ENDPOINT_TEMPLATE = "foo.{UNIVERSE_DOMAIN}"
33-
34-
3526
def test_get_default_mtls_endpoint():
3627
# Test valid API endpoints
3728
assert get_default_mtls_endpoint("foo.googleapis.com") == "foo.mtls.googleapis.com"
@@ -89,156 +80,101 @@ def test_get_default_mtls_endpoint():
8980

9081

9182
@pytest.mark.parametrize(
92-
"api_override,client_cert_source,universe_domain,use_mtls_endpoint,default_universe,default_mtls_endpoint,default_endpoint_template,expected",
83+
"api_override,universe_domain,default_universe,default_mtls_endpoint,default_endpoint_template,use_mtls,expected",
9384
[
9485
(
9586
"foo.com",
96-
mock.Mock(),
9787
"googleapis.com",
98-
"always",
9988
"googleapis.com",
10089
"foo.mtls.googleapis.com",
10190
"foo.{UNIVERSE_DOMAIN}",
91+
True,
10292
"foo.com",
10393
),
10494
(
10595
None,
106-
mock.Mock(),
107-
"googleapis.com",
108-
"auto",
109-
"googleapis.com",
110-
"foo.mtls.googleapis.com",
111-
"foo.{UNIVERSE_DOMAIN}",
112-
"foo.mtls.googleapis.com",
113-
),
114-
(
115-
None,
116-
None,
117-
"googleapis.com",
118-
"auto",
119-
"googleapis.com",
120-
"foo.mtls.googleapis.com",
121-
"foo.{UNIVERSE_DOMAIN}",
122-
"foo.googleapis.com",
123-
),
124-
(
125-
None,
126-
None,
127-
"googleapis.com",
128-
"always",
129-
"googleapis.com",
130-
"foo.mtls.googleapis.com",
131-
"foo.{UNIVERSE_DOMAIN}",
132-
"foo.mtls.googleapis.com",
133-
),
134-
(
135-
None,
136-
mock.Mock(),
13796
"googleapis.com",
138-
"always",
13997
"googleapis.com",
14098
"foo.mtls.googleapis.com",
14199
"foo.{UNIVERSE_DOMAIN}",
100+
True,
142101
"foo.mtls.googleapis.com",
143102
),
144103
(
145-
None,
146-
None,
147-
"bar.com",
148-
"never",
149-
"googleapis.com",
150-
"foo.mtls.googleapis.com",
151-
"foo.{UNIVERSE_DOMAIN}",
152-
"foo.bar.com",
153-
),
154-
(
155-
None,
156104
None,
157105
"googleapis.com",
158-
"never",
159106
"googleapis.com",
160107
"foo.mtls.googleapis.com",
161108
"foo.{UNIVERSE_DOMAIN}",
109+
False,
162110
"foo.googleapis.com",
163111
),
164112
(
165113
None,
166-
mock.Mock(),
167114
"bar.com",
168-
"auto",
169115
"googleapis.com",
170116
"foo.mtls.googleapis.com",
171117
"foo.{UNIVERSE_DOMAIN}",
118+
True,
172119
MutualTLSChannelError,
173120
),
174121
(
175122
None,
176-
mock.Mock(),
177123
"googleapis.com",
178-
"always",
179124
"googleapis.com",
180125
None,
181126
"foo.{UNIVERSE_DOMAIN}",
127+
True,
182128
ValueError,
183129
),
184130
],
185131
)
186132
def test_get_api_endpoint(
187133
api_override,
188-
client_cert_source,
189134
universe_domain,
190-
use_mtls_endpoint,
191135
default_universe,
192136
default_mtls_endpoint,
193137
default_endpoint_template,
138+
use_mtls,
194139
expected,
195140
):
196-
with mock.patch.dict(
197-
os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_endpoint}
198-
):
199-
if isinstance(expected, type) and issubclass(expected, Exception):
200-
with pytest.raises(expected):
201-
get_api_endpoint(
202-
api_override,
203-
client_cert_source,
204-
universe_domain,
205-
default_universe,
206-
default_mtls_endpoint,
207-
default_endpoint_template,
208-
)
209-
else:
210-
assert (
211-
get_api_endpoint(
212-
api_override,
213-
client_cert_source,
214-
universe_domain,
215-
default_universe,
216-
default_mtls_endpoint,
217-
default_endpoint_template,
218-
)
219-
== expected
141+
if isinstance(expected, type) and issubclass(expected, Exception):
142+
with pytest.raises(expected):
143+
get_api_endpoint(
144+
api_override,
145+
universe_domain,
146+
default_universe,
147+
default_mtls_endpoint,
148+
default_endpoint_template,
149+
use_mtls,
220150
)
151+
else:
152+
assert (
153+
get_api_endpoint(
154+
api_override,
155+
universe_domain,
156+
default_universe,
157+
default_mtls_endpoint,
158+
default_endpoint_template,
159+
use_mtls,
160+
)
161+
== expected
162+
)
221163

222164

223-
def test__get_universe_domain():
224-
client_universe_domain = "foo.com"
225-
universe_domain_env = "bar.com"
165+
def test_get_universe_domain():
166+
# When universe_domain is provided
167+
assert get_universe_domain("foo.com", "default.com") == "foo.com"
168+
assert get_universe_domain(" foo.com ", "default.com") == "foo.com"
226169

227-
assert (
228-
get_universe_domain(
229-
client_universe_domain, universe_domain_env, MockClient._DEFAULT_UNIVERSE
230-
)
231-
== client_universe_domain
232-
)
233-
assert (
234-
get_universe_domain(None, universe_domain_env, MockClient._DEFAULT_UNIVERSE)
235-
== universe_domain_env
236-
)
237-
assert (
238-
get_universe_domain(None, None, MockClient._DEFAULT_UNIVERSE)
239-
== MockClient._DEFAULT_UNIVERSE
240-
)
170+
# When universe_domain is None, falls back to default_universe
171+
assert get_universe_domain(None, "default.com") == "default.com"
172+
173+
# ValueError raised when resolved value is empty string
174+
with pytest.raises(ValueError) as excinfo:
175+
get_universe_domain("", "default.com")
176+
assert str(excinfo.value) == "Universe Domain cannot be an empty string."
241177

242178
with pytest.raises(ValueError) as excinfo:
243-
get_universe_domain("", None, MockClient._DEFAULT_UNIVERSE)
179+
get_universe_domain(" ", "default.com")
244180
assert str(excinfo.value) == "Universe Domain cannot be an empty string."

0 commit comments

Comments
 (0)