diff --git a/owl-bot-staging/v1/.coveragerc b/owl-bot-staging/v1/.coveragerc new file mode 100644 index 00000000..d59cabf2 --- /dev/null +++ b/owl-bot-staging/v1/.coveragerc @@ -0,0 +1,17 @@ +[run] +branch = True + +[report] +show_missing = True +omit = + google/cloud/pubsublite/__init__.py +exclude_lines = + # Re-enable the standard pragma + pragma: NO COVER + # Ignore debug-only repr + def __repr__ + # Ignore pkg_resources exceptions. + # This is added at the module level as a safeguard for if someone + # generates the code and tries to run it without pip installing. This + # makes it virtually impossible to test properly. + except pkg_resources.DistributionNotFound diff --git a/owl-bot-staging/v1/MANIFEST.in b/owl-bot-staging/v1/MANIFEST.in new file mode 100644 index 00000000..922de3e9 --- /dev/null +++ b/owl-bot-staging/v1/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include google/cloud/pubsublite *.py +recursive-include google/cloud/pubsublite_v1 *.py diff --git a/owl-bot-staging/v1/README.rst b/owl-bot-staging/v1/README.rst new file mode 100644 index 00000000..ffdb5e08 --- /dev/null +++ b/owl-bot-staging/v1/README.rst @@ -0,0 +1,49 @@ +Python Client for Google Cloud Pubsublite API +================================================= + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. Enable the Google Cloud Pubsublite API. +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + + +Mac/Linux +^^^^^^^^^ + +.. code-block:: console + + python3 -m venv + source /bin/activate + /bin/pip install /path/to/library + + +Windows +^^^^^^^ + +.. code-block:: console + + python3 -m venv + \Scripts\activate + \Scripts\pip.exe install \path\to\library diff --git a/owl-bot-staging/v1/docs/conf.py b/owl-bot-staging/v1/docs/conf.py new file mode 100644 index 00000000..5e4fc1c1 --- /dev/null +++ b/owl-bot-staging/v1/docs/conf.py @@ -0,0 +1,376 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# google-cloud-pubsublite documentation build configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath("..")) + +__version__ = "0.1.0" + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.6.3" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.coverage", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", +] + +# autodoc/autosummary flags +autoclass_content = "both" +autodoc_default_flags = ["members"] +autosummary_generate = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# Allow markdown includes (so releases.md can include CHANGLEOG.md) +# http://www.sphinx-doc.org/en/master/markdown.html +source_parsers = {".md": "recommonmark.parser.CommonMarkParser"} + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = [".rst", ".md"] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = u"google-cloud-pubsublite" +copyright = u"2020, Google, LLC" +author = u"Google APIs" # TODO: autogenerate this bit + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = ".".join(release.split(".")[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["_build"] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "alabaster" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "description": "Google Cloud Client Libraries for Python", + "github_user": "googleapis", + "github_repo": "google-cloud-python", + "github_banner": True, + "font_family": "'Roboto', Georgia, sans", + "head_font_family": "'Roboto', Georgia, serif", + "code_font_family": "'Roboto Mono', 'Consolas', monospace", +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = "google-cloud-pubsublite-doc" + +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [ + # Temporarily suppress this to avoid "more than one target found for + # cross-reference" warning, which are intractable for us to avoid while in + # a mono-repo. + # See https://github.com/sphinx-doc/sphinx/blob + # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 + "ref.python" +] + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', + # Latex figure (float) alignment + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + master_doc, + "google-cloud-pubsublite.tex", + u"google-cloud-pubsublite Documentation", + author, + "manual", + ) +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + master_doc, + "google-cloud-pubsublite", + u"Google Cloud Pubsublite Documentation", + [author], + 1, + ) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + master_doc, + "google-cloud-pubsublite", + u"google-cloud-pubsublite Documentation", + author, + "google-cloud-pubsublite", + "GAPIC library for Google Cloud Pubsublite API", + "APIs", + ) +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("http://python.readthedocs.org/en/latest/", None), + "gax": ("https://gax-python.readthedocs.org/en/latest/", None), + "google-auth": ("https://google-auth.readthedocs.io/en/stable", None), + "google-gax": ("https://gax-python.readthedocs.io/en/latest/", None), + "google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None), + "grpc": ("https://grpc.io/grpc/python/", None), + "requests": ("http://requests.kennethreitz.org/en/stable/", None), + "proto": ("https://proto-plus-python.readthedocs.io/en/stable", None), + "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), +} + + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/owl-bot-staging/v1/docs/index.rst b/owl-bot-staging/v1/docs/index.rst new file mode 100644 index 00000000..0f1caf8a --- /dev/null +++ b/owl-bot-staging/v1/docs/index.rst @@ -0,0 +1,7 @@ +API Reference +------------- +.. toctree:: + :maxdepth: 2 + + pubsublite_v1/services + pubsublite_v1/types diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/admin_service.rst b/owl-bot-staging/v1/docs/pubsublite_v1/admin_service.rst new file mode 100644 index 00000000..6053749b --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/admin_service.rst @@ -0,0 +1,10 @@ +AdminService +------------------------------ + +.. automodule:: google.cloud.pubsublite_v1.services.admin_service + :members: + :inherited-members: + +.. automodule:: google.cloud.pubsublite_v1.services.admin_service.pagers + :members: + :inherited-members: diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/cursor_service.rst b/owl-bot-staging/v1/docs/pubsublite_v1/cursor_service.rst new file mode 100644 index 00000000..40278003 --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/cursor_service.rst @@ -0,0 +1,10 @@ +CursorService +------------------------------- + +.. automodule:: google.cloud.pubsublite_v1.services.cursor_service + :members: + :inherited-members: + +.. automodule:: google.cloud.pubsublite_v1.services.cursor_service.pagers + :members: + :inherited-members: diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/partition_assignment_service.rst b/owl-bot-staging/v1/docs/pubsublite_v1/partition_assignment_service.rst new file mode 100644 index 00000000..39216dde --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/partition_assignment_service.rst @@ -0,0 +1,6 @@ +PartitionAssignmentService +-------------------------------------------- + +.. automodule:: google.cloud.pubsublite_v1.services.partition_assignment_service + :members: + :inherited-members: diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/publisher_service.rst b/owl-bot-staging/v1/docs/pubsublite_v1/publisher_service.rst new file mode 100644 index 00000000..94fed19b --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/publisher_service.rst @@ -0,0 +1,6 @@ +PublisherService +---------------------------------- + +.. automodule:: google.cloud.pubsublite_v1.services.publisher_service + :members: + :inherited-members: diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/services.rst b/owl-bot-staging/v1/docs/pubsublite_v1/services.rst new file mode 100644 index 00000000..ff4589a8 --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/services.rst @@ -0,0 +1,11 @@ +Services for Google Cloud Pubsublite v1 API +=========================================== +.. toctree:: + :maxdepth: 2 + + admin_service + cursor_service + partition_assignment_service + publisher_service + subscriber_service + topic_stats_service diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/subscriber_service.rst b/owl-bot-staging/v1/docs/pubsublite_v1/subscriber_service.rst new file mode 100644 index 00000000..0ad35695 --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/subscriber_service.rst @@ -0,0 +1,6 @@ +SubscriberService +----------------------------------- + +.. automodule:: google.cloud.pubsublite_v1.services.subscriber_service + :members: + :inherited-members: diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/topic_stats_service.rst b/owl-bot-staging/v1/docs/pubsublite_v1/topic_stats_service.rst new file mode 100644 index 00000000..b5420f42 --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/topic_stats_service.rst @@ -0,0 +1,6 @@ +TopicStatsService +----------------------------------- + +.. automodule:: google.cloud.pubsublite_v1.services.topic_stats_service + :members: + :inherited-members: diff --git a/owl-bot-staging/v1/docs/pubsublite_v1/types.rst b/owl-bot-staging/v1/docs/pubsublite_v1/types.rst new file mode 100644 index 00000000..ae839102 --- /dev/null +++ b/owl-bot-staging/v1/docs/pubsublite_v1/types.rst @@ -0,0 +1,7 @@ +Types for Google Cloud Pubsublite v1 API +======================================== + +.. automodule:: google.cloud.pubsublite_v1.types + :members: + :undoc-members: + :show-inheritance: diff --git a/owl-bot-staging/v1/google/cloud/pubsublite/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite/__init__.py new file mode 100644 index 00000000..b691745c --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite/__init__.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from google.cloud.pubsublite_v1.services.admin_service.client import AdminServiceClient +from google.cloud.pubsublite_v1.services.admin_service.async_client import AdminServiceAsyncClient +from google.cloud.pubsublite_v1.services.cursor_service.client import CursorServiceClient +from google.cloud.pubsublite_v1.services.cursor_service.async_client import CursorServiceAsyncClient +from google.cloud.pubsublite_v1.services.partition_assignment_service.client import PartitionAssignmentServiceClient +from google.cloud.pubsublite_v1.services.partition_assignment_service.async_client import PartitionAssignmentServiceAsyncClient +from google.cloud.pubsublite_v1.services.publisher_service.client import PublisherServiceClient +from google.cloud.pubsublite_v1.services.publisher_service.async_client import PublisherServiceAsyncClient +from google.cloud.pubsublite_v1.services.subscriber_service.client import SubscriberServiceClient +from google.cloud.pubsublite_v1.services.subscriber_service.async_client import SubscriberServiceAsyncClient +from google.cloud.pubsublite_v1.services.topic_stats_service.client import TopicStatsServiceClient +from google.cloud.pubsublite_v1.services.topic_stats_service.async_client import TopicStatsServiceAsyncClient + +from google.cloud.pubsublite_v1.types.admin import CreateReservationRequest +from google.cloud.pubsublite_v1.types.admin import CreateSubscriptionRequest +from google.cloud.pubsublite_v1.types.admin import CreateTopicRequest +from google.cloud.pubsublite_v1.types.admin import DeleteReservationRequest +from google.cloud.pubsublite_v1.types.admin import DeleteSubscriptionRequest +from google.cloud.pubsublite_v1.types.admin import DeleteTopicRequest +from google.cloud.pubsublite_v1.types.admin import GetReservationRequest +from google.cloud.pubsublite_v1.types.admin import GetSubscriptionRequest +from google.cloud.pubsublite_v1.types.admin import GetTopicPartitionsRequest +from google.cloud.pubsublite_v1.types.admin import GetTopicRequest +from google.cloud.pubsublite_v1.types.admin import ListReservationsRequest +from google.cloud.pubsublite_v1.types.admin import ListReservationsResponse +from google.cloud.pubsublite_v1.types.admin import ListReservationTopicsRequest +from google.cloud.pubsublite_v1.types.admin import ListReservationTopicsResponse +from google.cloud.pubsublite_v1.types.admin import ListSubscriptionsRequest +from google.cloud.pubsublite_v1.types.admin import ListSubscriptionsResponse +from google.cloud.pubsublite_v1.types.admin import ListTopicsRequest +from google.cloud.pubsublite_v1.types.admin import ListTopicsResponse +from google.cloud.pubsublite_v1.types.admin import ListTopicSubscriptionsRequest +from google.cloud.pubsublite_v1.types.admin import ListTopicSubscriptionsResponse +from google.cloud.pubsublite_v1.types.admin import OperationMetadata +from google.cloud.pubsublite_v1.types.admin import SeekSubscriptionRequest +from google.cloud.pubsublite_v1.types.admin import SeekSubscriptionResponse +from google.cloud.pubsublite_v1.types.admin import TopicPartitions +from google.cloud.pubsublite_v1.types.admin import UpdateReservationRequest +from google.cloud.pubsublite_v1.types.admin import UpdateSubscriptionRequest +from google.cloud.pubsublite_v1.types.admin import UpdateTopicRequest +from google.cloud.pubsublite_v1.types.common import AttributeValues +from google.cloud.pubsublite_v1.types.common import Cursor +from google.cloud.pubsublite_v1.types.common import PubSubMessage +from google.cloud.pubsublite_v1.types.common import Reservation +from google.cloud.pubsublite_v1.types.common import SequencedMessage +from google.cloud.pubsublite_v1.types.common import Subscription +from google.cloud.pubsublite_v1.types.common import TimeTarget +from google.cloud.pubsublite_v1.types.common import Topic +from google.cloud.pubsublite_v1.types.cursor import CommitCursorRequest +from google.cloud.pubsublite_v1.types.cursor import CommitCursorResponse +from google.cloud.pubsublite_v1.types.cursor import InitialCommitCursorRequest +from google.cloud.pubsublite_v1.types.cursor import InitialCommitCursorResponse +from google.cloud.pubsublite_v1.types.cursor import ListPartitionCursorsRequest +from google.cloud.pubsublite_v1.types.cursor import ListPartitionCursorsResponse +from google.cloud.pubsublite_v1.types.cursor import PartitionCursor +from google.cloud.pubsublite_v1.types.cursor import SequencedCommitCursorRequest +from google.cloud.pubsublite_v1.types.cursor import SequencedCommitCursorResponse +from google.cloud.pubsublite_v1.types.cursor import StreamingCommitCursorRequest +from google.cloud.pubsublite_v1.types.cursor import StreamingCommitCursorResponse +from google.cloud.pubsublite_v1.types.publisher import InitialPublishRequest +from google.cloud.pubsublite_v1.types.publisher import InitialPublishResponse +from google.cloud.pubsublite_v1.types.publisher import MessagePublishRequest +from google.cloud.pubsublite_v1.types.publisher import MessagePublishResponse +from google.cloud.pubsublite_v1.types.publisher import PublishRequest +from google.cloud.pubsublite_v1.types.publisher import PublishResponse +from google.cloud.pubsublite_v1.types.subscriber import FlowControlRequest +from google.cloud.pubsublite_v1.types.subscriber import InitialPartitionAssignmentRequest +from google.cloud.pubsublite_v1.types.subscriber import InitialSubscribeRequest +from google.cloud.pubsublite_v1.types.subscriber import InitialSubscribeResponse +from google.cloud.pubsublite_v1.types.subscriber import MessageResponse +from google.cloud.pubsublite_v1.types.subscriber import PartitionAssignment +from google.cloud.pubsublite_v1.types.subscriber import PartitionAssignmentAck +from google.cloud.pubsublite_v1.types.subscriber import PartitionAssignmentRequest +from google.cloud.pubsublite_v1.types.subscriber import SeekRequest +from google.cloud.pubsublite_v1.types.subscriber import SeekResponse +from google.cloud.pubsublite_v1.types.subscriber import SubscribeRequest +from google.cloud.pubsublite_v1.types.subscriber import SubscribeResponse +from google.cloud.pubsublite_v1.types.topic_stats import ComputeHeadCursorRequest +from google.cloud.pubsublite_v1.types.topic_stats import ComputeHeadCursorResponse +from google.cloud.pubsublite_v1.types.topic_stats import ComputeMessageStatsRequest +from google.cloud.pubsublite_v1.types.topic_stats import ComputeMessageStatsResponse +from google.cloud.pubsublite_v1.types.topic_stats import ComputeTimeCursorRequest +from google.cloud.pubsublite_v1.types.topic_stats import ComputeTimeCursorResponse + +__all__ = ('AdminServiceClient', + 'AdminServiceAsyncClient', + 'CursorServiceClient', + 'CursorServiceAsyncClient', + 'PartitionAssignmentServiceClient', + 'PartitionAssignmentServiceAsyncClient', + 'PublisherServiceClient', + 'PublisherServiceAsyncClient', + 'SubscriberServiceClient', + 'SubscriberServiceAsyncClient', + 'TopicStatsServiceClient', + 'TopicStatsServiceAsyncClient', + 'CreateReservationRequest', + 'CreateSubscriptionRequest', + 'CreateTopicRequest', + 'DeleteReservationRequest', + 'DeleteSubscriptionRequest', + 'DeleteTopicRequest', + 'GetReservationRequest', + 'GetSubscriptionRequest', + 'GetTopicPartitionsRequest', + 'GetTopicRequest', + 'ListReservationsRequest', + 'ListReservationsResponse', + 'ListReservationTopicsRequest', + 'ListReservationTopicsResponse', + 'ListSubscriptionsRequest', + 'ListSubscriptionsResponse', + 'ListTopicsRequest', + 'ListTopicsResponse', + 'ListTopicSubscriptionsRequest', + 'ListTopicSubscriptionsResponse', + 'OperationMetadata', + 'SeekSubscriptionRequest', + 'SeekSubscriptionResponse', + 'TopicPartitions', + 'UpdateReservationRequest', + 'UpdateSubscriptionRequest', + 'UpdateTopicRequest', + 'AttributeValues', + 'Cursor', + 'PubSubMessage', + 'Reservation', + 'SequencedMessage', + 'Subscription', + 'TimeTarget', + 'Topic', + 'CommitCursorRequest', + 'CommitCursorResponse', + 'InitialCommitCursorRequest', + 'InitialCommitCursorResponse', + 'ListPartitionCursorsRequest', + 'ListPartitionCursorsResponse', + 'PartitionCursor', + 'SequencedCommitCursorRequest', + 'SequencedCommitCursorResponse', + 'StreamingCommitCursorRequest', + 'StreamingCommitCursorResponse', + 'InitialPublishRequest', + 'InitialPublishResponse', + 'MessagePublishRequest', + 'MessagePublishResponse', + 'PublishRequest', + 'PublishResponse', + 'FlowControlRequest', + 'InitialPartitionAssignmentRequest', + 'InitialSubscribeRequest', + 'InitialSubscribeResponse', + 'MessageResponse', + 'PartitionAssignment', + 'PartitionAssignmentAck', + 'PartitionAssignmentRequest', + 'SeekRequest', + 'SeekResponse', + 'SubscribeRequest', + 'SubscribeResponse', + 'ComputeHeadCursorRequest', + 'ComputeHeadCursorResponse', + 'ComputeMessageStatsRequest', + 'ComputeMessageStatsResponse', + 'ComputeTimeCursorRequest', + 'ComputeTimeCursorResponse', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite/py.typed b/owl-bot-staging/v1/google/cloud/pubsublite/py.typed new file mode 100644 index 00000000..7b70f0c0 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-pubsublite package uses inline types. diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/__init__.py new file mode 100644 index 00000000..6af4313b --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/__init__.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from .services.admin_service import AdminServiceClient +from .services.admin_service import AdminServiceAsyncClient +from .services.cursor_service import CursorServiceClient +from .services.cursor_service import CursorServiceAsyncClient +from .services.partition_assignment_service import PartitionAssignmentServiceClient +from .services.partition_assignment_service import PartitionAssignmentServiceAsyncClient +from .services.publisher_service import PublisherServiceClient +from .services.publisher_service import PublisherServiceAsyncClient +from .services.subscriber_service import SubscriberServiceClient +from .services.subscriber_service import SubscriberServiceAsyncClient +from .services.topic_stats_service import TopicStatsServiceClient +from .services.topic_stats_service import TopicStatsServiceAsyncClient + +from .types.admin import CreateReservationRequest +from .types.admin import CreateSubscriptionRequest +from .types.admin import CreateTopicRequest +from .types.admin import DeleteReservationRequest +from .types.admin import DeleteSubscriptionRequest +from .types.admin import DeleteTopicRequest +from .types.admin import GetReservationRequest +from .types.admin import GetSubscriptionRequest +from .types.admin import GetTopicPartitionsRequest +from .types.admin import GetTopicRequest +from .types.admin import ListReservationsRequest +from .types.admin import ListReservationsResponse +from .types.admin import ListReservationTopicsRequest +from .types.admin import ListReservationTopicsResponse +from .types.admin import ListSubscriptionsRequest +from .types.admin import ListSubscriptionsResponse +from .types.admin import ListTopicsRequest +from .types.admin import ListTopicsResponse +from .types.admin import ListTopicSubscriptionsRequest +from .types.admin import ListTopicSubscriptionsResponse +from .types.admin import OperationMetadata +from .types.admin import SeekSubscriptionRequest +from .types.admin import SeekSubscriptionResponse +from .types.admin import TopicPartitions +from .types.admin import UpdateReservationRequest +from .types.admin import UpdateSubscriptionRequest +from .types.admin import UpdateTopicRequest +from .types.common import AttributeValues +from .types.common import Cursor +from .types.common import PubSubMessage +from .types.common import Reservation +from .types.common import SequencedMessage +from .types.common import Subscription +from .types.common import TimeTarget +from .types.common import Topic +from .types.cursor import CommitCursorRequest +from .types.cursor import CommitCursorResponse +from .types.cursor import InitialCommitCursorRequest +from .types.cursor import InitialCommitCursorResponse +from .types.cursor import ListPartitionCursorsRequest +from .types.cursor import ListPartitionCursorsResponse +from .types.cursor import PartitionCursor +from .types.cursor import SequencedCommitCursorRequest +from .types.cursor import SequencedCommitCursorResponse +from .types.cursor import StreamingCommitCursorRequest +from .types.cursor import StreamingCommitCursorResponse +from .types.publisher import InitialPublishRequest +from .types.publisher import InitialPublishResponse +from .types.publisher import MessagePublishRequest +from .types.publisher import MessagePublishResponse +from .types.publisher import PublishRequest +from .types.publisher import PublishResponse +from .types.subscriber import FlowControlRequest +from .types.subscriber import InitialPartitionAssignmentRequest +from .types.subscriber import InitialSubscribeRequest +from .types.subscriber import InitialSubscribeResponse +from .types.subscriber import MessageResponse +from .types.subscriber import PartitionAssignment +from .types.subscriber import PartitionAssignmentAck +from .types.subscriber import PartitionAssignmentRequest +from .types.subscriber import SeekRequest +from .types.subscriber import SeekResponse +from .types.subscriber import SubscribeRequest +from .types.subscriber import SubscribeResponse +from .types.topic_stats import ComputeHeadCursorRequest +from .types.topic_stats import ComputeHeadCursorResponse +from .types.topic_stats import ComputeMessageStatsRequest +from .types.topic_stats import ComputeMessageStatsResponse +from .types.topic_stats import ComputeTimeCursorRequest +from .types.topic_stats import ComputeTimeCursorResponse + +__all__ = ( + 'AdminServiceAsyncClient', + 'CursorServiceAsyncClient', + 'PartitionAssignmentServiceAsyncClient', + 'PublisherServiceAsyncClient', + 'SubscriberServiceAsyncClient', + 'TopicStatsServiceAsyncClient', +'AdminServiceClient', +'AttributeValues', +'CommitCursorRequest', +'CommitCursorResponse', +'ComputeHeadCursorRequest', +'ComputeHeadCursorResponse', +'ComputeMessageStatsRequest', +'ComputeMessageStatsResponse', +'ComputeTimeCursorRequest', +'ComputeTimeCursorResponse', +'CreateReservationRequest', +'CreateSubscriptionRequest', +'CreateTopicRequest', +'Cursor', +'CursorServiceClient', +'DeleteReservationRequest', +'DeleteSubscriptionRequest', +'DeleteTopicRequest', +'FlowControlRequest', +'GetReservationRequest', +'GetSubscriptionRequest', +'GetTopicPartitionsRequest', +'GetTopicRequest', +'InitialCommitCursorRequest', +'InitialCommitCursorResponse', +'InitialPartitionAssignmentRequest', +'InitialPublishRequest', +'InitialPublishResponse', +'InitialSubscribeRequest', +'InitialSubscribeResponse', +'ListPartitionCursorsRequest', +'ListPartitionCursorsResponse', +'ListReservationTopicsRequest', +'ListReservationTopicsResponse', +'ListReservationsRequest', +'ListReservationsResponse', +'ListSubscriptionsRequest', +'ListSubscriptionsResponse', +'ListTopicSubscriptionsRequest', +'ListTopicSubscriptionsResponse', +'ListTopicsRequest', +'ListTopicsResponse', +'MessagePublishRequest', +'MessagePublishResponse', +'MessageResponse', +'OperationMetadata', +'PartitionAssignment', +'PartitionAssignmentAck', +'PartitionAssignmentRequest', +'PartitionAssignmentServiceClient', +'PartitionCursor', +'PubSubMessage', +'PublishRequest', +'PublishResponse', +'PublisherServiceClient', +'Reservation', +'SeekRequest', +'SeekResponse', +'SeekSubscriptionRequest', +'SeekSubscriptionResponse', +'SequencedCommitCursorRequest', +'SequencedCommitCursorResponse', +'SequencedMessage', +'StreamingCommitCursorRequest', +'StreamingCommitCursorResponse', +'SubscribeRequest', +'SubscribeResponse', +'SubscriberServiceClient', +'Subscription', +'TimeTarget', +'Topic', +'TopicPartitions', +'TopicStatsServiceClient', +'UpdateReservationRequest', +'UpdateSubscriptionRequest', +'UpdateTopicRequest', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/gapic_metadata.json b/owl-bot-staging/v1/google/cloud/pubsublite_v1/gapic_metadata.json new file mode 100644 index 00000000..1e350404 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/gapic_metadata.json @@ -0,0 +1,373 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.pubsublite_v1", + "protoPackage": "google.cloud.pubsublite.v1", + "schema": "1.0", + "services": { + "AdminService": { + "clients": { + "grpc": { + "libraryClient": "AdminServiceClient", + "rpcs": { + "CreateReservation": { + "methods": [ + "create_reservation" + ] + }, + "CreateSubscription": { + "methods": [ + "create_subscription" + ] + }, + "CreateTopic": { + "methods": [ + "create_topic" + ] + }, + "DeleteReservation": { + "methods": [ + "delete_reservation" + ] + }, + "DeleteSubscription": { + "methods": [ + "delete_subscription" + ] + }, + "DeleteTopic": { + "methods": [ + "delete_topic" + ] + }, + "GetReservation": { + "methods": [ + "get_reservation" + ] + }, + "GetSubscription": { + "methods": [ + "get_subscription" + ] + }, + "GetTopic": { + "methods": [ + "get_topic" + ] + }, + "GetTopicPartitions": { + "methods": [ + "get_topic_partitions" + ] + }, + "ListReservationTopics": { + "methods": [ + "list_reservation_topics" + ] + }, + "ListReservations": { + "methods": [ + "list_reservations" + ] + }, + "ListSubscriptions": { + "methods": [ + "list_subscriptions" + ] + }, + "ListTopicSubscriptions": { + "methods": [ + "list_topic_subscriptions" + ] + }, + "ListTopics": { + "methods": [ + "list_topics" + ] + }, + "SeekSubscription": { + "methods": [ + "seek_subscription" + ] + }, + "UpdateReservation": { + "methods": [ + "update_reservation" + ] + }, + "UpdateSubscription": { + "methods": [ + "update_subscription" + ] + }, + "UpdateTopic": { + "methods": [ + "update_topic" + ] + } + } + }, + "grpc-async": { + "libraryClient": "AdminServiceAsyncClient", + "rpcs": { + "CreateReservation": { + "methods": [ + "create_reservation" + ] + }, + "CreateSubscription": { + "methods": [ + "create_subscription" + ] + }, + "CreateTopic": { + "methods": [ + "create_topic" + ] + }, + "DeleteReservation": { + "methods": [ + "delete_reservation" + ] + }, + "DeleteSubscription": { + "methods": [ + "delete_subscription" + ] + }, + "DeleteTopic": { + "methods": [ + "delete_topic" + ] + }, + "GetReservation": { + "methods": [ + "get_reservation" + ] + }, + "GetSubscription": { + "methods": [ + "get_subscription" + ] + }, + "GetTopic": { + "methods": [ + "get_topic" + ] + }, + "GetTopicPartitions": { + "methods": [ + "get_topic_partitions" + ] + }, + "ListReservationTopics": { + "methods": [ + "list_reservation_topics" + ] + }, + "ListReservations": { + "methods": [ + "list_reservations" + ] + }, + "ListSubscriptions": { + "methods": [ + "list_subscriptions" + ] + }, + "ListTopicSubscriptions": { + "methods": [ + "list_topic_subscriptions" + ] + }, + "ListTopics": { + "methods": [ + "list_topics" + ] + }, + "SeekSubscription": { + "methods": [ + "seek_subscription" + ] + }, + "UpdateReservation": { + "methods": [ + "update_reservation" + ] + }, + "UpdateSubscription": { + "methods": [ + "update_subscription" + ] + }, + "UpdateTopic": { + "methods": [ + "update_topic" + ] + } + } + } + } + }, + "CursorService": { + "clients": { + "grpc": { + "libraryClient": "CursorServiceClient", + "rpcs": { + "CommitCursor": { + "methods": [ + "commit_cursor" + ] + }, + "ListPartitionCursors": { + "methods": [ + "list_partition_cursors" + ] + }, + "StreamingCommitCursor": { + "methods": [ + "streaming_commit_cursor" + ] + } + } + }, + "grpc-async": { + "libraryClient": "CursorServiceAsyncClient", + "rpcs": { + "CommitCursor": { + "methods": [ + "commit_cursor" + ] + }, + "ListPartitionCursors": { + "methods": [ + "list_partition_cursors" + ] + }, + "StreamingCommitCursor": { + "methods": [ + "streaming_commit_cursor" + ] + } + } + } + } + }, + "PartitionAssignmentService": { + "clients": { + "grpc": { + "libraryClient": "PartitionAssignmentServiceClient", + "rpcs": { + "AssignPartitions": { + "methods": [ + "assign_partitions" + ] + } + } + }, + "grpc-async": { + "libraryClient": "PartitionAssignmentServiceAsyncClient", + "rpcs": { + "AssignPartitions": { + "methods": [ + "assign_partitions" + ] + } + } + } + } + }, + "PublisherService": { + "clients": { + "grpc": { + "libraryClient": "PublisherServiceClient", + "rpcs": { + "Publish": { + "methods": [ + "publish" + ] + } + } + }, + "grpc-async": { + "libraryClient": "PublisherServiceAsyncClient", + "rpcs": { + "Publish": { + "methods": [ + "publish" + ] + } + } + } + } + }, + "SubscriberService": { + "clients": { + "grpc": { + "libraryClient": "SubscriberServiceClient", + "rpcs": { + "Subscribe": { + "methods": [ + "subscribe" + ] + } + } + }, + "grpc-async": { + "libraryClient": "SubscriberServiceAsyncClient", + "rpcs": { + "Subscribe": { + "methods": [ + "subscribe" + ] + } + } + } + } + }, + "TopicStatsService": { + "clients": { + "grpc": { + "libraryClient": "TopicStatsServiceClient", + "rpcs": { + "ComputeHeadCursor": { + "methods": [ + "compute_head_cursor" + ] + }, + "ComputeMessageStats": { + "methods": [ + "compute_message_stats" + ] + }, + "ComputeTimeCursor": { + "methods": [ + "compute_time_cursor" + ] + } + } + }, + "grpc-async": { + "libraryClient": "TopicStatsServiceAsyncClient", + "rpcs": { + "ComputeHeadCursor": { + "methods": [ + "compute_head_cursor" + ] + }, + "ComputeMessageStats": { + "methods": [ + "compute_message_stats" + ] + }, + "ComputeTimeCursor": { + "methods": [ + "compute_time_cursor" + ] + } + } + } + } + } + } +} diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/py.typed b/owl-bot-staging/v1/google/cloud/pubsublite_v1/py.typed new file mode 100644 index 00000000..7b70f0c0 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-pubsublite package uses inline types. diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/__init__.py new file mode 100644 index 00000000..4de65971 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/__init__.py new file mode 100644 index 00000000..152ecccb --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .client import AdminServiceClient +from .async_client import AdminServiceAsyncClient + +__all__ = ( + 'AdminServiceClient', + 'AdminServiceAsyncClient', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/async_client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/async_client.py new file mode 100644 index 00000000..2854c380 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/async_client.py @@ -0,0 +1,1730 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.pubsublite_v1.services.admin_service import pagers +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common +from google.protobuf import field_mask_pb2 # type: ignore +from .transports.base import AdminServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import AdminServiceGrpcAsyncIOTransport +from .client import AdminServiceClient + + +class AdminServiceAsyncClient: + """The service that a client application uses to manage topics + and subscriptions, such creating, listing, and deleting topics + and subscriptions. + """ + + _client: AdminServiceClient + + DEFAULT_ENDPOINT = AdminServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = AdminServiceClient.DEFAULT_MTLS_ENDPOINT + + reservation_path = staticmethod(AdminServiceClient.reservation_path) + parse_reservation_path = staticmethod(AdminServiceClient.parse_reservation_path) + subscription_path = staticmethod(AdminServiceClient.subscription_path) + parse_subscription_path = staticmethod(AdminServiceClient.parse_subscription_path) + topic_path = staticmethod(AdminServiceClient.topic_path) + parse_topic_path = staticmethod(AdminServiceClient.parse_topic_path) + common_billing_account_path = staticmethod(AdminServiceClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod(AdminServiceClient.parse_common_billing_account_path) + common_folder_path = staticmethod(AdminServiceClient.common_folder_path) + parse_common_folder_path = staticmethod(AdminServiceClient.parse_common_folder_path) + common_organization_path = staticmethod(AdminServiceClient.common_organization_path) + parse_common_organization_path = staticmethod(AdminServiceClient.parse_common_organization_path) + common_project_path = staticmethod(AdminServiceClient.common_project_path) + parse_common_project_path = staticmethod(AdminServiceClient.parse_common_project_path) + common_location_path = staticmethod(AdminServiceClient.common_location_path) + parse_common_location_path = staticmethod(AdminServiceClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + AdminServiceAsyncClient: The constructed client. + """ + return AdminServiceClient.from_service_account_info.__func__(AdminServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + AdminServiceAsyncClient: The constructed client. + """ + return AdminServiceClient.from_service_account_file.__func__(AdminServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> AdminServiceTransport: + """Returns the transport used by the client instance. + + Returns: + AdminServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial(type(AdminServiceClient).get_transport_class, type(AdminServiceClient)) + + def __init__(self, *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, AdminServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the admin service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.AdminServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = AdminServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + + ) + + async def create_topic(self, + request: admin.CreateTopicRequest = None, + *, + parent: str = None, + topic: common.Topic = None, + topic_id: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Topic: + r"""Creates a new topic. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.CreateTopicRequest`): + The request object. Request for CreateTopic. + parent (:class:`str`): + Required. The parent location in which to create the + topic. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + topic (:class:`google.cloud.pubsublite_v1.types.Topic`): + Required. Configuration of the topic to create. Its + ``name`` field is ignored. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + topic_id (:class:`str`): + Required. The ID to use for the topic, which will become + the final component of the topic's name. + + This value is structured like: ``my-topic-name``. + + This corresponds to the ``topic_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Topic: + Metadata about a topic resource. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, topic, topic_id]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.CreateTopicRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if topic is not None: + request.topic = topic + if topic_id is not None: + request.topic_id = topic_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_topic, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_topic(self, + request: admin.GetTopicRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Topic: + r"""Returns the topic configuration. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.GetTopicRequest`): + The request object. Request for GetTopic. + name (:class:`str`): + Required. The name of the topic whose + configuration to return. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Topic: + Metadata about a topic resource. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.GetTopicRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_topic, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_topic_partitions(self, + request: admin.GetTopicPartitionsRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> admin.TopicPartitions: + r"""Returns the partition information for the requested + topic. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.GetTopicPartitionsRequest`): + The request object. Request for GetTopicPartitions. + name (:class:`str`): + Required. The topic whose partition + information to return. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.TopicPartitions: + Response for GetTopicPartitions. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.GetTopicPartitionsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_topic_partitions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_topics(self, + request: admin.ListTopicsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicsAsyncPager: + r"""Returns the list of topics for the given project. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ListTopicsRequest`): + The request object. Request for ListTopics. + parent (:class:`str`): + Required. The parent whose topics are to be listed. + Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListTopicsAsyncPager: + Response for ListTopics. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.ListTopicsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_topics, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTopicsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_topic(self, + request: admin.UpdateTopicRequest = None, + *, + topic: common.Topic = None, + update_mask: field_mask_pb2.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Topic: + r"""Updates properties of the specified topic. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.UpdateTopicRequest`): + The request object. Request for UpdateTopic. + topic (:class:`google.cloud.pubsublite_v1.types.Topic`): + Required. The topic to update. Its ``name`` field must + be populated. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + Required. A mask specifying the topic + fields to change. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Topic: + Metadata about a topic resource. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic, update_mask]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.UpdateTopicRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_topic, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic.name", request.topic.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_topic(self, + request: admin.DeleteTopicRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the specified topic. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.DeleteTopicRequest`): + The request object. Request for DeleteTopic. + name (:class:`str`): + Required. The name of the topic to + delete. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.DeleteTopicRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_topic, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def list_topic_subscriptions(self, + request: admin.ListTopicSubscriptionsRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicSubscriptionsAsyncPager: + r"""Lists the subscriptions attached to the specified + topic. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ListTopicSubscriptionsRequest`): + The request object. Request for ListTopicSubscriptions. + name (:class:`str`): + Required. The name of the topic whose + subscriptions to list. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListTopicSubscriptionsAsyncPager: + Response for ListTopicSubscriptions. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.ListTopicSubscriptionsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_topic_subscriptions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTopicSubscriptionsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def create_subscription(self, + request: admin.CreateSubscriptionRequest = None, + *, + parent: str = None, + subscription: common.Subscription = None, + subscription_id: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Subscription: + r"""Creates a new subscription. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.CreateSubscriptionRequest`): + The request object. Request for CreateSubscription. + parent (:class:`str`): + Required. The parent location in which to create the + subscription. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + subscription (:class:`google.cloud.pubsublite_v1.types.Subscription`): + Required. Configuration of the subscription to create. + Its ``name`` field is ignored. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + subscription_id (:class:`str`): + Required. The ID to use for the subscription, which will + become the final component of the subscription's name. + + This value is structured like: ``my-sub-name``. + + This corresponds to the ``subscription_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Subscription: + Metadata about a subscription + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, subscription, subscription_id]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.CreateSubscriptionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if subscription is not None: + request.subscription = subscription + if subscription_id is not None: + request.subscription_id = subscription_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_subscription, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_subscription(self, + request: admin.GetSubscriptionRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Subscription: + r"""Returns the subscription configuration. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.GetSubscriptionRequest`): + The request object. Request for GetSubscription. + name (:class:`str`): + Required. The name of the + subscription whose configuration to + return. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Subscription: + Metadata about a subscription + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.GetSubscriptionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_subscription, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_subscriptions(self, + request: admin.ListSubscriptionsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSubscriptionsAsyncPager: + r"""Returns the list of subscriptions for the given + project. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ListSubscriptionsRequest`): + The request object. Request for ListSubscriptions. + parent (:class:`str`): + Required. The parent whose subscriptions are to be + listed. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListSubscriptionsAsyncPager: + Response for ListSubscriptions. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.ListSubscriptionsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_subscriptions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListSubscriptionsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_subscription(self, + request: admin.UpdateSubscriptionRequest = None, + *, + subscription: common.Subscription = None, + update_mask: field_mask_pb2.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Subscription: + r"""Updates properties of the specified subscription. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.UpdateSubscriptionRequest`): + The request object. Request for UpdateSubscription. + subscription (:class:`google.cloud.pubsublite_v1.types.Subscription`): + Required. The subscription to update. Its ``name`` field + must be populated. Topic field must not be populated. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + Required. A mask specifying the + subscription fields to change. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Subscription: + Metadata about a subscription + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, update_mask]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.UpdateSubscriptionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_subscription, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("subscription.name", request.subscription.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_subscription(self, + request: admin.DeleteSubscriptionRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the specified subscription. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.DeleteSubscriptionRequest`): + The request object. Request for DeleteSubscription. + name (:class:`str`): + Required. The name of the + subscription to delete. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.DeleteSubscriptionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_subscription, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def seek_subscription(self, + request: admin.SeekSubscriptionRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Performs an out-of-band seek for a subscription to a + specified target, which may be timestamps or named + positions within the message backlog. Seek translates + these targets to cursors for each partition and + orchestrates subscribers to start consuming messages + from these seek cursors. + + If an operation is returned, the seek has been + registered and subscribers will eventually receive + messages from the seek cursors (i.e. eventual + consistency), as long as they are using a minimum + supported client library version and not a system that + tracks cursors independently of Pub/Sub Lite (e.g. + Apache Beam, Dataflow, Spark). The seek operation will + fail for unsupported clients. + + If clients would like to know when subscribers react to + the seek (or not), they can poll the operation. The seek + operation will succeed and complete once subscribers are + ready to receive messages from the seek cursors for all + partitions of the topic. This means that the seek + operation will not complete until all subscribers come + online. + + If the previous seek operation has not yet completed, it + will be aborted and the new invocation of seek will + supersede it. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.SeekSubscriptionRequest`): + The request object. Request for SeekSubscription. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.pubsublite_v1.types.SeekSubscriptionResponse` + Response for SeekSubscription long running operation. + + """ + # Create or coerce a protobuf request object. + request = admin.SeekSubscriptionRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.seek_subscription, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + admin.SeekSubscriptionResponse, + metadata_type=admin.OperationMetadata, + ) + + # Done; return the response. + return response + + async def create_reservation(self, + request: admin.CreateReservationRequest = None, + *, + parent: str = None, + reservation: common.Reservation = None, + reservation_id: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Reservation: + r"""Creates a new reservation. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.CreateReservationRequest`): + The request object. Request for CreateReservation. + parent (:class:`str`): + Required. The parent location in which to create the + reservation. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + reservation (:class:`google.cloud.pubsublite_v1.types.Reservation`): + Required. Configuration of the reservation to create. + Its ``name`` field is ignored. + + This corresponds to the ``reservation`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + reservation_id (:class:`str`): + Required. The ID to use for the reservation, which will + become the final component of the reservation's name. + + This value is structured like: ``my-reservation-name``. + + This corresponds to the ``reservation_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Reservation: + Metadata about a reservation + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, reservation, reservation_id]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.CreateReservationRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if reservation is not None: + request.reservation = reservation + if reservation_id is not None: + request.reservation_id = reservation_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_reservation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_reservation(self, + request: admin.GetReservationRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Reservation: + r"""Returns the reservation configuration. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.GetReservationRequest`): + The request object. Request for GetReservation. + name (:class:`str`): + Required. The name of the reservation whose + configuration to return. Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Reservation: + Metadata about a reservation + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.GetReservationRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_reservation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_reservations(self, + request: admin.ListReservationsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListReservationsAsyncPager: + r"""Returns the list of reservations for the given + project. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ListReservationsRequest`): + The request object. Request for ListReservations. + parent (:class:`str`): + Required. The parent whose reservations are to be + listed. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListReservationsAsyncPager: + Response for ListReservations. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.ListReservationsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_reservations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListReservationsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_reservation(self, + request: admin.UpdateReservationRequest = None, + *, + reservation: common.Reservation = None, + update_mask: field_mask_pb2.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Reservation: + r"""Updates properties of the specified reservation. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.UpdateReservationRequest`): + The request object. Request for UpdateReservation. + reservation (:class:`google.cloud.pubsublite_v1.types.Reservation`): + Required. The reservation to update. Its ``name`` field + must be populated. + + This corresponds to the ``reservation`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + Required. A mask specifying the + reservation fields to change. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Reservation: + Metadata about a reservation + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([reservation, update_mask]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.UpdateReservationRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if reservation is not None: + request.reservation = reservation + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_reservation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("reservation.name", request.reservation.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_reservation(self, + request: admin.DeleteReservationRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the specified reservation. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.DeleteReservationRequest`): + The request object. Request for DeleteReservation. + name (:class:`str`): + Required. The name of the reservation to delete. + Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.DeleteReservationRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_reservation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def list_reservation_topics(self, + request: admin.ListReservationTopicsRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListReservationTopicsAsyncPager: + r"""Lists the topics attached to the specified + reservation. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ListReservationTopicsRequest`): + The request object. Request for ListReservationTopics. + name (:class:`str`): + Required. The name of the reservation whose topics to + list. Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListReservationTopicsAsyncPager: + Response for ListReservationTopics. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = admin.ListReservationTopicsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_reservation_topics, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListReservationTopicsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "AdminServiceAsyncClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/client.py new file mode 100644 index 00000000..c3e37c80 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/client.py @@ -0,0 +1,1946 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Dict, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.pubsublite_v1.services.admin_service import pagers +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common +from google.protobuf import field_mask_pb2 # type: ignore +from .transports.base import AdminServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import AdminServiceGrpcTransport +from .transports.grpc_asyncio import AdminServiceGrpcAsyncIOTransport + + +class AdminServiceClientMeta(type): + """Metaclass for the AdminService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + _transport_registry = OrderedDict() # type: Dict[str, Type[AdminServiceTransport]] + _transport_registry["grpc"] = AdminServiceGrpcTransport + _transport_registry["grpc_asyncio"] = AdminServiceGrpcAsyncIOTransport + + def get_transport_class(cls, + label: str = None, + ) -> Type[AdminServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class AdminServiceClient(metaclass=AdminServiceClientMeta): + """The service that a client application uses to manage topics + and subscriptions, such creating, listing, and deleting topics + and subscriptions. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsublite.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + AdminServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + AdminServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file( + filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> AdminServiceTransport: + """Returns the transport used by the client instance. + + Returns: + AdminServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def reservation_path(project: str,location: str,reservation: str,) -> str: + """Returns a fully-qualified reservation string.""" + return "projects/{project}/locations/{location}/reservations/{reservation}".format(project=project, location=location, reservation=reservation, ) + + @staticmethod + def parse_reservation_path(path: str) -> Dict[str,str]: + """Parses a reservation path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)/reservations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def subscription_path(project: str,location: str,subscription: str,) -> str: + """Returns a fully-qualified subscription string.""" + return "projects/{project}/locations/{location}/subscriptions/{subscription}".format(project=project, location=location, subscription=subscription, ) + + @staticmethod + def parse_subscription_path(path: str) -> Dict[str,str]: + """Parses a subscription path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)/subscriptions/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def topic_path(project: str,location: str,topic: str,) -> str: + """Returns a fully-qualified topic string.""" + return "projects/{project}/locations/{location}/topics/{topic}".format(project=project, location=location, topic=topic, ) + + @staticmethod + def parse_topic_path(path: str) -> Dict[str,str]: + """Parses a topic path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)/topics/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path(billing_account: str, ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str,str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str, ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder, ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str,str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str, ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization, ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str,str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str, ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format(project=project, ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str,str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str, ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format(project=project, location=location, ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str,str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__(self, *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, AdminServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the admin service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, AdminServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool(util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, AdminServiceTransport): + # transport is a AdminServiceTransport instance. + if credentials or client_options.credentials_file: + raise ValueError("When providing a transport instance, " + "provide its credentials directly.") + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + ) + + def create_topic(self, + request: Union[admin.CreateTopicRequest, dict] = None, + *, + parent: str = None, + topic: common.Topic = None, + topic_id: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Topic: + r"""Creates a new topic. + + Args: + request (Union[google.cloud.pubsublite_v1.types.CreateTopicRequest, dict]): + The request object. Request for CreateTopic. + parent (str): + Required. The parent location in which to create the + topic. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + topic (google.cloud.pubsublite_v1.types.Topic): + Required. Configuration of the topic to create. Its + ``name`` field is ignored. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + topic_id (str): + Required. The ID to use for the topic, which will become + the final component of the topic's name. + + This value is structured like: ``my-topic-name``. + + This corresponds to the ``topic_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Topic: + Metadata about a topic resource. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, topic, topic_id]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.CreateTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.CreateTopicRequest): + request = admin.CreateTopicRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if topic is not None: + request.topic = topic + if topic_id is not None: + request.topic_id = topic_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_topic(self, + request: Union[admin.GetTopicRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Topic: + r"""Returns the topic configuration. + + Args: + request (Union[google.cloud.pubsublite_v1.types.GetTopicRequest, dict]): + The request object. Request for GetTopic. + name (str): + Required. The name of the topic whose + configuration to return. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Topic: + Metadata about a topic resource. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.GetTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.GetTopicRequest): + request = admin.GetTopicRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_topic_partitions(self, + request: Union[admin.GetTopicPartitionsRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> admin.TopicPartitions: + r"""Returns the partition information for the requested + topic. + + Args: + request (Union[google.cloud.pubsublite_v1.types.GetTopicPartitionsRequest, dict]): + The request object. Request for GetTopicPartitions. + name (str): + Required. The topic whose partition + information to return. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.TopicPartitions: + Response for GetTopicPartitions. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.GetTopicPartitionsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.GetTopicPartitionsRequest): + request = admin.GetTopicPartitionsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_topic_partitions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_topics(self, + request: Union[admin.ListTopicsRequest, dict] = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicsPager: + r"""Returns the list of topics for the given project. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ListTopicsRequest, dict]): + The request object. Request for ListTopics. + parent (str): + Required. The parent whose topics are to be listed. + Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListTopicsPager: + Response for ListTopics. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.ListTopicsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.ListTopicsRequest): + request = admin.ListTopicsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_topics] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTopicsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_topic(self, + request: Union[admin.UpdateTopicRequest, dict] = None, + *, + topic: common.Topic = None, + update_mask: field_mask_pb2.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Topic: + r"""Updates properties of the specified topic. + + Args: + request (Union[google.cloud.pubsublite_v1.types.UpdateTopicRequest, dict]): + The request object. Request for UpdateTopic. + topic (google.cloud.pubsublite_v1.types.Topic): + Required. The topic to update. Its ``name`` field must + be populated. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. A mask specifying the topic + fields to change. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Topic: + Metadata about a topic resource. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic, update_mask]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.UpdateTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.UpdateTopicRequest): + request = admin.UpdateTopicRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic.name", request.topic.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_topic(self, + request: Union[admin.DeleteTopicRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the specified topic. + + Args: + request (Union[google.cloud.pubsublite_v1.types.DeleteTopicRequest, dict]): + The request object. Request for DeleteTopic. + name (str): + Required. The name of the topic to + delete. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.DeleteTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.DeleteTopicRequest): + request = admin.DeleteTopicRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def list_topic_subscriptions(self, + request: Union[admin.ListTopicSubscriptionsRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicSubscriptionsPager: + r"""Lists the subscriptions attached to the specified + topic. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ListTopicSubscriptionsRequest, dict]): + The request object. Request for ListTopicSubscriptions. + name (str): + Required. The name of the topic whose + subscriptions to list. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListTopicSubscriptionsPager: + Response for ListTopicSubscriptions. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.ListTopicSubscriptionsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.ListTopicSubscriptionsRequest): + request = admin.ListTopicSubscriptionsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_topic_subscriptions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTopicSubscriptionsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def create_subscription(self, + request: Union[admin.CreateSubscriptionRequest, dict] = None, + *, + parent: str = None, + subscription: common.Subscription = None, + subscription_id: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Subscription: + r"""Creates a new subscription. + + Args: + request (Union[google.cloud.pubsublite_v1.types.CreateSubscriptionRequest, dict]): + The request object. Request for CreateSubscription. + parent (str): + Required. The parent location in which to create the + subscription. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + subscription (google.cloud.pubsublite_v1.types.Subscription): + Required. Configuration of the subscription to create. + Its ``name`` field is ignored. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + subscription_id (str): + Required. The ID to use for the subscription, which will + become the final component of the subscription's name. + + This value is structured like: ``my-sub-name``. + + This corresponds to the ``subscription_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Subscription: + Metadata about a subscription + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, subscription, subscription_id]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.CreateSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.CreateSubscriptionRequest): + request = admin.CreateSubscriptionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if subscription is not None: + request.subscription = subscription + if subscription_id is not None: + request.subscription_id = subscription_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_subscription(self, + request: Union[admin.GetSubscriptionRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Subscription: + r"""Returns the subscription configuration. + + Args: + request (Union[google.cloud.pubsublite_v1.types.GetSubscriptionRequest, dict]): + The request object. Request for GetSubscription. + name (str): + Required. The name of the + subscription whose configuration to + return. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Subscription: + Metadata about a subscription + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.GetSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.GetSubscriptionRequest): + request = admin.GetSubscriptionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_subscriptions(self, + request: Union[admin.ListSubscriptionsRequest, dict] = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSubscriptionsPager: + r"""Returns the list of subscriptions for the given + project. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ListSubscriptionsRequest, dict]): + The request object. Request for ListSubscriptions. + parent (str): + Required. The parent whose subscriptions are to be + listed. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListSubscriptionsPager: + Response for ListSubscriptions. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.ListSubscriptionsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.ListSubscriptionsRequest): + request = admin.ListSubscriptionsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_subscriptions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListSubscriptionsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_subscription(self, + request: Union[admin.UpdateSubscriptionRequest, dict] = None, + *, + subscription: common.Subscription = None, + update_mask: field_mask_pb2.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Subscription: + r"""Updates properties of the specified subscription. + + Args: + request (Union[google.cloud.pubsublite_v1.types.UpdateSubscriptionRequest, dict]): + The request object. Request for UpdateSubscription. + subscription (google.cloud.pubsublite_v1.types.Subscription): + Required. The subscription to update. Its ``name`` field + must be populated. Topic field must not be populated. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. A mask specifying the + subscription fields to change. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Subscription: + Metadata about a subscription + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, update_mask]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.UpdateSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.UpdateSubscriptionRequest): + request = admin.UpdateSubscriptionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("subscription.name", request.subscription.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_subscription(self, + request: Union[admin.DeleteSubscriptionRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the specified subscription. + + Args: + request (Union[google.cloud.pubsublite_v1.types.DeleteSubscriptionRequest, dict]): + The request object. Request for DeleteSubscription. + name (str): + Required. The name of the + subscription to delete. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.DeleteSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.DeleteSubscriptionRequest): + request = admin.DeleteSubscriptionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def seek_subscription(self, + request: Union[admin.SeekSubscriptionRequest, dict] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Performs an out-of-band seek for a subscription to a + specified target, which may be timestamps or named + positions within the message backlog. Seek translates + these targets to cursors for each partition and + orchestrates subscribers to start consuming messages + from these seek cursors. + + If an operation is returned, the seek has been + registered and subscribers will eventually receive + messages from the seek cursors (i.e. eventual + consistency), as long as they are using a minimum + supported client library version and not a system that + tracks cursors independently of Pub/Sub Lite (e.g. + Apache Beam, Dataflow, Spark). The seek operation will + fail for unsupported clients. + + If clients would like to know when subscribers react to + the seek (or not), they can poll the operation. The seek + operation will succeed and complete once subscribers are + ready to receive messages from the seek cursors for all + partitions of the topic. This means that the seek + operation will not complete until all subscribers come + online. + + If the previous seek operation has not yet completed, it + will be aborted and the new invocation of seek will + supersede it. + + Args: + request (Union[google.cloud.pubsublite_v1.types.SeekSubscriptionRequest, dict]): + The request object. Request for SeekSubscription. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.pubsublite_v1.types.SeekSubscriptionResponse` + Response for SeekSubscription long running operation. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a admin.SeekSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.SeekSubscriptionRequest): + request = admin.SeekSubscriptionRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.seek_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + admin.SeekSubscriptionResponse, + metadata_type=admin.OperationMetadata, + ) + + # Done; return the response. + return response + + def create_reservation(self, + request: Union[admin.CreateReservationRequest, dict] = None, + *, + parent: str = None, + reservation: common.Reservation = None, + reservation_id: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Reservation: + r"""Creates a new reservation. + + Args: + request (Union[google.cloud.pubsublite_v1.types.CreateReservationRequest, dict]): + The request object. Request for CreateReservation. + parent (str): + Required. The parent location in which to create the + reservation. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + reservation (google.cloud.pubsublite_v1.types.Reservation): + Required. Configuration of the reservation to create. + Its ``name`` field is ignored. + + This corresponds to the ``reservation`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + reservation_id (str): + Required. The ID to use for the reservation, which will + become the final component of the reservation's name. + + This value is structured like: ``my-reservation-name``. + + This corresponds to the ``reservation_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Reservation: + Metadata about a reservation + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, reservation, reservation_id]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.CreateReservationRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.CreateReservationRequest): + request = admin.CreateReservationRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if reservation is not None: + request.reservation = reservation + if reservation_id is not None: + request.reservation_id = reservation_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_reservation] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_reservation(self, + request: Union[admin.GetReservationRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Reservation: + r"""Returns the reservation configuration. + + Args: + request (Union[google.cloud.pubsublite_v1.types.GetReservationRequest, dict]): + The request object. Request for GetReservation. + name (str): + Required. The name of the reservation whose + configuration to return. Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Reservation: + Metadata about a reservation + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.GetReservationRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.GetReservationRequest): + request = admin.GetReservationRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_reservation] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_reservations(self, + request: Union[admin.ListReservationsRequest, dict] = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListReservationsPager: + r"""Returns the list of reservations for the given + project. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ListReservationsRequest, dict]): + The request object. Request for ListReservations. + parent (str): + Required. The parent whose reservations are to be + listed. Structured like + ``projects/{project_number}/locations/{location}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListReservationsPager: + Response for ListReservations. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.ListReservationsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.ListReservationsRequest): + request = admin.ListReservationsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_reservations] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListReservationsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_reservation(self, + request: Union[admin.UpdateReservationRequest, dict] = None, + *, + reservation: common.Reservation = None, + update_mask: field_mask_pb2.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> common.Reservation: + r"""Updates properties of the specified reservation. + + Args: + request (Union[google.cloud.pubsublite_v1.types.UpdateReservationRequest, dict]): + The request object. Request for UpdateReservation. + reservation (google.cloud.pubsublite_v1.types.Reservation): + Required. The reservation to update. Its ``name`` field + must be populated. + + This corresponds to the ``reservation`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. A mask specifying the + reservation fields to change. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.Reservation: + Metadata about a reservation + resource. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([reservation, update_mask]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.UpdateReservationRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.UpdateReservationRequest): + request = admin.UpdateReservationRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if reservation is not None: + request.reservation = reservation + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_reservation] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("reservation.name", request.reservation.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_reservation(self, + request: Union[admin.DeleteReservationRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the specified reservation. + + Args: + request (Union[google.cloud.pubsublite_v1.types.DeleteReservationRequest, dict]): + The request object. Request for DeleteReservation. + name (str): + Required. The name of the reservation to delete. + Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.DeleteReservationRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.DeleteReservationRequest): + request = admin.DeleteReservationRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_reservation] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def list_reservation_topics(self, + request: Union[admin.ListReservationTopicsRequest, dict] = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListReservationTopicsPager: + r"""Lists the topics attached to the specified + reservation. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ListReservationTopicsRequest, dict]): + The request object. Request for ListReservationTopics. + name (str): + Required. The name of the reservation whose topics to + list. Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.admin_service.pagers.ListReservationTopicsPager: + Response for ListReservationTopics. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a admin.ListReservationTopicsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, admin.ListReservationTopicsRequest): + request = admin.ListReservationTopicsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_reservation_topics] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("name", request.name), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListReservationTopicsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "AdminServiceClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/pagers.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/pagers.py new file mode 100644 index 00000000..1c577ce1 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/pagers.py @@ -0,0 +1,629 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, AsyncIterator, Awaitable, Callable, Sequence, Tuple, Optional, Iterator + +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common + + +class ListTopicsPager: + """A pager for iterating through ``list_topics`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListTopicsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``topics`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTopics`` requests and continue to iterate + through the ``topics`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListTopicsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., admin.ListTopicsResponse], + request: admin.ListTopicsRequest, + response: admin.ListTopicsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListTopicsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListTopicsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListTopicsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[admin.ListTopicsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[common.Topic]: + for page in self.pages: + yield from page.topics + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListTopicsAsyncPager: + """A pager for iterating through ``list_topics`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListTopicsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``topics`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTopics`` requests and continue to iterate + through the ``topics`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListTopicsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., Awaitable[admin.ListTopicsResponse]], + request: admin.ListTopicsRequest, + response: admin.ListTopicsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListTopicsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListTopicsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListTopicsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[admin.ListTopicsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[common.Topic]: + async def async_generator(): + async for page in self.pages: + for response in page.topics: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListTopicSubscriptionsPager: + """A pager for iterating through ``list_topic_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListTopicSubscriptionsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTopicSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListTopicSubscriptionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., admin.ListTopicSubscriptionsResponse], + request: admin.ListTopicSubscriptionsRequest, + response: admin.ListTopicSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListTopicSubscriptionsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListTopicSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListTopicSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[admin.ListTopicSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[str]: + for page in self.pages: + yield from page.subscriptions + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListTopicSubscriptionsAsyncPager: + """A pager for iterating through ``list_topic_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListTopicSubscriptionsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTopicSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListTopicSubscriptionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., Awaitable[admin.ListTopicSubscriptionsResponse]], + request: admin.ListTopicSubscriptionsRequest, + response: admin.ListTopicSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListTopicSubscriptionsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListTopicSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListTopicSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[admin.ListTopicSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[str]: + async def async_generator(): + async for page in self.pages: + for response in page.subscriptions: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListSubscriptionsPager: + """A pager for iterating through ``list_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListSubscriptionsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_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. + """ + def __init__(self, + method: Callable[..., admin.ListSubscriptionsResponse], + request: admin.ListSubscriptionsRequest, + response: admin.ListSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListSubscriptionsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[admin.ListSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[common.Subscription]: + for page in self.pages: + yield from page.subscriptions + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListSubscriptionsAsyncPager: + """A pager for iterating through ``list_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListSubscriptionsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_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. + """ + def __init__(self, + method: Callable[..., Awaitable[admin.ListSubscriptionsResponse]], + request: admin.ListSubscriptionsRequest, + response: admin.ListSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListSubscriptionsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[admin.ListSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[common.Subscription]: + async def async_generator(): + async for page in self.pages: + for response in page.subscriptions: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListReservationsPager: + """A pager for iterating through ``list_reservations`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListReservationsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``reservations`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListReservations`` requests and continue to iterate + through the ``reservations`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListReservationsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., admin.ListReservationsResponse], + request: admin.ListReservationsRequest, + response: admin.ListReservationsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListReservationsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListReservationsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListReservationsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[admin.ListReservationsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[common.Reservation]: + for page in self.pages: + yield from page.reservations + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListReservationsAsyncPager: + """A pager for iterating through ``list_reservations`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListReservationsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``reservations`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListReservations`` requests and continue to iterate + through the ``reservations`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListReservationsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., Awaitable[admin.ListReservationsResponse]], + request: admin.ListReservationsRequest, + response: admin.ListReservationsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListReservationsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListReservationsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListReservationsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[admin.ListReservationsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[common.Reservation]: + async def async_generator(): + async for page in self.pages: + for response in page.reservations: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListReservationTopicsPager: + """A pager for iterating through ``list_reservation_topics`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListReservationTopicsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``topics`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListReservationTopics`` requests and continue to iterate + through the ``topics`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListReservationTopicsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., admin.ListReservationTopicsResponse], + request: admin.ListReservationTopicsRequest, + response: admin.ListReservationTopicsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListReservationTopicsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListReservationTopicsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListReservationTopicsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[admin.ListReservationTopicsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[str]: + for page in self.pages: + yield from page.topics + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListReservationTopicsAsyncPager: + """A pager for iterating through ``list_reservation_topics`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListReservationTopicsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``topics`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListReservationTopics`` requests and continue to iterate + through the ``topics`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListReservationTopicsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., Awaitable[admin.ListReservationTopicsResponse]], + request: admin.ListReservationTopicsRequest, + response: admin.ListReservationTopicsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListReservationTopicsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListReservationTopicsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = admin.ListReservationTopicsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[admin.ListReservationTopicsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[str]: + async def async_generator(): + async for page in self.pages: + for response in page.topics: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/__init__.py new file mode 100644 index 00000000..fc0d3345 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import AdminServiceTransport +from .grpc import AdminServiceGrpcTransport +from .grpc_asyncio import AdminServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[AdminServiceTransport]] +_transport_registry['grpc'] = AdminServiceGrpcTransport +_transport_registry['grpc_asyncio'] = AdminServiceGrpcAsyncIOTransport + +__all__ = ( + 'AdminServiceTransport', + 'AdminServiceGrpcTransport', + 'AdminServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/base.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/base.py new file mode 100644 index 00000000..022de7c3 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/base.py @@ -0,0 +1,438 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version +import pkg_resources + +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + 'google-cloud-pubsublite', + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + + +class AdminServiceTransport(abc.ABC): + """Abstract transport class for AdminService.""" + + AUTH_SCOPES = ( + 'https://www.googleapis.com/auth/cloud-platform', + ) + + DEFAULT_HOST: str = 'pubsublite.googleapis.com' + def __init__( + self, *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ':' not in host: + host += ':443' + self._host = host + + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs("'credentials_file' and 'credentials' are mutually exclusive") + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, + **scopes_kwargs, + quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = google.auth.default(**scopes_kwargs, quota_project_id=quota_project_id) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if always_use_jwt_access and isinstance(credentials, service_account.Credentials) and hasattr(service_account.Credentials, "with_always_use_jwt_access"): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # TODO(busunkim): This method is in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-auth is increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs(cls, host: str, scopes: Optional[Sequence[str]]) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_topic: gapic_v1.method.wrap_method( + self.create_topic, + default_timeout=None, + client_info=client_info, + ), + self.get_topic: gapic_v1.method.wrap_method( + self.get_topic, + default_timeout=None, + client_info=client_info, + ), + self.get_topic_partitions: gapic_v1.method.wrap_method( + self.get_topic_partitions, + default_timeout=None, + client_info=client_info, + ), + self.list_topics: gapic_v1.method.wrap_method( + self.list_topics, + default_timeout=None, + client_info=client_info, + ), + self.update_topic: gapic_v1.method.wrap_method( + self.update_topic, + default_timeout=None, + client_info=client_info, + ), + self.delete_topic: gapic_v1.method.wrap_method( + self.delete_topic, + default_timeout=None, + client_info=client_info, + ), + self.list_topic_subscriptions: gapic_v1.method.wrap_method( + self.list_topic_subscriptions, + default_timeout=None, + client_info=client_info, + ), + self.create_subscription: gapic_v1.method.wrap_method( + self.create_subscription, + default_timeout=None, + client_info=client_info, + ), + self.get_subscription: gapic_v1.method.wrap_method( + self.get_subscription, + default_timeout=None, + client_info=client_info, + ), + self.list_subscriptions: gapic_v1.method.wrap_method( + self.list_subscriptions, + default_timeout=None, + client_info=client_info, + ), + self.update_subscription: gapic_v1.method.wrap_method( + self.update_subscription, + default_timeout=None, + client_info=client_info, + ), + self.delete_subscription: gapic_v1.method.wrap_method( + self.delete_subscription, + default_timeout=None, + client_info=client_info, + ), + self.seek_subscription: gapic_v1.method.wrap_method( + self.seek_subscription, + default_timeout=None, + client_info=client_info, + ), + self.create_reservation: gapic_v1.method.wrap_method( + self.create_reservation, + default_timeout=None, + client_info=client_info, + ), + self.get_reservation: gapic_v1.method.wrap_method( + self.get_reservation, + default_timeout=None, + client_info=client_info, + ), + self.list_reservations: gapic_v1.method.wrap_method( + self.list_reservations, + default_timeout=None, + client_info=client_info, + ), + self.update_reservation: gapic_v1.method.wrap_method( + self.update_reservation, + default_timeout=None, + client_info=client_info, + ), + self.delete_reservation: gapic_v1.method.wrap_method( + self.delete_reservation, + default_timeout=None, + client_info=client_info, + ), + self.list_reservation_topics: gapic_v1.method.wrap_method( + self.list_reservation_topics, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Return the client designed to process long-running operations.""" + raise NotImplementedError() + + @property + def create_topic(self) -> Callable[ + [admin.CreateTopicRequest], + Union[ + common.Topic, + Awaitable[common.Topic] + ]]: + raise NotImplementedError() + + @property + def get_topic(self) -> Callable[ + [admin.GetTopicRequest], + Union[ + common.Topic, + Awaitable[common.Topic] + ]]: + raise NotImplementedError() + + @property + def get_topic_partitions(self) -> Callable[ + [admin.GetTopicPartitionsRequest], + Union[ + admin.TopicPartitions, + Awaitable[admin.TopicPartitions] + ]]: + raise NotImplementedError() + + @property + def list_topics(self) -> Callable[ + [admin.ListTopicsRequest], + Union[ + admin.ListTopicsResponse, + Awaitable[admin.ListTopicsResponse] + ]]: + raise NotImplementedError() + + @property + def update_topic(self) -> Callable[ + [admin.UpdateTopicRequest], + Union[ + common.Topic, + Awaitable[common.Topic] + ]]: + raise NotImplementedError() + + @property + def delete_topic(self) -> Callable[ + [admin.DeleteTopicRequest], + Union[ + empty_pb2.Empty, + Awaitable[empty_pb2.Empty] + ]]: + raise NotImplementedError() + + @property + def list_topic_subscriptions(self) -> Callable[ + [admin.ListTopicSubscriptionsRequest], + Union[ + admin.ListTopicSubscriptionsResponse, + Awaitable[admin.ListTopicSubscriptionsResponse] + ]]: + raise NotImplementedError() + + @property + def create_subscription(self) -> Callable[ + [admin.CreateSubscriptionRequest], + Union[ + common.Subscription, + Awaitable[common.Subscription] + ]]: + raise NotImplementedError() + + @property + def get_subscription(self) -> Callable[ + [admin.GetSubscriptionRequest], + Union[ + common.Subscription, + Awaitable[common.Subscription] + ]]: + raise NotImplementedError() + + @property + def list_subscriptions(self) -> Callable[ + [admin.ListSubscriptionsRequest], + Union[ + admin.ListSubscriptionsResponse, + Awaitable[admin.ListSubscriptionsResponse] + ]]: + raise NotImplementedError() + + @property + def update_subscription(self) -> Callable[ + [admin.UpdateSubscriptionRequest], + Union[ + common.Subscription, + Awaitable[common.Subscription] + ]]: + raise NotImplementedError() + + @property + def delete_subscription(self) -> Callable[ + [admin.DeleteSubscriptionRequest], + Union[ + empty_pb2.Empty, + Awaitable[empty_pb2.Empty] + ]]: + raise NotImplementedError() + + @property + def seek_subscription(self) -> Callable[ + [admin.SeekSubscriptionRequest], + Union[ + operations_pb2.Operation, + Awaitable[operations_pb2.Operation] + ]]: + raise NotImplementedError() + + @property + def create_reservation(self) -> Callable[ + [admin.CreateReservationRequest], + Union[ + common.Reservation, + Awaitable[common.Reservation] + ]]: + raise NotImplementedError() + + @property + def get_reservation(self) -> Callable[ + [admin.GetReservationRequest], + Union[ + common.Reservation, + Awaitable[common.Reservation] + ]]: + raise NotImplementedError() + + @property + def list_reservations(self) -> Callable[ + [admin.ListReservationsRequest], + Union[ + admin.ListReservationsResponse, + Awaitable[admin.ListReservationsResponse] + ]]: + raise NotImplementedError() + + @property + def update_reservation(self) -> Callable[ + [admin.UpdateReservationRequest], + Union[ + common.Reservation, + Awaitable[common.Reservation] + ]]: + raise NotImplementedError() + + @property + def delete_reservation(self) -> Callable[ + [admin.DeleteReservationRequest], + Union[ + empty_pb2.Empty, + Awaitable[empty_pb2.Empty] + ]]: + raise NotImplementedError() + + @property + def list_reservation_topics(self) -> Callable[ + [admin.ListReservationTopicsRequest], + Union[ + admin.ListReservationTopicsResponse, + Awaitable[admin.ListReservationTopicsResponse] + ]]: + raise NotImplementedError() + + +__all__ = ( + 'AdminServiceTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/grpc.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/grpc.py new file mode 100644 index 00000000..74044a7d --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/grpc.py @@ -0,0 +1,776 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.api_core import gapic_v1 # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from .base import AdminServiceTransport, DEFAULT_CLIENT_INFO + + +class AdminServiceGrpcTransport(AdminServiceTransport): + """gRPC backend transport for AdminService. + + The service that a client application uses to manage topics + and subscriptions, such creating, listing, and deleting topics + and subscriptions. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + _stubs: Dict[str, Callable] + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client = None + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Sanity check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsClient( + self.grpc_channel + ) + + # Return the client from cache. + return self._operations_client + + @property + def create_topic(self) -> Callable[ + [admin.CreateTopicRequest], + common.Topic]: + r"""Return a callable for the create topic method over gRPC. + + Creates a new topic. + + Returns: + Callable[[~.CreateTopicRequest], + ~.Topic]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'create_topic' not in self._stubs: + self._stubs['create_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/CreateTopic', + request_serializer=admin.CreateTopicRequest.serialize, + response_deserializer=common.Topic.deserialize, + ) + return self._stubs['create_topic'] + + @property + def get_topic(self) -> Callable[ + [admin.GetTopicRequest], + common.Topic]: + r"""Return a callable for the get topic method over gRPC. + + Returns the topic configuration. + + Returns: + Callable[[~.GetTopicRequest], + ~.Topic]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_topic' not in self._stubs: + self._stubs['get_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetTopic', + request_serializer=admin.GetTopicRequest.serialize, + response_deserializer=common.Topic.deserialize, + ) + return self._stubs['get_topic'] + + @property + def get_topic_partitions(self) -> Callable[ + [admin.GetTopicPartitionsRequest], + admin.TopicPartitions]: + r"""Return a callable for the get topic partitions method over gRPC. + + Returns the partition information for the requested + topic. + + Returns: + Callable[[~.GetTopicPartitionsRequest], + ~.TopicPartitions]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_topic_partitions' not in self._stubs: + self._stubs['get_topic_partitions'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetTopicPartitions', + request_serializer=admin.GetTopicPartitionsRequest.serialize, + response_deserializer=admin.TopicPartitions.deserialize, + ) + return self._stubs['get_topic_partitions'] + + @property + def list_topics(self) -> Callable[ + [admin.ListTopicsRequest], + admin.ListTopicsResponse]: + r"""Return a callable for the list topics method over gRPC. + + Returns the list of topics for the given project. + + Returns: + Callable[[~.ListTopicsRequest], + ~.ListTopicsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_topics' not in self._stubs: + self._stubs['list_topics'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListTopics', + request_serializer=admin.ListTopicsRequest.serialize, + response_deserializer=admin.ListTopicsResponse.deserialize, + ) + return self._stubs['list_topics'] + + @property + def update_topic(self) -> Callable[ + [admin.UpdateTopicRequest], + common.Topic]: + r"""Return a callable for the update topic method over gRPC. + + Updates properties of the specified topic. + + Returns: + Callable[[~.UpdateTopicRequest], + ~.Topic]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'update_topic' not in self._stubs: + self._stubs['update_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/UpdateTopic', + request_serializer=admin.UpdateTopicRequest.serialize, + response_deserializer=common.Topic.deserialize, + ) + return self._stubs['update_topic'] + + @property + def delete_topic(self) -> Callable[ + [admin.DeleteTopicRequest], + empty_pb2.Empty]: + r"""Return a callable for the delete topic method over gRPC. + + Deletes the specified topic. + + Returns: + Callable[[~.DeleteTopicRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'delete_topic' not in self._stubs: + self._stubs['delete_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/DeleteTopic', + request_serializer=admin.DeleteTopicRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs['delete_topic'] + + @property + def list_topic_subscriptions(self) -> Callable[ + [admin.ListTopicSubscriptionsRequest], + admin.ListTopicSubscriptionsResponse]: + r"""Return a callable for the list topic subscriptions method over gRPC. + + Lists the subscriptions attached to the specified + topic. + + Returns: + Callable[[~.ListTopicSubscriptionsRequest], + ~.ListTopicSubscriptionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_topic_subscriptions' not in self._stubs: + self._stubs['list_topic_subscriptions'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListTopicSubscriptions', + request_serializer=admin.ListTopicSubscriptionsRequest.serialize, + response_deserializer=admin.ListTopicSubscriptionsResponse.deserialize, + ) + return self._stubs['list_topic_subscriptions'] + + @property + def create_subscription(self) -> Callable[ + [admin.CreateSubscriptionRequest], + common.Subscription]: + r"""Return a callable for the create subscription method over gRPC. + + Creates a new subscription. + + Returns: + Callable[[~.CreateSubscriptionRequest], + ~.Subscription]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'create_subscription' not in self._stubs: + self._stubs['create_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/CreateSubscription', + request_serializer=admin.CreateSubscriptionRequest.serialize, + response_deserializer=common.Subscription.deserialize, + ) + return self._stubs['create_subscription'] + + @property + def get_subscription(self) -> Callable[ + [admin.GetSubscriptionRequest], + common.Subscription]: + r"""Return a callable for the get subscription method over gRPC. + + Returns the subscription configuration. + + Returns: + Callable[[~.GetSubscriptionRequest], + ~.Subscription]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_subscription' not in self._stubs: + self._stubs['get_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetSubscription', + request_serializer=admin.GetSubscriptionRequest.serialize, + response_deserializer=common.Subscription.deserialize, + ) + return self._stubs['get_subscription'] + + @property + def list_subscriptions(self) -> Callable[ + [admin.ListSubscriptionsRequest], + admin.ListSubscriptionsResponse]: + r"""Return a callable for the list subscriptions method over gRPC. + + Returns the list of subscriptions for the given + project. + + Returns: + Callable[[~.ListSubscriptionsRequest], + ~.ListSubscriptionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_subscriptions' not in self._stubs: + self._stubs['list_subscriptions'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListSubscriptions', + request_serializer=admin.ListSubscriptionsRequest.serialize, + response_deserializer=admin.ListSubscriptionsResponse.deserialize, + ) + return self._stubs['list_subscriptions'] + + @property + def update_subscription(self) -> Callable[ + [admin.UpdateSubscriptionRequest], + common.Subscription]: + r"""Return a callable for the update subscription method over gRPC. + + Updates properties of the specified subscription. + + Returns: + Callable[[~.UpdateSubscriptionRequest], + ~.Subscription]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'update_subscription' not in self._stubs: + self._stubs['update_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/UpdateSubscription', + request_serializer=admin.UpdateSubscriptionRequest.serialize, + response_deserializer=common.Subscription.deserialize, + ) + return self._stubs['update_subscription'] + + @property + def delete_subscription(self) -> Callable[ + [admin.DeleteSubscriptionRequest], + empty_pb2.Empty]: + r"""Return a callable for the delete subscription method over gRPC. + + Deletes the specified subscription. + + Returns: + Callable[[~.DeleteSubscriptionRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'delete_subscription' not in self._stubs: + self._stubs['delete_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/DeleteSubscription', + request_serializer=admin.DeleteSubscriptionRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs['delete_subscription'] + + @property + def seek_subscription(self) -> Callable[ + [admin.SeekSubscriptionRequest], + operations_pb2.Operation]: + r"""Return a callable for the seek subscription method over gRPC. + + Performs an out-of-band seek for a subscription to a + specified target, which may be timestamps or named + positions within the message backlog. Seek translates + these targets to cursors for each partition and + orchestrates subscribers to start consuming messages + from these seek cursors. + + If an operation is returned, the seek has been + registered and subscribers will eventually receive + messages from the seek cursors (i.e. eventual + consistency), as long as they are using a minimum + supported client library version and not a system that + tracks cursors independently of Pub/Sub Lite (e.g. + Apache Beam, Dataflow, Spark). The seek operation will + fail for unsupported clients. + + If clients would like to know when subscribers react to + the seek (or not), they can poll the operation. The seek + operation will succeed and complete once subscribers are + ready to receive messages from the seek cursors for all + partitions of the topic. This means that the seek + operation will not complete until all subscribers come + online. + + If the previous seek operation has not yet completed, it + will be aborted and the new invocation of seek will + supersede it. + + Returns: + Callable[[~.SeekSubscriptionRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'seek_subscription' not in self._stubs: + self._stubs['seek_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/SeekSubscription', + request_serializer=admin.SeekSubscriptionRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs['seek_subscription'] + + @property + def create_reservation(self) -> Callable[ + [admin.CreateReservationRequest], + common.Reservation]: + r"""Return a callable for the create reservation method over gRPC. + + Creates a new reservation. + + Returns: + Callable[[~.CreateReservationRequest], + ~.Reservation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'create_reservation' not in self._stubs: + self._stubs['create_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/CreateReservation', + request_serializer=admin.CreateReservationRequest.serialize, + response_deserializer=common.Reservation.deserialize, + ) + return self._stubs['create_reservation'] + + @property + def get_reservation(self) -> Callable[ + [admin.GetReservationRequest], + common.Reservation]: + r"""Return a callable for the get reservation method over gRPC. + + Returns the reservation configuration. + + Returns: + Callable[[~.GetReservationRequest], + ~.Reservation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_reservation' not in self._stubs: + self._stubs['get_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetReservation', + request_serializer=admin.GetReservationRequest.serialize, + response_deserializer=common.Reservation.deserialize, + ) + return self._stubs['get_reservation'] + + @property + def list_reservations(self) -> Callable[ + [admin.ListReservationsRequest], + admin.ListReservationsResponse]: + r"""Return a callable for the list reservations method over gRPC. + + Returns the list of reservations for the given + project. + + Returns: + Callable[[~.ListReservationsRequest], + ~.ListReservationsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_reservations' not in self._stubs: + self._stubs['list_reservations'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListReservations', + request_serializer=admin.ListReservationsRequest.serialize, + response_deserializer=admin.ListReservationsResponse.deserialize, + ) + return self._stubs['list_reservations'] + + @property + def update_reservation(self) -> Callable[ + [admin.UpdateReservationRequest], + common.Reservation]: + r"""Return a callable for the update reservation method over gRPC. + + Updates properties of the specified reservation. + + Returns: + Callable[[~.UpdateReservationRequest], + ~.Reservation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'update_reservation' not in self._stubs: + self._stubs['update_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/UpdateReservation', + request_serializer=admin.UpdateReservationRequest.serialize, + response_deserializer=common.Reservation.deserialize, + ) + return self._stubs['update_reservation'] + + @property + def delete_reservation(self) -> Callable[ + [admin.DeleteReservationRequest], + empty_pb2.Empty]: + r"""Return a callable for the delete reservation method over gRPC. + + Deletes the specified reservation. + + Returns: + Callable[[~.DeleteReservationRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'delete_reservation' not in self._stubs: + self._stubs['delete_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/DeleteReservation', + request_serializer=admin.DeleteReservationRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs['delete_reservation'] + + @property + def list_reservation_topics(self) -> Callable[ + [admin.ListReservationTopicsRequest], + admin.ListReservationTopicsResponse]: + r"""Return a callable for the list reservation topics method over gRPC. + + Lists the topics attached to the specified + reservation. + + Returns: + Callable[[~.ListReservationTopicsRequest], + ~.ListReservationTopicsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_reservation_topics' not in self._stubs: + self._stubs['list_reservation_topics'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListReservationTopics', + request_serializer=admin.ListReservationTopicsRequest.serialize, + response_deserializer=admin.ListReservationTopicsResponse.deserialize, + ) + return self._stubs['list_reservation_topics'] + + def close(self): + self.grpc_channel.close() + +__all__ = ( + 'AdminServiceGrpcTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/grpc_asyncio.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/grpc_asyncio.py new file mode 100644 index 00000000..fc3518da --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/admin_service/transports/grpc_asyncio.py @@ -0,0 +1,781 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from .base import AdminServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import AdminServiceGrpcTransport + + +class AdminServiceGrpcAsyncIOTransport(AdminServiceTransport): + """gRPC AsyncIO backend transport for AdminService. + + The service that a client application uses to manage topics + and subscriptions, such creating, listing, and deleting topics + and subscriptions. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client = None + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsAsyncClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Sanity check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsAsyncClient( + self.grpc_channel + ) + + # Return the client from cache. + return self._operations_client + + @property + def create_topic(self) -> Callable[ + [admin.CreateTopicRequest], + Awaitable[common.Topic]]: + r"""Return a callable for the create topic method over gRPC. + + Creates a new topic. + + Returns: + Callable[[~.CreateTopicRequest], + Awaitable[~.Topic]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'create_topic' not in self._stubs: + self._stubs['create_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/CreateTopic', + request_serializer=admin.CreateTopicRequest.serialize, + response_deserializer=common.Topic.deserialize, + ) + return self._stubs['create_topic'] + + @property + def get_topic(self) -> Callable[ + [admin.GetTopicRequest], + Awaitable[common.Topic]]: + r"""Return a callable for the get topic method over gRPC. + + Returns the topic configuration. + + Returns: + Callable[[~.GetTopicRequest], + Awaitable[~.Topic]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_topic' not in self._stubs: + self._stubs['get_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetTopic', + request_serializer=admin.GetTopicRequest.serialize, + response_deserializer=common.Topic.deserialize, + ) + return self._stubs['get_topic'] + + @property + def get_topic_partitions(self) -> Callable[ + [admin.GetTopicPartitionsRequest], + Awaitable[admin.TopicPartitions]]: + r"""Return a callable for the get topic partitions method over gRPC. + + Returns the partition information for the requested + topic. + + Returns: + Callable[[~.GetTopicPartitionsRequest], + Awaitable[~.TopicPartitions]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_topic_partitions' not in self._stubs: + self._stubs['get_topic_partitions'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetTopicPartitions', + request_serializer=admin.GetTopicPartitionsRequest.serialize, + response_deserializer=admin.TopicPartitions.deserialize, + ) + return self._stubs['get_topic_partitions'] + + @property + def list_topics(self) -> Callable[ + [admin.ListTopicsRequest], + Awaitable[admin.ListTopicsResponse]]: + r"""Return a callable for the list topics method over gRPC. + + Returns the list of topics for the given project. + + Returns: + Callable[[~.ListTopicsRequest], + Awaitable[~.ListTopicsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_topics' not in self._stubs: + self._stubs['list_topics'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListTopics', + request_serializer=admin.ListTopicsRequest.serialize, + response_deserializer=admin.ListTopicsResponse.deserialize, + ) + return self._stubs['list_topics'] + + @property + def update_topic(self) -> Callable[ + [admin.UpdateTopicRequest], + Awaitable[common.Topic]]: + r"""Return a callable for the update topic method over gRPC. + + Updates properties of the specified topic. + + Returns: + Callable[[~.UpdateTopicRequest], + Awaitable[~.Topic]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'update_topic' not in self._stubs: + self._stubs['update_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/UpdateTopic', + request_serializer=admin.UpdateTopicRequest.serialize, + response_deserializer=common.Topic.deserialize, + ) + return self._stubs['update_topic'] + + @property + def delete_topic(self) -> Callable[ + [admin.DeleteTopicRequest], + Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete topic method over gRPC. + + Deletes the specified topic. + + Returns: + Callable[[~.DeleteTopicRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'delete_topic' not in self._stubs: + self._stubs['delete_topic'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/DeleteTopic', + request_serializer=admin.DeleteTopicRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs['delete_topic'] + + @property + def list_topic_subscriptions(self) -> Callable[ + [admin.ListTopicSubscriptionsRequest], + Awaitable[admin.ListTopicSubscriptionsResponse]]: + r"""Return a callable for the list topic subscriptions method over gRPC. + + Lists the subscriptions attached to the specified + topic. + + Returns: + Callable[[~.ListTopicSubscriptionsRequest], + Awaitable[~.ListTopicSubscriptionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_topic_subscriptions' not in self._stubs: + self._stubs['list_topic_subscriptions'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListTopicSubscriptions', + request_serializer=admin.ListTopicSubscriptionsRequest.serialize, + response_deserializer=admin.ListTopicSubscriptionsResponse.deserialize, + ) + return self._stubs['list_topic_subscriptions'] + + @property + def create_subscription(self) -> Callable[ + [admin.CreateSubscriptionRequest], + Awaitable[common.Subscription]]: + r"""Return a callable for the create subscription method over gRPC. + + Creates a new subscription. + + Returns: + Callable[[~.CreateSubscriptionRequest], + Awaitable[~.Subscription]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'create_subscription' not in self._stubs: + self._stubs['create_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/CreateSubscription', + request_serializer=admin.CreateSubscriptionRequest.serialize, + response_deserializer=common.Subscription.deserialize, + ) + return self._stubs['create_subscription'] + + @property + def get_subscription(self) -> Callable[ + [admin.GetSubscriptionRequest], + Awaitable[common.Subscription]]: + r"""Return a callable for the get subscription method over gRPC. + + Returns the subscription configuration. + + Returns: + Callable[[~.GetSubscriptionRequest], + Awaitable[~.Subscription]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_subscription' not in self._stubs: + self._stubs['get_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetSubscription', + request_serializer=admin.GetSubscriptionRequest.serialize, + response_deserializer=common.Subscription.deserialize, + ) + return self._stubs['get_subscription'] + + @property + def list_subscriptions(self) -> Callable[ + [admin.ListSubscriptionsRequest], + Awaitable[admin.ListSubscriptionsResponse]]: + r"""Return a callable for the list subscriptions method over gRPC. + + Returns the list of subscriptions for the given + project. + + Returns: + Callable[[~.ListSubscriptionsRequest], + Awaitable[~.ListSubscriptionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_subscriptions' not in self._stubs: + self._stubs['list_subscriptions'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListSubscriptions', + request_serializer=admin.ListSubscriptionsRequest.serialize, + response_deserializer=admin.ListSubscriptionsResponse.deserialize, + ) + return self._stubs['list_subscriptions'] + + @property + def update_subscription(self) -> Callable[ + [admin.UpdateSubscriptionRequest], + Awaitable[common.Subscription]]: + r"""Return a callable for the update subscription method over gRPC. + + Updates properties of the specified subscription. + + Returns: + Callable[[~.UpdateSubscriptionRequest], + Awaitable[~.Subscription]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'update_subscription' not in self._stubs: + self._stubs['update_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/UpdateSubscription', + request_serializer=admin.UpdateSubscriptionRequest.serialize, + response_deserializer=common.Subscription.deserialize, + ) + return self._stubs['update_subscription'] + + @property + def delete_subscription(self) -> Callable[ + [admin.DeleteSubscriptionRequest], + Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete subscription method over gRPC. + + Deletes the specified subscription. + + Returns: + Callable[[~.DeleteSubscriptionRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'delete_subscription' not in self._stubs: + self._stubs['delete_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/DeleteSubscription', + request_serializer=admin.DeleteSubscriptionRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs['delete_subscription'] + + @property + def seek_subscription(self) -> Callable[ + [admin.SeekSubscriptionRequest], + Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the seek subscription method over gRPC. + + Performs an out-of-band seek for a subscription to a + specified target, which may be timestamps or named + positions within the message backlog. Seek translates + these targets to cursors for each partition and + orchestrates subscribers to start consuming messages + from these seek cursors. + + If an operation is returned, the seek has been + registered and subscribers will eventually receive + messages from the seek cursors (i.e. eventual + consistency), as long as they are using a minimum + supported client library version and not a system that + tracks cursors independently of Pub/Sub Lite (e.g. + Apache Beam, Dataflow, Spark). The seek operation will + fail for unsupported clients. + + If clients would like to know when subscribers react to + the seek (or not), they can poll the operation. The seek + operation will succeed and complete once subscribers are + ready to receive messages from the seek cursors for all + partitions of the topic. This means that the seek + operation will not complete until all subscribers come + online. + + If the previous seek operation has not yet completed, it + will be aborted and the new invocation of seek will + supersede it. + + Returns: + Callable[[~.SeekSubscriptionRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'seek_subscription' not in self._stubs: + self._stubs['seek_subscription'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/SeekSubscription', + request_serializer=admin.SeekSubscriptionRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs['seek_subscription'] + + @property + def create_reservation(self) -> Callable[ + [admin.CreateReservationRequest], + Awaitable[common.Reservation]]: + r"""Return a callable for the create reservation method over gRPC. + + Creates a new reservation. + + Returns: + Callable[[~.CreateReservationRequest], + Awaitable[~.Reservation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'create_reservation' not in self._stubs: + self._stubs['create_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/CreateReservation', + request_serializer=admin.CreateReservationRequest.serialize, + response_deserializer=common.Reservation.deserialize, + ) + return self._stubs['create_reservation'] + + @property + def get_reservation(self) -> Callable[ + [admin.GetReservationRequest], + Awaitable[common.Reservation]]: + r"""Return a callable for the get reservation method over gRPC. + + Returns the reservation configuration. + + Returns: + Callable[[~.GetReservationRequest], + Awaitable[~.Reservation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'get_reservation' not in self._stubs: + self._stubs['get_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/GetReservation', + request_serializer=admin.GetReservationRequest.serialize, + response_deserializer=common.Reservation.deserialize, + ) + return self._stubs['get_reservation'] + + @property + def list_reservations(self) -> Callable[ + [admin.ListReservationsRequest], + Awaitable[admin.ListReservationsResponse]]: + r"""Return a callable for the list reservations method over gRPC. + + Returns the list of reservations for the given + project. + + Returns: + Callable[[~.ListReservationsRequest], + Awaitable[~.ListReservationsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_reservations' not in self._stubs: + self._stubs['list_reservations'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListReservations', + request_serializer=admin.ListReservationsRequest.serialize, + response_deserializer=admin.ListReservationsResponse.deserialize, + ) + return self._stubs['list_reservations'] + + @property + def update_reservation(self) -> Callable[ + [admin.UpdateReservationRequest], + Awaitable[common.Reservation]]: + r"""Return a callable for the update reservation method over gRPC. + + Updates properties of the specified reservation. + + Returns: + Callable[[~.UpdateReservationRequest], + Awaitable[~.Reservation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'update_reservation' not in self._stubs: + self._stubs['update_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/UpdateReservation', + request_serializer=admin.UpdateReservationRequest.serialize, + response_deserializer=common.Reservation.deserialize, + ) + return self._stubs['update_reservation'] + + @property + def delete_reservation(self) -> Callable[ + [admin.DeleteReservationRequest], + Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete reservation method over gRPC. + + Deletes the specified reservation. + + Returns: + Callable[[~.DeleteReservationRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'delete_reservation' not in self._stubs: + self._stubs['delete_reservation'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/DeleteReservation', + request_serializer=admin.DeleteReservationRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs['delete_reservation'] + + @property + def list_reservation_topics(self) -> Callable[ + [admin.ListReservationTopicsRequest], + Awaitable[admin.ListReservationTopicsResponse]]: + r"""Return a callable for the list reservation topics method over gRPC. + + Lists the topics attached to the specified + reservation. + + Returns: + Callable[[~.ListReservationTopicsRequest], + Awaitable[~.ListReservationTopicsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_reservation_topics' not in self._stubs: + self._stubs['list_reservation_topics'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.AdminService/ListReservationTopics', + request_serializer=admin.ListReservationTopicsRequest.serialize, + response_deserializer=admin.ListReservationTopicsResponse.deserialize, + ) + return self._stubs['list_reservation_topics'] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ( + 'AdminServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/__init__.py new file mode 100644 index 00000000..3e903471 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .client import CursorServiceClient +from .async_client import CursorServiceAsyncClient + +__all__ = ( + 'CursorServiceClient', + 'CursorServiceAsyncClient', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/async_client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/async_client.py new file mode 100644 index 00000000..5d8e77e6 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/async_client.py @@ -0,0 +1,374 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, AsyncIterable, Awaitable, AsyncIterator, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.services.cursor_service import pagers +from google.cloud.pubsublite_v1.types import cursor +from .transports.base import CursorServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import CursorServiceGrpcAsyncIOTransport +from .client import CursorServiceClient + + +class CursorServiceAsyncClient: + """The service that a subscriber client application uses to + manage committed cursors while receiving messsages. A cursor + represents a subscriber's progress within a topic partition for + a given subscription. + """ + + _client: CursorServiceClient + + DEFAULT_ENDPOINT = CursorServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = CursorServiceClient.DEFAULT_MTLS_ENDPOINT + + subscription_path = staticmethod(CursorServiceClient.subscription_path) + parse_subscription_path = staticmethod(CursorServiceClient.parse_subscription_path) + common_billing_account_path = staticmethod(CursorServiceClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod(CursorServiceClient.parse_common_billing_account_path) + common_folder_path = staticmethod(CursorServiceClient.common_folder_path) + parse_common_folder_path = staticmethod(CursorServiceClient.parse_common_folder_path) + common_organization_path = staticmethod(CursorServiceClient.common_organization_path) + parse_common_organization_path = staticmethod(CursorServiceClient.parse_common_organization_path) + common_project_path = staticmethod(CursorServiceClient.common_project_path) + parse_common_project_path = staticmethod(CursorServiceClient.parse_common_project_path) + common_location_path = staticmethod(CursorServiceClient.common_location_path) + parse_common_location_path = staticmethod(CursorServiceClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + CursorServiceAsyncClient: The constructed client. + """ + return CursorServiceClient.from_service_account_info.__func__(CursorServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + CursorServiceAsyncClient: The constructed client. + """ + return CursorServiceClient.from_service_account_file.__func__(CursorServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> CursorServiceTransport: + """Returns the transport used by the client instance. + + Returns: + CursorServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial(type(CursorServiceClient).get_transport_class, type(CursorServiceClient)) + + def __init__(self, *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, CursorServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the cursor service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.CursorServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = CursorServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + + ) + + def streaming_commit_cursor(self, + requests: AsyncIterator[cursor.StreamingCommitCursorRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Awaitable[AsyncIterable[cursor.StreamingCommitCursorResponse]]: + r"""Establishes a stream with the server for managing + committed cursors. + + Args: + requests (AsyncIterator[`google.cloud.pubsublite_v1.types.StreamingCommitCursorRequest`]): + The request object AsyncIterator. A request sent from the client to + the server on a stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + AsyncIterable[google.cloud.pubsublite_v1.types.StreamingCommitCursorResponse]: + Response to a + StreamingCommitCursorRequest. + + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.streaming_commit_cursor, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def commit_cursor(self, + request: cursor.CommitCursorRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cursor.CommitCursorResponse: + r"""Updates the committed cursor. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.CommitCursorRequest`): + The request object. Request for CommitCursor. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.CommitCursorResponse: + Response for CommitCursor. + """ + # Create or coerce a protobuf request object. + request = cursor.CommitCursorRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.commit_cursor, + default_retry=retries.Retry( +initial=0.1,maximum=60.0,multiplier=1.3, predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("subscription", request.subscription), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_partition_cursors(self, + request: cursor.ListPartitionCursorsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListPartitionCursorsAsyncPager: + r"""Returns all committed cursor information for a + subscription. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ListPartitionCursorsRequest`): + The request object. Request for ListPartitionCursors. + parent (:class:`str`): + Required. The subscription for which to retrieve + cursors. Structured like + ``projects/{project_number}/locations/{location}/subscriptions/{subscription_id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.cursor_service.pagers.ListPartitionCursorsAsyncPager: + Response for ListPartitionCursors + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = cursor.ListPartitionCursorsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_partition_cursors, + default_retry=retries.Retry( +initial=0.1,maximum=60.0,multiplier=1.3, predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListPartitionCursorsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "CursorServiceAsyncClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/client.py new file mode 100644 index 00000000..f2c57688 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/client.py @@ -0,0 +1,548 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Dict, Optional, Iterable, Iterator, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.services.cursor_service import pagers +from google.cloud.pubsublite_v1.types import cursor +from .transports.base import CursorServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import CursorServiceGrpcTransport +from .transports.grpc_asyncio import CursorServiceGrpcAsyncIOTransport + + +class CursorServiceClientMeta(type): + """Metaclass for the CursorService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + _transport_registry = OrderedDict() # type: Dict[str, Type[CursorServiceTransport]] + _transport_registry["grpc"] = CursorServiceGrpcTransport + _transport_registry["grpc_asyncio"] = CursorServiceGrpcAsyncIOTransport + + def get_transport_class(cls, + label: str = None, + ) -> Type[CursorServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class CursorServiceClient(metaclass=CursorServiceClientMeta): + """The service that a subscriber client application uses to + manage committed cursors while receiving messsages. A cursor + represents a subscriber's progress within a topic partition for + a given subscription. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsublite.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + CursorServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + CursorServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file( + filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> CursorServiceTransport: + """Returns the transport used by the client instance. + + Returns: + CursorServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def subscription_path(project: str,location: str,subscription: str,) -> str: + """Returns a fully-qualified subscription string.""" + return "projects/{project}/locations/{location}/subscriptions/{subscription}".format(project=project, location=location, subscription=subscription, ) + + @staticmethod + def parse_subscription_path(path: str) -> Dict[str,str]: + """Parses a subscription path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)/subscriptions/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path(billing_account: str, ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str,str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str, ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder, ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str,str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str, ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization, ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str,str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str, ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format(project=project, ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str,str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str, ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format(project=project, location=location, ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str,str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__(self, *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, CursorServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the cursor service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, CursorServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool(util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, CursorServiceTransport): + # transport is a CursorServiceTransport instance. + if credentials or client_options.credentials_file: + raise ValueError("When providing a transport instance, " + "provide its credentials directly.") + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + ) + + def streaming_commit_cursor(self, + requests: Iterator[cursor.StreamingCommitCursorRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Iterable[cursor.StreamingCommitCursorResponse]: + r"""Establishes a stream with the server for managing + committed cursors. + + Args: + requests (Iterator[google.cloud.pubsublite_v1.types.StreamingCommitCursorRequest]): + The request object iterator. A request sent from the client to + the server on a stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + Iterable[google.cloud.pubsublite_v1.types.StreamingCommitCursorResponse]: + Response to a + StreamingCommitCursorRequest. + + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.streaming_commit_cursor] + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def commit_cursor(self, + request: Union[cursor.CommitCursorRequest, dict] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cursor.CommitCursorResponse: + r"""Updates the committed cursor. + + Args: + request (Union[google.cloud.pubsublite_v1.types.CommitCursorRequest, dict]): + The request object. Request for CommitCursor. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.CommitCursorResponse: + Response for CommitCursor. + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a cursor.CommitCursorRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, cursor.CommitCursorRequest): + request = cursor.CommitCursorRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.commit_cursor] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("subscription", request.subscription), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_partition_cursors(self, + request: Union[cursor.ListPartitionCursorsRequest, dict] = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListPartitionCursorsPager: + r"""Returns all committed cursor information for a + subscription. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ListPartitionCursorsRequest, dict]): + The request object. Request for ListPartitionCursors. + parent (str): + Required. The subscription for which to retrieve + cursors. Structured like + ``projects/{project_number}/locations/{location}/subscriptions/{subscription_id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.services.cursor_service.pagers.ListPartitionCursorsPager: + Response for ListPartitionCursors + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a cursor.ListPartitionCursorsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, cursor.ListPartitionCursorsRequest): + request = cursor.ListPartitionCursorsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_partition_cursors] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListPartitionCursorsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "CursorServiceClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/pagers.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/pagers.py new file mode 100644 index 00000000..7ddfb055 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/pagers.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, AsyncIterator, Awaitable, Callable, Sequence, Tuple, Optional, Iterator + +from google.cloud.pubsublite_v1.types import cursor + + +class ListPartitionCursorsPager: + """A pager for iterating through ``list_partition_cursors`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListPartitionCursorsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``partition_cursors`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListPartitionCursors`` requests and continue to iterate + through the ``partition_cursors`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListPartitionCursorsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., cursor.ListPartitionCursorsResponse], + request: cursor.ListPartitionCursorsRequest, + response: cursor.ListPartitionCursorsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListPartitionCursorsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListPartitionCursorsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = cursor.ListPartitionCursorsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[cursor.ListPartitionCursorsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[cursor.PartitionCursor]: + for page in self.pages: + yield from page.partition_cursors + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListPartitionCursorsAsyncPager: + """A pager for iterating through ``list_partition_cursors`` requests. + + This class thinly wraps an initial + :class:`google.cloud.pubsublite_v1.types.ListPartitionCursorsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``partition_cursors`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListPartitionCursors`` requests and continue to iterate + through the ``partition_cursors`` field on the + corresponding responses. + + All the usual :class:`google.cloud.pubsublite_v1.types.ListPartitionCursorsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., Awaitable[cursor.ListPartitionCursorsResponse]], + request: cursor.ListPartitionCursorsRequest, + response: cursor.ListPartitionCursorsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.pubsublite_v1.types.ListPartitionCursorsRequest): + The initial request object. + response (google.cloud.pubsublite_v1.types.ListPartitionCursorsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = cursor.ListPartitionCursorsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[cursor.ListPartitionCursorsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[cursor.PartitionCursor]: + async def async_generator(): + async for page in self.pages: + for response in page.partition_cursors: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/__init__.py new file mode 100644 index 00000000..36e3acc8 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import CursorServiceTransport +from .grpc import CursorServiceGrpcTransport +from .grpc_asyncio import CursorServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[CursorServiceTransport]] +_transport_registry['grpc'] = CursorServiceGrpcTransport +_transport_registry['grpc_asyncio'] = CursorServiceGrpcAsyncIOTransport + +__all__ = ( + 'CursorServiceTransport', + 'CursorServiceGrpcTransport', + 'CursorServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/base.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/base.py new file mode 100644 index 00000000..700484da --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/base.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version +import pkg_resources + +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import cursor + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + 'google-cloud-pubsublite', + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + + +class CursorServiceTransport(abc.ABC): + """Abstract transport class for CursorService.""" + + AUTH_SCOPES = ( + 'https://www.googleapis.com/auth/cloud-platform', + ) + + DEFAULT_HOST: str = 'pubsublite.googleapis.com' + def __init__( + self, *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ':' not in host: + host += ':443' + self._host = host + + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs("'credentials_file' and 'credentials' are mutually exclusive") + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, + **scopes_kwargs, + quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = google.auth.default(**scopes_kwargs, quota_project_id=quota_project_id) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if always_use_jwt_access and isinstance(credentials, service_account.Credentials) and hasattr(service_account.Credentials, "with_always_use_jwt_access"): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # TODO(busunkim): This method is in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-auth is increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs(cls, host: str, scopes: Optional[Sequence[str]]) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.streaming_commit_cursor: gapic_v1.method.wrap_method( + self.streaming_commit_cursor, + default_timeout=None, + client_info=client_info, + ), + self.commit_cursor: gapic_v1.method.wrap_method( + self.commit_cursor, + default_retry=retries.Retry( +initial=0.1,maximum=60.0,multiplier=1.3, predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + self.list_partition_cursors: gapic_v1.method.wrap_method( + self.list_partition_cursors, + default_retry=retries.Retry( +initial=0.1,maximum=60.0,multiplier=1.3, predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=600.0, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def streaming_commit_cursor(self) -> Callable[ + [cursor.StreamingCommitCursorRequest], + Union[ + cursor.StreamingCommitCursorResponse, + Awaitable[cursor.StreamingCommitCursorResponse] + ]]: + raise NotImplementedError() + + @property + def commit_cursor(self) -> Callable[ + [cursor.CommitCursorRequest], + Union[ + cursor.CommitCursorResponse, + Awaitable[cursor.CommitCursorResponse] + ]]: + raise NotImplementedError() + + @property + def list_partition_cursors(self) -> Callable[ + [cursor.ListPartitionCursorsRequest], + Union[ + cursor.ListPartitionCursorsResponse, + Awaitable[cursor.ListPartitionCursorsResponse] + ]]: + raise NotImplementedError() + + +__all__ = ( + 'CursorServiceTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/grpc.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/grpc.py new file mode 100644 index 00000000..29b0f504 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/grpc.py @@ -0,0 +1,311 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.pubsublite_v1.types import cursor +from .base import CursorServiceTransport, DEFAULT_CLIENT_INFO + + +class CursorServiceGrpcTransport(CursorServiceTransport): + """gRPC backend transport for CursorService. + + The service that a subscriber client application uses to + manage committed cursors while receiving messsages. A cursor + represents a subscriber's progress within a topic partition for + a given subscription. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + _stubs: Dict[str, Callable] + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def streaming_commit_cursor(self) -> Callable[ + [cursor.StreamingCommitCursorRequest], + cursor.StreamingCommitCursorResponse]: + r"""Return a callable for the streaming commit cursor method over gRPC. + + Establishes a stream with the server for managing + committed cursors. + + Returns: + Callable[[~.StreamingCommitCursorRequest], + ~.StreamingCommitCursorResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'streaming_commit_cursor' not in self._stubs: + self._stubs['streaming_commit_cursor'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.CursorService/StreamingCommitCursor', + request_serializer=cursor.StreamingCommitCursorRequest.serialize, + response_deserializer=cursor.StreamingCommitCursorResponse.deserialize, + ) + return self._stubs['streaming_commit_cursor'] + + @property + def commit_cursor(self) -> Callable[ + [cursor.CommitCursorRequest], + cursor.CommitCursorResponse]: + r"""Return a callable for the commit cursor method over gRPC. + + Updates the committed cursor. + + Returns: + Callable[[~.CommitCursorRequest], + ~.CommitCursorResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'commit_cursor' not in self._stubs: + self._stubs['commit_cursor'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.CursorService/CommitCursor', + request_serializer=cursor.CommitCursorRequest.serialize, + response_deserializer=cursor.CommitCursorResponse.deserialize, + ) + return self._stubs['commit_cursor'] + + @property + def list_partition_cursors(self) -> Callable[ + [cursor.ListPartitionCursorsRequest], + cursor.ListPartitionCursorsResponse]: + r"""Return a callable for the list partition cursors method over gRPC. + + Returns all committed cursor information for a + subscription. + + Returns: + Callable[[~.ListPartitionCursorsRequest], + ~.ListPartitionCursorsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_partition_cursors' not in self._stubs: + self._stubs['list_partition_cursors'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.CursorService/ListPartitionCursors', + request_serializer=cursor.ListPartitionCursorsRequest.serialize, + response_deserializer=cursor.ListPartitionCursorsResponse.deserialize, + ) + return self._stubs['list_partition_cursors'] + + def close(self): + self.grpc_channel.close() + +__all__ = ( + 'CursorServiceGrpcTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/grpc_asyncio.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/grpc_asyncio.py new file mode 100644 index 00000000..4ccf3b40 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/cursor_service/transports/grpc_asyncio.py @@ -0,0 +1,316 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.pubsublite_v1.types import cursor +from .base import CursorServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import CursorServiceGrpcTransport + + +class CursorServiceGrpcAsyncIOTransport(CursorServiceTransport): + """gRPC AsyncIO backend transport for CursorService. + + The service that a subscriber client application uses to + manage committed cursors while receiving messsages. A cursor + represents a subscriber's progress within a topic partition for + a given subscription. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def streaming_commit_cursor(self) -> Callable[ + [cursor.StreamingCommitCursorRequest], + Awaitable[cursor.StreamingCommitCursorResponse]]: + r"""Return a callable for the streaming commit cursor method over gRPC. + + Establishes a stream with the server for managing + committed cursors. + + Returns: + Callable[[~.StreamingCommitCursorRequest], + Awaitable[~.StreamingCommitCursorResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'streaming_commit_cursor' not in self._stubs: + self._stubs['streaming_commit_cursor'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.CursorService/StreamingCommitCursor', + request_serializer=cursor.StreamingCommitCursorRequest.serialize, + response_deserializer=cursor.StreamingCommitCursorResponse.deserialize, + ) + return self._stubs['streaming_commit_cursor'] + + @property + def commit_cursor(self) -> Callable[ + [cursor.CommitCursorRequest], + Awaitable[cursor.CommitCursorResponse]]: + r"""Return a callable for the commit cursor method over gRPC. + + Updates the committed cursor. + + Returns: + Callable[[~.CommitCursorRequest], + Awaitable[~.CommitCursorResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'commit_cursor' not in self._stubs: + self._stubs['commit_cursor'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.CursorService/CommitCursor', + request_serializer=cursor.CommitCursorRequest.serialize, + response_deserializer=cursor.CommitCursorResponse.deserialize, + ) + return self._stubs['commit_cursor'] + + @property + def list_partition_cursors(self) -> Callable[ + [cursor.ListPartitionCursorsRequest], + Awaitable[cursor.ListPartitionCursorsResponse]]: + r"""Return a callable for the list partition cursors method over gRPC. + + Returns all committed cursor information for a + subscription. + + Returns: + Callable[[~.ListPartitionCursorsRequest], + Awaitable[~.ListPartitionCursorsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_partition_cursors' not in self._stubs: + self._stubs['list_partition_cursors'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.CursorService/ListPartitionCursors', + request_serializer=cursor.ListPartitionCursorsRequest.serialize, + response_deserializer=cursor.ListPartitionCursorsResponse.deserialize, + ) + return self._stubs['list_partition_cursors'] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ( + 'CursorServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/__init__.py new file mode 100644 index 00000000..bf0108df --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .client import PartitionAssignmentServiceClient +from .async_client import PartitionAssignmentServiceAsyncClient + +__all__ = ( + 'PartitionAssignmentServiceClient', + 'PartitionAssignmentServiceAsyncClient', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/async_client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/async_client.py new file mode 100644 index 00000000..cf340f71 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/async_client.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, AsyncIterable, Awaitable, AsyncIterator, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .transports.base import PartitionAssignmentServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import PartitionAssignmentServiceGrpcAsyncIOTransport +from .client import PartitionAssignmentServiceClient + + +class PartitionAssignmentServiceAsyncClient: + """The service that a subscriber client application uses to + determine which partitions it should connect to. + """ + + _client: PartitionAssignmentServiceClient + + DEFAULT_ENDPOINT = PartitionAssignmentServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = PartitionAssignmentServiceClient.DEFAULT_MTLS_ENDPOINT + + common_billing_account_path = staticmethod(PartitionAssignmentServiceClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod(PartitionAssignmentServiceClient.parse_common_billing_account_path) + common_folder_path = staticmethod(PartitionAssignmentServiceClient.common_folder_path) + parse_common_folder_path = staticmethod(PartitionAssignmentServiceClient.parse_common_folder_path) + common_organization_path = staticmethod(PartitionAssignmentServiceClient.common_organization_path) + parse_common_organization_path = staticmethod(PartitionAssignmentServiceClient.parse_common_organization_path) + common_project_path = staticmethod(PartitionAssignmentServiceClient.common_project_path) + parse_common_project_path = staticmethod(PartitionAssignmentServiceClient.parse_common_project_path) + common_location_path = staticmethod(PartitionAssignmentServiceClient.common_location_path) + parse_common_location_path = staticmethod(PartitionAssignmentServiceClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PartitionAssignmentServiceAsyncClient: The constructed client. + """ + return PartitionAssignmentServiceClient.from_service_account_info.__func__(PartitionAssignmentServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PartitionAssignmentServiceAsyncClient: The constructed client. + """ + return PartitionAssignmentServiceClient.from_service_account_file.__func__(PartitionAssignmentServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> PartitionAssignmentServiceTransport: + """Returns the transport used by the client instance. + + Returns: + PartitionAssignmentServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial(type(PartitionAssignmentServiceClient).get_transport_class, type(PartitionAssignmentServiceClient)) + + def __init__(self, *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, PartitionAssignmentServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the partition assignment service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.PartitionAssignmentServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = PartitionAssignmentServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + + ) + + def assign_partitions(self, + requests: AsyncIterator[subscriber.PartitionAssignmentRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Awaitable[AsyncIterable[subscriber.PartitionAssignment]]: + r"""Assign partitions for this client to handle for the + specified subscription. + The client must send an + InitialPartitionAssignmentRequest first. The server will + then send at most one unacknowledged PartitionAssignment + outstanding on the stream at a time. + The client should send a PartitionAssignmentAck after + updating the partitions it is connected to to reflect + the new assignment. + + Args: + requests (AsyncIterator[`google.cloud.pubsublite_v1.types.PartitionAssignmentRequest`]): + The request object AsyncIterator. A request on the PartitionAssignment + stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + AsyncIterable[google.cloud.pubsublite_v1.types.PartitionAssignment]: + PartitionAssignments should not race + with acknowledgements. There should be + exactly one unacknowledged + PartitionAssignment at a time. If not, + the client must break the stream. + + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.assign_partitions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "PartitionAssignmentServiceAsyncClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/client.py new file mode 100644 index 00000000..8d79b8d6 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/client.py @@ -0,0 +1,404 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Dict, Optional, Iterable, Iterator, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .transports.base import PartitionAssignmentServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import PartitionAssignmentServiceGrpcTransport +from .transports.grpc_asyncio import PartitionAssignmentServiceGrpcAsyncIOTransport + + +class PartitionAssignmentServiceClientMeta(type): + """Metaclass for the PartitionAssignmentService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + _transport_registry = OrderedDict() # type: Dict[str, Type[PartitionAssignmentServiceTransport]] + _transport_registry["grpc"] = PartitionAssignmentServiceGrpcTransport + _transport_registry["grpc_asyncio"] = PartitionAssignmentServiceGrpcAsyncIOTransport + + def get_transport_class(cls, + label: str = None, + ) -> Type[PartitionAssignmentServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class PartitionAssignmentServiceClient(metaclass=PartitionAssignmentServiceClientMeta): + """The service that a subscriber client application uses to + determine which partitions it should connect to. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsublite.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PartitionAssignmentServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PartitionAssignmentServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file( + filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> PartitionAssignmentServiceTransport: + """Returns the transport used by the client instance. + + Returns: + PartitionAssignmentServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def common_billing_account_path(billing_account: str, ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str,str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str, ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder, ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str,str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str, ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization, ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str,str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str, ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format(project=project, ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str,str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str, ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format(project=project, location=location, ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str,str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__(self, *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, PartitionAssignmentServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the partition assignment service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, PartitionAssignmentServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool(util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, PartitionAssignmentServiceTransport): + # transport is a PartitionAssignmentServiceTransport instance. + if credentials or client_options.credentials_file: + raise ValueError("When providing a transport instance, " + "provide its credentials directly.") + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + ) + + def assign_partitions(self, + requests: Iterator[subscriber.PartitionAssignmentRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Iterable[subscriber.PartitionAssignment]: + r"""Assign partitions for this client to handle for the + specified subscription. + The client must send an + InitialPartitionAssignmentRequest first. The server will + then send at most one unacknowledged PartitionAssignment + outstanding on the stream at a time. + The client should send a PartitionAssignmentAck after + updating the partitions it is connected to to reflect + the new assignment. + + Args: + requests (Iterator[google.cloud.pubsublite_v1.types.PartitionAssignmentRequest]): + The request object iterator. A request on the PartitionAssignment + stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + Iterable[google.cloud.pubsublite_v1.types.PartitionAssignment]: + PartitionAssignments should not race + with acknowledgements. There should be + exactly one unacknowledged + PartitionAssignment at a time. If not, + the client must break the stream. + + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.assign_partitions] + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "PartitionAssignmentServiceClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/__init__.py new file mode 100644 index 00000000..e62a8e32 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import PartitionAssignmentServiceTransport +from .grpc import PartitionAssignmentServiceGrpcTransport +from .grpc_asyncio import PartitionAssignmentServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[PartitionAssignmentServiceTransport]] +_transport_registry['grpc'] = PartitionAssignmentServiceGrpcTransport +_transport_registry['grpc_asyncio'] = PartitionAssignmentServiceGrpcAsyncIOTransport + +__all__ = ( + 'PartitionAssignmentServiceTransport', + 'PartitionAssignmentServiceGrpcTransport', + 'PartitionAssignmentServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/base.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/base.py new file mode 100644 index 00000000..4fddf4a0 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/base.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version +import pkg_resources + +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + 'google-cloud-pubsublite', + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + + +class PartitionAssignmentServiceTransport(abc.ABC): + """Abstract transport class for PartitionAssignmentService.""" + + AUTH_SCOPES = ( + 'https://www.googleapis.com/auth/cloud-platform', + ) + + DEFAULT_HOST: str = 'pubsublite.googleapis.com' + def __init__( + self, *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ':' not in host: + host += ':443' + self._host = host + + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs("'credentials_file' and 'credentials' are mutually exclusive") + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, + **scopes_kwargs, + quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = google.auth.default(**scopes_kwargs, quota_project_id=quota_project_id) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if always_use_jwt_access and isinstance(credentials, service_account.Credentials) and hasattr(service_account.Credentials, "with_always_use_jwt_access"): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # TODO(busunkim): This method is in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-auth is increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs(cls, host: str, scopes: Optional[Sequence[str]]) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.assign_partitions: gapic_v1.method.wrap_method( + self.assign_partitions, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def assign_partitions(self) -> Callable[ + [subscriber.PartitionAssignmentRequest], + Union[ + subscriber.PartitionAssignment, + Awaitable[subscriber.PartitionAssignment] + ]]: + raise NotImplementedError() + + +__all__ = ( + 'PartitionAssignmentServiceTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/grpc.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/grpc.py new file mode 100644 index 00000000..1834c5e6 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/grpc.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .base import PartitionAssignmentServiceTransport, DEFAULT_CLIENT_INFO + + +class PartitionAssignmentServiceGrpcTransport(PartitionAssignmentServiceTransport): + """gRPC backend transport for PartitionAssignmentService. + + The service that a subscriber client application uses to + determine which partitions it should connect to. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + _stubs: Dict[str, Callable] + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def assign_partitions(self) -> Callable[ + [subscriber.PartitionAssignmentRequest], + subscriber.PartitionAssignment]: + r"""Return a callable for the assign partitions method over gRPC. + + Assign partitions for this client to handle for the + specified subscription. + The client must send an + InitialPartitionAssignmentRequest first. The server will + then send at most one unacknowledged PartitionAssignment + outstanding on the stream at a time. + The client should send a PartitionAssignmentAck after + updating the partitions it is connected to to reflect + the new assignment. + + Returns: + Callable[[~.PartitionAssignmentRequest], + ~.PartitionAssignment]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'assign_partitions' not in self._stubs: + self._stubs['assign_partitions'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.PartitionAssignmentService/AssignPartitions', + request_serializer=subscriber.PartitionAssignmentRequest.serialize, + response_deserializer=subscriber.PartitionAssignment.deserialize, + ) + return self._stubs['assign_partitions'] + + def close(self): + self.grpc_channel.close() + +__all__ = ( + 'PartitionAssignmentServiceGrpcTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/grpc_asyncio.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/grpc_asyncio.py new file mode 100644 index 00000000..a0b06e7d --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/partition_assignment_service/transports/grpc_asyncio.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .base import PartitionAssignmentServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import PartitionAssignmentServiceGrpcTransport + + +class PartitionAssignmentServiceGrpcAsyncIOTransport(PartitionAssignmentServiceTransport): + """gRPC AsyncIO backend transport for PartitionAssignmentService. + + The service that a subscriber client application uses to + determine which partitions it should connect to. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def assign_partitions(self) -> Callable[ + [subscriber.PartitionAssignmentRequest], + Awaitable[subscriber.PartitionAssignment]]: + r"""Return a callable for the assign partitions method over gRPC. + + Assign partitions for this client to handle for the + specified subscription. + The client must send an + InitialPartitionAssignmentRequest first. The server will + then send at most one unacknowledged PartitionAssignment + outstanding on the stream at a time. + The client should send a PartitionAssignmentAck after + updating the partitions it is connected to to reflect + the new assignment. + + Returns: + Callable[[~.PartitionAssignmentRequest], + Awaitable[~.PartitionAssignment]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'assign_partitions' not in self._stubs: + self._stubs['assign_partitions'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.PartitionAssignmentService/AssignPartitions', + request_serializer=subscriber.PartitionAssignmentRequest.serialize, + response_deserializer=subscriber.PartitionAssignment.deserialize, + ) + return self._stubs['assign_partitions'] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ( + 'PartitionAssignmentServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/__init__.py new file mode 100644 index 00000000..41e3656c --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .client import PublisherServiceClient +from .async_client import PublisherServiceAsyncClient + +__all__ = ( + 'PublisherServiceClient', + 'PublisherServiceAsyncClient', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/async_client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/async_client.py new file mode 100644 index 00000000..0ada591e --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/async_client.py @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, AsyncIterable, Awaitable, AsyncIterator, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import publisher +from .transports.base import PublisherServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import PublisherServiceGrpcAsyncIOTransport +from .client import PublisherServiceClient + + +class PublisherServiceAsyncClient: + """The service that a publisher client application uses to publish + messages to topics. Published messages are retained by the service + for the duration of the retention period configured for the + respective topic, and are delivered to subscriber clients upon + request (via the ``SubscriberService``). + """ + + _client: PublisherServiceClient + + DEFAULT_ENDPOINT = PublisherServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = PublisherServiceClient.DEFAULT_MTLS_ENDPOINT + + common_billing_account_path = staticmethod(PublisherServiceClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod(PublisherServiceClient.parse_common_billing_account_path) + common_folder_path = staticmethod(PublisherServiceClient.common_folder_path) + parse_common_folder_path = staticmethod(PublisherServiceClient.parse_common_folder_path) + common_organization_path = staticmethod(PublisherServiceClient.common_organization_path) + parse_common_organization_path = staticmethod(PublisherServiceClient.parse_common_organization_path) + common_project_path = staticmethod(PublisherServiceClient.common_project_path) + parse_common_project_path = staticmethod(PublisherServiceClient.parse_common_project_path) + common_location_path = staticmethod(PublisherServiceClient.common_location_path) + parse_common_location_path = staticmethod(PublisherServiceClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherServiceAsyncClient: The constructed client. + """ + return PublisherServiceClient.from_service_account_info.__func__(PublisherServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherServiceAsyncClient: The constructed client. + """ + return PublisherServiceClient.from_service_account_file.__func__(PublisherServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> PublisherServiceTransport: + """Returns the transport used by the client instance. + + Returns: + PublisherServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial(type(PublisherServiceClient).get_transport_class, type(PublisherServiceClient)) + + def __init__(self, *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, PublisherServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the publisher service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.PublisherServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = PublisherServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + + ) + + def publish(self, + requests: AsyncIterator[publisher.PublishRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Awaitable[AsyncIterable[publisher.PublishResponse]]: + r"""Establishes a stream with the server for publishing + messages. Once the stream is initialized, the client + publishes messages by sending publish requests on the + stream. The server responds with a PublishResponse for + each PublishRequest sent by the client, in the same + order that the requests were sent. Note that multiple + PublishRequests can be in flight simultaneously, but + they will be processed by the server in the order that + they are sent by the client on a given stream. + + Args: + requests (AsyncIterator[`google.cloud.pubsublite_v1.types.PublishRequest`]): + The request object AsyncIterator. Request sent from the client to the + server on a stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + AsyncIterable[google.cloud.pubsublite_v1.types.PublishResponse]: + Response to a PublishRequest. + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.publish, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "PublisherServiceAsyncClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/client.py new file mode 100644 index 00000000..2387c546 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/client.py @@ -0,0 +1,402 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Dict, Optional, Iterable, Iterator, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import publisher +from .transports.base import PublisherServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import PublisherServiceGrpcTransport +from .transports.grpc_asyncio import PublisherServiceGrpcAsyncIOTransport + + +class PublisherServiceClientMeta(type): + """Metaclass for the PublisherService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + _transport_registry = OrderedDict() # type: Dict[str, Type[PublisherServiceTransport]] + _transport_registry["grpc"] = PublisherServiceGrpcTransport + _transport_registry["grpc_asyncio"] = PublisherServiceGrpcAsyncIOTransport + + def get_transport_class(cls, + label: str = None, + ) -> Type[PublisherServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class PublisherServiceClient(metaclass=PublisherServiceClientMeta): + """The service that a publisher client application uses to publish + messages to topics. Published messages are retained by the service + for the duration of the retention period configured for the + respective topic, and are delivered to subscriber clients upon + request (via the ``SubscriberService``). + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsublite.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file( + filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> PublisherServiceTransport: + """Returns the transport used by the client instance. + + Returns: + PublisherServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def common_billing_account_path(billing_account: str, ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str,str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str, ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder, ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str,str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str, ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization, ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str,str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str, ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format(project=project, ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str,str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str, ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format(project=project, location=location, ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str,str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__(self, *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, PublisherServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the publisher service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, PublisherServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool(util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, PublisherServiceTransport): + # transport is a PublisherServiceTransport instance. + if credentials or client_options.credentials_file: + raise ValueError("When providing a transport instance, " + "provide its credentials directly.") + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + ) + + def publish(self, + requests: Iterator[publisher.PublishRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Iterable[publisher.PublishResponse]: + r"""Establishes a stream with the server for publishing + messages. Once the stream is initialized, the client + publishes messages by sending publish requests on the + stream. The server responds with a PublishResponse for + each PublishRequest sent by the client, in the same + order that the requests were sent. Note that multiple + PublishRequests can be in flight simultaneously, but + they will be processed by the server in the order that + they are sent by the client on a given stream. + + Args: + requests (Iterator[google.cloud.pubsublite_v1.types.PublishRequest]): + The request object iterator. Request sent from the client to the + server on a stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + Iterable[google.cloud.pubsublite_v1.types.PublishResponse]: + Response to a PublishRequest. + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.publish] + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "PublisherServiceClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/__init__.py new file mode 100644 index 00000000..4216d297 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import PublisherServiceTransport +from .grpc import PublisherServiceGrpcTransport +from .grpc_asyncio import PublisherServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[PublisherServiceTransport]] +_transport_registry['grpc'] = PublisherServiceGrpcTransport +_transport_registry['grpc_asyncio'] = PublisherServiceGrpcAsyncIOTransport + +__all__ = ( + 'PublisherServiceTransport', + 'PublisherServiceGrpcTransport', + 'PublisherServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/base.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/base.py new file mode 100644 index 00000000..42f877e4 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/base.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version +import pkg_resources + +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import publisher + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + 'google-cloud-pubsublite', + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + + +class PublisherServiceTransport(abc.ABC): + """Abstract transport class for PublisherService.""" + + AUTH_SCOPES = ( + 'https://www.googleapis.com/auth/cloud-platform', + ) + + DEFAULT_HOST: str = 'pubsublite.googleapis.com' + def __init__( + self, *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ':' not in host: + host += ':443' + self._host = host + + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs("'credentials_file' and 'credentials' are mutually exclusive") + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, + **scopes_kwargs, + quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = google.auth.default(**scopes_kwargs, quota_project_id=quota_project_id) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if always_use_jwt_access and isinstance(credentials, service_account.Credentials) and hasattr(service_account.Credentials, "with_always_use_jwt_access"): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # TODO(busunkim): This method is in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-auth is increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs(cls, host: str, scopes: Optional[Sequence[str]]) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.publish: gapic_v1.method.wrap_method( + self.publish, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def publish(self) -> Callable[ + [publisher.PublishRequest], + Union[ + publisher.PublishResponse, + Awaitable[publisher.PublishResponse] + ]]: + raise NotImplementedError() + + +__all__ = ( + 'PublisherServiceTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/grpc.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/grpc.py new file mode 100644 index 00000000..4357c994 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/grpc.py @@ -0,0 +1,266 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.pubsublite_v1.types import publisher +from .base import PublisherServiceTransport, DEFAULT_CLIENT_INFO + + +class PublisherServiceGrpcTransport(PublisherServiceTransport): + """gRPC backend transport for PublisherService. + + The service that a publisher client application uses to publish + messages to topics. Published messages are retained by the service + for the duration of the retention period configured for the + respective topic, and are delivered to subscriber clients upon + request (via the ``SubscriberService``). + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + _stubs: Dict[str, Callable] + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def publish(self) -> Callable[ + [publisher.PublishRequest], + publisher.PublishResponse]: + r"""Return a callable for the publish method over gRPC. + + Establishes a stream with the server for publishing + messages. Once the stream is initialized, the client + publishes messages by sending publish requests on the + stream. The server responds with a PublishResponse for + each PublishRequest sent by the client, in the same + order that the requests were sent. Note that multiple + PublishRequests can be in flight simultaneously, but + they will be processed by the server in the order that + they are sent by the client on a given stream. + + Returns: + Callable[[~.PublishRequest], + ~.PublishResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'publish' not in self._stubs: + self._stubs['publish'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.PublisherService/Publish', + request_serializer=publisher.PublishRequest.serialize, + response_deserializer=publisher.PublishResponse.deserialize, + ) + return self._stubs['publish'] + + def close(self): + self.grpc_channel.close() + +__all__ = ( + 'PublisherServiceGrpcTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/grpc_asyncio.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/grpc_asyncio.py new file mode 100644 index 00000000..f91d577a --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/publisher_service/transports/grpc_asyncio.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.pubsublite_v1.types import publisher +from .base import PublisherServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import PublisherServiceGrpcTransport + + +class PublisherServiceGrpcAsyncIOTransport(PublisherServiceTransport): + """gRPC AsyncIO backend transport for PublisherService. + + The service that a publisher client application uses to publish + messages to topics. Published messages are retained by the service + for the duration of the retention period configured for the + respective topic, and are delivered to subscriber clients upon + request (via the ``SubscriberService``). + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def publish(self) -> Callable[ + [publisher.PublishRequest], + Awaitable[publisher.PublishResponse]]: + r"""Return a callable for the publish method over gRPC. + + Establishes a stream with the server for publishing + messages. Once the stream is initialized, the client + publishes messages by sending publish requests on the + stream. The server responds with a PublishResponse for + each PublishRequest sent by the client, in the same + order that the requests were sent. Note that multiple + PublishRequests can be in flight simultaneously, but + they will be processed by the server in the order that + they are sent by the client on a given stream. + + Returns: + Callable[[~.PublishRequest], + Awaitable[~.PublishResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'publish' not in self._stubs: + self._stubs['publish'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.PublisherService/Publish', + request_serializer=publisher.PublishRequest.serialize, + response_deserializer=publisher.PublishResponse.deserialize, + ) + return self._stubs['publish'] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ( + 'PublisherServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/__init__.py new file mode 100644 index 00000000..789d2583 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .client import SubscriberServiceClient +from .async_client import SubscriberServiceAsyncClient + +__all__ = ( + 'SubscriberServiceClient', + 'SubscriberServiceAsyncClient', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/async_client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/async_client.py new file mode 100644 index 00000000..8db30095 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/async_client.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, AsyncIterable, Awaitable, AsyncIterator, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .transports.base import SubscriberServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import SubscriberServiceGrpcAsyncIOTransport +from .client import SubscriberServiceClient + + +class SubscriberServiceAsyncClient: + """The service that a subscriber client application uses to + receive messages from subscriptions. + """ + + _client: SubscriberServiceClient + + DEFAULT_ENDPOINT = SubscriberServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = SubscriberServiceClient.DEFAULT_MTLS_ENDPOINT + + common_billing_account_path = staticmethod(SubscriberServiceClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod(SubscriberServiceClient.parse_common_billing_account_path) + common_folder_path = staticmethod(SubscriberServiceClient.common_folder_path) + parse_common_folder_path = staticmethod(SubscriberServiceClient.parse_common_folder_path) + common_organization_path = staticmethod(SubscriberServiceClient.common_organization_path) + parse_common_organization_path = staticmethod(SubscriberServiceClient.parse_common_organization_path) + common_project_path = staticmethod(SubscriberServiceClient.common_project_path) + parse_common_project_path = staticmethod(SubscriberServiceClient.parse_common_project_path) + common_location_path = staticmethod(SubscriberServiceClient.common_location_path) + parse_common_location_path = staticmethod(SubscriberServiceClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberServiceAsyncClient: The constructed client. + """ + return SubscriberServiceClient.from_service_account_info.__func__(SubscriberServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberServiceAsyncClient: The constructed client. + """ + return SubscriberServiceClient.from_service_account_file.__func__(SubscriberServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> SubscriberServiceTransport: + """Returns the transport used by the client instance. + + Returns: + SubscriberServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial(type(SubscriberServiceClient).get_transport_class, type(SubscriberServiceClient)) + + def __init__(self, *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, SubscriberServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the subscriber service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.SubscriberServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = SubscriberServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + + ) + + def subscribe(self, + requests: AsyncIterator[subscriber.SubscribeRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Awaitable[AsyncIterable[subscriber.SubscribeResponse]]: + r"""Establishes a stream with the server for receiving + messages. + + Args: + requests (AsyncIterator[`google.cloud.pubsublite_v1.types.SubscribeRequest`]): + The request object AsyncIterator. A request sent from the client to + the server on a stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + AsyncIterable[google.cloud.pubsublite_v1.types.SubscribeResponse]: + Response to SubscribeRequest. + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.subscribe, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "SubscriberServiceAsyncClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/client.py new file mode 100644 index 00000000..7340e05f --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/client.py @@ -0,0 +1,392 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Dict, Optional, Iterable, Iterator, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .transports.base import SubscriberServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import SubscriberServiceGrpcTransport +from .transports.grpc_asyncio import SubscriberServiceGrpcAsyncIOTransport + + +class SubscriberServiceClientMeta(type): + """Metaclass for the SubscriberService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + _transport_registry = OrderedDict() # type: Dict[str, Type[SubscriberServiceTransport]] + _transport_registry["grpc"] = SubscriberServiceGrpcTransport + _transport_registry["grpc_asyncio"] = SubscriberServiceGrpcAsyncIOTransport + + def get_transport_class(cls, + label: str = None, + ) -> Type[SubscriberServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class SubscriberServiceClient(metaclass=SubscriberServiceClientMeta): + """The service that a subscriber client application uses to + receive messages from subscriptions. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsublite.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file( + filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> SubscriberServiceTransport: + """Returns the transport used by the client instance. + + Returns: + SubscriberServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def common_billing_account_path(billing_account: str, ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str,str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str, ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder, ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str,str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str, ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization, ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str,str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str, ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format(project=project, ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str,str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str, ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format(project=project, location=location, ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str,str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__(self, *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, SubscriberServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the subscriber service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, SubscriberServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool(util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, SubscriberServiceTransport): + # transport is a SubscriberServiceTransport instance. + if credentials or client_options.credentials_file: + raise ValueError("When providing a transport instance, " + "provide its credentials directly.") + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + ) + + def subscribe(self, + requests: Iterator[subscriber.SubscribeRequest] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Iterable[subscriber.SubscribeResponse]: + r"""Establishes a stream with the server for receiving + messages. + + Args: + requests (Iterator[google.cloud.pubsublite_v1.types.SubscribeRequest]): + The request object iterator. A request sent from the client to + the server on a stream. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + Iterable[google.cloud.pubsublite_v1.types.SubscribeResponse]: + Response to SubscribeRequest. + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.subscribe] + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "SubscriberServiceClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/__init__.py new file mode 100644 index 00000000..91ec2866 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import SubscriberServiceTransport +from .grpc import SubscriberServiceGrpcTransport +from .grpc_asyncio import SubscriberServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[SubscriberServiceTransport]] +_transport_registry['grpc'] = SubscriberServiceGrpcTransport +_transport_registry['grpc_asyncio'] = SubscriberServiceGrpcAsyncIOTransport + +__all__ = ( + 'SubscriberServiceTransport', + 'SubscriberServiceGrpcTransport', + 'SubscriberServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/base.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/base.py new file mode 100644 index 00000000..509069b5 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/base.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version +import pkg_resources + +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + 'google-cloud-pubsublite', + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + + +class SubscriberServiceTransport(abc.ABC): + """Abstract transport class for SubscriberService.""" + + AUTH_SCOPES = ( + 'https://www.googleapis.com/auth/cloud-platform', + ) + + DEFAULT_HOST: str = 'pubsublite.googleapis.com' + def __init__( + self, *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ':' not in host: + host += ':443' + self._host = host + + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs("'credentials_file' and 'credentials' are mutually exclusive") + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, + **scopes_kwargs, + quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = google.auth.default(**scopes_kwargs, quota_project_id=quota_project_id) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if always_use_jwt_access and isinstance(credentials, service_account.Credentials) and hasattr(service_account.Credentials, "with_always_use_jwt_access"): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # TODO(busunkim): This method is in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-auth is increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs(cls, host: str, scopes: Optional[Sequence[str]]) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.subscribe: gapic_v1.method.wrap_method( + self.subscribe, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def subscribe(self) -> Callable[ + [subscriber.SubscribeRequest], + Union[ + subscriber.SubscribeResponse, + Awaitable[subscriber.SubscribeResponse] + ]]: + raise NotImplementedError() + + +__all__ = ( + 'SubscriberServiceTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/grpc.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/grpc.py new file mode 100644 index 00000000..03ee9472 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/grpc.py @@ -0,0 +1,256 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .base import SubscriberServiceTransport, DEFAULT_CLIENT_INFO + + +class SubscriberServiceGrpcTransport(SubscriberServiceTransport): + """gRPC backend transport for SubscriberService. + + The service that a subscriber client application uses to + receive messages from subscriptions. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + _stubs: Dict[str, Callable] + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def subscribe(self) -> Callable[ + [subscriber.SubscribeRequest], + subscriber.SubscribeResponse]: + r"""Return a callable for the subscribe method over gRPC. + + Establishes a stream with the server for receiving + messages. + + Returns: + Callable[[~.SubscribeRequest], + ~.SubscribeResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'subscribe' not in self._stubs: + self._stubs['subscribe'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.SubscriberService/Subscribe', + request_serializer=subscriber.SubscribeRequest.serialize, + response_deserializer=subscriber.SubscribeResponse.deserialize, + ) + return self._stubs['subscribe'] + + def close(self): + self.grpc_channel.close() + +__all__ = ( + 'SubscriberServiceGrpcTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/grpc_asyncio.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/grpc_asyncio.py new file mode 100644 index 00000000..0aad54fe --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/subscriber_service/transports/grpc_asyncio.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.pubsublite_v1.types import subscriber +from .base import SubscriberServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import SubscriberServiceGrpcTransport + + +class SubscriberServiceGrpcAsyncIOTransport(SubscriberServiceTransport): + """gRPC AsyncIO backend transport for SubscriberService. + + The service that a subscriber client application uses to + receive messages from subscriptions. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def subscribe(self) -> Callable[ + [subscriber.SubscribeRequest], + Awaitable[subscriber.SubscribeResponse]]: + r"""Return a callable for the subscribe method over gRPC. + + Establishes a stream with the server for receiving + messages. + + Returns: + Callable[[~.SubscribeRequest], + Awaitable[~.SubscribeResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'subscribe' not in self._stubs: + self._stubs['subscribe'] = self.grpc_channel.stream_stream( + '/google.cloud.pubsublite.v1.SubscriberService/Subscribe', + request_serializer=subscriber.SubscribeRequest.serialize, + response_deserializer=subscriber.SubscribeResponse.deserialize, + ) + return self._stubs['subscribe'] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ( + 'SubscriberServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/__init__.py new file mode 100644 index 00000000..7c242edc --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .client import TopicStatsServiceClient +from .async_client import TopicStatsServiceAsyncClient + +__all__ = ( + 'TopicStatsServiceClient', + 'TopicStatsServiceAsyncClient', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/async_client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/async_client.py new file mode 100644 index 00000000..db7148a2 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/async_client.py @@ -0,0 +1,343 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import common +from google.cloud.pubsublite_v1.types import topic_stats +from google.protobuf import timestamp_pb2 # type: ignore +from .transports.base import TopicStatsServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import TopicStatsServiceGrpcAsyncIOTransport +from .client import TopicStatsServiceClient + + +class TopicStatsServiceAsyncClient: + """This service allows users to get stats about messages in + their topic. + """ + + _client: TopicStatsServiceClient + + DEFAULT_ENDPOINT = TopicStatsServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = TopicStatsServiceClient.DEFAULT_MTLS_ENDPOINT + + topic_path = staticmethod(TopicStatsServiceClient.topic_path) + parse_topic_path = staticmethod(TopicStatsServiceClient.parse_topic_path) + common_billing_account_path = staticmethod(TopicStatsServiceClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod(TopicStatsServiceClient.parse_common_billing_account_path) + common_folder_path = staticmethod(TopicStatsServiceClient.common_folder_path) + parse_common_folder_path = staticmethod(TopicStatsServiceClient.parse_common_folder_path) + common_organization_path = staticmethod(TopicStatsServiceClient.common_organization_path) + parse_common_organization_path = staticmethod(TopicStatsServiceClient.parse_common_organization_path) + common_project_path = staticmethod(TopicStatsServiceClient.common_project_path) + parse_common_project_path = staticmethod(TopicStatsServiceClient.parse_common_project_path) + common_location_path = staticmethod(TopicStatsServiceClient.common_location_path) + parse_common_location_path = staticmethod(TopicStatsServiceClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TopicStatsServiceAsyncClient: The constructed client. + """ + return TopicStatsServiceClient.from_service_account_info.__func__(TopicStatsServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TopicStatsServiceAsyncClient: The constructed client. + """ + return TopicStatsServiceClient.from_service_account_file.__func__(TopicStatsServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TopicStatsServiceTransport: + """Returns the transport used by the client instance. + + Returns: + TopicStatsServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial(type(TopicStatsServiceClient).get_transport_class, type(TopicStatsServiceClient)) + + def __init__(self, *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, TopicStatsServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the topic stats service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.TopicStatsServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = TopicStatsServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + + ) + + async def compute_message_stats(self, + request: topic_stats.ComputeMessageStatsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> topic_stats.ComputeMessageStatsResponse: + r"""Compute statistics about a range of messages in a + given topic and partition. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ComputeMessageStatsRequest`): + The request object. Compute statistics about a range of + messages in a given topic and partition. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.ComputeMessageStatsResponse: + Response containing stats for + messages in the requested topic and + partition. + + """ + # Create or coerce a protobuf request object. + request = topic_stats.ComputeMessageStatsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.compute_message_stats, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic", request.topic), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def compute_head_cursor(self, + request: topic_stats.ComputeHeadCursorRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> topic_stats.ComputeHeadCursorResponse: + r"""Compute the head cursor for the partition. + The head cursor's offset is guaranteed to be less than + or equal to all messages which have not yet been + acknowledged as published, and greater than the offset + of any message whose publish has already been + acknowledged. It is zero if there have never been + messages in the partition. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ComputeHeadCursorRequest`): + The request object. Compute the current head cursor for + a partition. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.ComputeHeadCursorResponse: + Response containing the head cursor + for the requested topic and partition. + + """ + # Create or coerce a protobuf request object. + request = topic_stats.ComputeHeadCursorRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.compute_head_cursor, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic", request.topic), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def compute_time_cursor(self, + request: topic_stats.ComputeTimeCursorRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> topic_stats.ComputeTimeCursorResponse: + r"""Compute the corresponding cursor for a publish or + event time in a topic partition. + + Args: + request (:class:`google.cloud.pubsublite_v1.types.ComputeTimeCursorRequest`): + The request object. Compute the corresponding cursor for + a publish or event time in a topic partition. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.ComputeTimeCursorResponse: + Response containing the cursor + corresponding to a publish or event time + in a topic partition. + + """ + # Create or coerce a protobuf request object. + request = topic_stats.ComputeTimeCursorRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.compute_time_cursor, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic", request.topic), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "TopicStatsServiceAsyncClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/client.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/client.py new file mode 100644 index 00000000..28f99a28 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/client.py @@ -0,0 +1,543 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Dict, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import common +from google.cloud.pubsublite_v1.types import topic_stats +from google.protobuf import timestamp_pb2 # type: ignore +from .transports.base import TopicStatsServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import TopicStatsServiceGrpcTransport +from .transports.grpc_asyncio import TopicStatsServiceGrpcAsyncIOTransport + + +class TopicStatsServiceClientMeta(type): + """Metaclass for the TopicStatsService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + _transport_registry = OrderedDict() # type: Dict[str, Type[TopicStatsServiceTransport]] + _transport_registry["grpc"] = TopicStatsServiceGrpcTransport + _transport_registry["grpc_asyncio"] = TopicStatsServiceGrpcAsyncIOTransport + + def get_transport_class(cls, + label: str = None, + ) -> Type[TopicStatsServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class TopicStatsServiceClient(metaclass=TopicStatsServiceClientMeta): + """This service allows users to get stats about messages in + their topic. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsublite.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TopicStatsServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TopicStatsServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file( + filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TopicStatsServiceTransport: + """Returns the transport used by the client instance. + + Returns: + TopicStatsServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def topic_path(project: str,location: str,topic: str,) -> str: + """Returns a fully-qualified topic string.""" + return "projects/{project}/locations/{location}/topics/{topic}".format(project=project, location=location, topic=topic, ) + + @staticmethod + def parse_topic_path(path: str) -> Dict[str,str]: + """Parses a topic path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)/topics/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path(billing_account: str, ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str,str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str, ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder, ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str,str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str, ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization, ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str,str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str, ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format(project=project, ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str,str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str, ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format(project=project, location=location, ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str,str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__(self, *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, TopicStatsServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the topic stats service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, TopicStatsServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool(util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + is_mtls = mtls.has_default_client_cert_source() + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, TopicStatsServiceTransport): + # transport is a TopicStatsServiceTransport instance. + if credentials or client_options.credentials_file: + raise ValueError("When providing a transport instance, " + "provide its credentials directly.") + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + ) + + def compute_message_stats(self, + request: Union[topic_stats.ComputeMessageStatsRequest, dict] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> topic_stats.ComputeMessageStatsResponse: + r"""Compute statistics about a range of messages in a + given topic and partition. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ComputeMessageStatsRequest, dict]): + The request object. Compute statistics about a range of + messages in a given topic and partition. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.ComputeMessageStatsResponse: + Response containing stats for + messages in the requested topic and + partition. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a topic_stats.ComputeMessageStatsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, topic_stats.ComputeMessageStatsRequest): + request = topic_stats.ComputeMessageStatsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.compute_message_stats] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic", request.topic), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def compute_head_cursor(self, + request: Union[topic_stats.ComputeHeadCursorRequest, dict] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> topic_stats.ComputeHeadCursorResponse: + r"""Compute the head cursor for the partition. + The head cursor's offset is guaranteed to be less than + or equal to all messages which have not yet been + acknowledged as published, and greater than the offset + of any message whose publish has already been + acknowledged. It is zero if there have never been + messages in the partition. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ComputeHeadCursorRequest, dict]): + The request object. Compute the current head cursor for + a partition. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.ComputeHeadCursorResponse: + Response containing the head cursor + for the requested topic and partition. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a topic_stats.ComputeHeadCursorRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, topic_stats.ComputeHeadCursorRequest): + request = topic_stats.ComputeHeadCursorRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.compute_head_cursor] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic", request.topic), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def compute_time_cursor(self, + request: Union[topic_stats.ComputeTimeCursorRequest, dict] = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> topic_stats.ComputeTimeCursorResponse: + r"""Compute the corresponding cursor for a publish or + event time in a topic partition. + + Args: + request (Union[google.cloud.pubsublite_v1.types.ComputeTimeCursorRequest, dict]): + The request object. Compute the corresponding cursor for + a publish or event time in a topic partition. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.pubsublite_v1.types.ComputeTimeCursorResponse: + Response containing the cursor + corresponding to a publish or event time + in a topic partition. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a topic_stats.ComputeTimeCursorRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, topic_stats.ComputeTimeCursorRequest): + request = topic_stats.ComputeTimeCursorRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.compute_time_cursor] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("topic", request.topic), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-pubsublite", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ( + "TopicStatsServiceClient", +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/__init__.py new file mode 100644 index 00000000..f6278ef5 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import TopicStatsServiceTransport +from .grpc import TopicStatsServiceGrpcTransport +from .grpc_asyncio import TopicStatsServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[TopicStatsServiceTransport]] +_transport_registry['grpc'] = TopicStatsServiceGrpcTransport +_transport_registry['grpc_asyncio'] = TopicStatsServiceGrpcAsyncIOTransport + +__all__ = ( + 'TopicStatsServiceTransport', + 'TopicStatsServiceGrpcTransport', + 'TopicStatsServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/base.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/base.py new file mode 100644 index 00000000..98bc05a4 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/base.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version +import pkg_resources + +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsublite_v1.types import topic_stats + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + 'google-cloud-pubsublite', + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + + +class TopicStatsServiceTransport(abc.ABC): + """Abstract transport class for TopicStatsService.""" + + AUTH_SCOPES = ( + 'https://www.googleapis.com/auth/cloud-platform', + ) + + DEFAULT_HOST: str = 'pubsublite.googleapis.com' + def __init__( + self, *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ':' not in host: + host += ':443' + self._host = host + + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs("'credentials_file' and 'credentials' are mutually exclusive") + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, + **scopes_kwargs, + quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = google.auth.default(**scopes_kwargs, quota_project_id=quota_project_id) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if always_use_jwt_access and isinstance(credentials, service_account.Credentials) and hasattr(service_account.Credentials, "with_always_use_jwt_access"): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # TODO(busunkim): This method is in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-auth is increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs(cls, host: str, scopes: Optional[Sequence[str]]) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.compute_message_stats: gapic_v1.method.wrap_method( + self.compute_message_stats, + default_timeout=None, + client_info=client_info, + ), + self.compute_head_cursor: gapic_v1.method.wrap_method( + self.compute_head_cursor, + default_timeout=None, + client_info=client_info, + ), + self.compute_time_cursor: gapic_v1.method.wrap_method( + self.compute_time_cursor, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def compute_message_stats(self) -> Callable[ + [topic_stats.ComputeMessageStatsRequest], + Union[ + topic_stats.ComputeMessageStatsResponse, + Awaitable[topic_stats.ComputeMessageStatsResponse] + ]]: + raise NotImplementedError() + + @property + def compute_head_cursor(self) -> Callable[ + [topic_stats.ComputeHeadCursorRequest], + Union[ + topic_stats.ComputeHeadCursorResponse, + Awaitable[topic_stats.ComputeHeadCursorResponse] + ]]: + raise NotImplementedError() + + @property + def compute_time_cursor(self) -> Callable[ + [topic_stats.ComputeTimeCursorRequest], + Union[ + topic_stats.ComputeTimeCursorResponse, + Awaitable[topic_stats.ComputeTimeCursorResponse] + ]]: + raise NotImplementedError() + + +__all__ = ( + 'TopicStatsServiceTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/grpc.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/grpc.py new file mode 100644 index 00000000..e5577a39 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/grpc.py @@ -0,0 +1,315 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import gapic_v1 # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.pubsublite_v1.types import topic_stats +from .base import TopicStatsServiceTransport, DEFAULT_CLIENT_INFO + + +class TopicStatsServiceGrpcTransport(TopicStatsServiceTransport): + """gRPC backend transport for TopicStatsService. + + This service allows users to get stats about messages in + their topic. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + _stubs: Dict[str, Callable] + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def compute_message_stats(self) -> Callable[ + [topic_stats.ComputeMessageStatsRequest], + topic_stats.ComputeMessageStatsResponse]: + r"""Return a callable for the compute message stats method over gRPC. + + Compute statistics about a range of messages in a + given topic and partition. + + Returns: + Callable[[~.ComputeMessageStatsRequest], + ~.ComputeMessageStatsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'compute_message_stats' not in self._stubs: + self._stubs['compute_message_stats'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.TopicStatsService/ComputeMessageStats', + request_serializer=topic_stats.ComputeMessageStatsRequest.serialize, + response_deserializer=topic_stats.ComputeMessageStatsResponse.deserialize, + ) + return self._stubs['compute_message_stats'] + + @property + def compute_head_cursor(self) -> Callable[ + [topic_stats.ComputeHeadCursorRequest], + topic_stats.ComputeHeadCursorResponse]: + r"""Return a callable for the compute head cursor method over gRPC. + + Compute the head cursor for the partition. + The head cursor's offset is guaranteed to be less than + or equal to all messages which have not yet been + acknowledged as published, and greater than the offset + of any message whose publish has already been + acknowledged. It is zero if there have never been + messages in the partition. + + Returns: + Callable[[~.ComputeHeadCursorRequest], + ~.ComputeHeadCursorResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'compute_head_cursor' not in self._stubs: + self._stubs['compute_head_cursor'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.TopicStatsService/ComputeHeadCursor', + request_serializer=topic_stats.ComputeHeadCursorRequest.serialize, + response_deserializer=topic_stats.ComputeHeadCursorResponse.deserialize, + ) + return self._stubs['compute_head_cursor'] + + @property + def compute_time_cursor(self) -> Callable[ + [topic_stats.ComputeTimeCursorRequest], + topic_stats.ComputeTimeCursorResponse]: + r"""Return a callable for the compute time cursor method over gRPC. + + Compute the corresponding cursor for a publish or + event time in a topic partition. + + Returns: + Callable[[~.ComputeTimeCursorRequest], + ~.ComputeTimeCursorResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'compute_time_cursor' not in self._stubs: + self._stubs['compute_time_cursor'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.TopicStatsService/ComputeTimeCursor', + request_serializer=topic_stats.ComputeTimeCursorRequest.serialize, + response_deserializer=topic_stats.ComputeTimeCursorResponse.deserialize, + ) + return self._stubs['compute_time_cursor'] + + def close(self): + self.grpc_channel.close() + +__all__ = ( + 'TopicStatsServiceGrpcTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/grpc_asyncio.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/grpc_asyncio.py new file mode 100644 index 00000000..4f6731a3 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/services/topic_stats_service/transports/grpc_asyncio.py @@ -0,0 +1,320 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.pubsublite_v1.types import topic_stats +from .base import TopicStatsServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import TopicStatsServiceGrpcTransport + + +class TopicStatsServiceGrpcAsyncIOTransport(TopicStatsServiceTransport): + """gRPC AsyncIO backend transport for TopicStatsService. + + This service allows users to get stats about messages in + their topic. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel(cls, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs + ) + + def __init__(self, *, + host: str = 'pubsublite.googleapis.com', + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + 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, + always_use_jwt_access: Optional[bool] = False, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the 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 a 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + 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: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + 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 + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + credentials=self._credentials, + credentials_file=credentials_file, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def compute_message_stats(self) -> Callable[ + [topic_stats.ComputeMessageStatsRequest], + Awaitable[topic_stats.ComputeMessageStatsResponse]]: + r"""Return a callable for the compute message stats method over gRPC. + + Compute statistics about a range of messages in a + given topic and partition. + + Returns: + Callable[[~.ComputeMessageStatsRequest], + Awaitable[~.ComputeMessageStatsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'compute_message_stats' not in self._stubs: + self._stubs['compute_message_stats'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.TopicStatsService/ComputeMessageStats', + request_serializer=topic_stats.ComputeMessageStatsRequest.serialize, + response_deserializer=topic_stats.ComputeMessageStatsResponse.deserialize, + ) + return self._stubs['compute_message_stats'] + + @property + def compute_head_cursor(self) -> Callable[ + [topic_stats.ComputeHeadCursorRequest], + Awaitable[topic_stats.ComputeHeadCursorResponse]]: + r"""Return a callable for the compute head cursor method over gRPC. + + Compute the head cursor for the partition. + The head cursor's offset is guaranteed to be less than + or equal to all messages which have not yet been + acknowledged as published, and greater than the offset + of any message whose publish has already been + acknowledged. It is zero if there have never been + messages in the partition. + + Returns: + Callable[[~.ComputeHeadCursorRequest], + Awaitable[~.ComputeHeadCursorResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'compute_head_cursor' not in self._stubs: + self._stubs['compute_head_cursor'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.TopicStatsService/ComputeHeadCursor', + request_serializer=topic_stats.ComputeHeadCursorRequest.serialize, + response_deserializer=topic_stats.ComputeHeadCursorResponse.deserialize, + ) + return self._stubs['compute_head_cursor'] + + @property + def compute_time_cursor(self) -> Callable[ + [topic_stats.ComputeTimeCursorRequest], + Awaitable[topic_stats.ComputeTimeCursorResponse]]: + r"""Return a callable for the compute time cursor method over gRPC. + + Compute the corresponding cursor for a publish or + event time in a topic partition. + + Returns: + Callable[[~.ComputeTimeCursorRequest], + Awaitable[~.ComputeTimeCursorResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'compute_time_cursor' not in self._stubs: + self._stubs['compute_time_cursor'] = self.grpc_channel.unary_unary( + '/google.cloud.pubsublite.v1.TopicStatsService/ComputeTimeCursor', + request_serializer=topic_stats.ComputeTimeCursorRequest.serialize, + response_deserializer=topic_stats.ComputeTimeCursorResponse.deserialize, + ) + return self._stubs['compute_time_cursor'] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ( + 'TopicStatsServiceGrpcAsyncIOTransport', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/__init__.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/__init__.py new file mode 100644 index 00000000..1e9b8f0c --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/__init__.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .admin import ( + CreateReservationRequest, + CreateSubscriptionRequest, + CreateTopicRequest, + DeleteReservationRequest, + DeleteSubscriptionRequest, + DeleteTopicRequest, + GetReservationRequest, + GetSubscriptionRequest, + GetTopicPartitionsRequest, + GetTopicRequest, + ListReservationsRequest, + ListReservationsResponse, + ListReservationTopicsRequest, + ListReservationTopicsResponse, + ListSubscriptionsRequest, + ListSubscriptionsResponse, + ListTopicsRequest, + ListTopicsResponse, + ListTopicSubscriptionsRequest, + ListTopicSubscriptionsResponse, + OperationMetadata, + SeekSubscriptionRequest, + SeekSubscriptionResponse, + TopicPartitions, + UpdateReservationRequest, + UpdateSubscriptionRequest, + UpdateTopicRequest, +) +from .common import ( + AttributeValues, + Cursor, + PubSubMessage, + Reservation, + SequencedMessage, + Subscription, + TimeTarget, + Topic, +) +from .cursor import ( + CommitCursorRequest, + CommitCursorResponse, + InitialCommitCursorRequest, + InitialCommitCursorResponse, + ListPartitionCursorsRequest, + ListPartitionCursorsResponse, + PartitionCursor, + SequencedCommitCursorRequest, + SequencedCommitCursorResponse, + StreamingCommitCursorRequest, + StreamingCommitCursorResponse, +) +from .publisher import ( + InitialPublishRequest, + InitialPublishResponse, + MessagePublishRequest, + MessagePublishResponse, + PublishRequest, + PublishResponse, +) +from .subscriber import ( + FlowControlRequest, + InitialPartitionAssignmentRequest, + InitialSubscribeRequest, + InitialSubscribeResponse, + MessageResponse, + PartitionAssignment, + PartitionAssignmentAck, + PartitionAssignmentRequest, + SeekRequest, + SeekResponse, + SubscribeRequest, + SubscribeResponse, +) +from .topic_stats import ( + ComputeHeadCursorRequest, + ComputeHeadCursorResponse, + ComputeMessageStatsRequest, + ComputeMessageStatsResponse, + ComputeTimeCursorRequest, + ComputeTimeCursorResponse, +) + +__all__ = ( + 'CreateReservationRequest', + 'CreateSubscriptionRequest', + 'CreateTopicRequest', + 'DeleteReservationRequest', + 'DeleteSubscriptionRequest', + 'DeleteTopicRequest', + 'GetReservationRequest', + 'GetSubscriptionRequest', + 'GetTopicPartitionsRequest', + 'GetTopicRequest', + 'ListReservationsRequest', + 'ListReservationsResponse', + 'ListReservationTopicsRequest', + 'ListReservationTopicsResponse', + 'ListSubscriptionsRequest', + 'ListSubscriptionsResponse', + 'ListTopicsRequest', + 'ListTopicsResponse', + 'ListTopicSubscriptionsRequest', + 'ListTopicSubscriptionsResponse', + 'OperationMetadata', + 'SeekSubscriptionRequest', + 'SeekSubscriptionResponse', + 'TopicPartitions', + 'UpdateReservationRequest', + 'UpdateSubscriptionRequest', + 'UpdateTopicRequest', + 'AttributeValues', + 'Cursor', + 'PubSubMessage', + 'Reservation', + 'SequencedMessage', + 'Subscription', + 'TimeTarget', + 'Topic', + 'CommitCursorRequest', + 'CommitCursorResponse', + 'InitialCommitCursorRequest', + 'InitialCommitCursorResponse', + 'ListPartitionCursorsRequest', + 'ListPartitionCursorsResponse', + 'PartitionCursor', + 'SequencedCommitCursorRequest', + 'SequencedCommitCursorResponse', + 'StreamingCommitCursorRequest', + 'StreamingCommitCursorResponse', + 'InitialPublishRequest', + 'InitialPublishResponse', + 'MessagePublishRequest', + 'MessagePublishResponse', + 'PublishRequest', + 'PublishResponse', + 'FlowControlRequest', + 'InitialPartitionAssignmentRequest', + 'InitialSubscribeRequest', + 'InitialSubscribeResponse', + 'MessageResponse', + 'PartitionAssignment', + 'PartitionAssignmentAck', + 'PartitionAssignmentRequest', + 'SeekRequest', + 'SeekResponse', + 'SubscribeRequest', + 'SubscribeResponse', + 'ComputeHeadCursorRequest', + 'ComputeHeadCursorResponse', + 'ComputeMessageStatsRequest', + 'ComputeMessageStatsResponse', + 'ComputeTimeCursorRequest', + 'ComputeTimeCursorResponse', +) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/admin.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/admin.py new file mode 100644 index 00000000..25d17ab4 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/admin.py @@ -0,0 +1,765 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.cloud.pubsublite_v1.types import common +from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore + + +__protobuf__ = proto.module( + package='google.cloud.pubsublite.v1', + manifest={ + 'CreateTopicRequest', + 'GetTopicRequest', + 'GetTopicPartitionsRequest', + 'TopicPartitions', + 'ListTopicsRequest', + 'ListTopicsResponse', + 'UpdateTopicRequest', + 'DeleteTopicRequest', + 'ListTopicSubscriptionsRequest', + 'ListTopicSubscriptionsResponse', + 'CreateSubscriptionRequest', + 'GetSubscriptionRequest', + 'ListSubscriptionsRequest', + 'ListSubscriptionsResponse', + 'UpdateSubscriptionRequest', + 'DeleteSubscriptionRequest', + 'SeekSubscriptionRequest', + 'SeekSubscriptionResponse', + 'OperationMetadata', + 'CreateReservationRequest', + 'GetReservationRequest', + 'ListReservationsRequest', + 'ListReservationsResponse', + 'UpdateReservationRequest', + 'DeleteReservationRequest', + 'ListReservationTopicsRequest', + 'ListReservationTopicsResponse', + }, +) + + +class CreateTopicRequest(proto.Message): + r"""Request for CreateTopic. + + Attributes: + parent (str): + Required. The parent location in which to create the topic. + Structured like + ``projects/{project_number}/locations/{location}``. + topic (google.cloud.pubsublite_v1.types.Topic): + Required. Configuration of the topic to create. Its ``name`` + field is ignored. + topic_id (str): + Required. The ID to use for the topic, which will become the + final component of the topic's name. + + This value is structured like: ``my-topic-name``. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + topic = proto.Field( + proto.MESSAGE, + number=2, + message=common.Topic, + ) + topic_id = proto.Field( + proto.STRING, + number=3, + ) + + +class GetTopicRequest(proto.Message): + r"""Request for GetTopic. + + Attributes: + name (str): + Required. The name of the topic whose + configuration to return. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class GetTopicPartitionsRequest(proto.Message): + r"""Request for GetTopicPartitions. + + Attributes: + name (str): + Required. The topic whose partition + information to return. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class TopicPartitions(proto.Message): + r"""Response for GetTopicPartitions. + + Attributes: + partition_count (int): + The number of partitions in the topic. + """ + + partition_count = proto.Field( + proto.INT64, + number=1, + ) + + +class ListTopicsRequest(proto.Message): + r"""Request for ListTopics. + + Attributes: + parent (str): + Required. The parent whose topics are to be listed. + Structured like + ``projects/{project_number}/locations/{location}``. + page_size (int): + The maximum number of topics to return. The + service may return fewer than this value. + If unset or zero, all topics for the parent will + be returned. + page_token (str): + A page token, received from a previous ``ListTopics`` call. + Provide this to retrieve the subsequent page. + + When paginating, all other parameters provided to + ``ListTopics`` must match the call that provided the page + token. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListTopicsResponse(proto.Message): + r"""Response for ListTopics. + + Attributes: + topics (Sequence[google.cloud.pubsublite_v1.types.Topic]): + The list of topic in the requested parent. + The order of the topics is unspecified. + next_page_token (str): + A token that can be sent as ``page_token`` to retrieve the + next page of results. If this field is omitted, there are no + more results. + """ + + @property + def raw_page(self): + return self + + topics = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=common.Topic, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class UpdateTopicRequest(proto.Message): + r"""Request for UpdateTopic. + + Attributes: + topic (google.cloud.pubsublite_v1.types.Topic): + Required. The topic to update. Its ``name`` field must be + populated. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. A mask specifying the topic fields + to change. + """ + + topic = proto.Field( + proto.MESSAGE, + number=1, + message=common.Topic, + ) + update_mask = proto.Field( + proto.MESSAGE, + number=2, + message=field_mask_pb2.FieldMask, + ) + + +class DeleteTopicRequest(proto.Message): + r"""Request for DeleteTopic. + + Attributes: + name (str): + Required. The name of the topic to delete. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class ListTopicSubscriptionsRequest(proto.Message): + r"""Request for ListTopicSubscriptions. + + Attributes: + name (str): + Required. The name of the topic whose + subscriptions to list. + page_size (int): + The maximum number of subscriptions to + return. The service may return fewer than this + value. If unset or zero, all subscriptions for + the given topic will be returned. + page_token (str): + A page token, received from a previous + ``ListTopicSubscriptions`` call. Provide this to retrieve + the subsequent page. + + When paginating, all other parameters provided to + ``ListTopicSubscriptions`` must match the call that provided + the page token. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListTopicSubscriptionsResponse(proto.Message): + r"""Response for ListTopicSubscriptions. + + Attributes: + subscriptions (Sequence[str]): + The names of subscriptions attached to the + topic. The order of the subscriptions is + unspecified. + next_page_token (str): + A token that can be sent as ``page_token`` to retrieve the + next page of results. If this field is omitted, there are no + more results. + """ + + @property + def raw_page(self): + return self + + subscriptions = proto.RepeatedField( + proto.STRING, + number=1, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class CreateSubscriptionRequest(proto.Message): + r"""Request for CreateSubscription. + + Attributes: + parent (str): + Required. The parent location in which to create the + subscription. Structured like + ``projects/{project_number}/locations/{location}``. + subscription (google.cloud.pubsublite_v1.types.Subscription): + Required. Configuration of the subscription to create. Its + ``name`` field is ignored. + subscription_id (str): + Required. The ID to use for the subscription, which will + become the final component of the subscription's name. + + This value is structured like: ``my-sub-name``. + skip_backlog (bool): + If true, the newly created subscription will + only receive messages published after the + subscription was created. Otherwise, the entire + message backlog will be received on the + subscription. Defaults to false. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + subscription = proto.Field( + proto.MESSAGE, + number=2, + message=common.Subscription, + ) + subscription_id = proto.Field( + proto.STRING, + number=3, + ) + skip_backlog = proto.Field( + proto.BOOL, + number=4, + ) + + +class GetSubscriptionRequest(proto.Message): + r"""Request for GetSubscription. + + Attributes: + name (str): + Required. The name of the subscription whose + configuration to return. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class ListSubscriptionsRequest(proto.Message): + r"""Request for ListSubscriptions. + + Attributes: + parent (str): + Required. The parent whose subscriptions are to be listed. + Structured like + ``projects/{project_number}/locations/{location}``. + page_size (int): + The maximum number of subscriptions to + return. The service may return fewer than this + value. If unset or zero, all subscriptions for + the parent will be returned. + page_token (str): + A page token, received from a previous ``ListSubscriptions`` + call. Provide this to retrieve the subsequent page. + + When paginating, all other parameters provided to + ``ListSubscriptions`` must match the call that provided the + page token. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListSubscriptionsResponse(proto.Message): + r"""Response for ListSubscriptions. + + Attributes: + subscriptions (Sequence[google.cloud.pubsublite_v1.types.Subscription]): + The list of subscriptions in the requested + parent. The order of the subscriptions is + unspecified. + next_page_token (str): + A token that can be sent as ``page_token`` to retrieve the + next page of results. If this field is omitted, there are no + more results. + """ + + @property + def raw_page(self): + return self + + subscriptions = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=common.Subscription, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class UpdateSubscriptionRequest(proto.Message): + r"""Request for UpdateSubscription. + + Attributes: + subscription (google.cloud.pubsublite_v1.types.Subscription): + Required. The subscription to update. Its ``name`` field + must be populated. Topic field must not be populated. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. A mask specifying the subscription + fields to change. + """ + + subscription = proto.Field( + proto.MESSAGE, + number=1, + message=common.Subscription, + ) + update_mask = proto.Field( + proto.MESSAGE, + number=2, + message=field_mask_pb2.FieldMask, + ) + + +class DeleteSubscriptionRequest(proto.Message): + r"""Request for DeleteSubscription. + + Attributes: + name (str): + Required. The name of the subscription to + delete. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class SeekSubscriptionRequest(proto.Message): + r"""Request for SeekSubscription. + + Attributes: + name (str): + Required. The name of the subscription to + seek. + named_target (google.cloud.pubsublite_v1.types.SeekSubscriptionRequest.NamedTarget): + Seek to a named position with respect to the + message backlog. + time_target (google.cloud.pubsublite_v1.types.TimeTarget): + Seek to the first message whose publish or + event time is greater than or equal to the + specified query time. If no such message can be + located, will seek to the end of the message + backlog. + """ + class NamedTarget(proto.Enum): + r"""A named position with respect to the message backlog.""" + NAMED_TARGET_UNSPECIFIED = 0 + TAIL = 1 + HEAD = 2 + + name = proto.Field( + proto.STRING, + number=1, + ) + named_target = proto.Field( + proto.ENUM, + number=2, + oneof='target', + enum=NamedTarget, + ) + time_target = proto.Field( + proto.MESSAGE, + number=3, + oneof='target', + message=common.TimeTarget, + ) + + +class SeekSubscriptionResponse(proto.Message): + r"""Response for SeekSubscription long running operation. + """ + + +class OperationMetadata(proto.Message): + r"""Metadata for long running operations. + + Attributes: + create_time (google.protobuf.timestamp_pb2.Timestamp): + The time the operation was created. + end_time (google.protobuf.timestamp_pb2.Timestamp): + The time the operation finished running. Not + set if the operation has not completed. + target (str): + Resource path for the target of the operation. For example, + targets of seeks are subscription resources, structured + like: + projects/{project_number}/locations/{location}/subscriptions/{subscription_id} + verb (str): + Name of the verb executed by the operation. + """ + + create_time = proto.Field( + proto.MESSAGE, + number=1, + message=timestamp_pb2.Timestamp, + ) + end_time = proto.Field( + proto.MESSAGE, + number=2, + message=timestamp_pb2.Timestamp, + ) + target = proto.Field( + proto.STRING, + number=3, + ) + verb = proto.Field( + proto.STRING, + number=4, + ) + + +class CreateReservationRequest(proto.Message): + r"""Request for CreateReservation. + + Attributes: + parent (str): + Required. The parent location in which to create the + reservation. Structured like + ``projects/{project_number}/locations/{location}``. + reservation (google.cloud.pubsublite_v1.types.Reservation): + Required. Configuration of the reservation to create. Its + ``name`` field is ignored. + reservation_id (str): + Required. The ID to use for the reservation, which will + become the final component of the reservation's name. + + This value is structured like: ``my-reservation-name``. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + reservation = proto.Field( + proto.MESSAGE, + number=2, + message=common.Reservation, + ) + reservation_id = proto.Field( + proto.STRING, + number=3, + ) + + +class GetReservationRequest(proto.Message): + r"""Request for GetReservation. + + Attributes: + name (str): + Required. The name of the reservation whose configuration to + return. Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class ListReservationsRequest(proto.Message): + r"""Request for ListReservations. + + Attributes: + parent (str): + Required. The parent whose reservations are to be listed. + Structured like + ``projects/{project_number}/locations/{location}``. + page_size (int): + The maximum number of reservations to return. + The service may return fewer than this value. If + unset or zero, all reservations for the parent + will be returned. + page_token (str): + A page token, received from a previous ``ListReservations`` + call. Provide this to retrieve the subsequent page. + + When paginating, all other parameters provided to + ``ListReservations`` must match the call that provided the + page token. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListReservationsResponse(proto.Message): + r"""Response for ListReservations. + + Attributes: + reservations (Sequence[google.cloud.pubsublite_v1.types.Reservation]): + The list of reservation in the requested + parent. The order of the reservations is + unspecified. + next_page_token (str): + A token that can be sent as ``page_token`` to retrieve the + next page of results. If this field is omitted, there are no + more results. + """ + + @property + def raw_page(self): + return self + + reservations = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=common.Reservation, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class UpdateReservationRequest(proto.Message): + r"""Request for UpdateReservation. + + Attributes: + reservation (google.cloud.pubsublite_v1.types.Reservation): + Required. The reservation to update. Its ``name`` field must + be populated. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. A mask specifying the reservation + fields to change. + """ + + reservation = proto.Field( + proto.MESSAGE, + number=1, + message=common.Reservation, + ) + update_mask = proto.Field( + proto.MESSAGE, + number=2, + message=field_mask_pb2.FieldMask, + ) + + +class DeleteReservationRequest(proto.Message): + r"""Request for DeleteReservation. + + Attributes: + name (str): + Required. The name of the reservation to delete. Structured + like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class ListReservationTopicsRequest(proto.Message): + r"""Request for ListReservationTopics. + + Attributes: + name (str): + Required. The name of the reservation whose topics to list. + Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + page_size (int): + The maximum number of topics to return. The + service may return fewer than this value. + If unset or zero, all topics for the given + reservation will be returned. + page_token (str): + A page token, received from a previous + ``ListReservationTopics`` call. Provide this to retrieve the + subsequent page. + + When paginating, all other parameters provided to + ``ListReservationTopics`` must match the call that provided + the page token. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListReservationTopicsResponse(proto.Message): + r"""Response for ListReservationTopics. + + Attributes: + topics (Sequence[str]): + The names of topics attached to the + reservation. The order of the topics is + unspecified. + next_page_token (str): + A token that can be sent as ``page_token`` to retrieve the + next page of results. If this field is omitted, there are no + more results. + """ + + @property + def raw_page(self): + return self + + topics = proto.RepeatedField( + proto.STRING, + number=1, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/common.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/common.py new file mode 100644 index 00000000..8d4575e3 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/common.py @@ -0,0 +1,403 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore + + +__protobuf__ = proto.module( + package='google.cloud.pubsublite.v1', + manifest={ + 'AttributeValues', + 'PubSubMessage', + 'Cursor', + 'SequencedMessage', + 'Reservation', + 'Topic', + 'Subscription', + 'TimeTarget', + }, +) + + +class AttributeValues(proto.Message): + r"""The values associated with a key of an attribute. + + Attributes: + values (Sequence[bytes]): + The list of values associated with a key. + """ + + values = proto.RepeatedField( + proto.BYTES, + number=1, + ) + + +class PubSubMessage(proto.Message): + r"""A message that is published by publishers and delivered to + subscribers. + + Attributes: + key (bytes): + The key used for routing messages to + partitions or for compaction (e.g., keep the + last N messages per key). If the key is empty, + the message is routed to an arbitrary partition. + data (bytes): + The payload of the message. + attributes (Sequence[google.cloud.pubsublite_v1.types.PubSubMessage.AttributesEntry]): + Optional attributes that can be used for + message metadata/headers. + event_time (google.protobuf.timestamp_pb2.Timestamp): + An optional, user-specified event time. + """ + + key = proto.Field( + proto.BYTES, + number=1, + ) + data = proto.Field( + proto.BYTES, + number=2, + ) + attributes = proto.MapField( + proto.STRING, + proto.MESSAGE, + number=3, + message='AttributeValues', + ) + event_time = proto.Field( + proto.MESSAGE, + number=4, + message=timestamp_pb2.Timestamp, + ) + + +class Cursor(proto.Message): + r"""A cursor that describes the position of a message within a + topic partition. + + Attributes: + offset (int): + The offset of a message within a topic + partition. Must be greater than or equal 0. + """ + + offset = proto.Field( + proto.INT64, + number=1, + ) + + +class SequencedMessage(proto.Message): + r"""A message that has been stored and sequenced by the Pub/Sub + Lite system. + + Attributes: + cursor (google.cloud.pubsublite_v1.types.Cursor): + The position of a message within the + partition where it is stored. + publish_time (google.protobuf.timestamp_pb2.Timestamp): + The time when the message was received by the + server when it was first published. + message (google.cloud.pubsublite_v1.types.PubSubMessage): + The user message. + size_bytes (int): + The size in bytes of this message for flow + control and quota purposes. + """ + + cursor = proto.Field( + proto.MESSAGE, + number=1, + message='Cursor', + ) + publish_time = proto.Field( + proto.MESSAGE, + number=2, + message=timestamp_pb2.Timestamp, + ) + message = proto.Field( + proto.MESSAGE, + number=3, + message='PubSubMessage', + ) + size_bytes = proto.Field( + proto.INT64, + number=4, + ) + + +class Reservation(proto.Message): + r"""Metadata about a reservation resource. + + Attributes: + name (str): + The name of the reservation. Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + throughput_capacity (int): + The reserved throughput capacity. Every unit + of throughput capacity is equivalent to 1 MiB/s + of published messages or 2 MiB/s of subscribed + messages. + + Any topics which are declared as using capacity + from a Reservation will consume resources from + this reservation instead of being charged + individually. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + throughput_capacity = proto.Field( + proto.INT64, + number=2, + ) + + +class Topic(proto.Message): + r"""Metadata about a topic resource. + + Attributes: + name (str): + The name of the topic. Structured like: + projects/{project_number}/locations/{location}/topics/{topic_id} + partition_config (google.cloud.pubsublite_v1.types.Topic.PartitionConfig): + The settings for this topic's partitions. + retention_config (google.cloud.pubsublite_v1.types.Topic.RetentionConfig): + The settings for this topic's message + retention. + reservation_config (google.cloud.pubsublite_v1.types.Topic.ReservationConfig): + The settings for this topic's Reservation + usage. + """ + + class PartitionConfig(proto.Message): + r"""The settings for a topic's partitions. + + Attributes: + count (int): + The number of partitions in the topic. Must be at least 1. + + Once a topic has been created the number of partitions can + be increased but not decreased. Message ordering is not + guaranteed across a topic resize. For more information see + https://cloud.google.com/pubsub/lite/docs/topics#scaling_capacity + scale (int): + DEPRECATED: Use capacity instead which can express a + superset of configurations. + + Every partition in the topic is allocated throughput + equivalent to ``scale`` times the standard partition + throughput (4 MiB/s). This is also reflected in the cost of + this topic; a topic with ``scale`` of 2 and count of 10 is + charged for 20 partitions. This value must be in the range + [1,4]. + capacity (google.cloud.pubsublite_v1.types.Topic.PartitionConfig.Capacity): + The capacity configuration. + """ + + class Capacity(proto.Message): + r"""The throughput capacity configuration for each partition. + + Attributes: + publish_mib_per_sec (int): + Publish throughput capacity per partition in + MiB/s. Must be >= 4 and <= 16. + subscribe_mib_per_sec (int): + Subscribe throughput capacity per partition + in MiB/s. Must be >= 4 and <= 32. + """ + + publish_mib_per_sec = proto.Field( + proto.INT32, + number=1, + ) + subscribe_mib_per_sec = proto.Field( + proto.INT32, + number=2, + ) + + count = proto.Field( + proto.INT64, + number=1, + ) + scale = proto.Field( + proto.INT32, + number=2, + oneof='dimension', + ) + capacity = proto.Field( + proto.MESSAGE, + number=3, + oneof='dimension', + message='Topic.PartitionConfig.Capacity', + ) + + class RetentionConfig(proto.Message): + r"""The settings for a topic's message retention. + + Attributes: + per_partition_bytes (int): + The provisioned storage, in bytes, per partition. If the + number of bytes stored in any of the topic's partitions + grows beyond this value, older messages will be dropped to + make room for newer ones, regardless of the value of + ``period``. + period (google.protobuf.duration_pb2.Duration): + How long a published message is retained. If unset, messages + will be retained as long as the bytes retained for each + partition is below ``per_partition_bytes``. + """ + + per_partition_bytes = proto.Field( + proto.INT64, + number=1, + ) + period = proto.Field( + proto.MESSAGE, + number=2, + message=duration_pb2.Duration, + ) + + class ReservationConfig(proto.Message): + r"""The settings for this topic's Reservation usage. + + Attributes: + throughput_reservation (str): + The Reservation to use for this topic's throughput capacity. + Structured like: + projects/{project_number}/locations/{location}/reservations/{reservation_id} + """ + + throughput_reservation = proto.Field( + proto.STRING, + number=1, + ) + + name = proto.Field( + proto.STRING, + number=1, + ) + partition_config = proto.Field( + proto.MESSAGE, + number=2, + message=PartitionConfig, + ) + retention_config = proto.Field( + proto.MESSAGE, + number=3, + message=RetentionConfig, + ) + reservation_config = proto.Field( + proto.MESSAGE, + number=4, + message=ReservationConfig, + ) + + +class Subscription(proto.Message): + r"""Metadata about a subscription resource. + + Attributes: + name (str): + The name of the subscription. Structured like: + projects/{project_number}/locations/{location}/subscriptions/{subscription_id} + topic (str): + The name of the topic this subscription is attached to. + Structured like: + projects/{project_number}/locations/{location}/topics/{topic_id} + delivery_config (google.cloud.pubsublite_v1.types.Subscription.DeliveryConfig): + The settings for this subscription's message + delivery. + """ + + class DeliveryConfig(proto.Message): + r"""The settings for a subscription's message delivery. + + Attributes: + delivery_requirement (google.cloud.pubsublite_v1.types.Subscription.DeliveryConfig.DeliveryRequirement): + The DeliveryRequirement for this + subscription. + """ + class DeliveryRequirement(proto.Enum): + r"""When this subscription should send messages to subscribers relative + to messages persistence in storage. For details, see `Creating Lite + subscriptions `__. + """ + DELIVERY_REQUIREMENT_UNSPECIFIED = 0 + DELIVER_IMMEDIATELY = 1 + DELIVER_AFTER_STORED = 2 + + delivery_requirement = proto.Field( + proto.ENUM, + number=3, + enum='Subscription.DeliveryConfig.DeliveryRequirement', + ) + + name = proto.Field( + proto.STRING, + number=1, + ) + topic = proto.Field( + proto.STRING, + number=2, + ) + delivery_config = proto.Field( + proto.MESSAGE, + number=3, + message=DeliveryConfig, + ) + + +class TimeTarget(proto.Message): + r"""A target publish or event time. Can be used for seeking to or + retrieving the corresponding cursor. + + Attributes: + publish_time (google.protobuf.timestamp_pb2.Timestamp): + Request the cursor of the first message with publish time + greater than or equal to ``publish_time``. All messages + thereafter are guaranteed to have publish times >= + ``publish_time``. + event_time (google.protobuf.timestamp_pb2.Timestamp): + Request the cursor of the first message with event time + greater than or equal to ``event_time``. If messages are + missing an event time, the publish time is used as a + fallback. As event times are user supplied, subsequent + messages may have event times less than ``event_time`` and + should be filtered by the client, if necessary. + """ + + publish_time = proto.Field( + proto.MESSAGE, + number=1, + oneof='time', + message=timestamp_pb2.Timestamp, + ) + event_time = proto.Field( + proto.MESSAGE, + number=2, + oneof='time', + message=timestamp_pb2.Timestamp, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/cursor.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/cursor.py new file mode 100644 index 00000000..c5cca0cb --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/cursor.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.cloud.pubsublite_v1.types import common + + +__protobuf__ = proto.module( + package='google.cloud.pubsublite.v1', + manifest={ + 'InitialCommitCursorRequest', + 'InitialCommitCursorResponse', + 'SequencedCommitCursorRequest', + 'SequencedCommitCursorResponse', + 'StreamingCommitCursorRequest', + 'StreamingCommitCursorResponse', + 'CommitCursorRequest', + 'CommitCursorResponse', + 'ListPartitionCursorsRequest', + 'PartitionCursor', + 'ListPartitionCursorsResponse', + }, +) + + +class InitialCommitCursorRequest(proto.Message): + r"""The first streaming request that must be sent on a newly- + pened stream. The client must wait for the response before + sending subsequent requests on the stream. + + Attributes: + subscription (str): + The subscription for which to manage + committed cursors. + partition (int): + The partition for which to manage committed cursors. + Partitions are zero indexed, so ``partition`` must be in the + range [0, topic.num_partitions). + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + + +class InitialCommitCursorResponse(proto.Message): + r"""Response to an InitialCommitCursorRequest. + """ + + +class SequencedCommitCursorRequest(proto.Message): + r"""Streaming request to update the committed cursor. Subsequent + SequencedCommitCursorRequests override outstanding ones. + + Attributes: + cursor (google.cloud.pubsublite_v1.types.Cursor): + The new value for the committed cursor. + """ + + cursor = proto.Field( + proto.MESSAGE, + number=1, + message=common.Cursor, + ) + + +class SequencedCommitCursorResponse(proto.Message): + r"""Response to a SequencedCommitCursorRequest. + + Attributes: + acknowledged_commits (int): + The number of outstanding + SequencedCommitCursorRequests acknowledged by + this response. Note that + SequencedCommitCursorRequests are acknowledged + in the order that they are received. + """ + + acknowledged_commits = proto.Field( + proto.INT64, + number=1, + ) + + +class StreamingCommitCursorRequest(proto.Message): + r"""A request sent from the client to the server on a stream. + + Attributes: + initial (google.cloud.pubsublite_v1.types.InitialCommitCursorRequest): + Initial request on the stream. + commit (google.cloud.pubsublite_v1.types.SequencedCommitCursorRequest): + Request to commit a new cursor value. + """ + + initial = proto.Field( + proto.MESSAGE, + number=1, + oneof='request', + message='InitialCommitCursorRequest', + ) + commit = proto.Field( + proto.MESSAGE, + number=2, + oneof='request', + message='SequencedCommitCursorRequest', + ) + + +class StreamingCommitCursorResponse(proto.Message): + r"""Response to a StreamingCommitCursorRequest. + + Attributes: + initial (google.cloud.pubsublite_v1.types.InitialCommitCursorResponse): + Initial response on the stream. + commit (google.cloud.pubsublite_v1.types.SequencedCommitCursorResponse): + Response to committing a new cursor value. + """ + + initial = proto.Field( + proto.MESSAGE, + number=1, + oneof='request', + message='InitialCommitCursorResponse', + ) + commit = proto.Field( + proto.MESSAGE, + number=2, + oneof='request', + message='SequencedCommitCursorResponse', + ) + + +class CommitCursorRequest(proto.Message): + r"""Request for CommitCursor. + + Attributes: + subscription (str): + The subscription for which to update the + cursor. + partition (int): + The partition for which to update the cursor. Partitions are + zero indexed, so ``partition`` must be in the range [0, + topic.num_partitions). + cursor (google.cloud.pubsublite_v1.types.Cursor): + The new value for the committed cursor. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + cursor = proto.Field( + proto.MESSAGE, + number=3, + message=common.Cursor, + ) + + +class CommitCursorResponse(proto.Message): + r"""Response for CommitCursor. + """ + + +class ListPartitionCursorsRequest(proto.Message): + r"""Request for ListPartitionCursors. + + Attributes: + parent (str): + Required. The subscription for which to retrieve cursors. + Structured like + ``projects/{project_number}/locations/{location}/subscriptions/{subscription_id}``. + page_size (int): + The maximum number of cursors to return. The + service may return fewer than this value. + If unset or zero, all cursors for the parent + will be returned. + page_token (str): + A page token, received from a previous + ``ListPartitionCursors`` call. Provide this to retrieve the + subsequent page. + + When paginating, all other parameters provided to + ``ListPartitionCursors`` must match the call that provided + the page token. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class PartitionCursor(proto.Message): + r"""A pair of a Cursor and the partition it is for. + + Attributes: + partition (int): + The partition this is for. + cursor (google.cloud.pubsublite_v1.types.Cursor): + The value of the cursor. + """ + + partition = proto.Field( + proto.INT64, + number=1, + ) + cursor = proto.Field( + proto.MESSAGE, + number=2, + message=common.Cursor, + ) + + +class ListPartitionCursorsResponse(proto.Message): + r"""Response for ListPartitionCursors + + Attributes: + partition_cursors (Sequence[google.cloud.pubsublite_v1.types.PartitionCursor]): + The partition cursors from this request. + next_page_token (str): + A token, which can be sent as ``page_token`` to retrieve the + next page. If this field is omitted, there are no subsequent + pages. + """ + + @property + def raw_page(self): + return self + + partition_cursors = proto.RepeatedField( + proto.MESSAGE, + number=1, + message='PartitionCursor', + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/publisher.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/publisher.py new file mode 100644 index 00000000..1c486da4 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/publisher.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.cloud.pubsublite_v1.types import common + + +__protobuf__ = proto.module( + package='google.cloud.pubsublite.v1', + manifest={ + 'InitialPublishRequest', + 'InitialPublishResponse', + 'MessagePublishRequest', + 'MessagePublishResponse', + 'PublishRequest', + 'PublishResponse', + }, +) + + +class InitialPublishRequest(proto.Message): + r"""The first request that must be sent on a newly-opened stream. + + Attributes: + topic (str): + The topic to which messages will be written. + partition (int): + The partition within the topic to which messages will be + written. Partitions are zero indexed, so ``partition`` must + be in the range [0, topic.num_partitions). + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + + +class InitialPublishResponse(proto.Message): + r"""Response to an InitialPublishRequest. + """ + + +class MessagePublishRequest(proto.Message): + r"""Request to publish messages to the topic. + + Attributes: + messages (Sequence[google.cloud.pubsublite_v1.types.PubSubMessage]): + The messages to publish. + """ + + messages = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=common.PubSubMessage, + ) + + +class MessagePublishResponse(proto.Message): + r"""Response to a MessagePublishRequest. + + Attributes: + start_cursor (google.cloud.pubsublite_v1.types.Cursor): + The cursor of the first published message in + the batch. The cursors for any remaining + messages in the batch are guaranteed to be + sequential. + """ + + start_cursor = proto.Field( + proto.MESSAGE, + number=1, + message=common.Cursor, + ) + + +class PublishRequest(proto.Message): + r"""Request sent from the client to the server on a stream. + + Attributes: + initial_request (google.cloud.pubsublite_v1.types.InitialPublishRequest): + Initial request on the stream. + message_publish_request (google.cloud.pubsublite_v1.types.MessagePublishRequest): + Request to publish messages. + """ + + initial_request = proto.Field( + proto.MESSAGE, + number=1, + oneof='request_type', + message='InitialPublishRequest', + ) + message_publish_request = proto.Field( + proto.MESSAGE, + number=2, + oneof='request_type', + message='MessagePublishRequest', + ) + + +class PublishResponse(proto.Message): + r"""Response to a PublishRequest. + + Attributes: + initial_response (google.cloud.pubsublite_v1.types.InitialPublishResponse): + Initial response on the stream. + message_response (google.cloud.pubsublite_v1.types.MessagePublishResponse): + Response to publishing messages. + """ + + initial_response = proto.Field( + proto.MESSAGE, + number=1, + oneof='response_type', + message='InitialPublishResponse', + ) + message_response = proto.Field( + proto.MESSAGE, + number=2, + oneof='response_type', + message='MessagePublishResponse', + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/subscriber.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/subscriber.py new file mode 100644 index 00000000..43cb2577 --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/subscriber.py @@ -0,0 +1,341 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.cloud.pubsublite_v1.types import common + + +__protobuf__ = proto.module( + package='google.cloud.pubsublite.v1', + manifest={ + 'InitialSubscribeRequest', + 'InitialSubscribeResponse', + 'SeekRequest', + 'SeekResponse', + 'FlowControlRequest', + 'SubscribeRequest', + 'MessageResponse', + 'SubscribeResponse', + 'InitialPartitionAssignmentRequest', + 'PartitionAssignment', + 'PartitionAssignmentAck', + 'PartitionAssignmentRequest', + }, +) + + +class InitialSubscribeRequest(proto.Message): + r"""The first request that must be sent on a newly-opened stream. + The client must wait for the response before sending subsequent + requests on the stream. + + Attributes: + subscription (str): + The subscription from which to receive + messages. + partition (int): + The partition from which to receive messages. Partitions are + zero indexed, so ``partition`` must be in the range [0, + topic.num_partitions). + initial_location (google.cloud.pubsublite_v1.types.SeekRequest): + Optional. Initial target location within the + message backlog. If not set, messages will be + delivered from the commit cursor for the given + subscription and partition. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + initial_location = proto.Field( + proto.MESSAGE, + number=4, + message='SeekRequest', + ) + + +class InitialSubscribeResponse(proto.Message): + r"""Response to an InitialSubscribeRequest. + + Attributes: + cursor (google.cloud.pubsublite_v1.types.Cursor): + The cursor from which the subscriber will + start receiving messages once flow control + tokens become available. + """ + + cursor = proto.Field( + proto.MESSAGE, + number=1, + message=common.Cursor, + ) + + +class SeekRequest(proto.Message): + r"""Request to update the stream's delivery cursor based on the + given target. Resets the server available tokens to 0. + SeekRequests past head result in stream breakage. + + SeekRequests may not be sent while another SeekRequest is + outstanding (i.e., has not received a SeekResponse) on the same + stream. + + Attributes: + named_target (google.cloud.pubsublite_v1.types.SeekRequest.NamedTarget): + A named target. + cursor (google.cloud.pubsublite_v1.types.Cursor): + A target corresponding to the cursor, + pointing to anywhere in the topic partition. + """ + class NamedTarget(proto.Enum): + r"""A special target in the partition that takes no other + parameters. + """ + NAMED_TARGET_UNSPECIFIED = 0 + HEAD = 1 + COMMITTED_CURSOR = 2 + + named_target = proto.Field( + proto.ENUM, + number=1, + oneof='target', + enum=NamedTarget, + ) + cursor = proto.Field( + proto.MESSAGE, + number=2, + oneof='target', + message=common.Cursor, + ) + + +class SeekResponse(proto.Message): + r"""Response to a SeekRequest. + + Attributes: + cursor (google.cloud.pubsublite_v1.types.Cursor): + The new delivery cursor for the current + stream. + """ + + cursor = proto.Field( + proto.MESSAGE, + number=1, + message=common.Cursor, + ) + + +class FlowControlRequest(proto.Message): + r"""Request to grant tokens to the server, requesting delivery of + messages when they become available. + + Attributes: + allowed_messages (int): + The number of message tokens to grant. Must + be greater than or equal to 0. + allowed_bytes (int): + The number of byte tokens to grant. Must be + greater than or equal to 0. + """ + + allowed_messages = proto.Field( + proto.INT64, + number=1, + ) + allowed_bytes = proto.Field( + proto.INT64, + number=2, + ) + + +class SubscribeRequest(proto.Message): + r"""A request sent from the client to the server on a stream. + + Attributes: + initial (google.cloud.pubsublite_v1.types.InitialSubscribeRequest): + Initial request on the stream. + seek (google.cloud.pubsublite_v1.types.SeekRequest): + Request to update the stream's delivery + cursor. + flow_control (google.cloud.pubsublite_v1.types.FlowControlRequest): + Request to grant tokens to the server, + """ + + initial = proto.Field( + proto.MESSAGE, + number=1, + oneof='request', + message='InitialSubscribeRequest', + ) + seek = proto.Field( + proto.MESSAGE, + number=2, + oneof='request', + message='SeekRequest', + ) + flow_control = proto.Field( + proto.MESSAGE, + number=3, + oneof='request', + message='FlowControlRequest', + ) + + +class MessageResponse(proto.Message): + r"""Response containing a list of messages. Upon delivering a + MessageResponse to the client, the server: + + - Updates the stream's delivery cursor to one greater than the + cursor of the last message in the list. + - Subtracts the total number of bytes and messages from the tokens + available to the server. + + Attributes: + messages (Sequence[google.cloud.pubsublite_v1.types.SequencedMessage]): + Messages from the topic partition. + """ + + messages = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=common.SequencedMessage, + ) + + +class SubscribeResponse(proto.Message): + r"""Response to SubscribeRequest. + + Attributes: + initial (google.cloud.pubsublite_v1.types.InitialSubscribeResponse): + Initial response on the stream. + seek (google.cloud.pubsublite_v1.types.SeekResponse): + Response to a Seek operation. + messages (google.cloud.pubsublite_v1.types.MessageResponse): + Response containing messages from the topic + partition. + """ + + initial = proto.Field( + proto.MESSAGE, + number=1, + oneof='response', + message='InitialSubscribeResponse', + ) + seek = proto.Field( + proto.MESSAGE, + number=2, + oneof='response', + message='SeekResponse', + ) + messages = proto.Field( + proto.MESSAGE, + number=3, + oneof='response', + message='MessageResponse', + ) + + +class InitialPartitionAssignmentRequest(proto.Message): + r"""The first request that must be sent on a newly-opened stream. + The client must wait for the response before sending subsequent + requests on the stream. + + Attributes: + subscription (str): + The subscription name. Structured like: + projects//locations//subscriptions/ + client_id (bytes): + An opaque, unique client identifier. This + field must be exactly 16 bytes long and is + interpreted as an unsigned 128 bit integer. + Other size values will be rejected and the + stream will be failed with a non-retryable + error. + This field is large enough to fit a uuid from + standard uuid algorithms like uuid1 or uuid4, + which should be used to generate this number. + The same identifier should be reused following + disconnections with retryable stream errors. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + client_id = proto.Field( + proto.BYTES, + number=2, + ) + + +class PartitionAssignment(proto.Message): + r"""PartitionAssignments should not race with acknowledgements. + There should be exactly one unacknowledged PartitionAssignment + at a time. If not, the client must break the stream. + + Attributes: + partitions (Sequence[int]): + The list of partition numbers this subscriber + is assigned to. + """ + + partitions = proto.RepeatedField( + proto.INT64, + number=1, + ) + + +class PartitionAssignmentAck(proto.Message): + r"""Acknowledge receipt and handling of the previous assignment. + If not sent within a short period after receiving the + assignment, partitions may remain unassigned for a period of + time until the client is known to be inactive, after which time + the server will break the stream. + + """ + + +class PartitionAssignmentRequest(proto.Message): + r"""A request on the PartitionAssignment stream. + + Attributes: + initial (google.cloud.pubsublite_v1.types.InitialPartitionAssignmentRequest): + Initial request on the stream. + ack (google.cloud.pubsublite_v1.types.PartitionAssignmentAck): + Acknowledgement of a partition assignment. + """ + + initial = proto.Field( + proto.MESSAGE, + number=1, + oneof='request', + message='InitialPartitionAssignmentRequest', + ) + ack = proto.Field( + proto.MESSAGE, + number=2, + oneof='request', + message='PartitionAssignmentAck', + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/topic_stats.py b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/topic_stats.py new file mode 100644 index 00000000..2b3a3f8b --- /dev/null +++ b/owl-bot-staging/v1/google/cloud/pubsublite_v1/types/topic_stats.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.cloud.pubsublite_v1.types import common +from google.protobuf import timestamp_pb2 # type: ignore + + +__protobuf__ = proto.module( + package='google.cloud.pubsublite.v1', + manifest={ + 'ComputeMessageStatsRequest', + 'ComputeMessageStatsResponse', + 'ComputeHeadCursorRequest', + 'ComputeHeadCursorResponse', + 'ComputeTimeCursorRequest', + 'ComputeTimeCursorResponse', + }, +) + + +class ComputeMessageStatsRequest(proto.Message): + r"""Compute statistics about a range of messages in a given topic + and partition. + + Attributes: + topic (str): + Required. The topic for which we should + compute message stats. + partition (int): + Required. The partition for which we should + compute message stats. + start_cursor (google.cloud.pubsublite_v1.types.Cursor): + The inclusive start of the range. + end_cursor (google.cloud.pubsublite_v1.types.Cursor): + The exclusive end of the range. The range is empty if + end_cursor <= start_cursor. Specifying a start_cursor before + the first message and an end_cursor after the last message + will retrieve all messages. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + start_cursor = proto.Field( + proto.MESSAGE, + number=3, + message=common.Cursor, + ) + end_cursor = proto.Field( + proto.MESSAGE, + number=4, + message=common.Cursor, + ) + + +class ComputeMessageStatsResponse(proto.Message): + r"""Response containing stats for messages in the requested topic + and partition. + + Attributes: + message_count (int): + The count of messages. + message_bytes (int): + The number of quota bytes accounted to these + messages. + minimum_publish_time (google.protobuf.timestamp_pb2.Timestamp): + The minimum publish timestamp across these + messages. Note that publish timestamps within a + partition are not guaranteed to be non- + decreasing. The timestamp will be unset if there + are no messages. + minimum_event_time (google.protobuf.timestamp_pb2.Timestamp): + The minimum event timestamp across these + messages. For the purposes of this computation, + if a message does not have an event time, we use + the publish time. The timestamp will be unset if + there are no messages. + """ + + message_count = proto.Field( + proto.INT64, + number=1, + ) + message_bytes = proto.Field( + proto.INT64, + number=2, + ) + minimum_publish_time = proto.Field( + proto.MESSAGE, + number=3, + message=timestamp_pb2.Timestamp, + ) + minimum_event_time = proto.Field( + proto.MESSAGE, + number=4, + message=timestamp_pb2.Timestamp, + ) + + +class ComputeHeadCursorRequest(proto.Message): + r"""Compute the current head cursor for a partition. + + Attributes: + topic (str): + Required. The topic for which we should + compute the head cursor. + partition (int): + Required. The partition for which we should + compute the head cursor. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + + +class ComputeHeadCursorResponse(proto.Message): + r"""Response containing the head cursor for the requested topic + and partition. + + Attributes: + head_cursor (google.cloud.pubsublite_v1.types.Cursor): + The head cursor. + """ + + head_cursor = proto.Field( + proto.MESSAGE, + number=1, + message=common.Cursor, + ) + + +class ComputeTimeCursorRequest(proto.Message): + r"""Compute the corresponding cursor for a publish or event time + in a topic partition. + + Attributes: + topic (str): + Required. The topic for which we should + compute the cursor. + partition (int): + Required. The partition for which we should + compute the cursor. + target (google.cloud.pubsublite_v1.types.TimeTarget): + Required. The target publish or event time. + Specifying a future time will return an unset + cursor. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + partition = proto.Field( + proto.INT64, + number=2, + ) + target = proto.Field( + proto.MESSAGE, + number=3, + message=common.TimeTarget, + ) + + +class ComputeTimeCursorResponse(proto.Message): + r"""Response containing the cursor corresponding to a publish or + event time in a topic partition. + + Attributes: + cursor (google.cloud.pubsublite_v1.types.Cursor): + If present, the cursor references the first message with + time greater than or equal to the specified target time. If + such a message cannot be found, the cursor will be unset + (i.e. ``cursor`` is not present). + """ + + cursor = proto.Field( + proto.MESSAGE, + number=1, + message=common.Cursor, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/owl-bot-staging/v1/mypy.ini b/owl-bot-staging/v1/mypy.ini new file mode 100644 index 00000000..4505b485 --- /dev/null +++ b/owl-bot-staging/v1/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +python_version = 3.6 +namespace_packages = True diff --git a/owl-bot-staging/v1/noxfile.py b/owl-bot-staging/v1/noxfile.py new file mode 100644 index 00000000..b6c6a14a --- /dev/null +++ b/owl-bot-staging/v1/noxfile.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import pathlib +import shutil +import subprocess +import sys + + +import nox # type: ignore + +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +LOWER_BOUND_CONSTRAINTS_FILE = CURRENT_DIRECTORY / "constraints.txt" +PACKAGE_NAME = subprocess.check_output([sys.executable, "setup.py", "--name"], encoding="utf-8") + + +nox.sessions = [ + "unit", + "cover", + "mypy", + "check_lower_bounds" + # exclude update_lower_bounds from default + "docs", +] + +@nox.session(python=['3.6', '3.7', '3.8', '3.9']) +def unit(session): + """Run the unit test suite.""" + + session.install('coverage', 'pytest', 'pytest-cov', 'asyncmock', 'pytest-asyncio') + session.install('-e', '.') + + session.run( + 'py.test', + '--quiet', + '--cov=google/cloud/pubsublite_v1/', + '--cov-config=.coveragerc', + '--cov-report=term', + '--cov-report=html', + os.path.join('tests', 'unit', ''.join(session.posargs)) + ) + + +@nox.session(python='3.7') +def cover(session): + """Run the final coverage report. + This outputs the coverage report aggregating coverage from the unit + test runs (not system test runs), and then erases coverage data. + """ + session.install("coverage", "pytest-cov") + session.run("coverage", "report", "--show-missing", "--fail-under=100") + + session.run("coverage", "erase") + + +@nox.session(python=['3.6', '3.7']) +def mypy(session): + """Run the type checker.""" + session.install('mypy', 'types-pkg_resources') + session.install('.') + session.run( + 'mypy', + '--explicit-package-bases', + 'google', + ) + + +@nox.session +def update_lower_bounds(session): + """Update lower bounds in constraints.txt to match setup.py""" + session.install('google-cloud-testutils') + session.install('.') + + session.run( + 'lower-bound-checker', + 'update', + '--package-name', + PACKAGE_NAME, + '--constraints-file', + str(LOWER_BOUND_CONSTRAINTS_FILE), + ) + + +@nox.session +def check_lower_bounds(session): + """Check lower bounds in setup.py are reflected in constraints file""" + session.install('google-cloud-testutils') + session.install('.') + + session.run( + 'lower-bound-checker', + 'check', + '--package-name', + PACKAGE_NAME, + '--constraints-file', + str(LOWER_BOUND_CONSTRAINTS_FILE), + ) + +@nox.session(python='3.6') +def docs(session): + """Build the docs for this library.""" + + session.install("-e", ".") + session.install("sphinx<3.0.0", "alabaster", "recommonmark") + + shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run( + "sphinx-build", + "-W", # warnings as errors + "-T", # show full traceback on exception + "-N", # no colors + "-b", + "html", + "-d", + os.path.join("docs", "_build", "doctrees", ""), + os.path.join("docs", ""), + os.path.join("docs", "_build", "html", ""), + ) diff --git a/owl-bot-staging/v1/scripts/fixup_pubsublite_v1_keywords.py b/owl-bot-staging/v1/scripts/fixup_pubsublite_v1_keywords.py new file mode 100644 index 00000000..c81c7432 --- /dev/null +++ b/owl-bot-staging/v1/scripts/fixup_pubsublite_v1_keywords.py @@ -0,0 +1,203 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class pubsubliteCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'assign_partitions': ('initial', 'ack', ), + 'commit_cursor': ('subscription', 'partition', 'cursor', ), + 'compute_head_cursor': ('topic', 'partition', ), + 'compute_message_stats': ('topic', 'partition', 'start_cursor', 'end_cursor', ), + 'compute_time_cursor': ('topic', 'partition', 'target', ), + 'create_reservation': ('parent', 'reservation', 'reservation_id', ), + 'create_subscription': ('parent', 'subscription', 'subscription_id', 'skip_backlog', ), + 'create_topic': ('parent', 'topic', 'topic_id', ), + 'delete_reservation': ('name', ), + 'delete_subscription': ('name', ), + 'delete_topic': ('name', ), + 'get_reservation': ('name', ), + 'get_subscription': ('name', ), + 'get_topic': ('name', ), + 'get_topic_partitions': ('name', ), + 'list_partition_cursors': ('parent', 'page_size', 'page_token', ), + 'list_reservations': ('parent', 'page_size', 'page_token', ), + 'list_reservation_topics': ('name', 'page_size', 'page_token', ), + 'list_subscriptions': ('parent', 'page_size', 'page_token', ), + 'list_topics': ('parent', 'page_size', 'page_token', ), + 'list_topic_subscriptions': ('name', 'page_size', 'page_token', ), + 'publish': ('initial_request', 'message_publish_request', ), + 'seek_subscription': ('name', 'named_target', 'time_target', ), + 'streaming_commit_cursor': ('initial', 'commit', ), + 'subscribe': ('initial', 'seek', 'flow_control', ), + 'update_reservation': ('reservation', 'update_mask', ), + 'update_subscription': ('subscription', 'update_mask', ), + 'update_topic': ('topic', 'update_mask', ), + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: a.keyword.value not in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), +cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=pubsubliteCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the pubsublite client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/owl-bot-staging/v1/setup.py b/owl-bot-staging/v1/setup.py new file mode 100644 index 00000000..4ad93087 --- /dev/null +++ b/owl-bot-staging/v1/setup.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import io +import os +import setuptools # type: ignore + +version = '0.1.0' + +package_root = os.path.abspath(os.path.dirname(__file__)) + +readme_filename = os.path.join(package_root, 'README.rst') +with io.open(readme_filename, encoding='utf-8') as readme_file: + readme = readme_file.read() + +setuptools.setup( + name='google-cloud-pubsublite', + version=version, + long_description=readme, + packages=setuptools.PEP420PackageFinder.find(), + namespace_packages=('google', 'google.cloud'), + platforms='Posix; MacOS X; Windows', + include_package_data=True, + install_requires=( + 'google-api-core[grpc] >= 1.27.0, < 3.0.0dev', + 'libcst >= 0.2.5', + 'proto-plus >= 1.15.0', + 'packaging >= 14.3', ), + python_requires='>=3.6', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Topic :: Internet', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], + zip_safe=False, +) diff --git a/owl-bot-staging/v1/tests/__init__.py b/owl-bot-staging/v1/tests/__init__.py new file mode 100644 index 00000000..b54a5fcc --- /dev/null +++ b/owl-bot-staging/v1/tests/__init__.py @@ -0,0 +1,16 @@ + +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/owl-bot-staging/v1/tests/unit/__init__.py b/owl-bot-staging/v1/tests/unit/__init__.py new file mode 100644 index 00000000..b54a5fcc --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/__init__.py @@ -0,0 +1,16 @@ + +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/owl-bot-staging/v1/tests/unit/gapic/__init__.py b/owl-bot-staging/v1/tests/unit/gapic/__init__.py new file mode 100644 index 00000000..b54a5fcc --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/__init__.py @@ -0,0 +1,16 @@ + +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/__init__.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/__init__.py new file mode 100644 index 00000000..b54a5fcc --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/__init__.py @@ -0,0 +1,16 @@ + +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_admin_service.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_admin_service.py new file mode 100644 index 00000000..d6aeca79 --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_admin_service.py @@ -0,0 +1,6394 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import mock +import packaging.version + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + + +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import future +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import operation_async # type: ignore +from google.api_core import operations_v1 +from google.api_core import path_template +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.pubsublite_v1.services.admin_service import AdminServiceAsyncClient +from google.cloud.pubsublite_v1.services.admin_service import AdminServiceClient +from google.cloud.pubsublite_v1.services.admin_service import pagers +from google.cloud.pubsublite_v1.services.admin_service import transports +from google.cloud.pubsublite_v1.services.admin_service.transports.base import _GOOGLE_AUTH_VERSION +from google.cloud.pubsublite_v1.types import admin +from google.cloud.pubsublite_v1.types import common +from google.longrunning import operations_pb2 +from google.oauth2 import service_account +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +import google.auth + + +# TODO(busunkim): Once google-auth >= 1.25.0 is required transitively +# through google-api-core: +# - Delete the auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return "foo.googleapis.com" if ("localhost" in client.DEFAULT_ENDPOINT) else client.DEFAULT_ENDPOINT + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert AdminServiceClient._get_default_mtls_endpoint(None) is None + assert AdminServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert AdminServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert AdminServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + assert AdminServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint + assert AdminServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [ + AdminServiceClient, + AdminServiceAsyncClient, +]) +def test_admin_service_client_from_service_account_info(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_info') as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +@pytest.mark.parametrize("transport_class,transport_name", [ + (transports.AdminServiceGrpcTransport, "grpc"), + (transports.AdminServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_admin_service_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize("client_class", [ + AdminServiceClient, + AdminServiceAsyncClient, +]) +def test_admin_service_client_from_service_account_file(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_file') as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_admin_service_client_get_transport_class(): + transport = AdminServiceClient.get_transport_class() + available_transports = [ + transports.AdminServiceGrpcTransport, + ] + assert transport in available_transports + + transport = AdminServiceClient.get_transport_class("grpc") + assert transport == transports.AdminServiceGrpcTransport + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (AdminServiceClient, transports.AdminServiceGrpcTransport, "grpc"), + (AdminServiceAsyncClient, transports.AdminServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +@mock.patch.object(AdminServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AdminServiceClient)) +@mock.patch.object(AdminServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AdminServiceAsyncClient)) +def test_admin_service_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(AdminServiceClient, 'get_transport_class') as gtc: + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(AdminServiceClient, 'get_transport_class') as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, '__init__') as patched: + 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, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + 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="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name,use_client_cert_env", [ + (AdminServiceClient, transports.AdminServiceGrpcTransport, "grpc", "true"), + (AdminServiceAsyncClient, transports.AdminServiceGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (AdminServiceClient, transports.AdminServiceGrpcTransport, "grpc", "false"), + (AdminServiceAsyncClient, transports.AdminServiceGrpcAsyncIOTransport, "grpc_asyncio", "false"), +]) +@mock.patch.object(AdminServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AdminServiceClient)) +@mock.patch.object(AdminServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AdminServiceAsyncClient)) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_admin_service_client_mtls_env_auto(client_class, transport_class, transport_name, use_client_cert_env): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}): + options = client_options.ClientOptions(client_cert_source=client_cert_source_callback) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + + 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, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + 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=True): + with mock.patch('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 + + patched.return_value = None + client = client_class() + 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, + always_use_jwt_access=True, + ) + + # 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, + always_use_jwt_access=True, + ) + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (AdminServiceClient, transports.AdminServiceGrpcTransport, "grpc"), + (AdminServiceAsyncClient, transports.AdminServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_admin_service_client_client_options_scopes(client_class, transport_class, transport_name): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (AdminServiceClient, transports.AdminServiceGrpcTransport, "grpc"), + (AdminServiceAsyncClient, transports.AdminServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_admin_service_client_client_options_credentials_file(client_class, transport_class, transport_name): + # Check the case credentials file is provided. + options = client_options.ClientOptions( + credentials_file="credentials.json" + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_admin_service_client_client_options_from_dict(): + with mock.patch('google.cloud.pubsublite_v1.services.admin_service.transports.AdminServiceGrpcTransport.__init__') as grpc_transport: + grpc_transport.return_value = None + client = AdminServiceClient( + client_options={'api_endpoint': 'squid.clam.whelk'} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_create_topic(transport: str = 'grpc', request_type=admin.CreateTopicRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic( + name='name_value', + ) + response = client.create_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateTopicRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Topic) + assert response.name == 'name_value' + + +def test_create_topic_from_dict(): + test_create_topic(request_type=dict) + + +def test_create_topic_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + client.create_topic() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateTopicRequest() + + +@pytest.mark.asyncio +async def test_create_topic_async(transport: str = 'grpc_asyncio', request_type=admin.CreateTopicRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Topic( + name='name_value', + )) + response = await client.create_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateTopicRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Topic) + assert response.name == 'name_value' + + +@pytest.mark.asyncio +async def test_create_topic_async_from_dict(): + await test_create_topic_async(request_type=dict) + + +def test_create_topic_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.CreateTopicRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + call.return_value = common.Topic() + client.create_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_create_topic_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.CreateTopicRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Topic()) + await client.create_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_create_topic_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.create_topic( + parent='parent_value', + topic=common.Topic(name='name_value'), + topic_id='topic_id_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + assert args[0].topic == common.Topic(name='name_value') + assert args[0].topic_id == 'topic_id_value' + + +def test_create_topic_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_topic( + admin.CreateTopicRequest(), + parent='parent_value', + topic=common.Topic(name='name_value'), + topic_id='topic_id_value', + ) + + +@pytest.mark.asyncio +async def test_create_topic_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Topic()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.create_topic( + parent='parent_value', + topic=common.Topic(name='name_value'), + topic_id='topic_id_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + assert args[0].topic == common.Topic(name='name_value') + assert args[0].topic_id == 'topic_id_value' + + +@pytest.mark.asyncio +async def test_create_topic_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.create_topic( + admin.CreateTopicRequest(), + parent='parent_value', + topic=common.Topic(name='name_value'), + topic_id='topic_id_value', + ) + + +def test_get_topic(transport: str = 'grpc', request_type=admin.GetTopicRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic( + name='name_value', + ) + response = client.get_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetTopicRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Topic) + assert response.name == 'name_value' + + +def test_get_topic_from_dict(): + test_get_topic(request_type=dict) + + +def test_get_topic_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + client.get_topic() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetTopicRequest() + + +@pytest.mark.asyncio +async def test_get_topic_async(transport: str = 'grpc_asyncio', request_type=admin.GetTopicRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Topic( + name='name_value', + )) + response = await client.get_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetTopicRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Topic) + assert response.name == 'name_value' + + +@pytest.mark.asyncio +async def test_get_topic_async_from_dict(): + await test_get_topic_async(request_type=dict) + + +def test_get_topic_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetTopicRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + call.return_value = common.Topic() + client.get_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_get_topic_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetTopicRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Topic()) + await client.get_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_get_topic_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_topic( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_get_topic_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_topic( + admin.GetTopicRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_get_topic_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Topic()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_topic( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_get_topic_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_topic( + admin.GetTopicRequest(), + name='name_value', + ) + + +def test_get_topic_partitions(transport: str = 'grpc', request_type=admin.GetTopicPartitionsRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.TopicPartitions( + partition_count=1634, + ) + response = client.get_topic_partitions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetTopicPartitionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, admin.TopicPartitions) + assert response.partition_count == 1634 + + +def test_get_topic_partitions_from_dict(): + test_get_topic_partitions(request_type=dict) + + +def test_get_topic_partitions_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + client.get_topic_partitions() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetTopicPartitionsRequest() + + +@pytest.mark.asyncio +async def test_get_topic_partitions_async(transport: str = 'grpc_asyncio', request_type=admin.GetTopicPartitionsRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(admin.TopicPartitions( + partition_count=1634, + )) + response = await client.get_topic_partitions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetTopicPartitionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, admin.TopicPartitions) + assert response.partition_count == 1634 + + +@pytest.mark.asyncio +async def test_get_topic_partitions_async_from_dict(): + await test_get_topic_partitions_async(request_type=dict) + + +def test_get_topic_partitions_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetTopicPartitionsRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + call.return_value = admin.TopicPartitions() + client.get_topic_partitions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_get_topic_partitions_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetTopicPartitionsRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.TopicPartitions()) + await client.get_topic_partitions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_get_topic_partitions_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.TopicPartitions() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_topic_partitions( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_get_topic_partitions_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_topic_partitions( + admin.GetTopicPartitionsRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_get_topic_partitions_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_topic_partitions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.TopicPartitions() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.TopicPartitions()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_topic_partitions( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_get_topic_partitions_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_topic_partitions( + admin.GetTopicPartitionsRequest(), + name='name_value', + ) + + +def test_list_topics(transport: str = 'grpc', request_type=admin.ListTopicsRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListTopicsResponse( + next_page_token='next_page_token_value', + ) + response = client.list_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListTopicsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTopicsPager) + assert response.next_page_token == 'next_page_token_value' + + +def test_list_topics_from_dict(): + test_list_topics(request_type=dict) + + +def test_list_topics_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + client.list_topics() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListTopicsRequest() + + +@pytest.mark.asyncio +async def test_list_topics_async(transport: str = 'grpc_asyncio', request_type=admin.ListTopicsRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(admin.ListTopicsResponse( + next_page_token='next_page_token_value', + )) + response = await client.list_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListTopicsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTopicsAsyncPager) + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_topics_async_from_dict(): + await test_list_topics_async(request_type=dict) + + +def test_list_topics_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListTopicsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + call.return_value = admin.ListTopicsResponse() + client.list_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_topics_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListTopicsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListTopicsResponse()) + await client.list_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_list_topics_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListTopicsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_topics( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +def test_list_topics_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_topics( + admin.ListTopicsRequest(), + parent='parent_value', + ) + + +@pytest.mark.asyncio +async def test_list_topics_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListTopicsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListTopicsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_topics( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +@pytest.mark.asyncio +async def test_list_topics_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_topics( + admin.ListTopicsRequest(), + parent='parent_value', + ) + + +def test_list_topics_pager(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + common.Topic(), + ], + next_page_token='abc', + ), + admin.ListTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + ], + next_page_token='ghi', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('parent', ''), + )), + ) + pager = client.list_topics(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, common.Topic) + for i in results) + +def test_list_topics_pages(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + common.Topic(), + ], + next_page_token='abc', + ), + admin.ListTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + ], + next_page_token='ghi', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + ], + ), + RuntimeError, + ) + pages = list(client.list_topics(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_topics_async_pager(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + common.Topic(), + ], + next_page_token='abc', + ), + admin.ListTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + ], + next_page_token='ghi', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_topics(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, common.Topic) + for i in responses) + +@pytest.mark.asyncio +async def test_list_topics_async_pages(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topics), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + common.Topic(), + ], + next_page_token='abc', + ), + admin.ListTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + ], + next_page_token='ghi', + ), + admin.ListTopicsResponse( + topics=[ + common.Topic(), + common.Topic(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_topics(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +def test_update_topic(transport: str = 'grpc', request_type=admin.UpdateTopicRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic( + name='name_value', + ) + response = client.update_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateTopicRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Topic) + assert response.name == 'name_value' + + +def test_update_topic_from_dict(): + test_update_topic(request_type=dict) + + +def test_update_topic_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + client.update_topic() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateTopicRequest() + + +@pytest.mark.asyncio +async def test_update_topic_async(transport: str = 'grpc_asyncio', request_type=admin.UpdateTopicRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Topic( + name='name_value', + )) + response = await client.update_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateTopicRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Topic) + assert response.name == 'name_value' + + +@pytest.mark.asyncio +async def test_update_topic_async_from_dict(): + await test_update_topic_async(request_type=dict) + + +def test_update_topic_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.UpdateTopicRequest() + + request.topic.name = 'topic.name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + call.return_value = common.Topic() + client.update_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic.name=topic.name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_update_topic_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.UpdateTopicRequest() + + request.topic.name = 'topic.name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Topic()) + await client.update_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic.name=topic.name/value', + ) in kw['metadata'] + + +def test_update_topic_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_topic( + topic=common.Topic(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].topic == common.Topic(name='name_value') + assert args[0].update_mask == field_mask_pb2.FieldMask(paths=['paths_value']) + + +def test_update_topic_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_topic( + admin.UpdateTopicRequest(), + topic=common.Topic(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + +@pytest.mark.asyncio +async def test_update_topic_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Topic() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Topic()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_topic( + topic=common.Topic(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].topic == common.Topic(name='name_value') + assert args[0].update_mask == field_mask_pb2.FieldMask(paths=['paths_value']) + + +@pytest.mark.asyncio +async def test_update_topic_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_topic( + admin.UpdateTopicRequest(), + topic=common.Topic(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + +def test_delete_topic(transport: str = 'grpc', request_type=admin.DeleteTopicRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteTopicRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_topic_from_dict(): + test_delete_topic(request_type=dict) + + +def test_delete_topic_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + client.delete_topic() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteTopicRequest() + + +@pytest.mark.asyncio +async def test_delete_topic_async(transport: str = 'grpc_asyncio', request_type=admin.DeleteTopicRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteTopicRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_topic_async_from_dict(): + await test_delete_topic_async(request_type=dict) + + +def test_delete_topic_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.DeleteTopicRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + call.return_value = None + client.delete_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_delete_topic_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.DeleteTopicRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_topic(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_delete_topic_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_topic( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_delete_topic_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_topic( + admin.DeleteTopicRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_delete_topic_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_topic), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_topic( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_delete_topic_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_topic( + admin.DeleteTopicRequest(), + name='name_value', + ) + + +def test_list_topic_subscriptions(transport: str = 'grpc', request_type=admin.ListTopicSubscriptionsRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListTopicSubscriptionsResponse( + subscriptions=['subscriptions_value'], + next_page_token='next_page_token_value', + ) + response = client.list_topic_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListTopicSubscriptionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTopicSubscriptionsPager) + assert response.subscriptions == ['subscriptions_value'] + assert response.next_page_token == 'next_page_token_value' + + +def test_list_topic_subscriptions_from_dict(): + test_list_topic_subscriptions(request_type=dict) + + +def test_list_topic_subscriptions_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + client.list_topic_subscriptions() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListTopicSubscriptionsRequest() + + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_async(transport: str = 'grpc_asyncio', request_type=admin.ListTopicSubscriptionsRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(admin.ListTopicSubscriptionsResponse( + subscriptions=['subscriptions_value'], + next_page_token='next_page_token_value', + )) + response = await client.list_topic_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListTopicSubscriptionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTopicSubscriptionsAsyncPager) + assert response.subscriptions == ['subscriptions_value'] + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_async_from_dict(): + await test_list_topic_subscriptions_async(request_type=dict) + + +def test_list_topic_subscriptions_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListTopicSubscriptionsRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + call.return_value = admin.ListTopicSubscriptionsResponse() + client.list_topic_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListTopicSubscriptionsRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListTopicSubscriptionsResponse()) + await client.list_topic_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_list_topic_subscriptions_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListTopicSubscriptionsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_topic_subscriptions( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_list_topic_subscriptions_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_topic_subscriptions( + admin.ListTopicSubscriptionsRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListTopicSubscriptionsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListTopicSubscriptionsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_topic_subscriptions( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_topic_subscriptions( + admin.ListTopicSubscriptionsRequest(), + name='name_value', + ) + + +def test_list_topic_subscriptions_pager(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('name', ''), + )), + ) + pager = client.list_topic_subscriptions(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, str) + for i in results) + +def test_list_topic_subscriptions_pages(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + ], + ), + RuntimeError, + ) + pages = list(client.list_topic_subscriptions(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_async_pager(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_topic_subscriptions(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, str) + for i in responses) + +@pytest.mark.asyncio +async def test_list_topic_subscriptions_async_pages(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_topic_subscriptions), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListTopicSubscriptionsResponse( + subscriptions=[ + str(), + str(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_topic_subscriptions(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +def test_create_subscription(transport: str = 'grpc', request_type=admin.CreateSubscriptionRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription( + name='name_value', + topic='topic_value', + ) + response = client.create_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Subscription) + assert response.name == 'name_value' + assert response.topic == 'topic_value' + + +def test_create_subscription_from_dict(): + test_create_subscription(request_type=dict) + + +def test_create_subscription_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + client.create_subscription() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateSubscriptionRequest() + + +@pytest.mark.asyncio +async def test_create_subscription_async(transport: str = 'grpc_asyncio', request_type=admin.CreateSubscriptionRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription( + name='name_value', + topic='topic_value', + )) + response = await client.create_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Subscription) + assert response.name == 'name_value' + assert response.topic == 'topic_value' + + +@pytest.mark.asyncio +async def test_create_subscription_async_from_dict(): + await test_create_subscription_async(request_type=dict) + + +def test_create_subscription_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.CreateSubscriptionRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + call.return_value = common.Subscription() + client.create_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_create_subscription_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.CreateSubscriptionRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription()) + await client.create_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_create_subscription_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.create_subscription( + parent='parent_value', + subscription=common.Subscription(name='name_value'), + subscription_id='subscription_id_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + assert args[0].subscription == common.Subscription(name='name_value') + assert args[0].subscription_id == 'subscription_id_value' + + +def test_create_subscription_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_subscription( + admin.CreateSubscriptionRequest(), + parent='parent_value', + subscription=common.Subscription(name='name_value'), + subscription_id='subscription_id_value', + ) + + +@pytest.mark.asyncio +async def test_create_subscription_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.create_subscription( + parent='parent_value', + subscription=common.Subscription(name='name_value'), + subscription_id='subscription_id_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + assert args[0].subscription == common.Subscription(name='name_value') + assert args[0].subscription_id == 'subscription_id_value' + + +@pytest.mark.asyncio +async def test_create_subscription_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.create_subscription( + admin.CreateSubscriptionRequest(), + parent='parent_value', + subscription=common.Subscription(name='name_value'), + subscription_id='subscription_id_value', + ) + + +def test_get_subscription(transport: str = 'grpc', request_type=admin.GetSubscriptionRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription( + name='name_value', + topic='topic_value', + ) + response = client.get_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Subscription) + assert response.name == 'name_value' + assert response.topic == 'topic_value' + + +def test_get_subscription_from_dict(): + test_get_subscription(request_type=dict) + + +def test_get_subscription_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + client.get_subscription() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetSubscriptionRequest() + + +@pytest.mark.asyncio +async def test_get_subscription_async(transport: str = 'grpc_asyncio', request_type=admin.GetSubscriptionRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription( + name='name_value', + topic='topic_value', + )) + response = await client.get_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Subscription) + assert response.name == 'name_value' + assert response.topic == 'topic_value' + + +@pytest.mark.asyncio +async def test_get_subscription_async_from_dict(): + await test_get_subscription_async(request_type=dict) + + +def test_get_subscription_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetSubscriptionRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + call.return_value = common.Subscription() + client.get_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_get_subscription_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetSubscriptionRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription()) + await client.get_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_get_subscription_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_subscription( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_get_subscription_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_subscription( + admin.GetSubscriptionRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_get_subscription_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_subscription( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_get_subscription_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_subscription( + admin.GetSubscriptionRequest(), + name='name_value', + ) + + +def test_list_subscriptions(transport: str = 'grpc', request_type=admin.ListSubscriptionsRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListSubscriptionsResponse( + next_page_token='next_page_token_value', + ) + response = client.list_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListSubscriptionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSubscriptionsPager) + assert response.next_page_token == 'next_page_token_value' + + +def test_list_subscriptions_from_dict(): + test_list_subscriptions(request_type=dict) + + +def test_list_subscriptions_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + client.list_subscriptions() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListSubscriptionsRequest() + + +@pytest.mark.asyncio +async def test_list_subscriptions_async(transport: str = 'grpc_asyncio', request_type=admin.ListSubscriptionsRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(admin.ListSubscriptionsResponse( + next_page_token='next_page_token_value', + )) + response = await client.list_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListSubscriptionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSubscriptionsAsyncPager) + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_subscriptions_async_from_dict(): + await test_list_subscriptions_async(request_type=dict) + + +def test_list_subscriptions_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListSubscriptionsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + call.return_value = admin.ListSubscriptionsResponse() + client.list_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_subscriptions_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListSubscriptionsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListSubscriptionsResponse()) + await client.list_subscriptions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_list_subscriptions_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListSubscriptionsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_subscriptions( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +def test_list_subscriptions_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_subscriptions( + admin.ListSubscriptionsRequest(), + parent='parent_value', + ) + + +@pytest.mark.asyncio +async def test_list_subscriptions_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListSubscriptionsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListSubscriptionsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_subscriptions( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +@pytest.mark.asyncio +async def test_list_subscriptions_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_subscriptions( + admin.ListSubscriptionsRequest(), + parent='parent_value', + ) + + +def test_list_subscriptions_pager(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + common.Subscription(), + ], + next_page_token='abc', + ), + admin.ListSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + ], + next_page_token='ghi', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('parent', ''), + )), + ) + pager = client.list_subscriptions(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, common.Subscription) + for i in results) + +def test_list_subscriptions_pages(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + common.Subscription(), + ], + next_page_token='abc', + ), + admin.ListSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + ], + next_page_token='ghi', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + ], + ), + RuntimeError, + ) + pages = list(client.list_subscriptions(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_subscriptions_async_pager(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + common.Subscription(), + ], + next_page_token='abc', + ), + admin.ListSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + ], + next_page_token='ghi', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_subscriptions(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, common.Subscription) + for i in responses) + +@pytest.mark.asyncio +async def test_list_subscriptions_async_pages(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_subscriptions), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + common.Subscription(), + ], + next_page_token='abc', + ), + admin.ListSubscriptionsResponse( + subscriptions=[], + next_page_token='def', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + ], + next_page_token='ghi', + ), + admin.ListSubscriptionsResponse( + subscriptions=[ + common.Subscription(), + common.Subscription(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_subscriptions(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +def test_update_subscription(transport: str = 'grpc', request_type=admin.UpdateSubscriptionRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription( + name='name_value', + topic='topic_value', + ) + response = client.update_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Subscription) + assert response.name == 'name_value' + assert response.topic == 'topic_value' + + +def test_update_subscription_from_dict(): + test_update_subscription(request_type=dict) + + +def test_update_subscription_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + client.update_subscription() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateSubscriptionRequest() + + +@pytest.mark.asyncio +async def test_update_subscription_async(transport: str = 'grpc_asyncio', request_type=admin.UpdateSubscriptionRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription( + name='name_value', + topic='topic_value', + )) + response = await client.update_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Subscription) + assert response.name == 'name_value' + assert response.topic == 'topic_value' + + +@pytest.mark.asyncio +async def test_update_subscription_async_from_dict(): + await test_update_subscription_async(request_type=dict) + + +def test_update_subscription_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.UpdateSubscriptionRequest() + + request.subscription.name = 'subscription.name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + call.return_value = common.Subscription() + client.update_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'subscription.name=subscription.name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_update_subscription_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.UpdateSubscriptionRequest() + + request.subscription.name = 'subscription.name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription()) + await client.update_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'subscription.name=subscription.name/value', + ) in kw['metadata'] + + +def test_update_subscription_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_subscription( + subscription=common.Subscription(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].subscription == common.Subscription(name='name_value') + assert args[0].update_mask == field_mask_pb2.FieldMask(paths=['paths_value']) + + +def test_update_subscription_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_subscription( + admin.UpdateSubscriptionRequest(), + subscription=common.Subscription(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + +@pytest.mark.asyncio +async def test_update_subscription_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Subscription() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Subscription()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_subscription( + subscription=common.Subscription(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].subscription == common.Subscription(name='name_value') + assert args[0].update_mask == field_mask_pb2.FieldMask(paths=['paths_value']) + + +@pytest.mark.asyncio +async def test_update_subscription_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_subscription( + admin.UpdateSubscriptionRequest(), + subscription=common.Subscription(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + +def test_delete_subscription(transport: str = 'grpc', request_type=admin.DeleteSubscriptionRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_subscription_from_dict(): + test_delete_subscription(request_type=dict) + + +def test_delete_subscription_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + client.delete_subscription() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteSubscriptionRequest() + + +@pytest.mark.asyncio +async def test_delete_subscription_async(transport: str = 'grpc_asyncio', request_type=admin.DeleteSubscriptionRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_subscription_async_from_dict(): + await test_delete_subscription_async(request_type=dict) + + +def test_delete_subscription_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.DeleteSubscriptionRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + call.return_value = None + client.delete_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_delete_subscription_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.DeleteSubscriptionRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_delete_subscription_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_subscription( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_delete_subscription_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_subscription( + admin.DeleteSubscriptionRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_delete_subscription_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_subscription( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_delete_subscription_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_subscription( + admin.DeleteSubscriptionRequest(), + name='name_value', + ) + + +def test_seek_subscription(transport: str = 'grpc', request_type=admin.SeekSubscriptionRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.seek_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name='operations/spam') + response = client.seek_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.SeekSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_seek_subscription_from_dict(): + test_seek_subscription(request_type=dict) + + +def test_seek_subscription_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.seek_subscription), + '__call__') as call: + client.seek_subscription() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.SeekSubscriptionRequest() + + +@pytest.mark.asyncio +async def test_seek_subscription_async(transport: str = 'grpc_asyncio', request_type=admin.SeekSubscriptionRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.seek_subscription), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name='operations/spam') + ) + response = await client.seek_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.SeekSubscriptionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_seek_subscription_async_from_dict(): + await test_seek_subscription_async(request_type=dict) + + +def test_seek_subscription_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.SeekSubscriptionRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.seek_subscription), + '__call__') as call: + call.return_value = operations_pb2.Operation(name='operations/op') + client.seek_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_seek_subscription_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.SeekSubscriptionRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.seek_subscription), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(operations_pb2.Operation(name='operations/op')) + await client.seek_subscription(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_create_reservation(transport: str = 'grpc', request_type=admin.CreateReservationRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation( + name='name_value', + throughput_capacity=2055, + ) + response = client.create_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateReservationRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Reservation) + assert response.name == 'name_value' + assert response.throughput_capacity == 2055 + + +def test_create_reservation_from_dict(): + test_create_reservation(request_type=dict) + + +def test_create_reservation_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + client.create_reservation() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateReservationRequest() + + +@pytest.mark.asyncio +async def test_create_reservation_async(transport: str = 'grpc_asyncio', request_type=admin.CreateReservationRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation( + name='name_value', + throughput_capacity=2055, + )) + response = await client.create_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.CreateReservationRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Reservation) + assert response.name == 'name_value' + assert response.throughput_capacity == 2055 + + +@pytest.mark.asyncio +async def test_create_reservation_async_from_dict(): + await test_create_reservation_async(request_type=dict) + + +def test_create_reservation_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.CreateReservationRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + call.return_value = common.Reservation() + client.create_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_create_reservation_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.CreateReservationRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation()) + await client.create_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_create_reservation_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.create_reservation( + parent='parent_value', + reservation=common.Reservation(name='name_value'), + reservation_id='reservation_id_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + assert args[0].reservation == common.Reservation(name='name_value') + assert args[0].reservation_id == 'reservation_id_value' + + +def test_create_reservation_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_reservation( + admin.CreateReservationRequest(), + parent='parent_value', + reservation=common.Reservation(name='name_value'), + reservation_id='reservation_id_value', + ) + + +@pytest.mark.asyncio +async def test_create_reservation_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.create_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.create_reservation( + parent='parent_value', + reservation=common.Reservation(name='name_value'), + reservation_id='reservation_id_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + assert args[0].reservation == common.Reservation(name='name_value') + assert args[0].reservation_id == 'reservation_id_value' + + +@pytest.mark.asyncio +async def test_create_reservation_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.create_reservation( + admin.CreateReservationRequest(), + parent='parent_value', + reservation=common.Reservation(name='name_value'), + reservation_id='reservation_id_value', + ) + + +def test_get_reservation(transport: str = 'grpc', request_type=admin.GetReservationRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation( + name='name_value', + throughput_capacity=2055, + ) + response = client.get_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetReservationRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Reservation) + assert response.name == 'name_value' + assert response.throughput_capacity == 2055 + + +def test_get_reservation_from_dict(): + test_get_reservation(request_type=dict) + + +def test_get_reservation_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + client.get_reservation() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetReservationRequest() + + +@pytest.mark.asyncio +async def test_get_reservation_async(transport: str = 'grpc_asyncio', request_type=admin.GetReservationRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation( + name='name_value', + throughput_capacity=2055, + )) + response = await client.get_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.GetReservationRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Reservation) + assert response.name == 'name_value' + assert response.throughput_capacity == 2055 + + +@pytest.mark.asyncio +async def test_get_reservation_async_from_dict(): + await test_get_reservation_async(request_type=dict) + + +def test_get_reservation_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetReservationRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + call.return_value = common.Reservation() + client.get_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_get_reservation_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.GetReservationRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation()) + await client.get_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_get_reservation_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_reservation( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_get_reservation_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_reservation( + admin.GetReservationRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_get_reservation_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_reservation( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_get_reservation_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_reservation( + admin.GetReservationRequest(), + name='name_value', + ) + + +def test_list_reservations(transport: str = 'grpc', request_type=admin.ListReservationsRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListReservationsResponse( + next_page_token='next_page_token_value', + ) + response = client.list_reservations(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListReservationsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListReservationsPager) + assert response.next_page_token == 'next_page_token_value' + + +def test_list_reservations_from_dict(): + test_list_reservations(request_type=dict) + + +def test_list_reservations_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + client.list_reservations() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListReservationsRequest() + + +@pytest.mark.asyncio +async def test_list_reservations_async(transport: str = 'grpc_asyncio', request_type=admin.ListReservationsRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(admin.ListReservationsResponse( + next_page_token='next_page_token_value', + )) + response = await client.list_reservations(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListReservationsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListReservationsAsyncPager) + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_reservations_async_from_dict(): + await test_list_reservations_async(request_type=dict) + + +def test_list_reservations_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListReservationsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + call.return_value = admin.ListReservationsResponse() + client.list_reservations(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_reservations_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListReservationsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListReservationsResponse()) + await client.list_reservations(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_list_reservations_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListReservationsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_reservations( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +def test_list_reservations_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_reservations( + admin.ListReservationsRequest(), + parent='parent_value', + ) + + +@pytest.mark.asyncio +async def test_list_reservations_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListReservationsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListReservationsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_reservations( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +@pytest.mark.asyncio +async def test_list_reservations_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_reservations( + admin.ListReservationsRequest(), + parent='parent_value', + ) + + +def test_list_reservations_pager(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + common.Reservation(), + ], + next_page_token='abc', + ), + admin.ListReservationsResponse( + reservations=[], + next_page_token='def', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + ], + next_page_token='ghi', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('parent', ''), + )), + ) + pager = client.list_reservations(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, common.Reservation) + for i in results) + +def test_list_reservations_pages(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + common.Reservation(), + ], + next_page_token='abc', + ), + admin.ListReservationsResponse( + reservations=[], + next_page_token='def', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + ], + next_page_token='ghi', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + ], + ), + RuntimeError, + ) + pages = list(client.list_reservations(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_reservations_async_pager(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + common.Reservation(), + ], + next_page_token='abc', + ), + admin.ListReservationsResponse( + reservations=[], + next_page_token='def', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + ], + next_page_token='ghi', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_reservations(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, common.Reservation) + for i in responses) + +@pytest.mark.asyncio +async def test_list_reservations_async_pages(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservations), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + common.Reservation(), + ], + next_page_token='abc', + ), + admin.ListReservationsResponse( + reservations=[], + next_page_token='def', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + ], + next_page_token='ghi', + ), + admin.ListReservationsResponse( + reservations=[ + common.Reservation(), + common.Reservation(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_reservations(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +def test_update_reservation(transport: str = 'grpc', request_type=admin.UpdateReservationRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation( + name='name_value', + throughput_capacity=2055, + ) + response = client.update_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateReservationRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Reservation) + assert response.name == 'name_value' + assert response.throughput_capacity == 2055 + + +def test_update_reservation_from_dict(): + test_update_reservation(request_type=dict) + + +def test_update_reservation_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + client.update_reservation() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateReservationRequest() + + +@pytest.mark.asyncio +async def test_update_reservation_async(transport: str = 'grpc_asyncio', request_type=admin.UpdateReservationRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation( + name='name_value', + throughput_capacity=2055, + )) + response = await client.update_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.UpdateReservationRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, common.Reservation) + assert response.name == 'name_value' + assert response.throughput_capacity == 2055 + + +@pytest.mark.asyncio +async def test_update_reservation_async_from_dict(): + await test_update_reservation_async(request_type=dict) + + +def test_update_reservation_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.UpdateReservationRequest() + + request.reservation.name = 'reservation.name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + call.return_value = common.Reservation() + client.update_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'reservation.name=reservation.name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_update_reservation_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.UpdateReservationRequest() + + request.reservation.name = 'reservation.name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation()) + await client.update_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'reservation.name=reservation.name/value', + ) in kw['metadata'] + + +def test_update_reservation_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_reservation( + reservation=common.Reservation(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].reservation == common.Reservation(name='name_value') + assert args[0].update_mask == field_mask_pb2.FieldMask(paths=['paths_value']) + + +def test_update_reservation_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_reservation( + admin.UpdateReservationRequest(), + reservation=common.Reservation(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + +@pytest.mark.asyncio +async def test_update_reservation_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = common.Reservation() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(common.Reservation()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_reservation( + reservation=common.Reservation(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].reservation == common.Reservation(name='name_value') + assert args[0].update_mask == field_mask_pb2.FieldMask(paths=['paths_value']) + + +@pytest.mark.asyncio +async def test_update_reservation_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_reservation( + admin.UpdateReservationRequest(), + reservation=common.Reservation(name='name_value'), + update_mask=field_mask_pb2.FieldMask(paths=['paths_value']), + ) + + +def test_delete_reservation(transport: str = 'grpc', request_type=admin.DeleteReservationRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteReservationRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_reservation_from_dict(): + test_delete_reservation(request_type=dict) + + +def test_delete_reservation_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + client.delete_reservation() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteReservationRequest() + + +@pytest.mark.asyncio +async def test_delete_reservation_async(transport: str = 'grpc_asyncio', request_type=admin.DeleteReservationRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.DeleteReservationRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_reservation_async_from_dict(): + await test_delete_reservation_async(request_type=dict) + + +def test_delete_reservation_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.DeleteReservationRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + call.return_value = None + client.delete_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_delete_reservation_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.DeleteReservationRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_reservation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_delete_reservation_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_reservation( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_delete_reservation_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_reservation( + admin.DeleteReservationRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_delete_reservation_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_reservation), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_reservation( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_delete_reservation_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_reservation( + admin.DeleteReservationRequest(), + name='name_value', + ) + + +def test_list_reservation_topics(transport: str = 'grpc', request_type=admin.ListReservationTopicsRequest): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListReservationTopicsResponse( + topics=['topics_value'], + next_page_token='next_page_token_value', + ) + response = client.list_reservation_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListReservationTopicsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListReservationTopicsPager) + assert response.topics == ['topics_value'] + assert response.next_page_token == 'next_page_token_value' + + +def test_list_reservation_topics_from_dict(): + test_list_reservation_topics(request_type=dict) + + +def test_list_reservation_topics_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + client.list_reservation_topics() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListReservationTopicsRequest() + + +@pytest.mark.asyncio +async def test_list_reservation_topics_async(transport: str = 'grpc_asyncio', request_type=admin.ListReservationTopicsRequest): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(admin.ListReservationTopicsResponse( + topics=['topics_value'], + next_page_token='next_page_token_value', + )) + response = await client.list_reservation_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == admin.ListReservationTopicsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListReservationTopicsAsyncPager) + assert response.topics == ['topics_value'] + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_reservation_topics_async_from_dict(): + await test_list_reservation_topics_async(request_type=dict) + + +def test_list_reservation_topics_field_headers(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListReservationTopicsRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + call.return_value = admin.ListReservationTopicsResponse() + client.list_reservation_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_reservation_topics_field_headers_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = admin.ListReservationTopicsRequest() + + request.name = 'name/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListReservationTopicsResponse()) + await client.list_reservation_topics(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'name=name/value', + ) in kw['metadata'] + + +def test_list_reservation_topics_flattened(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListReservationTopicsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_reservation_topics( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +def test_list_reservation_topics_flattened_error(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_reservation_topics( + admin.ListReservationTopicsRequest(), + name='name_value', + ) + + +@pytest.mark.asyncio +async def test_list_reservation_topics_flattened_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = admin.ListReservationTopicsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(admin.ListReservationTopicsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_reservation_topics( + name='name_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].name == 'name_value' + + +@pytest.mark.asyncio +async def test_list_reservation_topics_flattened_error_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_reservation_topics( + admin.ListReservationTopicsRequest(), + name='name_value', + ) + + +def test_list_reservation_topics_pager(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListReservationTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('name', ''), + )), + ) + pager = client.list_reservation_topics(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, str) + for i in results) + +def test_list_reservation_topics_pages(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListReservationTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + ], + ), + RuntimeError, + ) + pages = list(client.list_reservation_topics(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_reservation_topics_async_pager(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListReservationTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_reservation_topics(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, str) + for i in responses) + +@pytest.mark.asyncio +async def test_list_reservation_topics_async_pages(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_reservation_topics), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + str(), + ], + next_page_token='abc', + ), + admin.ListReservationTopicsResponse( + topics=[], + next_page_token='def', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + ], + next_page_token='ghi', + ), + admin.ListReservationTopicsResponse( + topics=[ + str(), + str(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_reservation_topics(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AdminServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AdminServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AdminServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AdminServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AdminServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AdminServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AdminServiceClient(transport=transport) + assert client.transport is transport + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AdminServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AdminServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + +@pytest.mark.parametrize("transport_class", [ + transports.AdminServiceGrpcTransport, + transports.AdminServiceGrpcAsyncIOTransport, +]) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AdminServiceGrpcTransport, + ) + +def test_admin_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AdminServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json" + ) + + +def test_admin_service_base_transport(): + # Instantiate the base transport. + with mock.patch('google.cloud.pubsublite_v1.services.admin_service.transports.AdminServiceTransport.__init__') as Transport: + Transport.return_value = None + transport = transports.AdminServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + 'create_topic', + 'get_topic', + 'get_topic_partitions', + 'list_topics', + 'update_topic', + 'delete_topic', + 'list_topic_subscriptions', + 'create_subscription', + 'get_subscription', + 'list_subscriptions', + 'update_subscription', + 'delete_subscription', + 'seek_subscription', + 'create_reservation', + 'get_reservation', + 'list_reservations', + 'update_reservation', + 'delete_reservation', + 'list_reservation_topics', + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + +@requires_google_auth_gte_1_25_0 +def test_admin_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.admin_service.transports.AdminServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AdminServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_admin_service_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.admin_service.transports.AdminServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AdminServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", scopes=( + 'https://www.googleapis.com/auth/cloud-platform', + ), + quota_project_id="octopus", + ) + + +def test_admin_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, 'default', autospec=True) as adc, mock.patch('google.cloud.pubsublite_v1.services.admin_service.transports.AdminServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AdminServiceTransport() + adc.assert_called_once() + + +@requires_google_auth_gte_1_25_0 +def test_admin_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + AdminServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_admin_service_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + AdminServiceClient() + adc.assert_called_once_with( + scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AdminServiceGrpcTransport, + transports.AdminServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_admin_service_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AdminServiceGrpcTransport, + transports.AdminServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_admin_service_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") + adc.assert_called_once_with(scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.AdminServiceGrpcTransport, grpc_helpers), + (transports.AdminServiceGrpcAsyncIOTransport, grpc_helpers_async) + ], +) +def test_admin_service_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class( + quota_project_id="octopus", + scopes=["1", "2"] + ) + + create_channel.assert_called_with( + "pubsublite.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + scopes=["1", "2"], + default_host="pubsublite.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize("transport_class", [transports.AdminServiceGrpcTransport, transports.AdminServiceGrpcAsyncIOTransport]) +def test_admin_service_grpc_transport_client_cert_source_for_mtls( + transport_class +): + cred = ga_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=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # 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_admin_service_host_no_port(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_admin_service_host_with_port(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com:8000'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:8000' + +def test_admin_service_grpc_transport_channel(): + channel = grpc.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.AdminServiceGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_admin_service_grpc_asyncio_transport_channel(): + channel = aio.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.AdminServiceGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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.AdminServiceGrpcTransport, transports.AdminServiceGrpcAsyncIOTransport]) +def test_admin_service_transport_channel_mtls_with_client_cert_source( + transport_class +): + with mock.patch("grpc.ssl_channel_credentials", autospec=True) as grpc_ssl_channel_cred: + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + 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.AdminServiceGrpcTransport, transports.AdminServiceGrpcAsyncIOTransport]) +def test_admin_service_transport_channel_mtls_with_adc( + transport_class +): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_admin_service_grpc_lro_client(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.OperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_admin_service_grpc_lro_async_client(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc_asyncio', + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.OperationsAsyncClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_reservation_path(): + project = "squid" + location = "clam" + reservation = "whelk" + expected = "projects/{project}/locations/{location}/reservations/{reservation}".format(project=project, location=location, reservation=reservation, ) + actual = AdminServiceClient.reservation_path(project, location, reservation) + assert expected == actual + + +def test_parse_reservation_path(): + expected = { + "project": "octopus", + "location": "oyster", + "reservation": "nudibranch", + } + path = AdminServiceClient.reservation_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_reservation_path(path) + assert expected == actual + +def test_subscription_path(): + project = "cuttlefish" + location = "mussel" + subscription = "winkle" + expected = "projects/{project}/locations/{location}/subscriptions/{subscription}".format(project=project, location=location, subscription=subscription, ) + actual = AdminServiceClient.subscription_path(project, location, subscription) + assert expected == actual + + +def test_parse_subscription_path(): + expected = { + "project": "nautilus", + "location": "scallop", + "subscription": "abalone", + } + path = AdminServiceClient.subscription_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_subscription_path(path) + assert expected == actual + +def test_topic_path(): + project = "squid" + location = "clam" + topic = "whelk" + expected = "projects/{project}/locations/{location}/topics/{topic}".format(project=project, location=location, topic=topic, ) + actual = AdminServiceClient.topic_path(project, location, topic) + assert expected == actual + + +def test_parse_topic_path(): + expected = { + "project": "octopus", + "location": "oyster", + "topic": "nudibranch", + } + path = AdminServiceClient.topic_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_topic_path(path) + assert expected == actual + +def test_common_billing_account_path(): + billing_account = "cuttlefish" + expected = "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + actual = AdminServiceClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "mussel", + } + path = AdminServiceClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_common_billing_account_path(path) + assert expected == actual + +def test_common_folder_path(): + folder = "winkle" + expected = "folders/{folder}".format(folder=folder, ) + actual = AdminServiceClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nautilus", + } + path = AdminServiceClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_common_folder_path(path) + assert expected == actual + +def test_common_organization_path(): + organization = "scallop" + expected = "organizations/{organization}".format(organization=organization, ) + actual = AdminServiceClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "abalone", + } + path = AdminServiceClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_common_organization_path(path) + assert expected == actual + +def test_common_project_path(): + project = "squid" + expected = "projects/{project}".format(project=project, ) + actual = AdminServiceClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "clam", + } + path = AdminServiceClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_common_project_path(path) + assert expected == actual + +def test_common_location_path(): + project = "whelk" + location = "octopus" + expected = "projects/{project}/locations/{location}".format(project=project, location=location, ) + actual = AdminServiceClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + } + path = AdminServiceClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = AdminServiceClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.AdminServiceTransport, '_prep_wrapped_messages') as prep: + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.AdminServiceTransport, '_prep_wrapped_messages') as prep: + transport_class = AdminServiceClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = AdminServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object(type(getattr(client.transport, "grpc_channel")), "close") as close: + async with client: + close.assert_not_called() + close.assert_called_once() + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + with mock.patch.object(type(getattr(client.transport, close_name)), "close") as close: + with client: + close.assert_not_called() + close.assert_called_once() + +def test_client_ctx(): + transports = [ + 'grpc', + ] + for transport in transports: + client = AdminServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_cursor_service.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_cursor_service.py new file mode 100644 index 00000000..f0093cc1 --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_cursor_service.py @@ -0,0 +1,1620 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import mock +import packaging.version + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + + +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import path_template +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.pubsublite_v1.services.cursor_service import CursorServiceAsyncClient +from google.cloud.pubsublite_v1.services.cursor_service import CursorServiceClient +from google.cloud.pubsublite_v1.services.cursor_service import pagers +from google.cloud.pubsublite_v1.services.cursor_service import transports +from google.cloud.pubsublite_v1.services.cursor_service.transports.base import _GOOGLE_AUTH_VERSION +from google.cloud.pubsublite_v1.types import common +from google.cloud.pubsublite_v1.types import cursor +from google.oauth2 import service_account +import google.auth + + +# TODO(busunkim): Once google-auth >= 1.25.0 is required transitively +# through google-api-core: +# - Delete the auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return "foo.googleapis.com" if ("localhost" in client.DEFAULT_ENDPOINT) else client.DEFAULT_ENDPOINT + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert CursorServiceClient._get_default_mtls_endpoint(None) is None + assert CursorServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert CursorServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert CursorServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + assert CursorServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint + assert CursorServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [ + CursorServiceClient, + CursorServiceAsyncClient, +]) +def test_cursor_service_client_from_service_account_info(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_info') as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +@pytest.mark.parametrize("transport_class,transport_name", [ + (transports.CursorServiceGrpcTransport, "grpc"), + (transports.CursorServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_cursor_service_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize("client_class", [ + CursorServiceClient, + CursorServiceAsyncClient, +]) +def test_cursor_service_client_from_service_account_file(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_file') as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_cursor_service_client_get_transport_class(): + transport = CursorServiceClient.get_transport_class() + available_transports = [ + transports.CursorServiceGrpcTransport, + ] + assert transport in available_transports + + transport = CursorServiceClient.get_transport_class("grpc") + assert transport == transports.CursorServiceGrpcTransport + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (CursorServiceClient, transports.CursorServiceGrpcTransport, "grpc"), + (CursorServiceAsyncClient, transports.CursorServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +@mock.patch.object(CursorServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(CursorServiceClient)) +@mock.patch.object(CursorServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(CursorServiceAsyncClient)) +def test_cursor_service_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(CursorServiceClient, 'get_transport_class') as gtc: + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(CursorServiceClient, 'get_transport_class') as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, '__init__') as patched: + 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, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + 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="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name,use_client_cert_env", [ + (CursorServiceClient, transports.CursorServiceGrpcTransport, "grpc", "true"), + (CursorServiceAsyncClient, transports.CursorServiceGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (CursorServiceClient, transports.CursorServiceGrpcTransport, "grpc", "false"), + (CursorServiceAsyncClient, transports.CursorServiceGrpcAsyncIOTransport, "grpc_asyncio", "false"), +]) +@mock.patch.object(CursorServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(CursorServiceClient)) +@mock.patch.object(CursorServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(CursorServiceAsyncClient)) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_cursor_service_client_mtls_env_auto(client_class, transport_class, transport_name, use_client_cert_env): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}): + options = client_options.ClientOptions(client_cert_source=client_cert_source_callback) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + + 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, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + 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=True): + with mock.patch('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 + + patched.return_value = None + client = client_class() + 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, + always_use_jwt_access=True, + ) + + # 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, + always_use_jwt_access=True, + ) + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (CursorServiceClient, transports.CursorServiceGrpcTransport, "grpc"), + (CursorServiceAsyncClient, transports.CursorServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_cursor_service_client_client_options_scopes(client_class, transport_class, transport_name): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (CursorServiceClient, transports.CursorServiceGrpcTransport, "grpc"), + (CursorServiceAsyncClient, transports.CursorServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_cursor_service_client_client_options_credentials_file(client_class, transport_class, transport_name): + # Check the case credentials file is provided. + options = client_options.ClientOptions( + credentials_file="credentials.json" + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_cursor_service_client_client_options_from_dict(): + with mock.patch('google.cloud.pubsublite_v1.services.cursor_service.transports.CursorServiceGrpcTransport.__init__') as grpc_transport: + grpc_transport.return_value = None + client = CursorServiceClient( + client_options={'api_endpoint': 'squid.clam.whelk'} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_streaming_commit_cursor(transport: str = 'grpc', request_type=cursor.StreamingCommitCursorRequest): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.streaming_commit_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = iter([cursor.StreamingCommitCursorResponse()]) + response = client.streaming_commit_cursor(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + for message in response: + assert isinstance(message, cursor.StreamingCommitCursorResponse) + + +def test_streaming_commit_cursor_from_dict(): + test_streaming_commit_cursor(request_type=dict) + + +@pytest.mark.asyncio +async def test_streaming_commit_cursor_async(transport: str = 'grpc_asyncio', request_type=cursor.StreamingCommitCursorRequest): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.streaming_commit_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = mock.Mock(aio.StreamStreamCall, autospec=True) + call.return_value.read = mock.AsyncMock(side_effect=[cursor.StreamingCommitCursorResponse()]) + response = await client.streaming_commit_cursor(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + message = await response.read() + assert isinstance(message, cursor.StreamingCommitCursorResponse) + + +@pytest.mark.asyncio +async def test_streaming_commit_cursor_async_from_dict(): + await test_streaming_commit_cursor_async(request_type=dict) + + +def test_commit_cursor(transport: str = 'grpc', request_type=cursor.CommitCursorRequest): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.commit_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = cursor.CommitCursorResponse( + ) + response = client.commit_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == cursor.CommitCursorRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, cursor.CommitCursorResponse) + + +def test_commit_cursor_from_dict(): + test_commit_cursor(request_type=dict) + + +def test_commit_cursor_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.commit_cursor), + '__call__') as call: + client.commit_cursor() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == cursor.CommitCursorRequest() + + +@pytest.mark.asyncio +async def test_commit_cursor_async(transport: str = 'grpc_asyncio', request_type=cursor.CommitCursorRequest): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.commit_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(cursor.CommitCursorResponse( + )) + response = await client.commit_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == cursor.CommitCursorRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, cursor.CommitCursorResponse) + + +@pytest.mark.asyncio +async def test_commit_cursor_async_from_dict(): + await test_commit_cursor_async(request_type=dict) + + +def test_commit_cursor_field_headers(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = cursor.CommitCursorRequest() + + request.subscription = 'subscription/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.commit_cursor), + '__call__') as call: + call.return_value = cursor.CommitCursorResponse() + client.commit_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'subscription=subscription/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_commit_cursor_field_headers_async(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = cursor.CommitCursorRequest() + + request.subscription = 'subscription/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.commit_cursor), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(cursor.CommitCursorResponse()) + await client.commit_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'subscription=subscription/value', + ) in kw['metadata'] + + +def test_list_partition_cursors(transport: str = 'grpc', request_type=cursor.ListPartitionCursorsRequest): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = cursor.ListPartitionCursorsResponse( + next_page_token='next_page_token_value', + ) + response = client.list_partition_cursors(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == cursor.ListPartitionCursorsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListPartitionCursorsPager) + assert response.next_page_token == 'next_page_token_value' + + +def test_list_partition_cursors_from_dict(): + test_list_partition_cursors(request_type=dict) + + +def test_list_partition_cursors_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + client.list_partition_cursors() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == cursor.ListPartitionCursorsRequest() + + +@pytest.mark.asyncio +async def test_list_partition_cursors_async(transport: str = 'grpc_asyncio', request_type=cursor.ListPartitionCursorsRequest): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(cursor.ListPartitionCursorsResponse( + next_page_token='next_page_token_value', + )) + response = await client.list_partition_cursors(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == cursor.ListPartitionCursorsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListPartitionCursorsAsyncPager) + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_partition_cursors_async_from_dict(): + await test_list_partition_cursors_async(request_type=dict) + + +def test_list_partition_cursors_field_headers(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = cursor.ListPartitionCursorsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + call.return_value = cursor.ListPartitionCursorsResponse() + client.list_partition_cursors(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_partition_cursors_field_headers_async(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = cursor.ListPartitionCursorsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(cursor.ListPartitionCursorsResponse()) + await client.list_partition_cursors(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_list_partition_cursors_flattened(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = cursor.ListPartitionCursorsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_partition_cursors( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +def test_list_partition_cursors_flattened_error(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_partition_cursors( + cursor.ListPartitionCursorsRequest(), + parent='parent_value', + ) + + +@pytest.mark.asyncio +async def test_list_partition_cursors_flattened_async(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = cursor.ListPartitionCursorsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(cursor.ListPartitionCursorsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_partition_cursors( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +@pytest.mark.asyncio +async def test_list_partition_cursors_flattened_error_async(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_partition_cursors( + cursor.ListPartitionCursorsRequest(), + parent='parent_value', + ) + + +def test_list_partition_cursors_pager(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + next_page_token='abc', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[], + next_page_token='def', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + ], + next_page_token='ghi', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('parent', ''), + )), + ) + pager = client.list_partition_cursors(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, cursor.PartitionCursor) + for i in results) + +def test_list_partition_cursors_pages(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + next_page_token='abc', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[], + next_page_token='def', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + ], + next_page_token='ghi', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + ), + RuntimeError, + ) + pages = list(client.list_partition_cursors(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_partition_cursors_async_pager(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + next_page_token='abc', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[], + next_page_token='def', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + ], + next_page_token='ghi', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_partition_cursors(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, cursor.PartitionCursor) + for i in responses) + +@pytest.mark.asyncio +async def test_list_partition_cursors_async_pages(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_partition_cursors), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + next_page_token='abc', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[], + next_page_token='def', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + ], + next_page_token='ghi', + ), + cursor.ListPartitionCursorsResponse( + partition_cursors=[ + cursor.PartitionCursor(), + cursor.PartitionCursor(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_partition_cursors(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.CursorServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.CursorServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = CursorServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.CursorServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = CursorServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.CursorServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = CursorServiceClient(transport=transport) + assert client.transport is transport + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.CursorServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.CursorServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + +@pytest.mark.parametrize("transport_class", [ + transports.CursorServiceGrpcTransport, + transports.CursorServiceGrpcAsyncIOTransport, +]) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.CursorServiceGrpcTransport, + ) + +def test_cursor_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.CursorServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json" + ) + + +def test_cursor_service_base_transport(): + # Instantiate the base transport. + with mock.patch('google.cloud.pubsublite_v1.services.cursor_service.transports.CursorServiceTransport.__init__') as Transport: + Transport.return_value = None + transport = transports.CursorServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + 'streaming_commit_cursor', + 'commit_cursor', + 'list_partition_cursors', + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + +@requires_google_auth_gte_1_25_0 +def test_cursor_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.cursor_service.transports.CursorServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.CursorServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_cursor_service_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.cursor_service.transports.CursorServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.CursorServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", scopes=( + 'https://www.googleapis.com/auth/cloud-platform', + ), + quota_project_id="octopus", + ) + + +def test_cursor_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, 'default', autospec=True) as adc, mock.patch('google.cloud.pubsublite_v1.services.cursor_service.transports.CursorServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.CursorServiceTransport() + adc.assert_called_once() + + +@requires_google_auth_gte_1_25_0 +def test_cursor_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + CursorServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_cursor_service_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + CursorServiceClient() + adc.assert_called_once_with( + scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.CursorServiceGrpcTransport, + transports.CursorServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_cursor_service_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.CursorServiceGrpcTransport, + transports.CursorServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_cursor_service_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") + adc.assert_called_once_with(scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.CursorServiceGrpcTransport, grpc_helpers), + (transports.CursorServiceGrpcAsyncIOTransport, grpc_helpers_async) + ], +) +def test_cursor_service_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class( + quota_project_id="octopus", + scopes=["1", "2"] + ) + + create_channel.assert_called_with( + "pubsublite.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + scopes=["1", "2"], + default_host="pubsublite.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize("transport_class", [transports.CursorServiceGrpcTransport, transports.CursorServiceGrpcAsyncIOTransport]) +def test_cursor_service_grpc_transport_client_cert_source_for_mtls( + transport_class +): + cred = ga_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=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # 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_cursor_service_host_no_port(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_cursor_service_host_with_port(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com:8000'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:8000' + +def test_cursor_service_grpc_transport_channel(): + channel = grpc.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.CursorServiceGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_cursor_service_grpc_asyncio_transport_channel(): + channel = aio.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.CursorServiceGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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.CursorServiceGrpcTransport, transports.CursorServiceGrpcAsyncIOTransport]) +def test_cursor_service_transport_channel_mtls_with_client_cert_source( + transport_class +): + with mock.patch("grpc.ssl_channel_credentials", autospec=True) as grpc_ssl_channel_cred: + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + 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.CursorServiceGrpcTransport, transports.CursorServiceGrpcAsyncIOTransport]) +def test_cursor_service_transport_channel_mtls_with_adc( + transport_class +): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_subscription_path(): + project = "squid" + location = "clam" + subscription = "whelk" + expected = "projects/{project}/locations/{location}/subscriptions/{subscription}".format(project=project, location=location, subscription=subscription, ) + actual = CursorServiceClient.subscription_path(project, location, subscription) + assert expected == actual + + +def test_parse_subscription_path(): + expected = { + "project": "octopus", + "location": "oyster", + "subscription": "nudibranch", + } + path = CursorServiceClient.subscription_path(**expected) + + # Check that the path construction is reversible. + actual = CursorServiceClient.parse_subscription_path(path) + assert expected == actual + +def test_common_billing_account_path(): + billing_account = "cuttlefish" + expected = "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + actual = CursorServiceClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "mussel", + } + path = CursorServiceClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = CursorServiceClient.parse_common_billing_account_path(path) + assert expected == actual + +def test_common_folder_path(): + folder = "winkle" + expected = "folders/{folder}".format(folder=folder, ) + actual = CursorServiceClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nautilus", + } + path = CursorServiceClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = CursorServiceClient.parse_common_folder_path(path) + assert expected == actual + +def test_common_organization_path(): + organization = "scallop" + expected = "organizations/{organization}".format(organization=organization, ) + actual = CursorServiceClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "abalone", + } + path = CursorServiceClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = CursorServiceClient.parse_common_organization_path(path) + assert expected == actual + +def test_common_project_path(): + project = "squid" + expected = "projects/{project}".format(project=project, ) + actual = CursorServiceClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "clam", + } + path = CursorServiceClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = CursorServiceClient.parse_common_project_path(path) + assert expected == actual + +def test_common_location_path(): + project = "whelk" + location = "octopus" + expected = "projects/{project}/locations/{location}".format(project=project, location=location, ) + actual = CursorServiceClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + } + path = CursorServiceClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = CursorServiceClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.CursorServiceTransport, '_prep_wrapped_messages') as prep: + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.CursorServiceTransport, '_prep_wrapped_messages') as prep: + transport_class = CursorServiceClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = CursorServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object(type(getattr(client.transport, "grpc_channel")), "close") as close: + async with client: + close.assert_not_called() + close.assert_called_once() + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + with mock.patch.object(type(getattr(client.transport, close_name)), "close") as close: + with client: + close.assert_not_called() + close.assert_called_once() + +def test_client_ctx(): + transports = [ + 'grpc', + ] + for transport in transports: + client = CursorServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_partition_assignment_service.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_partition_assignment_service.py new file mode 100644 index 00000000..526afbdc --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_partition_assignment_service.py @@ -0,0 +1,1030 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import mock +import packaging.version + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + + +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import path_template +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.pubsublite_v1.services.partition_assignment_service import PartitionAssignmentServiceAsyncClient +from google.cloud.pubsublite_v1.services.partition_assignment_service import PartitionAssignmentServiceClient +from google.cloud.pubsublite_v1.services.partition_assignment_service import transports +from google.cloud.pubsublite_v1.services.partition_assignment_service.transports.base import _GOOGLE_AUTH_VERSION +from google.cloud.pubsublite_v1.types import subscriber +from google.oauth2 import service_account +import google.auth + + +# TODO(busunkim): Once google-auth >= 1.25.0 is required transitively +# through google-api-core: +# - Delete the auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return "foo.googleapis.com" if ("localhost" in client.DEFAULT_ENDPOINT) else client.DEFAULT_ENDPOINT + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert PartitionAssignmentServiceClient._get_default_mtls_endpoint(None) is None + assert PartitionAssignmentServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert PartitionAssignmentServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert PartitionAssignmentServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + assert PartitionAssignmentServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint + assert PartitionAssignmentServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [ + PartitionAssignmentServiceClient, + PartitionAssignmentServiceAsyncClient, +]) +def test_partition_assignment_service_client_from_service_account_info(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_info') as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +@pytest.mark.parametrize("transport_class,transport_name", [ + (transports.PartitionAssignmentServiceGrpcTransport, "grpc"), + (transports.PartitionAssignmentServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_partition_assignment_service_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize("client_class", [ + PartitionAssignmentServiceClient, + PartitionAssignmentServiceAsyncClient, +]) +def test_partition_assignment_service_client_from_service_account_file(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_file') as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_partition_assignment_service_client_get_transport_class(): + transport = PartitionAssignmentServiceClient.get_transport_class() + available_transports = [ + transports.PartitionAssignmentServiceGrpcTransport, + ] + assert transport in available_transports + + transport = PartitionAssignmentServiceClient.get_transport_class("grpc") + assert transport == transports.PartitionAssignmentServiceGrpcTransport + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (PartitionAssignmentServiceClient, transports.PartitionAssignmentServiceGrpcTransport, "grpc"), + (PartitionAssignmentServiceAsyncClient, transports.PartitionAssignmentServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +@mock.patch.object(PartitionAssignmentServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PartitionAssignmentServiceClient)) +@mock.patch.object(PartitionAssignmentServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PartitionAssignmentServiceAsyncClient)) +def test_partition_assignment_service_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(PartitionAssignmentServiceClient, 'get_transport_class') as gtc: + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(PartitionAssignmentServiceClient, 'get_transport_class') as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, '__init__') as patched: + 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, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + 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="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name,use_client_cert_env", [ + (PartitionAssignmentServiceClient, transports.PartitionAssignmentServiceGrpcTransport, "grpc", "true"), + (PartitionAssignmentServiceAsyncClient, transports.PartitionAssignmentServiceGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (PartitionAssignmentServiceClient, transports.PartitionAssignmentServiceGrpcTransport, "grpc", "false"), + (PartitionAssignmentServiceAsyncClient, transports.PartitionAssignmentServiceGrpcAsyncIOTransport, "grpc_asyncio", "false"), +]) +@mock.patch.object(PartitionAssignmentServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PartitionAssignmentServiceClient)) +@mock.patch.object(PartitionAssignmentServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PartitionAssignmentServiceAsyncClient)) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_partition_assignment_service_client_mtls_env_auto(client_class, transport_class, transport_name, use_client_cert_env): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}): + options = client_options.ClientOptions(client_cert_source=client_cert_source_callback) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + + 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, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + 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=True): + with mock.patch('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 + + patched.return_value = None + client = client_class() + 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, + always_use_jwt_access=True, + ) + + # 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, + always_use_jwt_access=True, + ) + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (PartitionAssignmentServiceClient, transports.PartitionAssignmentServiceGrpcTransport, "grpc"), + (PartitionAssignmentServiceAsyncClient, transports.PartitionAssignmentServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_partition_assignment_service_client_client_options_scopes(client_class, transport_class, transport_name): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (PartitionAssignmentServiceClient, transports.PartitionAssignmentServiceGrpcTransport, "grpc"), + (PartitionAssignmentServiceAsyncClient, transports.PartitionAssignmentServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_partition_assignment_service_client_client_options_credentials_file(client_class, transport_class, transport_name): + # Check the case credentials file is provided. + options = client_options.ClientOptions( + credentials_file="credentials.json" + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_partition_assignment_service_client_client_options_from_dict(): + with mock.patch('google.cloud.pubsublite_v1.services.partition_assignment_service.transports.PartitionAssignmentServiceGrpcTransport.__init__') as grpc_transport: + grpc_transport.return_value = None + client = PartitionAssignmentServiceClient( + client_options={'api_endpoint': 'squid.clam.whelk'} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_assign_partitions(transport: str = 'grpc', request_type=subscriber.PartitionAssignmentRequest): + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.assign_partitions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = iter([subscriber.PartitionAssignment()]) + response = client.assign_partitions(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + for message in response: + assert isinstance(message, subscriber.PartitionAssignment) + + +def test_assign_partitions_from_dict(): + test_assign_partitions(request_type=dict) + + +@pytest.mark.asyncio +async def test_assign_partitions_async(transport: str = 'grpc_asyncio', request_type=subscriber.PartitionAssignmentRequest): + client = PartitionAssignmentServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.assign_partitions), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = mock.Mock(aio.StreamStreamCall, autospec=True) + call.return_value.read = mock.AsyncMock(side_effect=[subscriber.PartitionAssignment()]) + response = await client.assign_partitions(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + message = await response.read() + assert isinstance(message, subscriber.PartitionAssignment) + + +@pytest.mark.asyncio +async def test_assign_partitions_async_from_dict(): + await test_assign_partitions_async(request_type=dict) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.PartitionAssignmentServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.PartitionAssignmentServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PartitionAssignmentServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.PartitionAssignmentServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PartitionAssignmentServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.PartitionAssignmentServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = PartitionAssignmentServiceClient(transport=transport) + assert client.transport is transport + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.PartitionAssignmentServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.PartitionAssignmentServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + +@pytest.mark.parametrize("transport_class", [ + transports.PartitionAssignmentServiceGrpcTransport, + transports.PartitionAssignmentServiceGrpcAsyncIOTransport, +]) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.PartitionAssignmentServiceGrpcTransport, + ) + +def test_partition_assignment_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.PartitionAssignmentServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json" + ) + + +def test_partition_assignment_service_base_transport(): + # Instantiate the base transport. + with mock.patch('google.cloud.pubsublite_v1.services.partition_assignment_service.transports.PartitionAssignmentServiceTransport.__init__') as Transport: + Transport.return_value = None + transport = transports.PartitionAssignmentServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + 'assign_partitions', + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + +@requires_google_auth_gte_1_25_0 +def test_partition_assignment_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.partition_assignment_service.transports.PartitionAssignmentServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PartitionAssignmentServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_partition_assignment_service_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.partition_assignment_service.transports.PartitionAssignmentServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PartitionAssignmentServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", scopes=( + 'https://www.googleapis.com/auth/cloud-platform', + ), + quota_project_id="octopus", + ) + + +def test_partition_assignment_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, 'default', autospec=True) as adc, mock.patch('google.cloud.pubsublite_v1.services.partition_assignment_service.transports.PartitionAssignmentServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PartitionAssignmentServiceTransport() + adc.assert_called_once() + + +@requires_google_auth_gte_1_25_0 +def test_partition_assignment_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + PartitionAssignmentServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_partition_assignment_service_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + PartitionAssignmentServiceClient() + adc.assert_called_once_with( + scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PartitionAssignmentServiceGrpcTransport, + transports.PartitionAssignmentServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_partition_assignment_service_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PartitionAssignmentServiceGrpcTransport, + transports.PartitionAssignmentServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_partition_assignment_service_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") + adc.assert_called_once_with(scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.PartitionAssignmentServiceGrpcTransport, grpc_helpers), + (transports.PartitionAssignmentServiceGrpcAsyncIOTransport, grpc_helpers_async) + ], +) +def test_partition_assignment_service_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class( + quota_project_id="octopus", + scopes=["1", "2"] + ) + + create_channel.assert_called_with( + "pubsublite.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + scopes=["1", "2"], + default_host="pubsublite.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize("transport_class", [transports.PartitionAssignmentServiceGrpcTransport, transports.PartitionAssignmentServiceGrpcAsyncIOTransport]) +def test_partition_assignment_service_grpc_transport_client_cert_source_for_mtls( + transport_class +): + cred = ga_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=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # 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_partition_assignment_service_host_no_port(): + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_partition_assignment_service_host_with_port(): + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com:8000'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:8000' + +def test_partition_assignment_service_grpc_transport_channel(): + channel = grpc.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.PartitionAssignmentServiceGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_partition_assignment_service_grpc_asyncio_transport_channel(): + channel = aio.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.PartitionAssignmentServiceGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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.PartitionAssignmentServiceGrpcTransport, transports.PartitionAssignmentServiceGrpcAsyncIOTransport]) +def test_partition_assignment_service_transport_channel_mtls_with_client_cert_source( + transport_class +): + with mock.patch("grpc.ssl_channel_credentials", autospec=True) as grpc_ssl_channel_cred: + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + 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.PartitionAssignmentServiceGrpcTransport, transports.PartitionAssignmentServiceGrpcAsyncIOTransport]) +def test_partition_assignment_service_transport_channel_mtls_with_adc( + transport_class +): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_common_billing_account_path(): + billing_account = "squid" + expected = "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + actual = PartitionAssignmentServiceClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = PartitionAssignmentServiceClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = PartitionAssignmentServiceClient.parse_common_billing_account_path(path) + assert expected == actual + +def test_common_folder_path(): + folder = "whelk" + expected = "folders/{folder}".format(folder=folder, ) + actual = PartitionAssignmentServiceClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = PartitionAssignmentServiceClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = PartitionAssignmentServiceClient.parse_common_folder_path(path) + assert expected == actual + +def test_common_organization_path(): + organization = "oyster" + expected = "organizations/{organization}".format(organization=organization, ) + actual = PartitionAssignmentServiceClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = PartitionAssignmentServiceClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = PartitionAssignmentServiceClient.parse_common_organization_path(path) + assert expected == actual + +def test_common_project_path(): + project = "cuttlefish" + expected = "projects/{project}".format(project=project, ) + actual = PartitionAssignmentServiceClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = PartitionAssignmentServiceClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = PartitionAssignmentServiceClient.parse_common_project_path(path) + assert expected == actual + +def test_common_location_path(): + project = "winkle" + location = "nautilus" + expected = "projects/{project}/locations/{location}".format(project=project, location=location, ) + actual = PartitionAssignmentServiceClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = PartitionAssignmentServiceClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = PartitionAssignmentServiceClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.PartitionAssignmentServiceTransport, '_prep_wrapped_messages') as prep: + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.PartitionAssignmentServiceTransport, '_prep_wrapped_messages') as prep: + transport_class = PartitionAssignmentServiceClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = PartitionAssignmentServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object(type(getattr(client.transport, "grpc_channel")), "close") as close: + async with client: + close.assert_not_called() + close.assert_called_once() + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + with mock.patch.object(type(getattr(client.transport, close_name)), "close") as close: + with client: + close.assert_not_called() + close.assert_called_once() + +def test_client_ctx(): + transports = [ + 'grpc', + ] + for transport in transports: + client = PartitionAssignmentServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_publisher_service.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_publisher_service.py new file mode 100644 index 00000000..83c9f336 --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_publisher_service.py @@ -0,0 +1,1032 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import mock +import packaging.version + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + + +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import path_template +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.pubsublite_v1.services.publisher_service import PublisherServiceAsyncClient +from google.cloud.pubsublite_v1.services.publisher_service import PublisherServiceClient +from google.cloud.pubsublite_v1.services.publisher_service import transports +from google.cloud.pubsublite_v1.services.publisher_service.transports.base import _GOOGLE_AUTH_VERSION +from google.cloud.pubsublite_v1.types import common +from google.cloud.pubsublite_v1.types import publisher +from google.oauth2 import service_account +from google.protobuf import timestamp_pb2 # type: ignore +import google.auth + + +# TODO(busunkim): Once google-auth >= 1.25.0 is required transitively +# through google-api-core: +# - Delete the auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return "foo.googleapis.com" if ("localhost" in client.DEFAULT_ENDPOINT) else client.DEFAULT_ENDPOINT + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert PublisherServiceClient._get_default_mtls_endpoint(None) is None + assert PublisherServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert PublisherServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert PublisherServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + assert PublisherServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint + assert PublisherServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [ + PublisherServiceClient, + PublisherServiceAsyncClient, +]) +def test_publisher_service_client_from_service_account_info(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_info') as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +@pytest.mark.parametrize("transport_class,transport_name", [ + (transports.PublisherServiceGrpcTransport, "grpc"), + (transports.PublisherServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_publisher_service_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize("client_class", [ + PublisherServiceClient, + PublisherServiceAsyncClient, +]) +def test_publisher_service_client_from_service_account_file(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_file') as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_publisher_service_client_get_transport_class(): + transport = PublisherServiceClient.get_transport_class() + available_transports = [ + transports.PublisherServiceGrpcTransport, + ] + assert transport in available_transports + + transport = PublisherServiceClient.get_transport_class("grpc") + assert transport == transports.PublisherServiceGrpcTransport + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (PublisherServiceClient, transports.PublisherServiceGrpcTransport, "grpc"), + (PublisherServiceAsyncClient, transports.PublisherServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +@mock.patch.object(PublisherServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PublisherServiceClient)) +@mock.patch.object(PublisherServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PublisherServiceAsyncClient)) +def test_publisher_service_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(PublisherServiceClient, 'get_transport_class') as gtc: + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(PublisherServiceClient, 'get_transport_class') as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, '__init__') as patched: + 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, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + 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="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name,use_client_cert_env", [ + (PublisherServiceClient, transports.PublisherServiceGrpcTransport, "grpc", "true"), + (PublisherServiceAsyncClient, transports.PublisherServiceGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (PublisherServiceClient, transports.PublisherServiceGrpcTransport, "grpc", "false"), + (PublisherServiceAsyncClient, transports.PublisherServiceGrpcAsyncIOTransport, "grpc_asyncio", "false"), +]) +@mock.patch.object(PublisherServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PublisherServiceClient)) +@mock.patch.object(PublisherServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PublisherServiceAsyncClient)) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_publisher_service_client_mtls_env_auto(client_class, transport_class, transport_name, use_client_cert_env): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}): + options = client_options.ClientOptions(client_cert_source=client_cert_source_callback) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + + 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, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + 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=True): + with mock.patch('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 + + patched.return_value = None + client = client_class() + 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, + always_use_jwt_access=True, + ) + + # 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, + always_use_jwt_access=True, + ) + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (PublisherServiceClient, transports.PublisherServiceGrpcTransport, "grpc"), + (PublisherServiceAsyncClient, transports.PublisherServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_publisher_service_client_client_options_scopes(client_class, transport_class, transport_name): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (PublisherServiceClient, transports.PublisherServiceGrpcTransport, "grpc"), + (PublisherServiceAsyncClient, transports.PublisherServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_publisher_service_client_client_options_credentials_file(client_class, transport_class, transport_name): + # Check the case credentials file is provided. + options = client_options.ClientOptions( + credentials_file="credentials.json" + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_publisher_service_client_client_options_from_dict(): + with mock.patch('google.cloud.pubsublite_v1.services.publisher_service.transports.PublisherServiceGrpcTransport.__init__') as grpc_transport: + grpc_transport.return_value = None + client = PublisherServiceClient( + client_options={'api_endpoint': 'squid.clam.whelk'} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_publish(transport: str = 'grpc', request_type=publisher.PublishRequest): + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.publish), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = iter([publisher.PublishResponse()]) + response = client.publish(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + for message in response: + assert isinstance(message, publisher.PublishResponse) + + +def test_publish_from_dict(): + test_publish(request_type=dict) + + +@pytest.mark.asyncio +async def test_publish_async(transport: str = 'grpc_asyncio', request_type=publisher.PublishRequest): + client = PublisherServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.publish), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = mock.Mock(aio.StreamStreamCall, autospec=True) + call.return_value.read = mock.AsyncMock(side_effect=[publisher.PublishResponse()]) + response = await client.publish(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + message = await response.read() + assert isinstance(message, publisher.PublishResponse) + + +@pytest.mark.asyncio +async def test_publish_async_from_dict(): + await test_publish_async(request_type=dict) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.PublisherServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.PublisherServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PublisherServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.PublisherServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PublisherServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.PublisherServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = PublisherServiceClient(transport=transport) + assert client.transport is transport + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.PublisherServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.PublisherServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + +@pytest.mark.parametrize("transport_class", [ + transports.PublisherServiceGrpcTransport, + transports.PublisherServiceGrpcAsyncIOTransport, +]) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.PublisherServiceGrpcTransport, + ) + +def test_publisher_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.PublisherServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json" + ) + + +def test_publisher_service_base_transport(): + # Instantiate the base transport. + with mock.patch('google.cloud.pubsublite_v1.services.publisher_service.transports.PublisherServiceTransport.__init__') as Transport: + Transport.return_value = None + transport = transports.PublisherServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + 'publish', + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + +@requires_google_auth_gte_1_25_0 +def test_publisher_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.publisher_service.transports.PublisherServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PublisherServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_publisher_service_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.publisher_service.transports.PublisherServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PublisherServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", scopes=( + 'https://www.googleapis.com/auth/cloud-platform', + ), + quota_project_id="octopus", + ) + + +def test_publisher_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, 'default', autospec=True) as adc, mock.patch('google.cloud.pubsublite_v1.services.publisher_service.transports.PublisherServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PublisherServiceTransport() + adc.assert_called_once() + + +@requires_google_auth_gte_1_25_0 +def test_publisher_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + PublisherServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_publisher_service_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + PublisherServiceClient() + adc.assert_called_once_with( + scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PublisherServiceGrpcTransport, + transports.PublisherServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_publisher_service_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PublisherServiceGrpcTransport, + transports.PublisherServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_publisher_service_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") + adc.assert_called_once_with(scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.PublisherServiceGrpcTransport, grpc_helpers), + (transports.PublisherServiceGrpcAsyncIOTransport, grpc_helpers_async) + ], +) +def test_publisher_service_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class( + quota_project_id="octopus", + scopes=["1", "2"] + ) + + create_channel.assert_called_with( + "pubsublite.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + scopes=["1", "2"], + default_host="pubsublite.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize("transport_class", [transports.PublisherServiceGrpcTransport, transports.PublisherServiceGrpcAsyncIOTransport]) +def test_publisher_service_grpc_transport_client_cert_source_for_mtls( + transport_class +): + cred = ga_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=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # 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_service_host_no_port(): + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_publisher_service_host_with_port(): + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com:8000'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:8000' + +def test_publisher_service_grpc_transport_channel(): + channel = grpc.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.PublisherServiceGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_publisher_service_grpc_asyncio_transport_channel(): + channel = aio.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.PublisherServiceGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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.PublisherServiceGrpcTransport, transports.PublisherServiceGrpcAsyncIOTransport]) +def test_publisher_service_transport_channel_mtls_with_client_cert_source( + transport_class +): + with mock.patch("grpc.ssl_channel_credentials", autospec=True) as grpc_ssl_channel_cred: + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + 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.PublisherServiceGrpcTransport, transports.PublisherServiceGrpcAsyncIOTransport]) +def test_publisher_service_transport_channel_mtls_with_adc( + transport_class +): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_common_billing_account_path(): + billing_account = "squid" + expected = "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + actual = PublisherServiceClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = PublisherServiceClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = PublisherServiceClient.parse_common_billing_account_path(path) + assert expected == actual + +def test_common_folder_path(): + folder = "whelk" + expected = "folders/{folder}".format(folder=folder, ) + actual = PublisherServiceClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = PublisherServiceClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = PublisherServiceClient.parse_common_folder_path(path) + assert expected == actual + +def test_common_organization_path(): + organization = "oyster" + expected = "organizations/{organization}".format(organization=organization, ) + actual = PublisherServiceClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = PublisherServiceClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = PublisherServiceClient.parse_common_organization_path(path) + assert expected == actual + +def test_common_project_path(): + project = "cuttlefish" + expected = "projects/{project}".format(project=project, ) + actual = PublisherServiceClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = PublisherServiceClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = PublisherServiceClient.parse_common_project_path(path) + assert expected == actual + +def test_common_location_path(): + project = "winkle" + location = "nautilus" + expected = "projects/{project}/locations/{location}".format(project=project, location=location, ) + actual = PublisherServiceClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = PublisherServiceClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = PublisherServiceClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.PublisherServiceTransport, '_prep_wrapped_messages') as prep: + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.PublisherServiceTransport, '_prep_wrapped_messages') as prep: + transport_class = PublisherServiceClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = PublisherServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object(type(getattr(client.transport, "grpc_channel")), "close") as close: + async with client: + close.assert_not_called() + close.assert_called_once() + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + with mock.patch.object(type(getattr(client.transport, close_name)), "close") as close: + with client: + close.assert_not_called() + close.assert_called_once() + +def test_client_ctx(): + transports = [ + 'grpc', + ] + for transport in transports: + client = PublisherServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_subscriber_service.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_subscriber_service.py new file mode 100644 index 00000000..40e0578e --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_subscriber_service.py @@ -0,0 +1,1031 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import mock +import packaging.version + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + + +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import path_template +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.pubsublite_v1.services.subscriber_service import SubscriberServiceAsyncClient +from google.cloud.pubsublite_v1.services.subscriber_service import SubscriberServiceClient +from google.cloud.pubsublite_v1.services.subscriber_service import transports +from google.cloud.pubsublite_v1.services.subscriber_service.transports.base import _GOOGLE_AUTH_VERSION +from google.cloud.pubsublite_v1.types import common +from google.cloud.pubsublite_v1.types import subscriber +from google.oauth2 import service_account +import google.auth + + +# TODO(busunkim): Once google-auth >= 1.25.0 is required transitively +# through google-api-core: +# - Delete the auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return "foo.googleapis.com" if ("localhost" in client.DEFAULT_ENDPOINT) else client.DEFAULT_ENDPOINT + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert SubscriberServiceClient._get_default_mtls_endpoint(None) is None + assert SubscriberServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert SubscriberServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert SubscriberServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + assert SubscriberServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint + assert SubscriberServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [ + SubscriberServiceClient, + SubscriberServiceAsyncClient, +]) +def test_subscriber_service_client_from_service_account_info(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_info') as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +@pytest.mark.parametrize("transport_class,transport_name", [ + (transports.SubscriberServiceGrpcTransport, "grpc"), + (transports.SubscriberServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_subscriber_service_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize("client_class", [ + SubscriberServiceClient, + SubscriberServiceAsyncClient, +]) +def test_subscriber_service_client_from_service_account_file(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_file') as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_subscriber_service_client_get_transport_class(): + transport = SubscriberServiceClient.get_transport_class() + available_transports = [ + transports.SubscriberServiceGrpcTransport, + ] + assert transport in available_transports + + transport = SubscriberServiceClient.get_transport_class("grpc") + assert transport == transports.SubscriberServiceGrpcTransport + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (SubscriberServiceClient, transports.SubscriberServiceGrpcTransport, "grpc"), + (SubscriberServiceAsyncClient, transports.SubscriberServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +@mock.patch.object(SubscriberServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(SubscriberServiceClient)) +@mock.patch.object(SubscriberServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(SubscriberServiceAsyncClient)) +def test_subscriber_service_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(SubscriberServiceClient, 'get_transport_class') as gtc: + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(SubscriberServiceClient, 'get_transport_class') as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, '__init__') as patched: + 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, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + 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="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name,use_client_cert_env", [ + (SubscriberServiceClient, transports.SubscriberServiceGrpcTransport, "grpc", "true"), + (SubscriberServiceAsyncClient, transports.SubscriberServiceGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (SubscriberServiceClient, transports.SubscriberServiceGrpcTransport, "grpc", "false"), + (SubscriberServiceAsyncClient, transports.SubscriberServiceGrpcAsyncIOTransport, "grpc_asyncio", "false"), +]) +@mock.patch.object(SubscriberServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(SubscriberServiceClient)) +@mock.patch.object(SubscriberServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(SubscriberServiceAsyncClient)) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_subscriber_service_client_mtls_env_auto(client_class, transport_class, transport_name, use_client_cert_env): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}): + options = client_options.ClientOptions(client_cert_source=client_cert_source_callback) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + + 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, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + 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=True): + with mock.patch('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 + + patched.return_value = None + client = client_class() + 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, + always_use_jwt_access=True, + ) + + # 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, + always_use_jwt_access=True, + ) + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (SubscriberServiceClient, transports.SubscriberServiceGrpcTransport, "grpc"), + (SubscriberServiceAsyncClient, transports.SubscriberServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_subscriber_service_client_client_options_scopes(client_class, transport_class, transport_name): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (SubscriberServiceClient, transports.SubscriberServiceGrpcTransport, "grpc"), + (SubscriberServiceAsyncClient, transports.SubscriberServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_subscriber_service_client_client_options_credentials_file(client_class, transport_class, transport_name): + # Check the case credentials file is provided. + options = client_options.ClientOptions( + credentials_file="credentials.json" + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_subscriber_service_client_client_options_from_dict(): + with mock.patch('google.cloud.pubsublite_v1.services.subscriber_service.transports.SubscriberServiceGrpcTransport.__init__') as grpc_transport: + grpc_transport.return_value = None + client = SubscriberServiceClient( + client_options={'api_endpoint': 'squid.clam.whelk'} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_subscribe(transport: str = 'grpc', request_type=subscriber.SubscribeRequest): + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.subscribe), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = iter([subscriber.SubscribeResponse()]) + response = client.subscribe(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + for message in response: + assert isinstance(message, subscriber.SubscribeResponse) + + +def test_subscribe_from_dict(): + test_subscribe(request_type=dict) + + +@pytest.mark.asyncio +async def test_subscribe_async(transport: str = 'grpc_asyncio', request_type=subscriber.SubscribeRequest): + client = SubscriberServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + requests = [request] + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.subscribe), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = mock.Mock(aio.StreamStreamCall, autospec=True) + call.return_value.read = mock.AsyncMock(side_effect=[subscriber.SubscribeResponse()]) + response = await client.subscribe(iter(requests)) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert next(args[0]) == request + + # Establish that the response is the type that we expect. + message = await response.read() + assert isinstance(message, subscriber.SubscribeResponse) + + +@pytest.mark.asyncio +async def test_subscribe_async_from_dict(): + await test_subscribe_async(request_type=dict) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SubscriberServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SubscriberServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SubscriberServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SubscriberServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SubscriberServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SubscriberServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SubscriberServiceClient(transport=transport) + assert client.transport is transport + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SubscriberServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SubscriberServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + +@pytest.mark.parametrize("transport_class", [ + transports.SubscriberServiceGrpcTransport, + transports.SubscriberServiceGrpcAsyncIOTransport, +]) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SubscriberServiceGrpcTransport, + ) + +def test_subscriber_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SubscriberServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json" + ) + + +def test_subscriber_service_base_transport(): + # Instantiate the base transport. + with mock.patch('google.cloud.pubsublite_v1.services.subscriber_service.transports.SubscriberServiceTransport.__init__') as Transport: + Transport.return_value = None + transport = transports.SubscriberServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + 'subscribe', + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + +@requires_google_auth_gte_1_25_0 +def test_subscriber_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.subscriber_service.transports.SubscriberServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SubscriberServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_subscriber_service_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.subscriber_service.transports.SubscriberServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SubscriberServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", scopes=( + 'https://www.googleapis.com/auth/cloud-platform', + ), + quota_project_id="octopus", + ) + + +def test_subscriber_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, 'default', autospec=True) as adc, mock.patch('google.cloud.pubsublite_v1.services.subscriber_service.transports.SubscriberServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SubscriberServiceTransport() + adc.assert_called_once() + + +@requires_google_auth_gte_1_25_0 +def test_subscriber_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + SubscriberServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_subscriber_service_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + SubscriberServiceClient() + adc.assert_called_once_with( + scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SubscriberServiceGrpcTransport, + transports.SubscriberServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_subscriber_service_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SubscriberServiceGrpcTransport, + transports.SubscriberServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_subscriber_service_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") + adc.assert_called_once_with(scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.SubscriberServiceGrpcTransport, grpc_helpers), + (transports.SubscriberServiceGrpcAsyncIOTransport, grpc_helpers_async) + ], +) +def test_subscriber_service_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class( + quota_project_id="octopus", + scopes=["1", "2"] + ) + + create_channel.assert_called_with( + "pubsublite.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + scopes=["1", "2"], + default_host="pubsublite.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize("transport_class", [transports.SubscriberServiceGrpcTransport, transports.SubscriberServiceGrpcAsyncIOTransport]) +def test_subscriber_service_grpc_transport_client_cert_source_for_mtls( + transport_class +): + cred = ga_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=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # 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_service_host_no_port(): + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_subscriber_service_host_with_port(): + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com:8000'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:8000' + +def test_subscriber_service_grpc_transport_channel(): + channel = grpc.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.SubscriberServiceGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_subscriber_service_grpc_asyncio_transport_channel(): + channel = aio.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.SubscriberServiceGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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.SubscriberServiceGrpcTransport, transports.SubscriberServiceGrpcAsyncIOTransport]) +def test_subscriber_service_transport_channel_mtls_with_client_cert_source( + transport_class +): + with mock.patch("grpc.ssl_channel_credentials", autospec=True) as grpc_ssl_channel_cred: + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + 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.SubscriberServiceGrpcTransport, transports.SubscriberServiceGrpcAsyncIOTransport]) +def test_subscriber_service_transport_channel_mtls_with_adc( + transport_class +): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_common_billing_account_path(): + billing_account = "squid" + expected = "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + actual = SubscriberServiceClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = SubscriberServiceClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = SubscriberServiceClient.parse_common_billing_account_path(path) + assert expected == actual + +def test_common_folder_path(): + folder = "whelk" + expected = "folders/{folder}".format(folder=folder, ) + actual = SubscriberServiceClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = SubscriberServiceClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = SubscriberServiceClient.parse_common_folder_path(path) + assert expected == actual + +def test_common_organization_path(): + organization = "oyster" + expected = "organizations/{organization}".format(organization=organization, ) + actual = SubscriberServiceClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = SubscriberServiceClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = SubscriberServiceClient.parse_common_organization_path(path) + assert expected == actual + +def test_common_project_path(): + project = "cuttlefish" + expected = "projects/{project}".format(project=project, ) + actual = SubscriberServiceClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = SubscriberServiceClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = SubscriberServiceClient.parse_common_project_path(path) + assert expected == actual + +def test_common_location_path(): + project = "winkle" + location = "nautilus" + expected = "projects/{project}/locations/{location}".format(project=project, location=location, ) + actual = SubscriberServiceClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = SubscriberServiceClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = SubscriberServiceClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.SubscriberServiceTransport, '_prep_wrapped_messages') as prep: + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.SubscriberServiceTransport, '_prep_wrapped_messages') as prep: + transport_class = SubscriberServiceClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = SubscriberServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object(type(getattr(client.transport, "grpc_channel")), "close") as close: + async with client: + close.assert_not_called() + close.assert_called_once() + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + with mock.patch.object(type(getattr(client.transport, close_name)), "close") as close: + with client: + close.assert_not_called() + close.assert_called_once() + +def test_client_ctx(): + transports = [ + 'grpc', + ] + for transport in transports: + client = SubscriberServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() diff --git a/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_topic_stats_service.py b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_topic_stats_service.py new file mode 100644 index 00000000..53be290f --- /dev/null +++ b/owl-bot-staging/v1/tests/unit/gapic/pubsublite_v1/test_topic_stats_service.py @@ -0,0 +1,1435 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import mock +import packaging.version + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + + +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import path_template +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.pubsublite_v1.services.topic_stats_service import TopicStatsServiceAsyncClient +from google.cloud.pubsublite_v1.services.topic_stats_service import TopicStatsServiceClient +from google.cloud.pubsublite_v1.services.topic_stats_service import transports +from google.cloud.pubsublite_v1.services.topic_stats_service.transports.base import _GOOGLE_AUTH_VERSION +from google.cloud.pubsublite_v1.types import common +from google.cloud.pubsublite_v1.types import topic_stats +from google.oauth2 import service_account +from google.protobuf import timestamp_pb2 # type: ignore +import google.auth + + +# TODO(busunkim): Once google-auth >= 1.25.0 is required transitively +# through google-api-core: +# - Delete the auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return "foo.googleapis.com" if ("localhost" in client.DEFAULT_ENDPOINT) else client.DEFAULT_ENDPOINT + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert TopicStatsServiceClient._get_default_mtls_endpoint(None) is None + assert TopicStatsServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert TopicStatsServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert TopicStatsServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + assert TopicStatsServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint + assert TopicStatsServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [ + TopicStatsServiceClient, + TopicStatsServiceAsyncClient, +]) +def test_topic_stats_service_client_from_service_account_info(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_info') as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +@pytest.mark.parametrize("transport_class,transport_name", [ + (transports.TopicStatsServiceGrpcTransport, "grpc"), + (transports.TopicStatsServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_topic_stats_service_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object(service_account.Credentials, 'with_always_use_jwt_access', create=True) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize("client_class", [ + TopicStatsServiceClient, + TopicStatsServiceAsyncClient, +]) +def test_topic_stats_service_client_from_service_account_file(client_class): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object(service_account.Credentials, 'from_service_account_file') as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json("dummy/file/path.json") + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_topic_stats_service_client_get_transport_class(): + transport = TopicStatsServiceClient.get_transport_class() + available_transports = [ + transports.TopicStatsServiceGrpcTransport, + ] + assert transport in available_transports + + transport = TopicStatsServiceClient.get_transport_class("grpc") + assert transport == transports.TopicStatsServiceGrpcTransport + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (TopicStatsServiceClient, transports.TopicStatsServiceGrpcTransport, "grpc"), + (TopicStatsServiceAsyncClient, transports.TopicStatsServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +@mock.patch.object(TopicStatsServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TopicStatsServiceClient)) +@mock.patch.object(TopicStatsServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TopicStatsServiceAsyncClient)) +def test_topic_stats_service_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(TopicStatsServiceClient, 'get_transport_class') as gtc: + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(TopicStatsServiceClient, 'get_transport_class') as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, '__init__') as patched: + 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, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + 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="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name,use_client_cert_env", [ + (TopicStatsServiceClient, transports.TopicStatsServiceGrpcTransport, "grpc", "true"), + (TopicStatsServiceAsyncClient, transports.TopicStatsServiceGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (TopicStatsServiceClient, transports.TopicStatsServiceGrpcTransport, "grpc", "false"), + (TopicStatsServiceAsyncClient, transports.TopicStatsServiceGrpcAsyncIOTransport, "grpc_asyncio", "false"), +]) +@mock.patch.object(TopicStatsServiceClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TopicStatsServiceClient)) +@mock.patch.object(TopicStatsServiceAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TopicStatsServiceAsyncClient)) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_topic_stats_service_client_mtls_env_auto(client_class, transport_class, transport_name, use_client_cert_env): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}): + options = client_options.ClientOptions(client_cert_source=client_cert_source_callback) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + + 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, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + 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=True): + with mock.patch('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 + + patched.return_value = None + client = client_class() + 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, + always_use_jwt_access=True, + ) + + # 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, + always_use_jwt_access=True, + ) + + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (TopicStatsServiceClient, transports.TopicStatsServiceGrpcTransport, "grpc"), + (TopicStatsServiceAsyncClient, transports.TopicStatsServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_topic_stats_service_client_client_options_scopes(client_class, transport_class, transport_name): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + +@pytest.mark.parametrize("client_class,transport_class,transport_name", [ + (TopicStatsServiceClient, transports.TopicStatsServiceGrpcTransport, "grpc"), + (TopicStatsServiceAsyncClient, transports.TopicStatsServiceGrpcAsyncIOTransport, "grpc_asyncio"), +]) +def test_topic_stats_service_client_client_options_credentials_file(client_class, transport_class, transport_name): + # Check the case credentials file is provided. + options = client_options.ClientOptions( + credentials_file="credentials.json" + ) + with mock.patch.object(transport_class, '__init__') as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_topic_stats_service_client_client_options_from_dict(): + with mock.patch('google.cloud.pubsublite_v1.services.topic_stats_service.transports.TopicStatsServiceGrpcTransport.__init__') as grpc_transport: + grpc_transport.return_value = None + client = TopicStatsServiceClient( + client_options={'api_endpoint': 'squid.clam.whelk'} + ) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) + + +def test_compute_message_stats(transport: str = 'grpc', request_type=topic_stats.ComputeMessageStatsRequest): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_message_stats), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = topic_stats.ComputeMessageStatsResponse( + message_count=1389, + message_bytes=1387, + ) + response = client.compute_message_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeMessageStatsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, topic_stats.ComputeMessageStatsResponse) + assert response.message_count == 1389 + assert response.message_bytes == 1387 + + +def test_compute_message_stats_from_dict(): + test_compute_message_stats(request_type=dict) + + +def test_compute_message_stats_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_message_stats), + '__call__') as call: + client.compute_message_stats() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeMessageStatsRequest() + + +@pytest.mark.asyncio +async def test_compute_message_stats_async(transport: str = 'grpc_asyncio', request_type=topic_stats.ComputeMessageStatsRequest): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_message_stats), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(topic_stats.ComputeMessageStatsResponse( + message_count=1389, + message_bytes=1387, + )) + response = await client.compute_message_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeMessageStatsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, topic_stats.ComputeMessageStatsResponse) + assert response.message_count == 1389 + assert response.message_bytes == 1387 + + +@pytest.mark.asyncio +async def test_compute_message_stats_async_from_dict(): + await test_compute_message_stats_async(request_type=dict) + + +def test_compute_message_stats_field_headers(): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = topic_stats.ComputeMessageStatsRequest() + + request.topic = 'topic/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_message_stats), + '__call__') as call: + call.return_value = topic_stats.ComputeMessageStatsResponse() + client.compute_message_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic=topic/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_compute_message_stats_field_headers_async(): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = topic_stats.ComputeMessageStatsRequest() + + request.topic = 'topic/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_message_stats), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(topic_stats.ComputeMessageStatsResponse()) + await client.compute_message_stats(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic=topic/value', + ) in kw['metadata'] + + +def test_compute_head_cursor(transport: str = 'grpc', request_type=topic_stats.ComputeHeadCursorRequest): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_head_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = topic_stats.ComputeHeadCursorResponse( + ) + response = client.compute_head_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeHeadCursorRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, topic_stats.ComputeHeadCursorResponse) + + +def test_compute_head_cursor_from_dict(): + test_compute_head_cursor(request_type=dict) + + +def test_compute_head_cursor_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_head_cursor), + '__call__') as call: + client.compute_head_cursor() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeHeadCursorRequest() + + +@pytest.mark.asyncio +async def test_compute_head_cursor_async(transport: str = 'grpc_asyncio', request_type=topic_stats.ComputeHeadCursorRequest): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_head_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(topic_stats.ComputeHeadCursorResponse( + )) + response = await client.compute_head_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeHeadCursorRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, topic_stats.ComputeHeadCursorResponse) + + +@pytest.mark.asyncio +async def test_compute_head_cursor_async_from_dict(): + await test_compute_head_cursor_async(request_type=dict) + + +def test_compute_head_cursor_field_headers(): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = topic_stats.ComputeHeadCursorRequest() + + request.topic = 'topic/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_head_cursor), + '__call__') as call: + call.return_value = topic_stats.ComputeHeadCursorResponse() + client.compute_head_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic=topic/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_compute_head_cursor_field_headers_async(): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = topic_stats.ComputeHeadCursorRequest() + + request.topic = 'topic/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_head_cursor), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(topic_stats.ComputeHeadCursorResponse()) + await client.compute_head_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic=topic/value', + ) in kw['metadata'] + + +def test_compute_time_cursor(transport: str = 'grpc', request_type=topic_stats.ComputeTimeCursorRequest): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_time_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = topic_stats.ComputeTimeCursorResponse( + ) + response = client.compute_time_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeTimeCursorRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, topic_stats.ComputeTimeCursorResponse) + + +def test_compute_time_cursor_from_dict(): + test_compute_time_cursor(request_type=dict) + + +def test_compute_time_cursor_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_time_cursor), + '__call__') as call: + client.compute_time_cursor() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeTimeCursorRequest() + + +@pytest.mark.asyncio +async def test_compute_time_cursor_async(transport: str = 'grpc_asyncio', request_type=topic_stats.ComputeTimeCursorRequest): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_time_cursor), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(topic_stats.ComputeTimeCursorResponse( + )) + response = await client.compute_time_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == topic_stats.ComputeTimeCursorRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, topic_stats.ComputeTimeCursorResponse) + + +@pytest.mark.asyncio +async def test_compute_time_cursor_async_from_dict(): + await test_compute_time_cursor_async(request_type=dict) + + +def test_compute_time_cursor_field_headers(): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = topic_stats.ComputeTimeCursorRequest() + + request.topic = 'topic/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_time_cursor), + '__call__') as call: + call.return_value = topic_stats.ComputeTimeCursorResponse() + client.compute_time_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic=topic/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_compute_time_cursor_field_headers_async(): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = topic_stats.ComputeTimeCursorRequest() + + request.topic = 'topic/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_time_cursor), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(topic_stats.ComputeTimeCursorResponse()) + await client.compute_time_cursor(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'topic=topic/value', + ) in kw['metadata'] + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TopicStatsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TopicStatsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TopicStatsServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TopicStatsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TopicStatsServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TopicStatsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = TopicStatsServiceClient(transport=transport) + assert client.transport is transport + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TopicStatsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TopicStatsServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + +@pytest.mark.parametrize("transport_class", [ + transports.TopicStatsServiceGrpcTransport, + transports.TopicStatsServiceGrpcAsyncIOTransport, +]) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.TopicStatsServiceGrpcTransport, + ) + +def test_topic_stats_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.TopicStatsServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json" + ) + + +def test_topic_stats_service_base_transport(): + # Instantiate the base transport. + with mock.patch('google.cloud.pubsublite_v1.services.topic_stats_service.transports.TopicStatsServiceTransport.__init__') as Transport: + Transport.return_value = None + transport = transports.TopicStatsServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + 'compute_message_stats', + 'compute_head_cursor', + 'compute_time_cursor', + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + +@requires_google_auth_gte_1_25_0 +def test_topic_stats_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.topic_stats_service.transports.TopicStatsServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TopicStatsServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_topic_stats_service_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object(google.auth, 'load_credentials_from_file', autospec=True) as load_creds, mock.patch('google.cloud.pubsublite_v1.services.topic_stats_service.transports.TopicStatsServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TopicStatsServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with("credentials.json", scopes=( + 'https://www.googleapis.com/auth/cloud-platform', + ), + quota_project_id="octopus", + ) + + +def test_topic_stats_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, 'default', autospec=True) as adc, mock.patch('google.cloud.pubsublite_v1.services.topic_stats_service.transports.TopicStatsServiceTransport._prep_wrapped_messages') as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TopicStatsServiceTransport() + adc.assert_called_once() + + +@requires_google_auth_gte_1_25_0 +def test_topic_stats_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + TopicStatsServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_topic_stats_service_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + TopicStatsServiceClient() + adc.assert_called_once_with( + scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TopicStatsServiceGrpcTransport, + transports.TopicStatsServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_topic_stats_service_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, 'default', autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( 'https://www.googleapis.com/auth/cloud-platform',), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TopicStatsServiceGrpcTransport, + transports.TopicStatsServiceGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_topic_stats_service_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") + adc.assert_called_once_with(scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TopicStatsServiceGrpcTransport, grpc_helpers), + (transports.TopicStatsServiceGrpcAsyncIOTransport, grpc_helpers_async) + ], +) +def test_topic_stats_service_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class( + quota_project_id="octopus", + scopes=["1", "2"] + ) + + create_channel.assert_called_with( + "pubsublite.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + 'https://www.googleapis.com/auth/cloud-platform', +), + scopes=["1", "2"], + default_host="pubsublite.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize("transport_class", [transports.TopicStatsServiceGrpcTransport, transports.TopicStatsServiceGrpcAsyncIOTransport]) +def test_topic_stats_service_grpc_transport_client_cert_source_for_mtls( + transport_class +): + cred = ga_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=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # 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_topic_stats_service_host_no_port(): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:443' + + +def test_topic_stats_service_host_with_port(): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint='pubsublite.googleapis.com:8000'), + ) + assert client.transport._host == 'pubsublite.googleapis.com:8000' + +def test_topic_stats_service_grpc_transport_channel(): + channel = grpc.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TopicStatsServiceGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_topic_stats_service_grpc_asyncio_transport_channel(): + channel = aio.secure_channel('http://localhost/', grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TopicStatsServiceGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + 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.TopicStatsServiceGrpcTransport, transports.TopicStatsServiceGrpcAsyncIOTransport]) +def test_topic_stats_service_transport_channel_mtls_with_client_cert_source( + transport_class +): + with mock.patch("grpc.ssl_channel_credentials", autospec=True) as grpc_ssl_channel_cred: + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, 'default') as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + 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.TopicStatsServiceGrpcTransport, transports.TopicStatsServiceGrpcAsyncIOTransport]) +def test_topic_stats_service_transport_channel_mtls_with_adc( + transport_class +): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object(transport_class, "create_channel") as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_topic_path(): + project = "squid" + location = "clam" + topic = "whelk" + expected = "projects/{project}/locations/{location}/topics/{topic}".format(project=project, location=location, topic=topic, ) + actual = TopicStatsServiceClient.topic_path(project, location, topic) + assert expected == actual + + +def test_parse_topic_path(): + expected = { + "project": "octopus", + "location": "oyster", + "topic": "nudibranch", + } + path = TopicStatsServiceClient.topic_path(**expected) + + # Check that the path construction is reversible. + actual = TopicStatsServiceClient.parse_topic_path(path) + assert expected == actual + +def test_common_billing_account_path(): + billing_account = "cuttlefish" + expected = "billingAccounts/{billing_account}".format(billing_account=billing_account, ) + actual = TopicStatsServiceClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "mussel", + } + path = TopicStatsServiceClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = TopicStatsServiceClient.parse_common_billing_account_path(path) + assert expected == actual + +def test_common_folder_path(): + folder = "winkle" + expected = "folders/{folder}".format(folder=folder, ) + actual = TopicStatsServiceClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nautilus", + } + path = TopicStatsServiceClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = TopicStatsServiceClient.parse_common_folder_path(path) + assert expected == actual + +def test_common_organization_path(): + organization = "scallop" + expected = "organizations/{organization}".format(organization=organization, ) + actual = TopicStatsServiceClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "abalone", + } + path = TopicStatsServiceClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = TopicStatsServiceClient.parse_common_organization_path(path) + assert expected == actual + +def test_common_project_path(): + project = "squid" + expected = "projects/{project}".format(project=project, ) + actual = TopicStatsServiceClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "clam", + } + path = TopicStatsServiceClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = TopicStatsServiceClient.parse_common_project_path(path) + assert expected == actual + +def test_common_location_path(): + project = "whelk" + location = "octopus" + expected = "projects/{project}/locations/{location}".format(project=project, location=location, ) + actual = TopicStatsServiceClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + } + path = TopicStatsServiceClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = TopicStatsServiceClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.TopicStatsServiceTransport, '_prep_wrapped_messages') as prep: + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.TopicStatsServiceTransport, '_prep_wrapped_messages') as prep: + transport_class = TopicStatsServiceClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = TopicStatsServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object(type(getattr(client.transport, "grpc_channel")), "close") as close: + async with client: + close.assert_not_called() + close.assert_called_once() + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + with mock.patch.object(type(getattr(client.transport, close_name)), "close") as close: + with client: + close.assert_not_called() + close.assert_called_once() + +def test_client_ctx(): + transports = [ + 'grpc', + ] + for transport in transports: + client = TopicStatsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called()