feat: Add attempt_direct_path argument to create_channel (#583)
* feat: Add attempt_direct_path argument to create_channel
* add more test cases
* fix docstring
* fix docstring
* update docstring of attempt_direct_path arg
* update docstring of target arg
* Add comment for dns_prefix local variable
* Set the default value of attempt_direct_path to False
* simplify conditional statement
* use warnings.warn instead of _LOGGER.debug
* update docstring of target arg in _modify_target_for_direct_path
* s/direct_path_prefix/direct_path_separator
* default->google_auth_default
* parametrize target in def test_create_channel_implicit
* Add github issue for TODO
* filter deprecation warning related to grpcio-gcp
* format docstring
diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py
index 793c884..21c7315 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 @@
# 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 @@
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 @@
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 @@
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 @@
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 5685e6f..9423d2b 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 @@
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 @@
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 @@
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 @@
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 66f72e4..13d5bf4 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -12,10 +12,10 @@
# 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 67c9b33..6bde59c 100644
--- a/tests/asyncio/test_grpc_helpers_async.py
+++ b/tests/asyncio/test_grpc_helpers_async.py
@@ -298,34 +298,62 @@
wrap_stream_errors.assert_called_once_with(callable_)
[email protected]("grpc.composite_channel_credentials")
[email protected](
+ "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"),
+ ],
+)
[email protected]("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
)
[email protected](
+ "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,
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch(
"google.auth.default",
autospec=True,
@@ -333,25 +361,40 @@
)
@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
)
[email protected](
+ "attempt_direct_path",
+ [
+ None,
+ False,
+ ],
+)
@mock.patch("grpc.composite_channel_credentials")
@mock.patch(
"google.auth.default",
@@ -359,13 +402,15 @@
)
@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 @@
)
[email protected]("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
+ )
+
+
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch(
"google.auth.default",
autospec=True,
@@ -398,7 +454,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch(
"google.auth.default",
autospec=True,
@@ -436,7 +492,7 @@
assert "mutually exclusive" in str(excinfo.value)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch("grpc.aio.secure_channel")
@mock.patch(
"google.auth.load_credentials_from_file",
@@ -559,7 +615,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch("grpc.aio.secure_channel")
@mock.patch(
"google.auth.load_credentials_from_file",
@@ -588,7 +644,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 58a6a32..59442d4 100644
--- a/tests/unit/test_grpc_helpers.py
+++ b/tests/unit/test_grpc_helpers.py
@@ -365,38 +365,72 @@
wrap_stream_errors.assert_called_once_with(callable_)
[email protected]("grpc.composite_channel_credentials")
[email protected](
+ "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"),
+ ],
+)
[email protected]("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
)
[email protected](
+ "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,
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch(
"google.auth.default",
autospec=True,
@@ -404,29 +438,48 @@
)
@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
)
[email protected](
+ "attempt_direct_path",
+ [
+ None,
+ False,
+ ],
+)
@mock.patch("grpc.composite_channel_credentials")
@mock.patch(
"google.auth.default",
@@ -435,13 +488,15 @@
)
@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 @@
)
[email protected]("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
+ )
+
+
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch(
"google.auth.default",
autospec=True,
@@ -483,7 +549,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch(
"google.auth.default",
autospec=True,
@@ -521,7 +587,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("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 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch("grpc.secure_channel")
@mock.patch(
"google.auth.load_credentials_from_file",
@@ -659,7 +725,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch("grpc.secure_channel")
@mock.patch(
"google.auth.load_credentials_from_file",
@@ -693,7 +759,7 @@
)
[email protected]("grpc.composite_channel_credentials")
[email protected]("grpc.compute_engine_channel_credentials")
@mock.patch("grpc.secure_channel")
@mock.patch(
"google.auth.load_credentials_from_file",