`__
- operations, which allow you to manage message
- acknowledgments in bulk. That is, you can set the
- acknowledgment state of messages in an existing
- subscription to the state captured by a snapshot.
+ [Seek](https://cloud.google.com/pubsub/docs/replay-overview)
+ operations, which allow you to manage message
+ acknowledgments in bulk. That is, you can set the
+ acknowledgment state of messages in an existing
+ subscription to the state captured by a snapshot.
"""
# Create or coerce a protobuf request object.
@@ -1622,12 +1664,13 @@ def delete_snapshot(
Args:
- request (:class:`~.pubsub.DeleteSnapshotRequest`):
+ request (google.pubsub_v1.types.DeleteSnapshotRequest):
The request object. Request for the `DeleteSnapshot`
method.
- snapshot (:class:`str`):
+ snapshot (str):
Required. The name of the snapshot to delete. Format is
``projects/{project}/snapshots/{snap}``.
+
This corresponds to the ``snapshot`` field
on the ``request`` instance; if ``request`` is provided, this
should not be set.
@@ -1696,7 +1739,7 @@ def seek(
Args:
- request (:class:`~.pubsub.SeekRequest`):
+ request (google.pubsub_v1.types.SeekRequest):
The request object. Request for the `Seek` method.
retry (google.api_core.retry.Retry): Designation of what errors, if any,
@@ -1706,10 +1749,8 @@ def seek(
sent along with the request as metadata.
Returns:
- ~.pubsub.SeekResponse:
- Response for the ``Seek`` method (this response is
- empty).
-
+ google.pubsub_v1.types.SeekResponse:
+ Response for the Seek method (this response is empty).
"""
# Create or coerce a protobuf request object.
diff --git a/google/pubsub_v1/services/subscriber/pagers.py b/google/pubsub_v1/services/subscriber/pagers.py
index 713184d79..b7ec9f6e3 100644
--- a/google/pubsub_v1/services/subscriber/pagers.py
+++ b/google/pubsub_v1/services/subscriber/pagers.py
@@ -15,7 +15,16 @@
# limitations under the License.
#
-from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple
+from typing import (
+ Any,
+ AsyncIterable,
+ Awaitable,
+ Callable,
+ Iterable,
+ Sequence,
+ Tuple,
+ Optional,
+)
from google.pubsub_v1.types import pubsub
@@ -24,7 +33,7 @@ class ListSubscriptionsPager:
"""A pager for iterating through ``list_subscriptions`` requests.
This class thinly wraps an initial
- :class:`~.pubsub.ListSubscriptionsResponse` object, and
+ :class:`google.pubsub_v1.types.ListSubscriptionsResponse` object, and
provides an ``__iter__`` method to iterate through its
``subscriptions`` field.
@@ -33,7 +42,7 @@ class ListSubscriptionsPager:
through the ``subscriptions`` field on the
corresponding responses.
- All the usual :class:`~.pubsub.ListSubscriptionsResponse`
+ All the usual :class:`google.pubsub_v1.types.ListSubscriptionsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""
@@ -51,9 +60,9 @@ def __init__(
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
- request (:class:`~.pubsub.ListSubscriptionsRequest`):
+ request (google.pubsub_v1.types.ListSubscriptionsRequest):
The initial request object.
- response (:class:`~.pubsub.ListSubscriptionsResponse`):
+ response (google.pubsub_v1.types.ListSubscriptionsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
@@ -86,7 +95,7 @@ class ListSubscriptionsAsyncPager:
"""A pager for iterating through ``list_subscriptions`` requests.
This class thinly wraps an initial
- :class:`~.pubsub.ListSubscriptionsResponse` object, and
+ :class:`google.pubsub_v1.types.ListSubscriptionsResponse` object, and
provides an ``__aiter__`` method to iterate through its
``subscriptions`` field.
@@ -95,7 +104,7 @@ class ListSubscriptionsAsyncPager:
through the ``subscriptions`` field on the
corresponding responses.
- All the usual :class:`~.pubsub.ListSubscriptionsResponse`
+ All the usual :class:`google.pubsub_v1.types.ListSubscriptionsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""
@@ -113,9 +122,9 @@ def __init__(
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
- request (:class:`~.pubsub.ListSubscriptionsRequest`):
+ request (google.pubsub_v1.types.ListSubscriptionsRequest):
The initial request object.
- response (:class:`~.pubsub.ListSubscriptionsResponse`):
+ response (google.pubsub_v1.types.ListSubscriptionsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
@@ -152,7 +161,7 @@ class ListSnapshotsPager:
"""A pager for iterating through ``list_snapshots`` requests.
This class thinly wraps an initial
- :class:`~.pubsub.ListSnapshotsResponse` object, and
+ :class:`google.pubsub_v1.types.ListSnapshotsResponse` object, and
provides an ``__iter__`` method to iterate through its
``snapshots`` field.
@@ -161,7 +170,7 @@ class ListSnapshotsPager:
through the ``snapshots`` field on the
corresponding responses.
- All the usual :class:`~.pubsub.ListSnapshotsResponse`
+ All the usual :class:`google.pubsub_v1.types.ListSnapshotsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""
@@ -179,9 +188,9 @@ def __init__(
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
- request (:class:`~.pubsub.ListSnapshotsRequest`):
+ request (google.pubsub_v1.types.ListSnapshotsRequest):
The initial request object.
- response (:class:`~.pubsub.ListSnapshotsResponse`):
+ response (google.pubsub_v1.types.ListSnapshotsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
@@ -214,7 +223,7 @@ class ListSnapshotsAsyncPager:
"""A pager for iterating through ``list_snapshots`` requests.
This class thinly wraps an initial
- :class:`~.pubsub.ListSnapshotsResponse` object, and
+ :class:`google.pubsub_v1.types.ListSnapshotsResponse` object, and
provides an ``__aiter__`` method to iterate through its
``snapshots`` field.
@@ -223,7 +232,7 @@ class ListSnapshotsAsyncPager:
through the ``snapshots`` field on the
corresponding responses.
- All the usual :class:`~.pubsub.ListSnapshotsResponse`
+ All the usual :class:`google.pubsub_v1.types.ListSnapshotsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""
@@ -241,9 +250,9 @@ def __init__(
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
- request (:class:`~.pubsub.ListSnapshotsRequest`):
+ request (google.pubsub_v1.types.ListSnapshotsRequest):
The initial request object.
- response (:class:`~.pubsub.ListSnapshotsResponse`):
+ response (google.pubsub_v1.types.ListSnapshotsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
diff --git a/google/pubsub_v1/services/subscriber/transports/grpc.py b/google/pubsub_v1/services/subscriber/transports/grpc.py
index 1be01d024..83815049e 100644
--- a/google/pubsub_v1/services/subscriber/transports/grpc.py
+++ b/google/pubsub_v1/services/subscriber/transports/grpc.py
@@ -63,6 +63,7 @@ def __init__(
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
+ client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id: Optional[str] = None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
@@ -93,6 +94,10 @@ def __init__(
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
+ client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
+ A callback to provide client certificate bytes and private key bytes,
+ both in PEM format. It is used to configure mutual TLS channel. It is
+ ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -109,6 +114,11 @@ def __init__(
"""
self._ssl_channel_credentials = ssl_channel_credentials
+ if api_mtls_endpoint:
+ warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
+ if client_cert_source:
+ warnings.warn("client_cert_source is deprecated", DeprecationWarning)
+
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
@@ -118,11 +128,6 @@ def __init__(
self._grpc_channel = channel
self._ssl_channel_credentials = None
elif api_mtls_endpoint:
- warnings.warn(
- "api_mtls_endpoint and client_cert_source are deprecated",
- DeprecationWarning,
- )
-
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
@@ -167,12 +172,18 @@ def __init__(
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
)
+ if client_cert_source_for_mtls and not ssl_channel_credentials:
+ cert, key = client_cert_source_for_mtls()
+ self._ssl_channel_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+
# create a new channel. The provided one is ignored.
self._grpc_channel = type(self).create_channel(
host,
credentials=credentials,
credentials_file=credentials_file,
- ssl_credentials=ssl_channel_credentials,
+ ssl_credentials=self._ssl_channel_credentials,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
options=[
diff --git a/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py b/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py
index fa89c11bc..d5efabf2f 100644
--- a/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py
+++ b/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py
@@ -107,6 +107,7 @@ def __init__(
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
+ client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id=None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
@@ -138,6 +139,10 @@ def __init__(
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
+ client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
+ A callback to provide client certificate bytes and private key bytes,
+ both in PEM format. It is used to configure mutual TLS channel. It is
+ ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -154,6 +159,11 @@ def __init__(
"""
self._ssl_channel_credentials = ssl_channel_credentials
+ if api_mtls_endpoint:
+ warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
+ if client_cert_source:
+ warnings.warn("client_cert_source is deprecated", DeprecationWarning)
+
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
@@ -163,11 +173,6 @@ def __init__(
self._grpc_channel = channel
self._ssl_channel_credentials = None
elif api_mtls_endpoint:
- warnings.warn(
- "api_mtls_endpoint and client_cert_source are deprecated",
- DeprecationWarning,
- )
-
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
@@ -212,12 +217,18 @@ def __init__(
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
)
+ if client_cert_source_for_mtls and not ssl_channel_credentials:
+ cert, key = client_cert_source_for_mtls()
+ self._ssl_channel_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+
# create a new channel. The provided one is ignored.
self._grpc_channel = type(self).create_channel(
host,
credentials=credentials,
credentials_file=credentials_file,
- ssl_credentials=ssl_channel_credentials,
+ ssl_credentials=self._ssl_channel_credentials,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
options=[
diff --git a/google/pubsub_v1/types/pubsub.py b/google/pubsub_v1/types/pubsub.py
index 39563bb58..001eea88a 100644
--- a/google/pubsub_v1/types/pubsub.py
+++ b/google/pubsub_v1/types/pubsub.py
@@ -104,7 +104,7 @@ class SchemaSettings(proto.Message):
``projects/{project}/schemas/{schema}``. The value of this
field will be ``_deleted-schema_`` if the schema has been
deleted.
- encoding (~.gp_schema.Encoding):
+ encoding (google.pubsub_v1.types.Encoding):
The encoding of messages validated against ``schema``.
"""
@@ -126,10 +126,10 @@ class Topic(proto.Message):
(``+``) or percent signs (``%``). It must be between 3 and
255 characters in length, and it must not start with
``"goog"``.
- labels (Sequence[~.pubsub.Topic.LabelsEntry]):
+ labels (Sequence[google.pubsub_v1.types.Topic.LabelsEntry]):
See [Creating and managing labels]
(https://cloud.google.com/pubsub/docs/labels).
- message_storage_policy (~.pubsub.MessageStoragePolicy):
+ message_storage_policy (google.pubsub_v1.types.MessageStoragePolicy):
Policy constraining the set of Google Cloud
Platform regions where messages published to the
topic may be stored. If not present, then no
@@ -140,7 +140,7 @@ class Topic(proto.Message):
The expected format is
``projects/*/locations/*/keyRings/*/cryptoKeys/*``.
- schema_settings (~.pubsub.SchemaSettings):
+ schema_settings (google.pubsub_v1.types.SchemaSettings):
Settings for validating messages published
against a schema.
EXPERIMENTAL: Schema support is in development
@@ -182,7 +182,7 @@ class PubsubMessage(proto.Message):
The message data field. If this field is
empty, the message must contain at least one
attribute.
- attributes (Sequence[~.pubsub.PubsubMessage.AttributesEntry]):
+ attributes (Sequence[google.pubsub_v1.types.PubsubMessage.AttributesEntry]):
Attributes for this message. If this field is
empty, the message must contain non-empty data.
This can be used to filter messages on the
@@ -194,7 +194,7 @@ class PubsubMessage(proto.Message):
``PubsubMessage`` via a ``Pull`` call or a push delivery. It
must not be populated by the publisher in a ``Publish``
call.
- publish_time (~.timestamp.Timestamp):
+ publish_time (google.protobuf.timestamp_pb2.Timestamp):
The time at which the message was published, populated by
the server when it receives the ``Publish`` call. It must
not be populated by the publisher in a ``Publish`` call.
@@ -236,9 +236,9 @@ class UpdateTopicRequest(proto.Message):
r"""Request for the UpdateTopic method.
Attributes:
- topic (~.pubsub.Topic):
+ topic (google.pubsub_v1.types.Topic):
Required. The updated topic object.
- update_mask (~.field_mask.FieldMask):
+ update_mask (google.protobuf.field_mask_pb2.FieldMask):
Required. Indicates which fields in the provided topic to
update. Must be specified and non-empty. Note that if
``update_mask`` contains "message_storage_policy" but the
@@ -259,7 +259,7 @@ class PublishRequest(proto.Message):
topic (str):
Required. The messages in the request will be published on
this topic. Format is ``projects/{project}/topics/{topic}``.
- messages (Sequence[~.pubsub.PubsubMessage]):
+ messages (Sequence[google.pubsub_v1.types.PubsubMessage]):
Required. The messages to publish.
"""
@@ -309,7 +309,7 @@ class ListTopicsResponse(proto.Message):
r"""Response for the ``ListTopics`` method.
Attributes:
- topics (Sequence[~.pubsub.Topic]):
+ topics (Sequence[google.pubsub_v1.types.Topic]):
The resulting topics.
next_page_token (str):
If not empty, indicates that there may be more topics that
@@ -468,7 +468,7 @@ class Subscription(proto.Message):
``projects/{project}/topics/{topic}``. The value of this
field will be ``_deleted-topic_`` if the topic has been
deleted.
- push_config (~.pubsub.PushConfig):
+ push_config (google.pubsub_v1.types.PushConfig):
If push delivery is used with this subscription, this field
is used to configure it. An empty ``pushConfig`` signifies
that the subscriber will pull and ack messages using API
@@ -503,7 +503,7 @@ class Subscription(proto.Message):
of the ``message_retention_duration`` window. This must be
true if you would like to [Seek to a timestamp]
(https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time).
- message_retention_duration (~.duration.Duration):
+ message_retention_duration (google.protobuf.duration_pb2.Duration):
How long to retain unacknowledged messages in the
subscription's backlog, from the moment a message is
published. If ``retain_acked_messages`` is true, then this
@@ -511,7 +511,7 @@ class Subscription(proto.Message):
thus configures how far back in time a ``Seek`` can be done.
Defaults to 7 days. Cannot be more than 7 days or less than
10 minutes.
- labels (Sequence[~.pubsub.Subscription.LabelsEntry]):
+ labels (Sequence[google.pubsub_v1.types.Subscription.LabelsEntry]):
See
Creating and managing labels.
@@ -520,7 +520,7 @@ class Subscription(proto.Message):
in ``PubsubMessage`` will be delivered to the subscribers in
the order in which they are received by the Pub/Sub system.
Otherwise, they may be delivered in any order.
- expiration_policy (~.pubsub.ExpirationPolicy):
+ expiration_policy (google.pubsub_v1.types.ExpirationPolicy):
A policy that specifies the conditions for this
subscription's expiration. A subscription is considered
active as long as any connected subscriber is successfully
@@ -536,7 +536,7 @@ class Subscription(proto.Message):
``attributes`` field matches the filter are delivered on
this subscription. If empty, then no messages are filtered
out.
- dead_letter_policy (~.pubsub.DeadLetterPolicy):
+ dead_letter_policy (google.pubsub_v1.types.DeadLetterPolicy):
A policy that specifies the conditions for dead lettering
messages in this subscription. If dead_letter_policy is not
set, dead lettering is disabled.
@@ -546,7 +546,7 @@ class Subscription(proto.Message):
service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com)
must have permission to Acknowledge() messages on this
subscription.
- retry_policy (~.pubsub.RetryPolicy):
+ retry_policy (google.pubsub_v1.types.RetryPolicy):
A policy that specifies how Pub/Sub retries
message delivery for this subscription.
@@ -613,12 +613,12 @@ class RetryPolicy(proto.Message):
backoff.
Attributes:
- minimum_backoff (~.duration.Duration):
+ minimum_backoff (google.protobuf.duration_pb2.Duration):
The minimum delay between consecutive
deliveries of a given message. Value should be
between 0 and 600 seconds. Defaults to 10
seconds.
- maximum_backoff (~.duration.Duration):
+ maximum_backoff (google.protobuf.duration_pb2.Duration):
The maximum delay between consecutive
deliveries of a given message. Value should be
between 0 and 600 seconds. Defaults to 600
@@ -679,7 +679,7 @@ class ExpirationPolicy(proto.Message):
expiration (i.e., automatic resource deletion).
Attributes:
- ttl (~.duration.Duration):
+ ttl (google.protobuf.duration_pb2.Duration):
Specifies the "time-to-live" duration for an associated
resource. The resource expires if it is not active for a
period of ``ttl``. The definition of "activity" depends on
@@ -700,7 +700,7 @@ class PushConfig(proto.Message):
A URL locating the endpoint to which messages should be
pushed. For example, a Webhook endpoint might use
``https://example.com/push``.
- attributes (Sequence[~.pubsub.PushConfig.AttributesEntry]):
+ attributes (Sequence[google.pubsub_v1.types.PushConfig.AttributesEntry]):
Endpoint configuration attributes that can be used to
control different aspects of the message delivery.
@@ -730,7 +730,7 @@ class PushConfig(proto.Message):
.. raw:: html
attributes { "x-goog-version": "v1" }
- oidc_token (~.pubsub.PushConfig.OidcToken):
+ oidc_token (google.pubsub_v1.types.PushConfig.OidcToken):
If specified, Pub/Sub will generate and attach an OIDC JWT
token as an ``Authorization`` header in the HTTP request for
every pushed message.
@@ -781,7 +781,7 @@ class ReceivedMessage(proto.Message):
ack_id (str):
This ID can be used to acknowledge the
received message.
- message (~.pubsub.PubsubMessage):
+ message (google.pubsub_v1.types.PubsubMessage):
The message.
delivery_attempt (int):
The approximate number of times that Cloud Pub/Sub has
@@ -827,9 +827,9 @@ class UpdateSubscriptionRequest(proto.Message):
r"""Request for the UpdateSubscription method.
Attributes:
- subscription (~.pubsub.Subscription):
+ subscription (google.pubsub_v1.types.Subscription):
Required. The updated subscription object.
- update_mask (~.field_mask.FieldMask):
+ update_mask (google.protobuf.field_mask_pb2.FieldMask):
Required. Indicates which fields in the
provided subscription to update. Must be
specified and non-empty.
@@ -867,7 +867,7 @@ class ListSubscriptionsResponse(proto.Message):
r"""Response for the ``ListSubscriptions`` method.
Attributes:
- subscriptions (Sequence[~.pubsub.Subscription]):
+ subscriptions (Sequence[google.pubsub_v1.types.Subscription]):
The subscriptions that match the request.
next_page_token (str):
If not empty, indicates that there may be more subscriptions
@@ -905,7 +905,7 @@ class ModifyPushConfigRequest(proto.Message):
subscription (str):
Required. The name of the subscription. Format is
``projects/{project}/subscriptions/{sub}``.
- push_config (~.pubsub.PushConfig):
+ push_config (google.pubsub_v1.types.PushConfig):
Required. The push configuration for future deliveries.
An empty ``pushConfig`` indicates that the Pub/Sub system
@@ -955,7 +955,7 @@ class PullResponse(proto.Message):
r"""Response for the ``Pull`` method.
Attributes:
- received_messages (Sequence[~.pubsub.ReceivedMessage]):
+ received_messages (Sequence[google.pubsub_v1.types.ReceivedMessage]):
Received Pub/Sub messages. The list will be empty if there
are no more messages available in the backlog. For JSON, the
response can be entirely empty. The Pub/Sub system may
@@ -1122,7 +1122,7 @@ class StreamingPullResponse(proto.Message):
stream messages from the server to the client.
Attributes:
- received_messages (Sequence[~.pubsub.ReceivedMessage]):
+ received_messages (Sequence[google.pubsub_v1.types.ReceivedMessage]):
Received Pub/Sub messages. This will not be
empty.
"""
@@ -1154,7 +1154,7 @@ class CreateSnapshotRequest(proto.Message):
topic following the successful completion of the
CreateSnapshot request. Format is
``projects/{project}/subscriptions/{sub}``.
- labels (Sequence[~.pubsub.CreateSnapshotRequest.LabelsEntry]):
+ labels (Sequence[google.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry]):
See
Creating and managing labels.
@@ -1171,9 +1171,9 @@ class UpdateSnapshotRequest(proto.Message):
r"""Request for the UpdateSnapshot method.
Attributes:
- snapshot (~.pubsub.Snapshot):
+ snapshot (google.pubsub_v1.types.Snapshot):
Required. The updated snapshot object.
- update_mask (~.field_mask.FieldMask):
+ update_mask (google.protobuf.field_mask_pb2.FieldMask):
Required. Indicates which fields in the
provided snapshot to update. Must be specified
and non-empty.
@@ -1197,7 +1197,7 @@ class Snapshot(proto.Message):
topic (str):
The name of the topic from which this
snapshot is retaining messages.
- expire_time (~.timestamp.Timestamp):
+ expire_time (google.protobuf.timestamp_pb2.Timestamp):
The snapshot is guaranteed to exist up until this time. A
newly-created snapshot expires no later than 7 days from the
time of its creation. Its exact lifetime is determined at
@@ -1211,7 +1211,7 @@ class Snapshot(proto.Message):
expire in 4 days. The service will refuse to create a
snapshot that would expire in less than 1 hour after
creation.
- labels (Sequence[~.pubsub.Snapshot.LabelsEntry]):
+ labels (Sequence[google.pubsub_v1.types.Snapshot.LabelsEntry]):
See [Creating and managing labels]
(https://cloud.google.com/pubsub/docs/labels).
"""
@@ -1264,7 +1264,7 @@ class ListSnapshotsResponse(proto.Message):
r"""Response for the ``ListSnapshots`` method.
Attributes:
- snapshots (Sequence[~.pubsub.Snapshot]):
+ snapshots (Sequence[google.pubsub_v1.types.Snapshot]):
The resulting snapshots.
next_page_token (str):
If not empty, indicates that there may be more snapshot that
@@ -1299,7 +1299,7 @@ class SeekRequest(proto.Message):
Attributes:
subscription (str):
Required. The subscription to affect.
- time (~.timestamp.Timestamp):
+ time (google.protobuf.timestamp_pb2.Timestamp):
The time to seek to. Messages retained in the subscription
that were published before this time are marked as
acknowledged, and messages retained in the subscription that
diff --git a/google/pubsub_v1/types/schema.py b/google/pubsub_v1/types/schema.py
index 2efa667c1..e4f71d132 100644
--- a/google/pubsub_v1/types/schema.py
+++ b/google/pubsub_v1/types/schema.py
@@ -60,7 +60,7 @@ class Schema(proto.Message):
name (str):
Required. Name of the schema. Format is
``projects/{project}/schemas/{schema}``.
- type_ (~.gp_schema.Schema.Type):
+ type_ (google.pubsub_v1.types.Schema.Type):
The type of the schema definition.
definition (str):
The definition of the schema. This should contain a string
@@ -88,7 +88,7 @@ class CreateSchemaRequest(proto.Message):
parent (str):
Required. The name of the project in which to create the
schema. Format is ``projects/{project-id}``.
- schema (~.gp_schema.Schema):
+ schema (google.pubsub_v1.types.Schema):
Required. The schema object to create.
This schema's ``name`` parameter is ignored. The schema
@@ -117,7 +117,7 @@ class GetSchemaRequest(proto.Message):
name (str):
Required. The name of the schema to get. Format is
``projects/{project}/schemas/{schema}``.
- view (~.gp_schema.SchemaView):
+ view (google.pubsub_v1.types.SchemaView):
The set of fields to return in the response. If not set,
returns a Schema with ``name`` and ``type``, but not
``definition``. Set to ``FULL`` to retrieve all fields.
@@ -135,7 +135,7 @@ class ListSchemasRequest(proto.Message):
parent (str):
Required. The name of the project in which to list schemas.
Format is ``projects/{project-id}``.
- view (~.gp_schema.SchemaView):
+ view (google.pubsub_v1.types.SchemaView):
The set of Schema fields to return in the response. If not
set, returns Schemas with ``name`` and ``type``, but not
``definition``. Set to ``FULL`` to retrieve all fields.
@@ -161,7 +161,7 @@ class ListSchemasResponse(proto.Message):
r"""Response for the ``ListSchemas`` method.
Attributes:
- schemas (Sequence[~.gp_schema.Schema]):
+ schemas (Sequence[google.pubsub_v1.types.Schema]):
The resulting schemas.
next_page_token (str):
If not empty, indicates that there may be more schemas that
@@ -197,7 +197,7 @@ class ValidateSchemaRequest(proto.Message):
parent (str):
Required. The name of the project in which to validate
schemas. Format is ``projects/{project-id}``.
- schema (~.gp_schema.Schema):
+ schema (google.pubsub_v1.types.Schema):
Required. The schema object to validate.
"""
@@ -221,11 +221,11 @@ class ValidateMessageRequest(proto.Message):
Name of the schema against which to validate.
Format is ``projects/{project}/schemas/{schema}``.
- schema (~.gp_schema.Schema):
+ schema (google.pubsub_v1.types.Schema):
Ad-hoc schema against which to validate
message (bytes):
Message to validate against the provided ``schema_spec``.
- encoding (~.gp_schema.Encoding):
+ encoding (google.pubsub_v1.types.Encoding):
The encoding expected for messages
"""
diff --git a/noxfile.py b/noxfile.py
index 913f271d5..6b178ad18 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -30,6 +30,17 @@
SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"]
UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"]
+# 'docfx' is excluded since it only needs to run in 'docs-presubmit'
+nox.options.sessions = [
+ "unit",
+ "system",
+ "cover",
+ "lint",
+ "lint_setup_py",
+ "blacken",
+ "docs",
+]
+
@nox.session(python=DEFAULT_PYTHON_VERSION)
def lint(session):
@@ -75,12 +86,14 @@ def default(session):
session.install(
"mock", "pytest", "pytest-cov",
)
+
session.install("-e", ".")
# Run py.test against the unit tests.
session.run(
"py.test",
"--quiet",
+ f"--junitxml=unit_{session.python}_sponge_log.xml",
"--cov=google/cloud",
"--cov=tests/unit",
"--cov-append",
@@ -127,9 +140,21 @@ def system(session):
# Run py.test against the system tests.
if system_test_exists:
- session.run("py.test", "--quiet", system_test_path, *session.posargs)
+ session.run(
+ "py.test",
+ "--quiet",
+ f"--junitxml=system_{session.python}_sponge_log.xml",
+ system_test_path,
+ *session.posargs,
+ )
if system_test_folder_exists:
- session.run("py.test", "--quiet", system_test_folder_path, *session.posargs)
+ session.run(
+ "py.test",
+ "--quiet",
+ f"--junitxml=system_{session.python}_sponge_log.xml",
+ system_test_folder_path,
+ *session.posargs,
+ )
@nox.session(python=DEFAULT_PYTHON_VERSION)
diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py
index bca0522ec..97bf7da80 100644
--- a/samples/snippets/noxfile.py
+++ b/samples/snippets/noxfile.py
@@ -85,7 +85,7 @@ def get_pytest_env_vars() -> Dict[str, str]:
# DO NOT EDIT - automatically generated.
# All versions used to tested samples.
-ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"]
+ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"]
# Any default versions that should be ignored.
IGNORED_VERSIONS = TEST_CONFIG['ignored_versions']
diff --git a/synth.metadata b/synth.metadata
index d4b5ca201..8d6a7126f 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -4,36 +4,36 @@
"git": {
"name": ".",
"remote": "git@github.com:plamut/python-pubsub.git",
- "sha": "a4eab77decdd7ea0d421b56a784e8a673a5595ec"
+ "sha": "12307d8f12d96974130c7a49bd1eba4d62956f21"
}
},
{
"git": {
"name": "googleapis",
"remote": "https://github.com/googleapis/googleapis.git",
- "sha": "61ab0348bd228c942898aee291d677f0afdb888c",
- "internalRef": "352069361"
+ "sha": "8b3d36daaf5561496b7d4075fba4f2c52d18ca1c",
+ "internalRef": "359285402"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "56ddc68f36b32341e9f22c2c59b4ce6aa3ba635f"
+ "sha": "79ab0b44a2cc7d803d07c107f9faf07729fc4012"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "56ddc68f36b32341e9f22c2c59b4ce6aa3ba635f"
+ "sha": "79ab0b44a2cc7d803d07c107f9faf07729fc4012"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "56ddc68f36b32341e9f22c2c59b4ce6aa3ba635f"
+ "sha": "79ab0b44a2cc7d803d07c107f9faf07729fc4012"
}
}
],
diff --git a/synth.py b/synth.py
index d2ade4b27..2c0bc5607 100644
--- a/synth.py
+++ b/synth.py
@@ -79,6 +79,50 @@
if count < 18:
raise Exception("Expected replacements for gRPC channel options not made.")
+# If the emulator is used, force an insecure gRPC channel to avoid SSL errors.
+clients_to_patch = [
+ "google/pubsub_v1/services/publisher/client.py",
+ "google/pubsub_v1/services/subscriber/client.py",
+]
+err_msg = "Expected replacements for gRPC channel to use with the emulator not made."
+
+count = s.replace(
+ clients_to_patch,
+ r"import os",
+ "import functools\n\g<0>"
+)
+
+if count < len(clients_to_patch):
+ raise Exception(err_msg)
+
+count = s.replace(
+ clients_to_patch,
+ r"from google\.pubsub_v1\.types import pubsub",
+ "\g<0>\n\nimport grpc"
+)
+
+if count < len(clients_to_patch):
+ raise Exception(err_msg)
+
+count = s.replace(
+ clients_to_patch,
+ r"Transport = type\(self\)\.get_transport_class\(transport\)",
+ """\g<0>
+
+ emulator_host = os.environ.get("PUBSUB_EMULATOR_HOST")
+ if emulator_host:
+ if issubclass(Transport, type(self)._transport_registry["grpc"]):
+ channel = grpc.insecure_channel(target=emulator_host)
+ else:
+ channel = grpc.aio.insecure_channel(target=emulator_host)
+ Transport = functools.partial(Transport, channel=channel)
+
+ """,
+)
+
+if count < len(clients_to_patch):
+ raise Exception(err_msg)
+
# Monkey patch the streaming_pull() GAPIC method to disable pre-fetching stream
# results.
s.replace(
diff --git a/tests/unit/gapic/pubsub_v1/test_publisher.py b/tests/unit/gapic/pubsub_v1/test_publisher.py
index d1c34d474..cf24f5273 100644
--- a/tests/unit/gapic/pubsub_v1/test_publisher.py
+++ b/tests/unit/gapic/pubsub_v1/test_publisher.py
@@ -85,7 +85,20 @@ def test__get_default_mtls_endpoint():
assert PublisherClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi
-@pytest.mark.parametrize("client_class", [PublisherClient, PublisherAsyncClient])
+def test_publisher_client_from_service_account_info():
+ creds = credentials.AnonymousCredentials()
+ with mock.patch.object(
+ service_account.Credentials, "from_service_account_info"
+ ) as factory:
+ factory.return_value = creds
+ info = {"valid": True}
+ client = PublisherClient.from_service_account_info(info)
+ assert client.transport._credentials == creds
+
+ assert client.transport._host == "pubsub.googleapis.com:443"
+
+
+@pytest.mark.parametrize("client_class", [PublisherClient, PublisherAsyncClient,])
def test_publisher_client_from_service_account_file(client_class):
creds = credentials.AnonymousCredentials()
with mock.patch.object(
@@ -103,7 +116,10 @@ def test_publisher_client_from_service_account_file(client_class):
def test_publisher_client_get_transport_class():
transport = PublisherClient.get_transport_class()
- assert transport == transports.PublisherGrpcTransport
+ available_transports = [
+ transports.PublisherGrpcTransport,
+ ]
+ assert transport in available_transports
transport = PublisherClient.get_transport_class("grpc")
assert transport == transports.PublisherGrpcTransport
@@ -150,7 +166,7 @@ def test_publisher_client_client_options(client_class, transport_class, transpor
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -166,7 +182,7 @@ def test_publisher_client_client_options(client_class, transport_class, transpor
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -182,7 +198,7 @@ def test_publisher_client_client_options(client_class, transport_class, transpor
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -210,7 +226,7 @@ def test_publisher_client_client_options(client_class, transport_class, transpor
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id="octopus",
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -259,29 +275,25 @@ def test_publisher_client_mtls_env_auto(
client_cert_source=client_cert_source_callback
)
with mock.patch.object(transport_class, "__init__") as patched:
- ssl_channel_creds = mock.Mock()
- with mock.patch(
- "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
- ):
- patched.return_value = None
- client = client_class(client_options=options)
+ patched.return_value = None
+ client = client_class(client_options=options)
- if use_client_cert_env == "false":
- expected_ssl_channel_creds = None
- expected_host = client.DEFAULT_ENDPOINT
- else:
- expected_ssl_channel_creds = ssl_channel_creds
- expected_host = client.DEFAULT_MTLS_ENDPOINT
+ if use_client_cert_env == "false":
+ expected_client_cert_source = None
+ expected_host = client.DEFAULT_ENDPOINT
+ else:
+ expected_client_cert_source = client_cert_source_callback
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=expected_host,
+ scopes=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
# Check the case ADC client cert is provided. Whether client cert is used depends on
# GOOGLE_API_USE_CLIENT_CERTIFICATE value.
@@ -290,66 +302,53 @@ def test_publisher_client_mtls_env_auto(
):
with mock.patch.object(transport_class, "__init__") as patched:
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=True,
):
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.ssl_credentials",
- new_callable=mock.PropertyMock,
- ) as ssl_credentials_mock:
- if use_client_cert_env == "false":
- is_mtls_mock.return_value = False
- ssl_credentials_mock.return_value = None
- expected_host = client.DEFAULT_ENDPOINT
- expected_ssl_channel_creds = None
- else:
- is_mtls_mock.return_value = True
- ssl_credentials_mock.return_value = mock.Mock()
- expected_host = client.DEFAULT_MTLS_ENDPOINT
- expected_ssl_channel_creds = (
- ssl_credentials_mock.return_value
- )
-
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ "google.auth.transport.mtls.default_client_cert_source",
+ return_value=client_cert_source_callback,
+ ):
+ if use_client_cert_env == "false":
+ expected_host = client.DEFAULT_ENDPOINT
+ expected_client_cert_source = None
+ else:
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
+ expected_client_cert_source = client_cert_source_callback
- # Check the case client_cert_source and ADC client cert are not provided.
- with mock.patch.dict(
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
- ):
- with mock.patch.object(transport_class, "__init__") as patched:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
- ):
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- is_mtls_mock.return_value = False
patched.return_value = None
client = client_class()
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
+ host=expected_host,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
+ # Check the case client_cert_source and ADC client cert are not provided.
+ with mock.patch.dict(
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
+ ):
+ with mock.patch.object(transport_class, "__init__") as patched:
+ with mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=False,
+ ):
+ patched.return_value = None
+ client = client_class()
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=client.DEFAULT_ENDPOINT,
+ scopes=None,
+ client_cert_source_for_mtls=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
+
@pytest.mark.parametrize(
"client_class,transport_class,transport_name",
@@ -375,7 +374,7 @@ def test_publisher_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -405,7 +404,7 @@ def test_publisher_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -422,7 +421,7 @@ def test_publisher_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -2492,7 +2491,7 @@ def test_transport_get_channel():
@pytest.mark.parametrize(
"transport_class",
- [transports.PublisherGrpcTransport, transports.PublisherGrpcAsyncIOTransport],
+ [transports.PublisherGrpcTransport, transports.PublisherGrpcAsyncIOTransport,],
)
def test_transport_adc(transport_class):
# Test default credentials are used if not provided.
@@ -2612,6 +2611,52 @@ def test_publisher_transport_auth_adc():
)
+@pytest.mark.parametrize(
+ "transport_class",
+ [transports.PublisherGrpcTransport, transports.PublisherGrpcAsyncIOTransport],
+)
+def test_publisher_grpc_transport_client_cert_source_for_mtls(transport_class):
+ cred = credentials.AnonymousCredentials()
+
+ # Check ssl_channel_credentials is used if provided.
+ with mock.patch.object(transport_class, "create_channel") as mock_create_channel:
+ mock_ssl_channel_creds = mock.Mock()
+ transport_class(
+ host="squid.clam.whelk",
+ credentials=cred,
+ ssl_channel_credentials=mock_ssl_channel_creds,
+ )
+ mock_create_channel.assert_called_once_with(
+ "squid.clam.whelk:443",
+ credentials=cred,
+ credentials_file=None,
+ scopes=(
+ "https://www.googleapis.com/auth/cloud-platform",
+ "https://www.googleapis.com/auth/pubsub",
+ ),
+ ssl_credentials=mock_ssl_channel_creds,
+ quota_project_id=None,
+ options=[
+ ("grpc.max_send_message_length", -1),
+ ("grpc.max_receive_message_length", -1),
+ ("grpc.keepalive_time_ms", 30000),
+ ],
+ )
+
+ # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls
+ # is used.
+ with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()):
+ with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred:
+ transport_class(
+ credentials=cred,
+ client_cert_source_for_mtls=client_cert_source_callback,
+ )
+ expected_cert, expected_key = client_cert_source_callback()
+ mock_ssl_cred.assert_called_once_with(
+ certificate_chain=expected_cert, private_key=expected_key
+ )
+
+
def test_publisher_host_no_port():
client = PublisherClient(
credentials=credentials.AnonymousCredentials(),
@@ -2633,7 +2678,7 @@ def test_publisher_host_with_port():
def test_publisher_grpc_transport_channel():
- channel = grpc.insecure_channel("http://localhost/")
+ channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials())
# Check that channel is used if provided.
transport = transports.PublisherGrpcTransport(
@@ -2645,7 +2690,7 @@ def test_publisher_grpc_transport_channel():
def test_publisher_grpc_asyncio_transport_channel():
- channel = aio.insecure_channel("http://localhost/")
+ channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials())
# Check that channel is used if provided.
transport = transports.PublisherGrpcAsyncIOTransport(
@@ -2656,6 +2701,8 @@ def test_publisher_grpc_asyncio_transport_channel():
assert transport._ssl_channel_credentials == None
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[transports.PublisherGrpcTransport, transports.PublisherGrpcAsyncIOTransport],
@@ -2665,7 +2712,7 @@ def test_publisher_transport_channel_mtls_with_client_cert_source(transport_clas
"grpc.ssl_channel_credentials", autospec=True
) as grpc_ssl_channel_cred:
with mock.patch.object(
- transport_class, "create_channel", autospec=True
+ transport_class, "create_channel"
) as grpc_create_channel:
mock_ssl_cred = mock.Mock()
grpc_ssl_channel_cred.return_value = mock_ssl_cred
@@ -2707,6 +2754,8 @@ def test_publisher_transport_channel_mtls_with_client_cert_source(transport_clas
assert transport._ssl_channel_credentials == mock_ssl_cred
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[transports.PublisherGrpcTransport, transports.PublisherGrpcAsyncIOTransport],
@@ -2719,7 +2768,7 @@ def test_publisher_transport_channel_mtls_with_adc(transport_class):
ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred),
):
with mock.patch.object(
- transport_class, "create_channel", autospec=True
+ transport_class, "create_channel"
) as grpc_create_channel:
mock_grpc_channel = mock.Mock()
grpc_create_channel.return_value = mock_grpc_channel
diff --git a/tests/unit/gapic/pubsub_v1/test_schema_service.py b/tests/unit/gapic/pubsub_v1/test_schema_service.py
index 79cc71324..7f2f9d055 100644
--- a/tests/unit/gapic/pubsub_v1/test_schema_service.py
+++ b/tests/unit/gapic/pubsub_v1/test_schema_service.py
@@ -88,8 +88,21 @@ def test__get_default_mtls_endpoint():
)
+def test_schema_service_client_from_service_account_info():
+ creds = credentials.AnonymousCredentials()
+ with mock.patch.object(
+ service_account.Credentials, "from_service_account_info"
+ ) as factory:
+ factory.return_value = creds
+ info = {"valid": True}
+ client = SchemaServiceClient.from_service_account_info(info)
+ assert client.transport._credentials == creds
+
+ assert client.transport._host == "pubsub.googleapis.com:443"
+
+
@pytest.mark.parametrize(
- "client_class", [SchemaServiceClient, SchemaServiceAsyncClient]
+ "client_class", [SchemaServiceClient, SchemaServiceAsyncClient,]
)
def test_schema_service_client_from_service_account_file(client_class):
creds = credentials.AnonymousCredentials()
@@ -108,7 +121,10 @@ def test_schema_service_client_from_service_account_file(client_class):
def test_schema_service_client_get_transport_class():
transport = SchemaServiceClient.get_transport_class()
- assert transport == transports.SchemaServiceGrpcTransport
+ available_transports = [
+ transports.SchemaServiceGrpcTransport,
+ ]
+ assert transport in available_transports
transport = SchemaServiceClient.get_transport_class("grpc")
assert transport == transports.SchemaServiceGrpcTransport
@@ -159,7 +175,7 @@ def test_schema_service_client_client_options(
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -175,7 +191,7 @@ def test_schema_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -191,7 +207,7 @@ def test_schema_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -219,7 +235,7 @@ def test_schema_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id="octopus",
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -270,29 +286,25 @@ def test_schema_service_client_mtls_env_auto(
client_cert_source=client_cert_source_callback
)
with mock.patch.object(transport_class, "__init__") as patched:
- ssl_channel_creds = mock.Mock()
- with mock.patch(
- "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
- ):
- patched.return_value = None
- client = client_class(client_options=options)
+ patched.return_value = None
+ client = client_class(client_options=options)
- if use_client_cert_env == "false":
- expected_ssl_channel_creds = None
- expected_host = client.DEFAULT_ENDPOINT
- else:
- expected_ssl_channel_creds = ssl_channel_creds
- expected_host = client.DEFAULT_MTLS_ENDPOINT
+ if use_client_cert_env == "false":
+ expected_client_cert_source = None
+ expected_host = client.DEFAULT_ENDPOINT
+ else:
+ expected_client_cert_source = client_cert_source_callback
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=expected_host,
+ scopes=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
# Check the case ADC client cert is provided. Whether client cert is used depends on
# GOOGLE_API_USE_CLIENT_CERTIFICATE value.
@@ -301,66 +313,53 @@ def test_schema_service_client_mtls_env_auto(
):
with mock.patch.object(transport_class, "__init__") as patched:
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=True,
):
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.ssl_credentials",
- new_callable=mock.PropertyMock,
- ) as ssl_credentials_mock:
- if use_client_cert_env == "false":
- is_mtls_mock.return_value = False
- ssl_credentials_mock.return_value = None
- expected_host = client.DEFAULT_ENDPOINT
- expected_ssl_channel_creds = None
- else:
- is_mtls_mock.return_value = True
- ssl_credentials_mock.return_value = mock.Mock()
- expected_host = client.DEFAULT_MTLS_ENDPOINT
- expected_ssl_channel_creds = (
- ssl_credentials_mock.return_value
- )
-
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ "google.auth.transport.mtls.default_client_cert_source",
+ return_value=client_cert_source_callback,
+ ):
+ if use_client_cert_env == "false":
+ expected_host = client.DEFAULT_ENDPOINT
+ expected_client_cert_source = None
+ else:
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
+ expected_client_cert_source = client_cert_source_callback
- # Check the case client_cert_source and ADC client cert are not provided.
- with mock.patch.dict(
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
- ):
- with mock.patch.object(transport_class, "__init__") as patched:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
- ):
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- is_mtls_mock.return_value = False
patched.return_value = None
client = client_class()
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
+ host=expected_host,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
+ # Check the case client_cert_source and ADC client cert are not provided.
+ with mock.patch.dict(
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
+ ):
+ with mock.patch.object(transport_class, "__init__") as patched:
+ with mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=False,
+ ):
+ patched.return_value = None
+ client = client_class()
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=client.DEFAULT_ENDPOINT,
+ scopes=None,
+ client_cert_source_for_mtls=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
+
@pytest.mark.parametrize(
"client_class,transport_class,transport_name",
@@ -386,7 +385,7 @@ def test_schema_service_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -416,7 +415,7 @@ def test_schema_service_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -435,7 +434,7 @@ def test_schema_service_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -1847,6 +1846,55 @@ def test_schema_service_transport_auth_adc():
)
+@pytest.mark.parametrize(
+ "transport_class",
+ [
+ transports.SchemaServiceGrpcTransport,
+ transports.SchemaServiceGrpcAsyncIOTransport,
+ ],
+)
+def test_schema_service_grpc_transport_client_cert_source_for_mtls(transport_class):
+ cred = credentials.AnonymousCredentials()
+
+ # Check ssl_channel_credentials is used if provided.
+ with mock.patch.object(transport_class, "create_channel") as mock_create_channel:
+ mock_ssl_channel_creds = mock.Mock()
+ transport_class(
+ host="squid.clam.whelk",
+ credentials=cred,
+ ssl_channel_credentials=mock_ssl_channel_creds,
+ )
+ mock_create_channel.assert_called_once_with(
+ "squid.clam.whelk:443",
+ credentials=cred,
+ credentials_file=None,
+ scopes=(
+ "https://www.googleapis.com/auth/cloud-platform",
+ "https://www.googleapis.com/auth/pubsub",
+ ),
+ ssl_credentials=mock_ssl_channel_creds,
+ quota_project_id=None,
+ options=[
+ ("grpc.max_send_message_length", -1),
+ ("grpc.max_receive_message_length", -1),
+ ("grpc.keepalive_time_ms", 30000),
+ ],
+ )
+
+ # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls
+ # is used.
+ with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()):
+ with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred:
+ transport_class(
+ credentials=cred,
+ client_cert_source_for_mtls=client_cert_source_callback,
+ )
+ expected_cert, expected_key = client_cert_source_callback()
+ mock_ssl_cred.assert_called_once_with(
+ certificate_chain=expected_cert, private_key=expected_key
+ )
+
+
def test_schema_service_host_no_port():
client = SchemaServiceClient(
credentials=credentials.AnonymousCredentials(),
@@ -1868,7 +1916,7 @@ def test_schema_service_host_with_port():
def test_schema_service_grpc_transport_channel():
- channel = grpc.insecure_channel("http://localhost/")
+ channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials())
# Check that channel is used if provided.
transport = transports.SchemaServiceGrpcTransport(
@@ -1880,7 +1928,7 @@ def test_schema_service_grpc_transport_channel():
def test_schema_service_grpc_asyncio_transport_channel():
- channel = aio.insecure_channel("http://localhost/")
+ channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials())
# Check that channel is used if provided.
transport = transports.SchemaServiceGrpcAsyncIOTransport(
@@ -1891,6 +1939,8 @@ def test_schema_service_grpc_asyncio_transport_channel():
assert transport._ssl_channel_credentials == None
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[
@@ -1903,7 +1953,7 @@ def test_schema_service_transport_channel_mtls_with_client_cert_source(transport
"grpc.ssl_channel_credentials", autospec=True
) as grpc_ssl_channel_cred:
with mock.patch.object(
- transport_class, "create_channel", autospec=True
+ transport_class, "create_channel"
) as grpc_create_channel:
mock_ssl_cred = mock.Mock()
grpc_ssl_channel_cred.return_value = mock_ssl_cred
@@ -1945,6 +1995,8 @@ def test_schema_service_transport_channel_mtls_with_client_cert_source(transport
assert transport._ssl_channel_credentials == mock_ssl_cred
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[
@@ -1960,7 +2012,7 @@ def test_schema_service_transport_channel_mtls_with_adc(transport_class):
ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred),
):
with mock.patch.object(
- transport_class, "create_channel", autospec=True
+ transport_class, "create_channel"
) as grpc_create_channel:
mock_grpc_channel = mock.Mock()
grpc_create_channel.return_value = mock_grpc_channel
diff --git a/tests/unit/gapic/pubsub_v1/test_subscriber.py b/tests/unit/gapic/pubsub_v1/test_subscriber.py
index 8dec1c27d..2eb3503cd 100644
--- a/tests/unit/gapic/pubsub_v1/test_subscriber.py
+++ b/tests/unit/gapic/pubsub_v1/test_subscriber.py
@@ -87,7 +87,20 @@ def test__get_default_mtls_endpoint():
assert SubscriberClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi
-@pytest.mark.parametrize("client_class", [SubscriberClient, SubscriberAsyncClient])
+def test_subscriber_client_from_service_account_info():
+ creds = credentials.AnonymousCredentials()
+ with mock.patch.object(
+ service_account.Credentials, "from_service_account_info"
+ ) as factory:
+ factory.return_value = creds
+ info = {"valid": True}
+ client = SubscriberClient.from_service_account_info(info)
+ assert client.transport._credentials == creds
+
+ assert client.transport._host == "pubsub.googleapis.com:443"
+
+
+@pytest.mark.parametrize("client_class", [SubscriberClient, SubscriberAsyncClient,])
def test_subscriber_client_from_service_account_file(client_class):
creds = credentials.AnonymousCredentials()
with mock.patch.object(
@@ -105,7 +118,10 @@ def test_subscriber_client_from_service_account_file(client_class):
def test_subscriber_client_get_transport_class():
transport = SubscriberClient.get_transport_class()
- assert transport == transports.SubscriberGrpcTransport
+ available_transports = [
+ transports.SubscriberGrpcTransport,
+ ]
+ assert transport in available_transports
transport = SubscriberClient.get_transport_class("grpc")
assert transport == transports.SubscriberGrpcTransport
@@ -154,7 +170,7 @@ def test_subscriber_client_client_options(
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -170,7 +186,7 @@ def test_subscriber_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -186,7 +202,7 @@ def test_subscriber_client_client_options(
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -214,7 +230,7 @@ def test_subscriber_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id="octopus",
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -263,29 +279,25 @@ def test_subscriber_client_mtls_env_auto(
client_cert_source=client_cert_source_callback
)
with mock.patch.object(transport_class, "__init__") as patched:
- ssl_channel_creds = mock.Mock()
- with mock.patch(
- "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
- ):
- patched.return_value = None
- client = client_class(client_options=options)
+ patched.return_value = None
+ client = client_class(client_options=options)
- if use_client_cert_env == "false":
- expected_ssl_channel_creds = None
- expected_host = client.DEFAULT_ENDPOINT
- else:
- expected_ssl_channel_creds = ssl_channel_creds
- expected_host = client.DEFAULT_MTLS_ENDPOINT
+ if use_client_cert_env == "false":
+ expected_client_cert_source = None
+ expected_host = client.DEFAULT_ENDPOINT
+ else:
+ expected_client_cert_source = client_cert_source_callback
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=expected_host,
+ scopes=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
# Check the case ADC client cert is provided. Whether client cert is used depends on
# GOOGLE_API_USE_CLIENT_CERTIFICATE value.
@@ -294,66 +306,53 @@ def test_subscriber_client_mtls_env_auto(
):
with mock.patch.object(transport_class, "__init__") as patched:
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=True,
):
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.ssl_credentials",
- new_callable=mock.PropertyMock,
- ) as ssl_credentials_mock:
- if use_client_cert_env == "false":
- is_mtls_mock.return_value = False
- ssl_credentials_mock.return_value = None
- expected_host = client.DEFAULT_ENDPOINT
- expected_ssl_channel_creds = None
- else:
- is_mtls_mock.return_value = True
- ssl_credentials_mock.return_value = mock.Mock()
- expected_host = client.DEFAULT_MTLS_ENDPOINT
- expected_ssl_channel_creds = (
- ssl_credentials_mock.return_value
- )
-
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ "google.auth.transport.mtls.default_client_cert_source",
+ return_value=client_cert_source_callback,
+ ):
+ if use_client_cert_env == "false":
+ expected_host = client.DEFAULT_ENDPOINT
+ expected_client_cert_source = None
+ else:
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
+ expected_client_cert_source = client_cert_source_callback
- # Check the case client_cert_source and ADC client cert are not provided.
- with mock.patch.dict(
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
- ):
- with mock.patch.object(transport_class, "__init__") as patched:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
- ):
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- is_mtls_mock.return_value = False
patched.return_value = None
client = client_class()
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
+ host=expected_host,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
+ # Check the case client_cert_source and ADC client cert are not provided.
+ with mock.patch.dict(
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
+ ):
+ with mock.patch.object(transport_class, "__init__") as patched:
+ with mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=False,
+ ):
+ patched.return_value = None
+ client = client_class()
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=client.DEFAULT_ENDPOINT,
+ scopes=None,
+ client_cert_source_for_mtls=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
+
@pytest.mark.parametrize(
"client_class,transport_class,transport_name",
@@ -379,7 +378,7 @@ def test_subscriber_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -409,7 +408,7 @@ def test_subscriber_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -426,7 +425,7 @@ def test_subscriber_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -3754,7 +3753,7 @@ def test_transport_get_channel():
@pytest.mark.parametrize(
"transport_class",
- [transports.SubscriberGrpcTransport, transports.SubscriberGrpcAsyncIOTransport],
+ [transports.SubscriberGrpcTransport, transports.SubscriberGrpcAsyncIOTransport,],
)
def test_transport_adc(transport_class):
# Test default credentials are used if not provided.
@@ -3881,6 +3880,52 @@ def test_subscriber_transport_auth_adc():
)
+@pytest.mark.parametrize(
+ "transport_class",
+ [transports.SubscriberGrpcTransport, transports.SubscriberGrpcAsyncIOTransport],
+)
+def test_subscriber_grpc_transport_client_cert_source_for_mtls(transport_class):
+ cred = credentials.AnonymousCredentials()
+
+ # Check ssl_channel_credentials is used if provided.
+ with mock.patch.object(transport_class, "create_channel") as mock_create_channel:
+ mock_ssl_channel_creds = mock.Mock()
+ transport_class(
+ host="squid.clam.whelk",
+ credentials=cred,
+ ssl_channel_credentials=mock_ssl_channel_creds,
+ )
+ mock_create_channel.assert_called_once_with(
+ "squid.clam.whelk:443",
+ credentials=cred,
+ credentials_file=None,
+ scopes=(
+ "https://www.googleapis.com/auth/cloud-platform",
+ "https://www.googleapis.com/auth/pubsub",
+ ),
+ ssl_credentials=mock_ssl_channel_creds,
+ quota_project_id=None,
+ options=[
+ ("grpc.max_send_message_length", -1),
+ ("grpc.max_receive_message_length", -1),
+ ("grpc.keepalive_time_ms", 30000),
+ ],
+ )
+
+ # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls
+ # is used.
+ with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()):
+ with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred:
+ transport_class(
+ credentials=cred,
+ client_cert_source_for_mtls=client_cert_source_callback,
+ )
+ expected_cert, expected_key = client_cert_source_callback()
+ mock_ssl_cred.assert_called_once_with(
+ certificate_chain=expected_cert, private_key=expected_key
+ )
+
+
def test_subscriber_host_no_port():
client = SubscriberClient(
credentials=credentials.AnonymousCredentials(),
@@ -3902,7 +3947,7 @@ def test_subscriber_host_with_port():
def test_subscriber_grpc_transport_channel():
- channel = grpc.insecure_channel("http://localhost/")
+ channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials())
# Check that channel is used if provided.
transport = transports.SubscriberGrpcTransport(
@@ -3914,7 +3959,7 @@ def test_subscriber_grpc_transport_channel():
def test_subscriber_grpc_asyncio_transport_channel():
- channel = aio.insecure_channel("http://localhost/")
+ channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials())
# Check that channel is used if provided.
transport = transports.SubscriberGrpcAsyncIOTransport(
@@ -3925,6 +3970,8 @@ def test_subscriber_grpc_asyncio_transport_channel():
assert transport._ssl_channel_credentials == None
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[transports.SubscriberGrpcTransport, transports.SubscriberGrpcAsyncIOTransport],
@@ -3934,7 +3981,7 @@ def test_subscriber_transport_channel_mtls_with_client_cert_source(transport_cla
"grpc.ssl_channel_credentials", autospec=True
) as grpc_ssl_channel_cred:
with mock.patch.object(
- transport_class, "create_channel", autospec=True
+ transport_class, "create_channel"
) as grpc_create_channel:
mock_ssl_cred = mock.Mock()
grpc_ssl_channel_cred.return_value = mock_ssl_cred
@@ -3976,6 +4023,8 @@ def test_subscriber_transport_channel_mtls_with_client_cert_source(transport_cla
assert transport._ssl_channel_credentials == mock_ssl_cred
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[transports.SubscriberGrpcTransport, transports.SubscriberGrpcAsyncIOTransport],
@@ -3988,7 +4037,7 @@ def test_subscriber_transport_channel_mtls_with_adc(transport_class):
ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred),
):
with mock.patch.object(
- transport_class, "create_channel", autospec=True
+ transport_class, "create_channel"
) as grpc_create_channel:
mock_grpc_channel = mock.Mock()
grpc_create_channel.return_value = mock_grpc_channel