diff --git a/.github/workflows/gapic-generator-tests.yml b/.github/workflows/gapic-generator-tests.yml index b9e65f1abf21..b43ae76d6038 100644 --- a/.github/workflows/gapic-generator-tests.yml +++ b/.github/workflows/gapic-generator-tests.yml @@ -85,6 +85,10 @@ jobs: curl --location https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip --output /usr/src/protoc/protoc.zip cd /usr/src/protoc/ && unzip protoc.zip sudo ln -s /usr/src/protoc/bin/protoc /usr/local/bin/protoc + - name: Configure Git Redirect + run: | + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python" + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python.git" - name: Run Nox env: GOOGLE_SDK_PYTHON_LOGGING_SCOPE: ${{ matrix.logging_scope }} @@ -126,6 +130,10 @@ jobs: python-version: ${{ needs.python_config.outputs.latest_stable_python }} - name: Install System Deps run: sudo apt-get update && sudo apt-get install -y pandoc + - name: Configure Git Redirect + run: | + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python" + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python.git" - name: Run Goldens env: LATEST_STABLE_PYTHON: ${{ needs.python_config.outputs.latest_stable_python }} @@ -201,6 +209,10 @@ jobs: curl --location https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip --output /usr/src/protoc/protoc.zip cd /usr/src/protoc/ && unzip protoc.zip sudo ln -s /usr/src/protoc/bin/protoc /usr/local/bin/protoc + - name: Configure Git Redirect + run: | + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python" + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python.git" - name: Run Tests run: | pip install nox @@ -232,6 +244,10 @@ jobs: # Ensure CACHE_VERSION is defined in the mono-repo secrets! key: ${{ runner.os }}-bazel-20210105-${{ secrets.CACHE_VERSION }} + - name: Configure Git Redirect + run: | + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python" + git config --global url."${{ github.workspace }}".insteadOf "https://github.com/googleapis/google-cloud-python.git" - name: Run Bazel Integration Tests run: | # We need to move into the package directory if the diff --git a/packages/gapic-generator/WORKSPACE b/packages/gapic-generator/WORKSPACE index 4da1de3cc7d4..9b420758aa51 100644 --- a/packages/gapic-generator/WORKSPACE +++ b/packages/gapic-generator/WORKSPACE @@ -42,7 +42,8 @@ load("@rules_python//python:pip.bzl", "pip_parse") pip_parse( name = "gapic_generator_python_pip_deps", - requirements_lock = "//:requirements.txt", + requirements_lock = "//:requirements.txt", + extra_pip_args = ["--index-url=https://pypi.org/simple"], ) load("@gapic_generator_python_pip_deps//:requirements.bzl", "install_deps") @@ -123,3 +124,13 @@ switched_rules_by_language( gapic = True, grpc = True, ) + +# BEGIN workaround +load("@rules_python//python:repositories.bzl", "python_register_toolchains") + +python_register_toolchains( + name = "python311", + python_version = "3.11", +) +# END workaround + diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 index e2e3edb24967..16cdc98982c8 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 @@ -6,6 +6,14 @@ {% import "%namespace/%name_%version/%sub/services/%service/_client_macros.j2" as macros %} {% import "%namespace/%name_%version/%sub/services/%service/_shared_macros.j2" as shared_macros %} +{% set ns = namespace(has_auto_populated=false) %} +{% for method in service.methods.values() %} + {% set method_settings = api.all_method_settings.get(method.meta.address.proto) %} + {% if method_settings is not none and method_settings.auto_populated_fields %} + {% set ns.has_auto_populated = true %} + {% endif %} +{% endfor %} + from collections import OrderedDict {% if service.any_extended_operations_methods %} import functools @@ -16,8 +24,8 @@ import logging as std_logging import os import re from typing import Dict, Callable, Mapping, MutableMapping, MutableSequence, Optional, {% if service.any_server_streaming %}Iterable, {% endif %}{% if service.any_client_streaming %}Iterator, {% endif %}Sequence, Tuple, Type, Union, cast -{% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %} -import uuid +{% if ns.has_auto_populated %} +from google.api_core.gapic_v1 import _method_helpers {% endif %} import warnings @@ -30,6 +38,9 @@ from google.api_core import exceptions as core_exceptions from google.api_core import extended_operation {% endif %} from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -154,28 +165,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = {% if service.host %}"{{ service.host }}"{% else %}None{% endif %} @@ -201,18 +191,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -365,12 +344,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = {{ service.client_name }}._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -383,13 +357,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -406,16 +374,18 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = {{ service.client_name }}._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + {{ service.client_name }}._DEFAULT_UNIVERSE, + {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT, + {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -431,14 +401,11 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = {{ service.client_name }}._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + {{ service.client_name }}._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -453,7 +420,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): # NOTE (b/349488459): universe validation is disabled until further notice. return True - {% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %} + {% if ns.has_auto_populated %} @staticmethod def _setup_request_id(request, field_name: str, is_proto3_optional: bool): """Populate a UUID4 field in the request if it is not already set. @@ -463,26 +430,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): field_name (str): The name of the field to populate. is_proto3_optional (bool): Whether the field is proto3 optional. """ - if isinstance(request, dict): - if is_proto3_optional: - if field_name not in request: - request[field_name] = str(uuid.uuid4()) - elif not request.get(field_name): - request[field_name] = str(uuid.uuid4()) - return - - if is_proto3_optional: - try: - # Pure protobuf messages - if not request.HasField(field_name): - setattr(request, field_name, str(uuid.uuid4())) - except (AttributeError, ValueError): - # Proto-plus messages or other objects - if field_name not in request: - setattr(request, field_name, str(uuid.uuid4())) - else: - if not getattr(request, field_name): - setattr(request, field_name, str(uuid.uuid4())) + _method_helpers.setup_request_id(request, field_name, is_proto3_optional) {% endif %} def _add_cred_info_for_auth_errors( diff --git a/packages/gapic-generator/gapic/templates/setup.py.j2 b/packages/gapic-generator/gapic/templates/setup.py.j2 index e82245c35d4f..e3daef648beb 100644 --- a/packages/gapic-generator/gapic/templates/setup.py.j2 +++ b/packages/gapic-generator/gapic/templates/setup.py.j2 @@ -36,7 +36,7 @@ else: release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/gapic/templates/testing/_default_constraints.j2 b/packages/gapic-generator/gapic/templates/testing/_default_constraints.j2 index 85d819aaff23..bd01aa01961d 100644 --- a/packages/gapic-generator/gapic/templates/testing/_default_constraints.j2 +++ b/packages/gapic-generator/gapic/templates/testing/_default_constraints.j2 @@ -1,7 +1,7 @@ {% from '_pypi_packages.j2' import pypi_packages %} # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/gapic/templates/testing/constraints-3.10-async-rest.txt.j2 b/packages/gapic-generator/gapic/templates/testing/constraints-3.10-async-rest.txt.j2 index 0f1a119d953e..f7f713779fd8 100644 --- a/packages/gapic-generator/gapic/templates/testing/constraints-3.10-async-rest.txt.j2 +++ b/packages/gapic-generator/gapic/templates/testing/constraints-3.10-async-rest.txt.j2 @@ -8,7 +8,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.35.0 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/gapic/templates/testing/constraints-3.10.txt.j2 b/packages/gapic-generator/gapic/templates/testing/constraints-3.10.txt.j2 index 809256a2cd34..82421df960d8 100644 --- a/packages/gapic-generator/gapic/templates/testing/constraints-3.10.txt.j2 +++ b/packages/gapic-generator/gapic/templates/testing/constraints-3.10.txt.j2 @@ -5,7 +5,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/gapic/templates/testing/constraints-3.13.txt.j2 b/packages/gapic-generator/gapic/templates/testing/constraints-3.13.txt.j2 index a2e0a3f4cb1e..0c57ad84a684 100644 --- a/packages/gapic-generator/gapic/templates/testing/constraints-3.13.txt.j2 +++ b/packages/gapic-generator/gapic/templates/testing/constraints-3.13.txt.j2 @@ -6,7 +6,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/gapic/templates/testing/constraints-3.14.txt.j2 b/packages/gapic-generator/gapic/templates/testing/constraints-3.14.txt.j2 index a2e0a3f4cb1e..0c57ad84a684 100644 --- a/packages/gapic-generator/gapic/templates/testing/constraints-3.14.txt.j2 +++ b/packages/gapic-generator/gapic/templates/testing/constraints-3.14.txt.j2 @@ -6,7 +6,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/gapic/templates/testing/constraints-3.15.txt.j2 b/packages/gapic-generator/gapic/templates/testing/constraints-3.15.txt.j2 index a2e0a3f4cb1e..0c57ad84a684 100644 --- a/packages/gapic-generator/gapic/templates/testing/constraints-3.15.txt.j2 +++ b/packages/gapic-generator/gapic/templates/testing/constraints-3.15.txt.j2 @@ -6,7 +6,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index c68b390b7c84..b024b72bc44c 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -156,186 +156,16 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert {{ service.client_name }}._get_default_mtls_endpoint(None) is None - assert {{ service.client_name }}._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert {{ service.client_name }}._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert {{ service.client_name }}._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - {{ service.client_name }}._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert {{ service.client_name }}._read_environment_variables() == ( - False, - "auto", - None, - ) - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", None) - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - {{ service.client_name }}._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", "foo.com") -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert {{ service.client_name }}._use_client_cert_effective() is True - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert {{ service.client_name }}._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert {{ service.client_name }}._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert {{ service.client_name }}._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - {{ service.client_name }}._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert {{ service.client_name }}._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert {{ service.client_name }}._get_client_cert_source(None, False) is None - assert {{ service.client_name }}._get_client_cert_source(mock_provided_cert_source, False) is None - assert {{ service.client_name }}._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert {{ service.client_name }}._get_client_cert_source(None, True) is mock_default_cert_source - assert {{ service.client_name }}._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source -@mock.patch.object({{ service.client_name }}, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template({{ service.client_name }})) -{% if 'grpc' in opts.transport %} -@mock.patch.object({{ service.async_client_name }}, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template({{ service.async_client_name }})) -{% endif %} -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = {{ service.client_name }}._DEFAULT_UNIVERSE - default_endpoint = {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - assert {{ service.client_name }}._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert {{ service.client_name }}._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - assert {{ service.client_name }}._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert {{ service.client_name }}._get_api_endpoint(None, None, default_universe, "always") == {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - assert {{ service.client_name }}._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - assert {{ service.client_name }}._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert {{ service.client_name }}._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - with pytest.raises(MutualTLSChannelError) as excinfo: - {{ service.client_name }}._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." + {% if service.version %} {% for method in service.methods.values() %}{% with method_name = method.name|snake_case %} @@ -384,17 +214,7 @@ def test_{{ method_name }}_api_version_header(transport_name): {% endfor %} {% endif %}{# service.version #} -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - assert {{ service.client_name }}._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert {{ service.client_name }}._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert {{ service.client_name }}._get_universe_domain(None, None) == {{ service.client_name }}._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - {{ service.client_name }}._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -434,84 +254,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] -{% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %} -def test__setup_request_id(): - class MockRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def __contains__(self, key): - return hasattr(self, key) - - class MockProtoRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def HasField(self, key): - return hasattr(self, key) - - # Test with proto3 optional field not in request - request = MockRequest() - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with proto3 optional field already in request - request = MockRequest(request_id="already_set") - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with non-proto3 optional field empty - request = MockRequest(request_id="") - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with non-proto3 optional field already set - request = MockRequest(request_id="already_set") - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert request.request_id == "already_set" - - # Test with proto3 optional field not in request (MockProtoRequest) - request = MockProtoRequest() - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with proto3 optional field already in request (MockProtoRequest) - request = MockProtoRequest(request_id="already_set") - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with ValueError - class MockValueErrorRequest: - def HasField(self, key): - raise ValueError("Mismatched field") - def __contains__(self, key): - return hasattr(self, key) - - request = MockValueErrorRequest() - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with dict and proto3 optional field not in request - request = {} - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request["request_id"]) - - # Test with dict and proto3 optional field already in request - request = {"request_id": "already_set"} - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert request["request_id"] == "already_set" - - # Test with dict and non-proto3 optional field empty - request = {"request_id": ""} - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request["request_id"]) - - # Test with dict and non-proto3 optional field already set - request = {"request_id": "already_set"} - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert request["request_id"] == "already_set" -{% endif %} @pytest.mark.parametrize("client_class,transport_name", [ {% if 'grpc' in opts.transport %} ({{ service.client_name }}, "grpc"), @@ -896,6 +639,7 @@ def test_{{ service.client_name|snake_case }}_get_mtls_endpoint_and_cert_source( for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -943,6 +687,7 @@ def test_{{ service.client_name|snake_case }}_get_mtls_endpoint_and_cert_source( for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/noxfile.py b/packages/gapic-generator/noxfile.py index 6fac5c48853d..dd21daeee584 100644 --- a/packages/gapic-generator/noxfile.py +++ b/packages/gapic-generator/noxfile.py @@ -154,9 +154,10 @@ def __call__(self, frag): ) self.session.install(tmp_dir, "-e", ".", "-qqq", "-r", constraints_path) - # Run the fragment's generated unit tests. - # Don't bother parallelizing them: we already parallelize - # the fragments, and there usually aren't too many tests per fragment. + env = os.environ.copy() + env["GOOGLE_API_USE_CLIENT_CERTIFICATE"] = "false" + env["CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE"] = "false" + outputs.append( self.session.run( "py.test", @@ -166,6 +167,7 @@ def __call__(self, frag): "--cov-fail-under=100", str(Path(tmp_dir) / "tests" / "unit"), silent=True, + env=env, ) ) @@ -487,6 +489,10 @@ def run_showcase_unit_tests(session, fail_under=100, rest_async_io_enabled=False # Freeze and print python environment package versions session.run("python", "-m", "pip", "freeze") + env = os.environ.copy() + env["GOOGLE_API_USE_CLIENT_CERTIFICATE"] = "false" + env["CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE"] = "false" + # Run the tests. session.run( "py.test", @@ -501,6 +507,7 @@ def run_showcase_unit_tests(session, fail_under=100, rest_async_io_enabled=False path.join("tests", "unit"), ] ), + env=env, ) diff --git a/packages/gapic-generator/requirements.in b/packages/gapic-generator/requirements.in index 2776bb919bb8..f848551c0c69 100644 --- a/packages/gapic-generator/requirements.in +++ b/packages/gapic-generator/requirements.in @@ -1,5 +1,5 @@ click -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core googleapis-common-protos jinja2 MarkupSafe diff --git a/packages/gapic-generator/requirements.txt b/packages/gapic-generator/requirements.txt index b4e1c89959be..7b43a3bc37b8 100644 --- a/packages/gapic-generator/requirements.txt +++ b/packages/gapic-generator/requirements.txt @@ -560,9 +560,7 @@ frozenlist==1.8.0 \ # via # aiohttp # aiosignal -google-api-core==2.30.3 \ - --hash=sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8 \ - --hash=sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core # via -r requirements.in google-auth==2.52.0 \ --hash=sha256:01f30e1a9e3638698d89464f5e603ce29d18e1c0e63ec31ac570aba4e164aaf5 \ diff --git a/packages/gapic-generator/setup.py b/packages/gapic-generator/setup.py index da2cccde365a..e3ae586adfa4 100644 --- a/packages/gapic-generator/setup.py +++ b/packages/gapic-generator/setup.py @@ -28,7 +28,7 @@ # Ensure that the lower bounds of these dependencies match what we have in the # templated setup.py.j2: https://github.com/googleapis/gapic-generator-python/blob/main/gapic/templates/setup.py.j2 "click >= 6.7", - "google-api-core[grpc] >= 2.25.0, < 3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", "googleapis-common-protos >= 1.55.0, < 2.0.0", "grpcio >= 1.24.3, < 2.0.0", # 2.11.0 is required which adds the `default` argument to `jinja-filters.map()` @@ -61,7 +61,7 @@ author="Google LLC", author_email="googleapis-packages@google.com", license="Apache-2.0", - packages=setuptools.find_namespace_packages(exclude=["docs", "tests"]), + packages=setuptools.find_namespace_packages(include=["gapic*", "test_utils*"]), url=url, classifiers=[ release_status, diff --git a/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py b/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py index 590b6fa1c615..47357253f3fa 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -111,28 +115,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "cloudasset.googleapis.com" @@ -156,18 +139,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -423,12 +395,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = AssetServiceClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -441,13 +408,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -464,16 +425,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = AssetServiceClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = AssetServiceClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + AssetServiceClient._DEFAULT_UNIVERSE, + AssetServiceClient.DEFAULT_MTLS_ENDPOINT, + AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -489,14 +452,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = AssetServiceClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + AssetServiceClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/asset/setup.py b/packages/gapic-generator/tests/integration/goldens/asset/setup.py index 2ff89d775eb7..084e11dd4374 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.10.txt index 05725bf21e16..9fef416899fa 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.11.txt index c5602c5029bf..ad1253bb5f85 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.12.txt index c5602c5029bf..ad1253bb5f85 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.13.txt index f63842dab6f9..5f738dc95c19 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.14.txt index f63842dab6f9..5f738dc95c19 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.15.txt index f63842dab6f9..5f738dc95c19 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/asset/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py b/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py index ea110a38acc3..0e721d16bb1d 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py @@ -121,198 +121,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert AssetServiceClient._get_default_mtls_endpoint(None) is None - assert AssetServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert AssetServiceClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert AssetServiceClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert AssetServiceClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert AssetServiceClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - AssetServiceClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert AssetServiceClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert AssetServiceClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert AssetServiceClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert AssetServiceClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - AssetServiceClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert AssetServiceClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - AssetServiceClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert AssetServiceClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert AssetServiceClient._get_client_cert_source(None, False) is None - assert AssetServiceClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert AssetServiceClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert AssetServiceClient._get_client_cert_source(None, True) is mock_default_cert_source - assert AssetServiceClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(AssetServiceClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(AssetServiceClient)) -@mock.patch.object(AssetServiceAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(AssetServiceAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = AssetServiceClient._DEFAULT_UNIVERSE - default_endpoint = AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert AssetServiceClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert AssetServiceClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == AssetServiceClient.DEFAULT_MTLS_ENDPOINT - assert AssetServiceClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert AssetServiceClient._get_api_endpoint(None, None, default_universe, "always") == AssetServiceClient.DEFAULT_MTLS_ENDPOINT - assert AssetServiceClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == AssetServiceClient.DEFAULT_MTLS_ENDPOINT - assert AssetServiceClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert AssetServiceClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - AssetServiceClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert AssetServiceClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert AssetServiceClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert AssetServiceClient._get_universe_domain(None, None) == AssetServiceClient._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - AssetServiceClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -351,6 +159,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), @@ -696,6 +505,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -743,6 +553,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py b/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py index 4ad970da32e9..034f4140e9e9 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -114,28 +118,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "iamcredentials.googleapis.com" @@ -159,18 +142,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -360,12 +332,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = IAMCredentialsClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -378,13 +345,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -401,16 +362,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = IAMCredentialsClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + IAMCredentialsClient._DEFAULT_UNIVERSE, + IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT, + IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -426,14 +389,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = IAMCredentialsClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + IAMCredentialsClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/setup.py b/packages/gapic-generator/tests/integration/goldens/credentials/setup.py index 790c39dcc5e8..eac337aca430 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.10.txt index d9d1cb25e696..53b2a9c8ead5 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.11.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.12.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.13.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.14.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.15.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/credentials/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py b/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py index 14a6074a40f9..ba5c5a347219 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py @@ -111,198 +111,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert IAMCredentialsClient._get_default_mtls_endpoint(None) is None - assert IAMCredentialsClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert IAMCredentialsClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert IAMCredentialsClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - IAMCredentialsClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert IAMCredentialsClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - IAMCredentialsClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - IAMCredentialsClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert IAMCredentialsClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert IAMCredentialsClient._get_client_cert_source(None, False) is None - assert IAMCredentialsClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert IAMCredentialsClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert IAMCredentialsClient._get_client_cert_source(None, True) is mock_default_cert_source - assert IAMCredentialsClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(IAMCredentialsClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(IAMCredentialsClient)) -@mock.patch.object(IAMCredentialsAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(IAMCredentialsAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = IAMCredentialsClient._DEFAULT_UNIVERSE - default_endpoint = IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert IAMCredentialsClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert IAMCredentialsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - assert IAMCredentialsClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert IAMCredentialsClient._get_api_endpoint(None, None, default_universe, "always") == IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - assert IAMCredentialsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - assert IAMCredentialsClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert IAMCredentialsClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - IAMCredentialsClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert IAMCredentialsClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert IAMCredentialsClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert IAMCredentialsClient._get_universe_domain(None, None) == IAMCredentialsClient._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - IAMCredentialsClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -341,6 +149,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (IAMCredentialsClient, "grpc"), (IAMCredentialsAsyncClient, "grpc_asyncio"), @@ -686,6 +495,7 @@ def test_iam_credentials_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -733,6 +543,7 @@ def test_iam_credentials_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py b/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py index 7255d3c91709..8a6eb79d2e2e 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -132,28 +136,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "eventarc.googleapis.com" @@ -177,18 +160,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -543,12 +515,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = EventarcClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -561,13 +528,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -584,16 +545,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = EventarcClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = EventarcClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = EventarcClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + EventarcClient._DEFAULT_UNIVERSE, + EventarcClient.DEFAULT_MTLS_ENDPOINT, + EventarcClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -609,14 +572,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = EventarcClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + EventarcClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/setup.py b/packages/gapic-generator/tests/integration/goldens/eventarc/setup.py index 9dce671cd319..cfc72c5dd844 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.10.txt index 0ce4b3d6e6f5..aee6bba07099 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.11.txt index 1cd0c5a2c3d4..24203e57ecab 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.12.txt index 1cd0c5a2c3d4..24203e57ecab 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.13.txt index f85022a2fb62..3b4af9260215 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.14.txt index f85022a2fb62..3b4af9260215 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.15.txt index f85022a2fb62..3b4af9260215 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py b/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py index 533e401eb1e7..f02f3fa9848d 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py @@ -142,198 +142,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert EventarcClient._get_default_mtls_endpoint(None) is None - assert EventarcClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert EventarcClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert EventarcClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert EventarcClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert EventarcClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - EventarcClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert EventarcClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert EventarcClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert EventarcClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert EventarcClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - EventarcClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert EventarcClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - EventarcClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert EventarcClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert EventarcClient._get_client_cert_source(None, False) is None - assert EventarcClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert EventarcClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert EventarcClient._get_client_cert_source(None, True) is mock_default_cert_source - assert EventarcClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(EventarcClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(EventarcClient)) -@mock.patch.object(EventarcAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(EventarcAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = EventarcClient._DEFAULT_UNIVERSE - default_endpoint = EventarcClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = EventarcClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert EventarcClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert EventarcClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == EventarcClient.DEFAULT_MTLS_ENDPOINT - assert EventarcClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert EventarcClient._get_api_endpoint(None, None, default_universe, "always") == EventarcClient.DEFAULT_MTLS_ENDPOINT - assert EventarcClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == EventarcClient.DEFAULT_MTLS_ENDPOINT - assert EventarcClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert EventarcClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - EventarcClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert EventarcClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert EventarcClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert EventarcClient._get_universe_domain(None, None) == EventarcClient._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - EventarcClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -372,6 +180,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (EventarcClient, "grpc"), (EventarcAsyncClient, "grpc_asyncio"), @@ -717,6 +526,7 @@ def test_eventarc_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -764,6 +574,7 @@ def test_eventarc_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py index 15922e6d865a..f6e09f81eb91 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -107,28 +111,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -152,18 +135,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -419,12 +391,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = ConfigServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -437,13 +404,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -460,16 +421,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = ConfigServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + ConfigServiceV2Client._DEFAULT_UNIVERSE, + ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT, + ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -485,14 +448,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = ConfigServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + ConfigServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py index e89762755eda..ee795a01bb2a 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -104,28 +108,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -149,18 +132,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -350,12 +322,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = LoggingServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -368,13 +335,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -391,16 +352,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT, + LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -416,14 +379,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = LoggingServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py index 90e9355f8c26..ebaef07d069a 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -105,28 +109,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -150,18 +133,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -351,12 +323,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = MetricsServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -369,13 +336,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -392,16 +353,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = MetricsServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + MetricsServiceV2Client._DEFAULT_UNIVERSE, + MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT, + MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -417,14 +380,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = MetricsServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + MetricsServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/logging/setup.py b/packages/gapic-generator/tests/integration/goldens/logging/setup.py index 67a55c012241..638d122c3845 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.10.txt index d9d1cb25e696..53b2a9c8ead5 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.11.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.12.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.13.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.14.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.15.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py index eada5b433c55..5872b343e282 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -112,198 +112,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert ConfigServiceV2Client._get_default_mtls_endpoint(None) is None - assert ConfigServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert ConfigServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert ConfigServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - ConfigServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert ConfigServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - ConfigServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - ConfigServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert ConfigServiceV2Client._get_client_cert_source(None, False) is None - assert ConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert ConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert ConfigServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert ConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(ConfigServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(ConfigServiceV2Client)) -@mock.patch.object(ConfigServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(ConfigServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = ConfigServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert ConfigServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert ConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert ConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert ConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert ConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert ConfigServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert ConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - ConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert ConfigServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert ConfigServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert ConfigServiceV2Client._get_universe_domain(None, None) == ConfigServiceV2Client._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - ConfigServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -342,6 +150,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (ConfigServiceV2Client, "grpc"), (ConfigServiceV2AsyncClient, "grpc_asyncio"), @@ -674,6 +483,7 @@ def test_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_class for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -721,6 +531,7 @@ def test_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_class for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 65559a5d1073..992d1bfb27b2 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -113,198 +113,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert LoggingServiceV2Client._get_default_mtls_endpoint(None) is None - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert LoggingServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert LoggingServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - LoggingServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert LoggingServiceV2Client._get_client_cert_source(None, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert LoggingServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(LoggingServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2Client)) -@mock.patch.object(LoggingServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert LoggingServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert LoggingServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert LoggingServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert LoggingServiceV2Client._get_universe_domain(None, None) == LoggingServiceV2Client._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -343,6 +151,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (LoggingServiceV2Client, "grpc"), (LoggingServiceV2AsyncClient, "grpc_asyncio"), @@ -675,6 +484,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -722,6 +532,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 90cdab2be2b2..ed80cd91315f 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -111,198 +111,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert MetricsServiceV2Client._get_default_mtls_endpoint(None) is None - assert MetricsServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert MetricsServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert MetricsServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - MetricsServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert MetricsServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - MetricsServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - MetricsServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert MetricsServiceV2Client._get_client_cert_source(None, False) is None - assert MetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert MetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert MetricsServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert MetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(MetricsServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(MetricsServiceV2Client)) -@mock.patch.object(MetricsServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(MetricsServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = MetricsServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert MetricsServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert MetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert MetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert MetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert MetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert MetricsServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert MetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - MetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert MetricsServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert MetricsServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert MetricsServiceV2Client._get_universe_domain(None, None) == MetricsServiceV2Client._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - MetricsServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -341,6 +149,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (MetricsServiceV2Client, "grpc"), (MetricsServiceV2AsyncClient, "grpc_asyncio"), @@ -673,6 +482,7 @@ def test_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -720,6 +530,7 @@ def test_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py index 61204cb87a52..7fe6d885ce46 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -107,28 +111,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -152,18 +135,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -419,12 +391,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = BaseConfigServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -437,13 +404,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -460,16 +421,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = BaseConfigServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + BaseConfigServiceV2Client._DEFAULT_UNIVERSE, + BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT, + BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -485,14 +448,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = BaseConfigServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + BaseConfigServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py index e89762755eda..ee795a01bb2a 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -104,28 +108,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -149,18 +132,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -350,12 +322,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = LoggingServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -368,13 +335,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -391,16 +352,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT, + LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -416,14 +379,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = LoggingServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py index fa55137223d1..203efc86348d 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -105,28 +109,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -150,18 +133,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -351,12 +323,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = BaseMetricsServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -369,13 +336,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -392,16 +353,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + BaseMetricsServiceV2Client._DEFAULT_UNIVERSE, + BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT, + BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -417,14 +380,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + BaseMetricsServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/setup.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/setup.py index 67a55c012241..638d122c3845 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.10.txt index d9d1cb25e696..53b2a9c8ead5 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.11.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.12.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.13.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.14.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.15.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py index 9eec837e6f58..a2b5d10a8d40 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -112,198 +112,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(None) is None - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - BaseConfigServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert BaseConfigServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseConfigServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - BaseConfigServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert BaseConfigServiceV2Client._get_client_cert_source(None, False) is None - assert BaseConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert BaseConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert BaseConfigServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert BaseConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(BaseConfigServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseConfigServiceV2Client)) -@mock.patch.object(BaseConfigServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseConfigServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = BaseConfigServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert BaseConfigServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert BaseConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert BaseConfigServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert BaseConfigServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert BaseConfigServiceV2Client._get_universe_domain(None, None) == BaseConfigServiceV2Client._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - BaseConfigServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -342,6 +150,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (BaseConfigServiceV2Client, "grpc"), (BaseConfigServiceV2AsyncClient, "grpc_asyncio"), @@ -674,6 +483,7 @@ def test_base_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_ for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -721,6 +531,7 @@ def test_base_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_ for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 65559a5d1073..992d1bfb27b2 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -113,198 +113,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert LoggingServiceV2Client._get_default_mtls_endpoint(None) is None - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert LoggingServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert LoggingServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - LoggingServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert LoggingServiceV2Client._get_client_cert_source(None, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert LoggingServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(LoggingServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2Client)) -@mock.patch.object(LoggingServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert LoggingServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert LoggingServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert LoggingServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert LoggingServiceV2Client._get_universe_domain(None, None) == LoggingServiceV2Client._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -343,6 +151,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (LoggingServiceV2Client, "grpc"), (LoggingServiceV2AsyncClient, "grpc_asyncio"), @@ -675,6 +484,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -722,6 +532,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 310677b64bc6..f2fbd9bdb2b6 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -111,198 +111,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(None) is None - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - BaseMetricsServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert BaseMetricsServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseMetricsServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - BaseMetricsServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert BaseMetricsServiceV2Client._get_client_cert_source(None, False) is None - assert BaseMetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert BaseMetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert BaseMetricsServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert BaseMetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(BaseMetricsServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseMetricsServiceV2Client)) -@mock.patch.object(BaseMetricsServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseMetricsServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert BaseMetricsServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert BaseMetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseMetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseMetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert BaseMetricsServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert BaseMetricsServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert BaseMetricsServiceV2Client._get_universe_domain(None, None) == BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - BaseMetricsServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -341,6 +149,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (BaseMetricsServiceV2Client, "grpc"), (BaseMetricsServiceV2AsyncClient, "grpc_asyncio"), @@ -673,6 +482,7 @@ def test_base_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -720,6 +530,7 @@ def test_base_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py b/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py index 33ccce478c8e..9458a36988c7 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -142,28 +146,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "redis.googleapis.com" @@ -187,18 +170,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -388,12 +360,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = CloudRedisClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -406,13 +373,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -429,16 +390,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = CloudRedisClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = CloudRedisClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + CloudRedisClient._DEFAULT_UNIVERSE, + CloudRedisClient.DEFAULT_MTLS_ENDPOINT, + CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -454,14 +417,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = CloudRedisClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + CloudRedisClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/redis/setup.py b/packages/gapic-generator/tests/integration/goldens/redis/setup.py index 868115ad7ad0..b7da523eb1c2 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10-async-rest.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10-async-rest.txt index a49941854a3f..e248b552880a 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10-async-rest.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10-async-rest.txt @@ -5,7 +5,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.35.0 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10.txt index d9d1cb25e696..53b2a9c8ead5 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.11.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.12.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.13.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.14.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.15.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py b/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py index 8ca1fb5194a6..7a967e083e53 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py @@ -129,198 +129,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert CloudRedisClient._get_default_mtls_endpoint(None) is None - assert CloudRedisClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert CloudRedisClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert CloudRedisClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert CloudRedisClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert CloudRedisClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - CloudRedisClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert CloudRedisClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert CloudRedisClient._get_client_cert_source(None, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert CloudRedisClient._get_client_cert_source(None, True) is mock_default_cert_source - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(CloudRedisClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisClient)) -@mock.patch.object(CloudRedisAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = CloudRedisClient._DEFAULT_UNIVERSE - default_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert CloudRedisClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert CloudRedisClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert CloudRedisClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert CloudRedisClient._get_universe_domain(None, None) == CloudRedisClient._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -359,6 +167,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (CloudRedisClient, "grpc"), (CloudRedisAsyncClient, "grpc_asyncio"), @@ -704,6 +513,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -751,6 +561,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py index 031573ef83d7..c61109b32c78 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -142,28 +146,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "redis.googleapis.com" @@ -187,18 +170,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -388,12 +360,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = CloudRedisClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -406,13 +373,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -429,16 +390,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = CloudRedisClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = CloudRedisClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + CloudRedisClient._DEFAULT_UNIVERSE, + CloudRedisClient.DEFAULT_MTLS_ENDPOINT, + CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -454,14 +417,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = CloudRedisClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + CloudRedisClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/setup.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/setup.py index 868115ad7ad0..b7da523eb1c2 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10-async-rest.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10-async-rest.txt index a49941854a3f..e248b552880a 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10-async-rest.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10-async-rest.txt @@ -5,7 +5,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.35.0 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10.txt index d9d1cb25e696..53b2a9c8ead5 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.11.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.12.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.13.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.14.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.15.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py index 3f6b7aa521f3..c1f81193596a 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py @@ -129,198 +129,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert CloudRedisClient._get_default_mtls_endpoint(None) is None - assert CloudRedisClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert CloudRedisClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert CloudRedisClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert CloudRedisClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert CloudRedisClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - CloudRedisClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert CloudRedisClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert CloudRedisClient._get_client_cert_source(None, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert CloudRedisClient._get_client_cert_source(None, True) is mock_default_cert_source - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(CloudRedisClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisClient)) -@mock.patch.object(CloudRedisAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = CloudRedisClient._DEFAULT_UNIVERSE - default_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert CloudRedisClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert CloudRedisClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert CloudRedisClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert CloudRedisClient._get_universe_domain(None, None) == CloudRedisClient._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -359,6 +167,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (CloudRedisClient, "grpc"), (CloudRedisAsyncClient, "grpc_asyncio"), @@ -704,6 +513,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -751,6 +561,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py index 5f79cf8e016a..b29a475c827f 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -20,7 +21,7 @@ import os import re from typing import Dict, Callable, Mapping, MutableMapping, MutableSequence, Optional, Sequence, Tuple, Type, Union, cast -import uuid +from google.api_core.gapic_v1 import _method_helpers import warnings from google.cloud.storagebatchoperations_v1 import gapic_version as package_version @@ -28,6 +29,9 @@ from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore @@ -115,28 +119,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "storagebatchoperations.googleapis.com" @@ -160,18 +143,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -383,12 +355,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = StorageBatchOperationsClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -401,13 +368,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -424,16 +385,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = StorageBatchOperationsClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + StorageBatchOperationsClient._DEFAULT_UNIVERSE, + StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT, + StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -449,14 +412,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = StorageBatchOperationsClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + StorageBatchOperationsClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -480,26 +440,7 @@ def _setup_request_id(request, field_name: str, is_proto3_optional: bool): field_name (str): The name of the field to populate. is_proto3_optional (bool): Whether the field is proto3 optional. """ - if isinstance(request, dict): - if is_proto3_optional: - if field_name not in request: - request[field_name] = str(uuid.uuid4()) - elif not request.get(field_name): - request[field_name] = str(uuid.uuid4()) - return - - if is_proto3_optional: - try: - # Pure protobuf messages - if not request.HasField(field_name): - setattr(request, field_name, str(uuid.uuid4())) - except (AttributeError, ValueError): - # Proto-plus messages or other objects - if field_name not in request: - setattr(request, field_name, str(uuid.uuid4())) - else: - if not getattr(request, field_name): - setattr(request, field_name, str(uuid.uuid4())) + _method_helpers.setup_request_id(request, field_name, is_proto3_optional) def _add_cred_info_for_auth_errors( self, diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/setup.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/setup.py index a6a33bd0f66f..7143cf0f17ad 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/setup.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/setup.py @@ -42,7 +42,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 2.25.0, <3.0.0", + "google-api-core[grpc] @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core", # Exclude incompatible versions of `google-auth` # See https://github.com/googleapis/google-cloud-python/issues/12364 "google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0", diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.10.txt b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.10.txt index d9d1cb25e696..53b2a9c8ead5 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.10.txt +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.10.txt @@ -4,7 +4,7 @@ # pinning their versions to their lower bounds. # For example, if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # then this file should have google-cloud-foo==1.14.0 -google-api-core==2.25.0 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth==2.14.1 grpcio==1.59.0 proto-plus==1.26.1 diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.11.txt b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.11.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.11.txt +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.11.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.12.txt b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.12.txt index 7599dea499ed..3644f9804483 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.12.txt +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.12.txt @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This constraints file is required for unit tests. # List all library dependencies and extras in this file. -google-api-core +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth grpcio proto-plus diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.13.txt b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.13.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.13.txt +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.13.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.14.txt b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.14.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.14.txt +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.14.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.15.txt b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.15.txt index 6bd7e1f5b03d..0323d68967c4 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.15.txt +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/testing/constraints-3.15.txt @@ -5,7 +5,7 @@ # Require the latest major version be installed for each dependency. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", # Then this file should have google-cloud-foo>=1 -google-api-core>=2 +google-api-core @ git+https://github.com/googleapis/google-cloud-python.git@feat/gapic-centralization-api-core#egg=google-api-core&subdirectory=packages/google-api-core google-auth>=2 grpcio>=1 proto-plus>=1 diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py index 5c53e97f8d12..51264e74dc13 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py @@ -121,198 +121,6 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert StorageBatchOperationsClient._get_default_mtls_endpoint(None) is None - assert StorageBatchOperationsClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert StorageBatchOperationsClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert StorageBatchOperationsClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} - ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - StorageBatchOperationsClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert StorageBatchOperationsClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - StorageBatchOperationsClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - StorageBatchOperationsClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert StorageBatchOperationsClient._get_client_cert_source(None, False) is None - assert StorageBatchOperationsClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert StorageBatchOperationsClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - with mock.patch('google.auth.transport.mtls.has_default_client_cert_source', return_value=True): - with mock.patch('google.auth.transport.mtls.default_client_cert_source', return_value=mock_default_cert_source): - assert StorageBatchOperationsClient._get_client_cert_source(None, True) is mock_default_cert_source - assert StorageBatchOperationsClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(StorageBatchOperationsClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(StorageBatchOperationsClient)) -@mock.patch.object(StorageBatchOperationsAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(StorageBatchOperationsAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = StorageBatchOperationsClient._DEFAULT_UNIVERSE - default_endpoint = StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert StorageBatchOperationsClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert StorageBatchOperationsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - assert StorageBatchOperationsClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert StorageBatchOperationsClient._get_api_endpoint(None, None, default_universe, "always") == StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - assert StorageBatchOperationsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - assert StorageBatchOperationsClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert StorageBatchOperationsClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - StorageBatchOperationsClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert StorageBatchOperationsClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert StorageBatchOperationsClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert StorageBatchOperationsClient._get_universe_domain(None, None) == StorageBatchOperationsClient._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - StorageBatchOperationsClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." - @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), (403, CRED_INFO_JSON, True), @@ -351,81 +159,6 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] -def test__setup_request_id(): - class MockRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def __contains__(self, key): - return hasattr(self, key) - - class MockProtoRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def HasField(self, key): - return hasattr(self, key) - - # Test with proto3 optional field not in request - request = MockRequest() - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with proto3 optional field already in request - request = MockRequest(request_id="already_set") - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with non-proto3 optional field empty - request = MockRequest(request_id="") - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with non-proto3 optional field already set - request = MockRequest(request_id="already_set") - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert request.request_id == "already_set" - - # Test with proto3 optional field not in request (MockProtoRequest) - request = MockProtoRequest() - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with proto3 optional field already in request (MockProtoRequest) - request = MockProtoRequest(request_id="already_set") - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with ValueError - class MockValueErrorRequest: - def HasField(self, key): - raise ValueError("Mismatched field") - def __contains__(self, key): - return hasattr(self, key) - - request = MockValueErrorRequest() - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with dict and proto3 optional field not in request - request = {} - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request["request_id"]) - - # Test with dict and proto3 optional field already in request - request = {"request_id": "already_set"} - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert request["request_id"] == "already_set" - - # Test with dict and non-proto3 optional field empty - request = {"request_id": ""} - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request["request_id"]) - - # Test with dict and non-proto3 optional field already set - request = {"request_id": "already_set"} - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert request["request_id"] == "already_set" @pytest.mark.parametrize("client_class,transport_name", [ (StorageBatchOperationsClient, "grpc"), @@ -772,6 +505,7 @@ def test_storage_batch_operations_client_get_mtls_endpoint_and_cert_source(clien for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -819,6 +553,7 @@ def test_storage_batch_operations_client_get_mtls_endpoint_and_cert_source(clien for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/google-api-core/google/api_core/gapic_v1/__init__.py b/packages/google-api-core/google/api_core/gapic_v1/__init__.py index e5b7ad352ee6..8bae665dabd0 100644 --- a/packages/google-api-core/google/api_core/gapic_v1/__init__.py +++ b/packages/google-api-core/google/api_core/gapic_v1/__init__.py @@ -13,17 +13,21 @@ # limitations under the License. from google.api_core.gapic_v1 import client_info -from google.api_core.gapic_v1 import config -from google.api_core.gapic_v1 import config_async -from google.api_core.gapic_v1 import method -from google.api_core.gapic_v1 import method_async from google.api_core.gapic_v1 import routing_header __all__ = [ "client_info", - "config", - "config_async", - "method", - "method_async", "routing_header", ] + +try: + import grpc # noqa: F401 + + from google.api_core.gapic_v1 import config # noqa: F401 + from google.api_core.gapic_v1 import config_async # noqa: F401 + from google.api_core.gapic_v1 import method # noqa: F401 + from google.api_core.gapic_v1 import method_async # noqa: F401 + + __all__.extend(["config", "config_async", "method", "method_async"]) +except ImportError: # pragma: NO COVER + pass diff --git a/packages/google-api-core/google/api_core/gapic_v1/_client_cert.py b/packages/google-api-core/google/api_core/gapic_v1/_client_cert.py new file mode 100644 index 000000000000..ac862a18baf3 --- /dev/null +++ b/packages/google-api-core/google/api_core/gapic_v1/_client_cert.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Helpers for client certificate handling and mTLS authentication.""" + +import os +from typing import Any, Optional + +from google.auth.transport import mtls # type: ignore + + +def use_client_cert_effective() -> bool: + """Returns whether client certificate should be used for mTLS if the + google-auth version supports should_use_client_cert automatic mTLS + enablement. + + Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var. + + Returns: + bool: whether client certificate should be used for mTLS + Raises: + ValueError: (If using a version of google-auth without + should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is + set to an unexpected value.) + """ + # check if google-auth version supports should_use_client_cert for + # automatic mTLS enablement + if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER + return mtls.should_use_client_cert() + else: # pragma: NO COVER + # if unsupported, fallback to reading from env var + use_client_cert_str = os.getenv( + "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" + ).lower() + if use_client_cert_str not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` " + "must be either `true` or `false`" + ) + return use_client_cert_str == "true" + + +def get_client_cert_source( + provided_cert_source: Optional[Any], use_cert_flag: bool +) -> Optional[Any]: + """Return the client cert source to be used by the client. + + Args: + provided_cert_source (Callable[[], Tuple[bytes, bytes]]): The client certificate source provided. + use_cert_flag (bool): A flag indicating whether to use the + client certificate. + + Returns: + Callable[[], Tuple[bytes, bytes]] or None: The client cert source to be used by the client. + """ + client_cert_source = None + if use_cert_flag: + if provided_cert_source: + client_cert_source = provided_cert_source + elif ( + hasattr(mtls, "has_default_client_cert_source") + and mtls.has_default_client_cert_source() + ): + client_cert_source = mtls.default_client_cert_source() + return client_cert_source diff --git a/packages/google-api-core/google/api_core/gapic_v1/_config_helpers.py b/packages/google-api-core/google/api_core/gapic_v1/_config_helpers.py new file mode 100644 index 000000000000..d2d86129ccec --- /dev/null +++ b/packages/google-api-core/google/api_core/gapic_v1/_config_helpers.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Helpers for parsing environment variables.""" + +import os +from typing import Optional, Tuple + +from google.api_core.gapic_v1._client_cert import use_client_cert_effective +from google.auth.exceptions import MutualTLSChannelError # type: ignore + + +def read_environment_variables() -> Tuple[bool, str, Optional[str]]: + """Returns the environment variables used by the client. + + Returns: + Tuple[bool, str, Optional[str]]: returns the + GOOGLE_API_USE_CLIENT_CERTIFICATE, GOOGLE_API_USE_MTLS_ENDPOINT, + and GOOGLE_CLOUD_UNIVERSE_DOMAIN environment variables. + + Raises: + ValueError: If GOOGLE_API_USE_CLIENT_CERTIFICATE is not + any of ["true", "false"]. + google.auth.exceptions.MutualTLSChannelError: If + GOOGLE_API_USE_MTLS_ENDPOINT is not any of + ["auto", "never", "always"]. + """ + use_client_cert = use_client_cert_effective() + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() + universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` " + "must be `never`, `auto` or `always`" + ) + return use_client_cert, use_mtls_endpoint, universe_domain_env diff --git a/packages/google-api-core/google/api_core/gapic_v1/_method_helpers.py b/packages/google-api-core/google/api_core/gapic_v1/_method_helpers.py new file mode 100644 index 000000000000..23b6ff753a1f --- /dev/null +++ b/packages/google-api-core/google/api_core/gapic_v1/_method_helpers.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Helpers for method requests.""" + +import uuid +from typing import Any + + +def setup_request_id(request: Any, field_name: str, is_proto3_optional: bool) -> None: + """Populate a UUID4 field in the request if it is not already set. + + Args: + request (Union[google.protobuf.message.Message, dict]): The + request object. + field_name (str): The name of the field to populate. + is_proto3_optional (bool): Whether the field is proto3 optional. + """ + if isinstance(request, dict): + if is_proto3_optional: + if field_name not in request: + request[field_name] = str(uuid.uuid4()) + elif not request.get(field_name): + request[field_name] = str(uuid.uuid4()) + return + + if is_proto3_optional: + try: + # Pure protobuf messages + if not request.HasField(field_name): + setattr(request, field_name, str(uuid.uuid4())) + except (AttributeError, ValueError): + # Proto-plus messages or other objects + if field_name not in request: + setattr(request, field_name, str(uuid.uuid4())) + else: + if not getattr(request, field_name): + setattr(request, field_name, str(uuid.uuid4())) diff --git a/packages/google-api-core/google/api_core/gapic_v1/_routing.py b/packages/google-api-core/google/api_core/gapic_v1/_routing.py new file mode 100644 index 000000000000..1ae5986ae553 --- /dev/null +++ b/packages/google-api-core/google/api_core/gapic_v1/_routing.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Helpers for routing and endpoint resolution.""" + +import re +from typing import Any, Optional + +from google.auth.exceptions import MutualTLSChannelError # type: ignore + +_MTLS_ENDPOINT_RE = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?" + r"(?P\.googleapis\.com)?" +) + + +def get_default_mtls_endpoint(api_endpoint: Optional[str]) -> Optional[str]: + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + Optional[str]: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + m = _MTLS_ENDPOINT_RE.match(api_endpoint) + if m is None: + # Could not parse api_endpoint; return as-is. + return api_endpoint + + name, mtls_group, sandbox, googledomain = m.groups() + if mtls_group or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + +def get_api_endpoint( + api_override: Optional[str], + client_cert_source: Optional[Any], + universe_domain: str, + use_mtls_endpoint: str, + default_universe: str, + default_mtls_endpoint: Optional[str], + default_endpoint_template: Optional[str], +) -> Optional[str]: + """Return the API endpoint used by the client.""" + if api_override is not None: + return api_override + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + if universe_domain != default_universe: + raise MutualTLSChannelError( + f"mTLS is not supported in any universe other than " + f"{default_universe}." + ) + return default_mtls_endpoint + else: + return ( + default_endpoint_template.format(UNIVERSE_DOMAIN=universe_domain) + if default_endpoint_template + else None + ) + + +def get_universe_domain( + client_universe_domain: Optional[str], + universe_domain_env: Optional[str], + default_universe: str, +) -> str: + """Return the universe domain used by the client.""" + universe_domain = default_universe + if client_universe_domain is not None: + universe_domain = client_universe_domain + elif universe_domain_env is not None: + universe_domain = universe_domain_env + if len(universe_domain.strip()) == 0: + raise ValueError("Universe Domain cannot be an empty string.") + return universe_domain diff --git a/packages/google-api-core/noxfile.py b/packages/google-api-core/noxfile.py index 0bad668a80dd..3cbebbaa84d2 100644 --- a/packages/google-api-core/noxfile.py +++ b/packages/google-api-core/noxfile.py @@ -350,7 +350,7 @@ def prerelease_deps(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def core_deps_from_source(session): """Run the test suite installing dependencies from source.""" - default(session, prerelease=True) + default(session, install_deps_from_source=True) @nox.session(python=DEFAULT_PYTHON_VERSION) diff --git a/packages/google-api-core/tests/conftest.py b/packages/google-api-core/tests/conftest.py new file mode 100644 index 000000000000..1872207be107 --- /dev/null +++ b/packages/google-api-core/tests/conftest.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from unittest import mock +import pytest + + +@pytest.fixture(scope="session", autouse=True) +def mock_mtls_env(): + """Autouse session-scoped fixture to isolate unit tests from workstation mTLS environments.""" + with mock.patch.dict( + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, + ): + yield diff --git a/packages/google-api-core/tests/unit/gapic/test_client_cert.py b/packages/google-api-core/tests/unit/gapic/test_client_cert.py new file mode 100644 index 000000000000..be563fb58b12 --- /dev/null +++ b/packages/google-api-core/tests/unit/gapic/test_client_cert.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from unittest import mock + +import pytest + +try: + import grpc # noqa: F401 +except ImportError: + pytest.skip("No GRPC", allow_module_level=True) + +from google.api_core.gapic_v1._client_cert import ( + get_client_cert_source, + use_client_cert_effective, +) + + +@mock.patch("google.auth.transport.mtls.should_use_client_cert", create=True) +def test_use_client_cert_effective_with_google_auth(mock_method): + # Test when google-auth supports the method + mock_method.return_value = True + assert use_client_cert_effective() is True + + mock_method.return_value = False + assert use_client_cert_effective() is False + + +@mock.patch.dict(os.environ, {}, clear=True) +def test_use_client_cert_effective_fallback(): + # We must patch hasattr to simulate google-auth lacking the method + with mock.patch( + "google.api_core.gapic_v1._client_cert.hasattr", return_value=False + ): + # Default is false + assert use_client_cert_effective() is False + + env_true = {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"} + with mock.patch.dict(os.environ, env_true): + assert use_client_cert_effective() is True + + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"} + ): + assert use_client_cert_effective() is False + + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "invalid"} + ): + match_str = "must be either `true` or `false`" + with pytest.raises(ValueError, match=match_str): + use_client_cert_effective() + + +@mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", create=True +) # noqa: E501 +@mock.patch( + "google.auth.transport.mtls.default_client_cert_source", create=True +) # noqa: E501 +def test_get_client_cert_source(mock_default, mock_has_default): + mock_default.return_value = b"default_cert" + mock_has_default.return_value = True + + # When use_cert_flag is False, return None + assert get_client_cert_source(b"provided", False) is None + + # When provided_cert_source is given, return provided + assert get_client_cert_source(b"provided", True) == b"provided" # noqa: E501 + + # When no provided cert but default is available + assert get_client_cert_source(None, True) == b"default_cert" diff --git a/packages/google-api-core/tests/unit/gapic/test_config_helpers.py b/packages/google-api-core/tests/unit/gapic/test_config_helpers.py new file mode 100644 index 000000000000..0d3ae61dc353 --- /dev/null +++ b/packages/google-api-core/tests/unit/gapic/test_config_helpers.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from unittest import mock + +import pytest + +try: + import grpc # noqa: F401 +except ImportError: + pytest.skip("No GRPC", allow_module_level=True) + +from google.auth.exceptions import MutualTLSChannelError + +from google.api_core.gapic_v1._config_helpers import read_environment_variables + + +@mock.patch( + "google.api_core.gapic_v1._config_helpers.use_client_cert_effective" +) # noqa: E501 +@mock.patch.dict(os.environ, clear=True) +def test_read_environment_variables(mock_effective): + mock_effective.return_value = True + os.environ["GOOGLE_API_USE_MTLS_ENDPOINT"] = "always" + os.environ["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] = "custom.com" + + cert, mtls, domain = read_environment_variables() + assert cert is True + assert mtls == "always" + assert domain == "custom.com" + + +@mock.patch.dict(os.environ, clear=True) +def test_read_environment_variables_invalid_mtls(): + os.environ["GOOGLE_API_USE_MTLS_ENDPOINT"] = "invalid" + with pytest.raises( + MutualTLSChannelError, match="must be `never`, `auto` or `always`" + ): + read_environment_variables() diff --git a/packages/google-api-core/tests/unit/gapic/test_method_helpers.py b/packages/google-api-core/tests/unit/gapic/test_method_helpers.py new file mode 100644 index 000000000000..b3d541faf18b --- /dev/null +++ b/packages/google-api-core/tests/unit/gapic/test_method_helpers.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from google.api_core.gapic_v1._method_helpers import setup_request_id + + +def test_setup_request_id(): + import uuid + + # test dict request + req = {} + setup_request_id(req, "request_id", True) + assert "request_id" in req + uuid_str = req["request_id"] + uuid.UUID(uuid_str) # verify it is a valid UUID + + # test dict request when already set + req = {"request_id": "existing"} + setup_request_id(req, "request_id", True) + assert req["request_id"] == "existing" + + class DummyRequest: + def __init__(self): + self.request_id = "" + + def HasField(self, field_name): + if not hasattr(self, field_name): + raise ValueError() + return bool(getattr(self, field_name)) + + # test object request proto3 optional true + req_obj = DummyRequest() + setup_request_id(req_obj, "request_id", True) + assert req_obj.request_id != "" + uuid.UUID(req_obj.request_id) + + # test object request proto3 optional false + req_obj2 = DummyRequest() + setup_request_id(req_obj2, "request_id", False) + assert req_obj2.request_id != "" + uuid.UUID(req_obj2.request_id) diff --git a/packages/google-api-core/tests/unit/gapic/test_routing.py b/packages/google-api-core/tests/unit/gapic/test_routing.py new file mode 100644 index 000000000000..9d119c65e9a6 --- /dev/null +++ b/packages/google-api-core/tests/unit/gapic/test_routing.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from unittest import mock + +import pytest + +try: + import grpc # noqa: F401 +except ImportError: + pytest.skip("No GRPC", allow_module_level=True) + +from google.auth.exceptions import MutualTLSChannelError + +from google.api_core.gapic_v1._routing import ( + get_api_endpoint, + get_default_mtls_endpoint, + get_universe_domain, +) + + +def test_get_default_mtls_endpoint(): + # Test valid API endpoints + assert get_default_mtls_endpoint("foo.googleapis.com") == "foo.mtls.googleapis.com" + assert ( + get_default_mtls_endpoint("foo.sandbox.googleapis.com") + == "foo.mtls.sandbox.googleapis.com" + ) + + # Test endpoints that shouldn't be converted + assert ( + get_default_mtls_endpoint("foo.mtls.googleapis.com") + == "foo.mtls.googleapis.com" + ) + assert get_default_mtls_endpoint("foo.com") == "foo.com" + + # Test empty/None endpoints + assert get_default_mtls_endpoint("") == "" + assert get_default_mtls_endpoint(None) is None + + +def test_get_api_endpoint_override(): + # If api_override is provided, it should be returned + # regardless of other args + endpoint = get_api_endpoint( + api_override="custom.endpoint.com", + client_cert_source=None, + universe_domain="googleapis.com", + use_mtls_endpoint="auto", + default_universe="googleapis.com", + default_mtls_endpoint="foo.mtls.googleapis.com", + default_endpoint_template="foo.{UNIVERSE_DOMAIN}", + ) + assert endpoint == "custom.endpoint.com" + + +def test_get_api_endpoint_mtls_always(): + # use_mtls_endpoint == "always" should use the default mtls endpoint + endpoint = get_api_endpoint( + api_override=None, + client_cert_source=None, + universe_domain="googleapis.com", + use_mtls_endpoint="always", + default_universe="googleapis.com", + default_mtls_endpoint="foo.mtls.googleapis.com", + default_endpoint_template="foo.{UNIVERSE_DOMAIN}", + ) + assert endpoint == "foo.mtls.googleapis.com" + + +def test_get_api_endpoint_mtls_auto_with_cert(): + # "auto" with client_cert_source should use mtls + endpoint = get_api_endpoint( + api_override=None, + client_cert_source=mock.Mock(), + universe_domain="googleapis.com", + use_mtls_endpoint="auto", + default_universe="googleapis.com", + default_mtls_endpoint="foo.mtls.googleapis.com", + default_endpoint_template="foo.{UNIVERSE_DOMAIN}", + ) + assert endpoint == "foo.mtls.googleapis.com" + + +def test_get_api_endpoint_mtls_auto_no_cert(): + # "auto" without client_cert_source should use the default template + endpoint = get_api_endpoint( + api_override=None, + client_cert_source=None, + universe_domain="googleapis.com", + use_mtls_endpoint="auto", + default_universe="googleapis.com", + default_mtls_endpoint="foo.mtls.googleapis.com", + default_endpoint_template="foo.{UNIVERSE_DOMAIN}", + ) + assert endpoint == "foo.googleapis.com" + + +def test_get_api_endpoint_mtls_universe_mismatch(): + # mTLS is only supported in the default universe + with pytest.raises(MutualTLSChannelError, match="mTLS is not supported"): + get_api_endpoint( + api_override=None, + client_cert_source=mock.Mock(), + universe_domain="custom-universe.com", + use_mtls_endpoint="auto", + default_universe="googleapis.com", + default_mtls_endpoint="foo.mtls.googleapis.com", + default_endpoint_template="foo.{UNIVERSE_DOMAIN}", + ) + + +def test_get_universe_domain(): + # client_universe_domain takes precedence + assert ( + get_universe_domain("client.com", "env.com", "default.com") # noqa: E501 + == "client.com" + ) + + # env takes precedence over default + assert ( + get_universe_domain(None, "env.com", "default.com") == "env.com" # noqa: E501 + ) + + # fallback to default + assert get_universe_domain(None, None, "default.com") == "default.com" # noqa: E501 + + +def test_get_universe_domain_empty(): + with pytest.raises(ValueError, match="cannot be an empty string"): + get_universe_domain("", None, "default.com") + + +def test_get_api_endpoint_none_template(): + endpoint = get_api_endpoint( + api_override=None, + client_cert_source=None, + universe_domain="googleapis.com", + use_mtls_endpoint="never", + default_universe="googleapis.com", + default_mtls_endpoint=None, + default_endpoint_template=None, + ) + assert endpoint is None diff --git a/packages/google-api-core/tests/unit/test_bidi.py b/packages/google-api-core/tests/unit/test_bidi.py index 4a8eb74fac94..0f4810cb0a12 100644 --- a/packages/google-api-core/tests/unit/test_bidi.py +++ b/packages/google-api-core/tests/unit/test_bidi.py @@ -31,8 +31,7 @@ except ImportError: # pragma: NO COVER pytest.skip("No GRPC", allow_module_level=True) -from google.api_core import bidi -from google.api_core import exceptions +from google.api_core import bidi, exceptions class Test_RequestQueueGenerator(object): @@ -195,7 +194,7 @@ def test_delays_entry_attempts_above_threshold(self): # (NOTE: not using assert all(...), b/c the coverage check would complain) for i, entry in enumerate(entries): if i != 3: - assert entry["reported_wait"] == 0.0 + assert entry["reported_wait"] < 0.01 # The delayed entry is expected to have been delayed for a significant # chunk of the full second, and the actual and reported delay times