diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py index 793c884d..21c7315f 100644 --- a/google/api_core/grpc_helpers.py +++ b/google/api_core/grpc_helpers.py @@ -13,11 +13,10 @@ # limitations under the License. """Helpers for :mod:`grpc`.""" -from typing import Generic, TypeVar, Iterator +from typing import Generic, Iterator, Optional, TypeVar import collections import functools -import logging import warnings import grpc @@ -53,8 +52,6 @@ # The list of gRPC Callable interfaces that return iterators. _STREAM_WRAP_CLASSES = (grpc.UnaryStreamMultiCallable, grpc.StreamStreamMultiCallable) -_LOGGER = logging.getLogger(__name__) - # denotes the proto response type for grpc calls P = TypeVar("P") @@ -271,11 +268,24 @@ def _create_composite_credentials( # Create a set of grpc.CallCredentials using the metadata plugin. google_auth_credentials = grpc.metadata_call_credentials(metadata_plugin) - if ssl_credentials is None: - ssl_credentials = grpc.ssl_channel_credentials() - - # Combine the ssl credentials and the authorization credentials. - return grpc.composite_channel_credentials(ssl_credentials, google_auth_credentials) + # if `ssl_credentials` is set, use `grpc.composite_channel_credentials` instead of + # `grpc.compute_engine_channel_credentials` as the former supports passing + # `ssl_credentials` via `channel_credentials` which is needed for mTLS. + if ssl_credentials: + # Combine the ssl credentials and the authorization credentials. + # See https://grpc.github.io/grpc/python/grpc.html#grpc.composite_channel_credentials + return grpc.composite_channel_credentials( + ssl_credentials, google_auth_credentials + ) + else: + # Use grpc.compute_engine_channel_credentials in order to support Direct Path. + # See https://grpc.github.io/grpc/python/grpc.html#grpc.compute_engine_channel_credentials + # TODO(https://github.com/googleapis/python-api-core/issues/598): + # Although `grpc.compute_engine_channel_credentials` returns channel credentials + # outside of a Google Compute Engine environment (GCE), we should determine if + # there is a way to reliably detect a GCE environment so that + # `grpc.compute_engine_channel_credentials` is not called outside of GCE. + return grpc.compute_engine_channel_credentials(google_auth_credentials) def create_channel( @@ -288,6 +298,7 @@ def create_channel( default_scopes=None, default_host=None, compression=None, + attempt_direct_path: Optional[bool] = False, **kwargs, ): """Create a secure channel with credentials. @@ -311,6 +322,22 @@ def create_channel( default_host (str): The default endpoint. e.g., "pubsub.googleapis.com". compression (grpc.Compression): An optional value indicating the compression method to be used over the lifetime of the channel. + attempt_direct_path (Optional[bool]): If set, Direct Path will be attempted + when the request is made. Direct Path is only available within a Google + Compute Engine (GCE) environment and provides a proxyless connection + which increases the available throughput, reduces latency, and increases + reliability. Note: + + - This argument should only be set in a GCE environment and for Services + that are known to support Direct Path. + - If this argument is set outside of GCE, then this request will fail + unless the back-end service happens to have configured fall-back to DNS. + - If the request causes a `ServiceUnavailable` response, it is recommended + that the client repeat the request with `attempt_direct_path` set to + `False` as the Service may not support Direct Path. + - Using `ssl_credentials` with `attempt_direct_path` set to `True` will + result in `ValueError` as this combination is not yet supported. + kwargs: Additional key-word args passed to :func:`grpc_gcp.secure_channel` or :func:`grpc.secure_channel`. Note: `grpc_gcp` is only supported in environments with protobuf < 4.0.0. @@ -320,8 +347,15 @@ def create_channel( Raises: google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. + ValueError: If `ssl_credentials` is set and `attempt_direct_path` is set to `True`. """ + # If `ssl_credentials` is set and `attempt_direct_path` is set to `True`, + # raise ValueError as this is not yet supported. + # See https://github.com/googleapis/python-api-core/issues/590 + if ssl_credentials and attempt_direct_path: + raise ValueError("Using ssl_credentials with Direct Path is not supported") + composite_credentials = _create_composite_credentials( credentials=credentials, credentials_file=credentials_file, @@ -332,17 +366,58 @@ def create_channel( default_host=default_host, ) + # Note that grpcio-gcp is deprecated if HAS_GRPC_GCP: # pragma: NO COVER if compression is not None and compression != grpc.Compression.NoCompression: - _LOGGER.debug( - "Compression argument is being ignored for grpc_gcp.secure_channel creation." + warnings.warn( + "The `compression` argument is ignored for grpc_gcp.secure_channel creation.", + DeprecationWarning, + ) + if attempt_direct_path: + warnings.warn( + """The `attempt_direct_path` argument is ignored for grpc_gcp.secure_channel creation.""", + DeprecationWarning, ) return grpc_gcp.secure_channel(target, composite_credentials, **kwargs) + + if attempt_direct_path: + target = _modify_target_for_direct_path(target) + return grpc.secure_channel( target, composite_credentials, compression=compression, **kwargs ) +def _modify_target_for_direct_path(target: str) -> str: + """ + Given a target, return a modified version which is compatible with Direct Path. + + Args: + target (str): The target service address in the format 'hostname[:port]' or + 'dns://hostname[:port]'. + + Returns: + target (str): The target service address which is converted into a format compatible with Direct Path. + If the target contains `dns:///` or does not contain `:///`, the target will be converted in + a format compatible with Direct Path; otherwise the original target will be returned as the + original target may already denote Direct Path. + """ + + # A DNS prefix may be included with the target to indicate the endpoint is living in the Internet, + # outside of Google Cloud Platform. + dns_prefix = "dns:///" + # Remove "dns:///" if `attempt_direct_path` is set to True as + # the Direct Path prefix `google-c2p:///` will be used instead. + target = target.replace(dns_prefix, "") + + direct_path_separator = ":///" + if direct_path_separator not in target: + target_without_port = target.split(":")[0] + # Modify the target to use Direct Path by adding the `google-c2p:///` prefix + target = f"google-c2p{direct_path_separator}{target_without_port}" + return target + + _MethodCall = collections.namedtuple( "_MethodCall", ("request", "timeout", "metadata", "credentials", "compression") ) diff --git a/google/api_core/grpc_helpers_async.py b/google/api_core/grpc_helpers_async.py index 5685e6f8..9423d2b6 100644 --- a/google/api_core/grpc_helpers_async.py +++ b/google/api_core/grpc_helpers_async.py @@ -21,7 +21,7 @@ import asyncio import functools -from typing import Generic, Iterator, AsyncGenerator, TypeVar +from typing import AsyncGenerator, Generic, Iterator, Optional, TypeVar import grpc from grpc import aio @@ -223,6 +223,7 @@ def create_channel( default_scopes=None, default_host=None, compression=None, + attempt_direct_path: Optional[bool] = False, **kwargs ): """Create an AsyncIO secure channel with credentials. @@ -246,6 +247,22 @@ def create_channel( default_host (str): The default endpoint. e.g., "pubsub.googleapis.com". compression (grpc.Compression): An optional value indicating the compression method to be used over the lifetime of the channel. + attempt_direct_path (Optional[bool]): If set, Direct Path will be attempted + when the request is made. Direct Path is only available within a Google + Compute Engine (GCE) environment and provides a proxyless connection + which increases the available throughput, reduces latency, and increases + reliability. Note: + + - This argument should only be set in a GCE environment and for Services + that are known to support Direct Path. + - If this argument is set outside of GCE, then this request will fail + unless the back-end service happens to have configured fall-back to DNS. + - If the request causes a `ServiceUnavailable` response, it is recommended + that the client repeat the request with `attempt_direct_path` set to + `False` as the Service may not support Direct Path. + - Using `ssl_credentials` with `attempt_direct_path` set to `True` will + result in `ValueError` as this combination is not yet supported. + kwargs: Additional key-word args passed to :func:`aio.secure_channel`. Returns: @@ -253,8 +270,15 @@ def create_channel( Raises: google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. + ValueError: If `ssl_credentials` is set and `attempt_direct_path` is set to `True`. """ + # If `ssl_credentials` is set and `attempt_direct_path` is set to `True`, + # raise ValueError as this is not yet supported. + # See https://github.com/googleapis/python-api-core/issues/590 + if ssl_credentials and attempt_direct_path: + raise ValueError("Using ssl_credentials with Direct Path is not supported") + composite_credentials = grpc_helpers._create_composite_credentials( credentials=credentials, credentials_file=credentials_file, @@ -265,6 +289,9 @@ def create_channel( default_host=default_host, ) + if attempt_direct_path: + target = grpc_helpers._modify_target_for_direct_path(target) + return aio.secure_channel( target, composite_credentials, compression=compression, **kwargs ) diff --git a/pytest.ini b/pytest.ini index 66f72e41..13d5bf4d 100644 --- a/pytest.ini +++ b/pytest.ini @@ -12,10 +12,10 @@ filterwarnings = # Remove once support for grpcio-gcp is deprecated # See https://github.com/googleapis/python-api-core/blob/42e8b6e6f426cab749b34906529e8aaf3f133d75/google/api_core/grpc_helpers.py#L39-L45 ignore:.*Support for grpcio-gcp is deprecated:DeprecationWarning - # Remove once https://github.com/googleapis/python-api-common-protos/pull/187/files is merged + ignore: The `compression` argument is ignored for grpc_gcp.secure_channel creation:DeprecationWarning + ignore:The `attempt_direct_path` argument is ignored for grpc_gcp.secure_channel creation:DeprecationWarning + # Remove once the minimum supported version of googleapis-common-protos is 1.62.0 ignore:.*pkg_resources.declare_namespace:DeprecationWarning ignore:.*pkg_resources is deprecated as an API:DeprecationWarning - # Remove once release PR https://github.com/googleapis/proto-plus-python/pull/391 is merged - ignore:datetime.datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:proto.datetime_helpers - # Remove once https://github.com/grpc/grpc/issues/35086 is fixed + # Remove once https://github.com/grpc/grpc/issues/35086 is fixed (and version newer than 1.60.0 is published) ignore:There is no current event loop:DeprecationWarning diff --git a/tests/asyncio/test_grpc_helpers_async.py b/tests/asyncio/test_grpc_helpers_async.py index 67c9b335..6bde59ca 100644 --- a/tests/asyncio/test_grpc_helpers_async.py +++ b/tests/asyncio/test_grpc_helpers_async.py @@ -298,34 +298,62 @@ def test_wrap_errors_streaming(wrap_stream_errors): wrap_stream_errors.assert_called_once_with(callable_) -@mock.patch("grpc.composite_channel_credentials") +@pytest.mark.parametrize( + "attempt_direct_path,target,expected_target", + [ + (None, "example.com:443", "example.com:443"), + (False, "example.com:443", "example.com:443"), + (True, "example.com:443", "google-c2p:///example.com"), + (True, "dns:///example.com", "google-c2p:///example.com"), + (True, "another-c2p:///example.com", "another-c2p:///example.com"), + ], +) +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, return_value=(mock.sentinel.credentials, mock.sentinel.project), ) @mock.patch("grpc.aio.secure_channel") -def test_create_channel_implicit(grpc_secure_channel, default, composite_creds_call): - target = "example.com:443" +def test_create_channel_implicit( + grpc_secure_channel, + google_auth_default, + composite_creds_call, + attempt_direct_path, + target, + expected_target, +): composite_creds = composite_creds_call.return_value - channel = grpc_helpers_async.create_channel(target) + channel = grpc_helpers_async.create_channel( + target, attempt_direct_path=attempt_direct_path + ) assert channel is grpc_secure_channel.return_value - default.assert_called_once_with(scopes=None, default_scopes=None) + google_auth_default.assert_called_once_with(scopes=None, default_scopes=None) grpc_secure_channel.assert_called_once_with( - target, composite_creds, compression=None + expected_target, composite_creds, compression=None ) +@pytest.mark.parametrize( + "attempt_direct_path,target, expected_target", + [ + (None, "example.com:443", "example.com:443"), + (False, "example.com:443", "example.com:443"), + (True, "example.com:443", "google-c2p:///example.com"), + (True, "dns:///example.com", "google-c2p:///example.com"), + (True, "another-c2p:///example.com", "another-c2p:///example.com"), + ], +) @mock.patch("google.auth.transport.grpc.AuthMetadataPlugin", autospec=True) @mock.patch( "google.auth.transport.requests.Request", autospec=True, return_value=mock.sentinel.Request, ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, @@ -333,25 +361,40 @@ def test_create_channel_implicit(grpc_secure_channel, default, composite_creds_c ) @mock.patch("grpc.aio.secure_channel") def test_create_channel_implicit_with_default_host( - grpc_secure_channel, default, composite_creds_call, request, auth_metadata_plugin + grpc_secure_channel, + google_auth_default, + composite_creds_call, + request, + auth_metadata_plugin, + attempt_direct_path, + target, + expected_target, ): - target = "example.com:443" default_host = "example.com" composite_creds = composite_creds_call.return_value - channel = grpc_helpers_async.create_channel(target, default_host=default_host) + channel = grpc_helpers_async.create_channel( + target, default_host=default_host, attempt_direct_path=attempt_direct_path + ) assert channel is grpc_secure_channel.return_value - default.assert_called_once_with(scopes=None, default_scopes=None) + google_auth_default.assert_called_once_with(scopes=None, default_scopes=None) auth_metadata_plugin.assert_called_once_with( mock.sentinel.credentials, mock.sentinel.Request, default_host=default_host ) grpc_secure_channel.assert_called_once_with( - target, composite_creds, compression=None + expected_target, composite_creds, compression=None ) +@pytest.mark.parametrize( + "attempt_direct_path", + [ + None, + False, + ], +) @mock.patch("grpc.composite_channel_credentials") @mock.patch( "google.auth.default", @@ -359,13 +402,15 @@ def test_create_channel_implicit_with_default_host( ) @mock.patch("grpc.aio.secure_channel") def test_create_channel_implicit_with_ssl_creds( - grpc_secure_channel, default, composite_creds_call + grpc_secure_channel, default, composite_creds_call, attempt_direct_path ): target = "example.com:443" ssl_creds = grpc.ssl_channel_credentials() - grpc_helpers_async.create_channel(target, ssl_credentials=ssl_creds) + grpc_helpers_async.create_channel( + target, ssl_credentials=ssl_creds, attempt_direct_path=attempt_direct_path + ) default.assert_called_once_with(scopes=None, default_scopes=None) composite_creds_call.assert_called_once_with(ssl_creds, mock.ANY) @@ -375,7 +420,18 @@ def test_create_channel_implicit_with_ssl_creds( ) -@mock.patch("grpc.composite_channel_credentials") +def test_create_channel_implicit_with_ssl_creds_attempt_direct_path_true(): + target = "example.com:443" + ssl_creds = grpc.ssl_channel_credentials() + with pytest.raises( + ValueError, match="Using ssl_credentials with Direct Path is not supported" + ): + grpc_helpers_async.create_channel( + target, ssl_credentials=ssl_creds, attempt_direct_path=True + ) + + +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, @@ -398,7 +454,7 @@ def test_create_channel_implicit_with_scopes( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, @@ -436,7 +492,7 @@ def test_create_channel_explicit_with_duplicate_credentials(): assert "mutually exclusive" in str(excinfo.value) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("google.auth.credentials.with_scopes_if_required", autospec=True) @mock.patch("grpc.aio.secure_channel") def test_create_channel_explicit(grpc_secure_channel, auth_creds, composite_creds_call): @@ -456,7 +512,7 @@ def test_create_channel_explicit(grpc_secure_channel, auth_creds, composite_cred ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.aio.secure_channel") def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_call): target = "example.com:443" @@ -480,7 +536,7 @@ def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_cal ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.aio.secure_channel") def test_create_channel_explicit_default_scopes( grpc_secure_channel, composite_creds_call @@ -508,7 +564,7 @@ def test_create_channel_explicit_default_scopes( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.aio.secure_channel") def test_create_channel_explicit_with_quota_project( grpc_secure_channel, composite_creds_call @@ -531,7 +587,7 @@ def test_create_channel_explicit_with_quota_project( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.aio.secure_channel") @mock.patch( "google.auth.load_credentials_from_file", @@ -559,7 +615,7 @@ def test_create_channel_with_credentials_file( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.aio.secure_channel") @mock.patch( "google.auth.load_credentials_from_file", @@ -588,7 +644,7 @@ def test_create_channel_with_credentials_file_and_scopes( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.aio.secure_channel") @mock.patch( "google.auth.load_credentials_from_file", diff --git a/tests/unit/test_grpc_helpers.py b/tests/unit/test_grpc_helpers.py index 58a6a329..59442d43 100644 --- a/tests/unit/test_grpc_helpers.py +++ b/tests/unit/test_grpc_helpers.py @@ -365,38 +365,72 @@ def test_wrap_errors_streaming(wrap_stream_errors): wrap_stream_errors.assert_called_once_with(callable_) -@mock.patch("grpc.composite_channel_credentials") +@pytest.mark.parametrize( + "attempt_direct_path,target,expected_target", + [ + (None, "example.com:443", "example.com:443"), + (False, "example.com:443", "example.com:443"), + (True, "example.com:443", "google-c2p:///example.com"), + (True, "dns:///example.com", "google-c2p:///example.com"), + (True, "another-c2p:///example.com", "another-c2p:///example.com"), + ], +) +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, return_value=(mock.sentinel.credentials, mock.sentinel.project), ) @mock.patch("grpc.secure_channel") -def test_create_channel_implicit(grpc_secure_channel, default, composite_creds_call): - target = "example.com:443" +def test_create_channel_implicit( + grpc_secure_channel, + google_auth_default, + composite_creds_call, + attempt_direct_path, + target, + expected_target, +): composite_creds = composite_creds_call.return_value - channel = grpc_helpers.create_channel(target, compression=grpc.Compression.Gzip) + channel = grpc_helpers.create_channel( + target, + compression=grpc.Compression.Gzip, + attempt_direct_path=attempt_direct_path, + ) assert channel is grpc_secure_channel.return_value - default.assert_called_once_with(scopes=None, default_scopes=None) + google_auth_default.assert_called_once_with(scopes=None, default_scopes=None) if grpc_helpers.HAS_GRPC_GCP: # pragma: NO COVER - grpc_secure_channel.assert_called_once_with(target, composite_creds, None) + # The original target is the expected target + expected_target = target + grpc_secure_channel.assert_called_once_with( + expected_target, composite_creds, None + ) else: grpc_secure_channel.assert_called_once_with( - target, composite_creds, compression=grpc.Compression.Gzip + expected_target, composite_creds, compression=grpc.Compression.Gzip ) +@pytest.mark.parametrize( + "attempt_direct_path,target, expected_target", + [ + (None, "example.com:443", "example.com:443"), + (False, "example.com:443", "example.com:443"), + (True, "example.com:443", "google-c2p:///example.com"), + (True, "dns:///example.com", "google-c2p:///example.com"), + (True, "another-c2p:///example.com", "another-c2p:///example.com"), + ], +) @mock.patch("google.auth.transport.grpc.AuthMetadataPlugin", autospec=True) @mock.patch( "google.auth.transport.requests.Request", autospec=True, return_value=mock.sentinel.Request, ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, @@ -404,29 +438,48 @@ def test_create_channel_implicit(grpc_secure_channel, default, composite_creds_c ) @mock.patch("grpc.secure_channel") def test_create_channel_implicit_with_default_host( - grpc_secure_channel, default, composite_creds_call, request, auth_metadata_plugin + grpc_secure_channel, + google_auth_default, + composite_creds_call, + request, + auth_metadata_plugin, + attempt_direct_path, + target, + expected_target, ): - target = "example.com:443" default_host = "example.com" composite_creds = composite_creds_call.return_value - channel = grpc_helpers.create_channel(target, default_host=default_host) + channel = grpc_helpers.create_channel( + target, default_host=default_host, attempt_direct_path=attempt_direct_path + ) assert channel is grpc_secure_channel.return_value - default.assert_called_once_with(scopes=None, default_scopes=None) + google_auth_default.assert_called_once_with(scopes=None, default_scopes=None) auth_metadata_plugin.assert_called_once_with( mock.sentinel.credentials, mock.sentinel.Request, default_host=default_host ) if grpc_helpers.HAS_GRPC_GCP: # pragma: NO COVER - grpc_secure_channel.assert_called_once_with(target, composite_creds, None) + # The original target is the expected target + expected_target = target + grpc_secure_channel.assert_called_once_with( + expected_target, composite_creds, None + ) else: grpc_secure_channel.assert_called_once_with( - target, composite_creds, compression=None + expected_target, composite_creds, compression=None ) +@pytest.mark.parametrize( + "attempt_direct_path", + [ + None, + False, + ], +) @mock.patch("grpc.composite_channel_credentials") @mock.patch( "google.auth.default", @@ -435,13 +488,15 @@ def test_create_channel_implicit_with_default_host( ) @mock.patch("grpc.secure_channel") def test_create_channel_implicit_with_ssl_creds( - grpc_secure_channel, default, composite_creds_call + grpc_secure_channel, default, composite_creds_call, attempt_direct_path ): target = "example.com:443" ssl_creds = grpc.ssl_channel_credentials() - grpc_helpers.create_channel(target, ssl_credentials=ssl_creds) + grpc_helpers.create_channel( + target, ssl_credentials=ssl_creds, attempt_direct_path=attempt_direct_path + ) default.assert_called_once_with(scopes=None, default_scopes=None) @@ -456,7 +511,18 @@ def test_create_channel_implicit_with_ssl_creds( ) -@mock.patch("grpc.composite_channel_credentials") +def test_create_channel_implicit_with_ssl_creds_attempt_direct_path_true(): + target = "example.com:443" + ssl_creds = grpc.ssl_channel_credentials() + with pytest.raises( + ValueError, match="Using ssl_credentials with Direct Path is not supported" + ): + grpc_helpers.create_channel( + target, ssl_credentials=ssl_creds, attempt_direct_path=True + ) + + +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, @@ -483,7 +549,7 @@ def test_create_channel_implicit_with_scopes( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch( "google.auth.default", autospec=True, @@ -521,7 +587,7 @@ def test_create_channel_explicit_with_duplicate_credentials(): ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("google.auth.credentials.with_scopes_if_required", autospec=True) @mock.patch("grpc.secure_channel") def test_create_channel_explicit(grpc_secure_channel, auth_creds, composite_creds_call): @@ -544,7 +610,7 @@ def test_create_channel_explicit(grpc_secure_channel, auth_creds, composite_cred ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.secure_channel") def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_call): target = "example.com:443" @@ -570,7 +636,7 @@ def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_cal ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.secure_channel") def test_create_channel_explicit_default_scopes( grpc_secure_channel, composite_creds_call @@ -600,7 +666,7 @@ def test_create_channel_explicit_default_scopes( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.secure_channel") def test_create_channel_explicit_with_quota_project( grpc_secure_channel, composite_creds_call @@ -628,7 +694,7 @@ def test_create_channel_explicit_with_quota_project( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.secure_channel") @mock.patch( "google.auth.load_credentials_from_file", @@ -659,7 +725,7 @@ def test_create_channel_with_credentials_file( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.secure_channel") @mock.patch( "google.auth.load_credentials_from_file", @@ -693,7 +759,7 @@ def test_create_channel_with_credentials_file_and_scopes( ) -@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.compute_engine_channel_credentials") @mock.patch("grpc.secure_channel") @mock.patch( "google.auth.load_credentials_from_file",