Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add showcase e2e tests for async rest #2167

Merged
merged 4 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ jobs:
strategy:
# Run showcase tests on the lowest and highest supported runtimes
matrix:
# TODO(https://github.com/googleapis/gapic-generator-python/issues/2121) Remove `showcase_w_rest_async` target when async rest is GA.
python: ["3.7", "3.12"]
target: [showcase, showcase_alternative_templates]
target: [showcase, showcase_alternative_templates, showcase_w_rest_async]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ The `try/except` below can be removed once the minimum version of
try:
from google.api_core import version_header
HAS_GOOGLE_API_CORE_VERSION_HEADER = True # pragma: NO COVER
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError: # pragma: NO COVER
HAS_GOOGLE_API_CORE_VERSION_HEADER = False
{% endif %}{# service_version #}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,18 @@ from .transports.rest import {{ service.name }}RestTransport
try:
from .transports.rest_asyncio import Async{{ service.name }}RestTransport
HAS_GOOGLE_AUTH_AIO = True
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError as e: # pragma: NO COVER
HAS_GOOGLE_AUTH_AIO = False
GOOGLE_AUTH_AIO_EXCEPTION = e

try:
import aiohttp # type: ignore
HAS_AIOHTTP_INSTALLED = True
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError as e: # pragma: NO COVER
HAS_AIOHTTP_INSTALLED = False

{% endif %}{# if rest_async_io_enabled #}
{% endif %}

Expand All @@ -93,7 +101,7 @@ class {{ service.client_name }}Meta(type):
_transport_registry["rest"] = {{ service.name }}RestTransport
{# TODO(https://github.com/googleapis/gapic-generator-python/issues/2121): Remove this condition when async rest is GA. #}
{% if rest_async_io_enabled %}
if HAS_GOOGLE_AUTH_AIO: # pragma: NO COVER
if HAS_GOOGLE_AUTH_AIO and HAS_AIOHTTP_INSTALLED: # pragma: NO COVER
_transport_registry["rest_asyncio"] = Async{{ service.name }}RestTransport
{% endif %}{# if rest_async_io_enabled #}
{% endif %}
Expand All @@ -113,8 +121,12 @@ class {{ service.client_name }}Meta(type):
# If a specific transport is requested, return that one.
{# TODO(https://github.com/googleapis/gapic-generator-python/issues/2121): Remove this condition when async rest is GA. #}
{% if rest_async_io_enabled %}
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
if label == "rest_asyncio" and not HAS_GOOGLE_AUTH_AIO: # pragma: NO COVER
raise GOOGLE_AUTH_AIO_EXCEPTION
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
elif label == "rest_asyncio" and not HAS_AIOHTTP_INSTALLED: # pragma: NO COVER
raise ImportError("async rest transport requires aiohttp external package.")
{% endif %}
if label:
return cls._transport_registry[label]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{# TODO(https://github.com/googleapis/gapic-generator-python/issues/2121): Remove the following variable (and the condition later in this file) for async rest transport once support for it is GA. #}
{% set rest_async_io_enabled = api.all_library_settings[api.naming.proto_package].python_settings.experimental_features.rest_async_io_enabled %}
{% extends '_base.py.j2' %}

{% block content %}

from collections import OrderedDict
from typing import Dict, Type
from typing import Dict, Type{% if rest_async_io_enabled %}, Tuple{% endif +%}

from .base import {{ service.name }}Transport
{% if 'grpc' in opts.transport %}
Expand All @@ -13,6 +15,16 @@ from .grpc_asyncio import {{ service.name }}GrpcAsyncIOTransport
{% if 'rest' in opts.transport %}
from .rest import {{ service.name }}RestTransport
from .rest import {{ service.name }}RestInterceptor
{% if rest_async_io_enabled %}
ASYNC_REST_CLASSES: Tuple[str, ...]
try:
from .rest_asyncio import Async{{ service.name }}RestTransport
ASYNC_REST_CLASSES = ('Async{{ service.name }}RestTransport',)
vchudnov-g marked this conversation as resolved.
Show resolved Hide resolved
HAS_REST_ASYNC = True
except ImportError: # pragma: NO COVER
ohmayr marked this conversation as resolved.
Show resolved Hide resolved
ASYNC_REST_CLASSES = ()
HAS_REST_ASYNC = False
{% endif %}{# if rest_async_io_enabled #}
{% endif %}


Expand All @@ -25,6 +37,10 @@ _transport_registry['grpc_asyncio'] = {{ service.name }}GrpcAsyncIOTransport
{% endif %}
{% if 'rest' in opts.transport %}
_transport_registry['rest'] = {{ service.name }}RestTransport
{% if rest_async_io_enabled %}
if HAS_REST_ASYNC: # pragma: NO COVER
_transport_registry['rest_asyncio'] = Async{{ service.name }}RestTransport
{% endif %}{# if rest_async_io_enabled #}
{% endif %}

__all__ = (
Expand All @@ -37,5 +53,5 @@ __all__ = (
'{{ service.name }}RestTransport',
'{{ service.name }}RestInterceptor',
{% endif %}
)
){% if 'rest' in opts.transport and rest_async_io_enabled%} + ASYNC_REST_CLASSES{%endif%}
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@

{% block content %}

try:
import aiohttp # type: ignore
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError as e: # pragma: NO COVER
raise ImportError("async rest transport requires aiohttp external package.") from e

import google.auth
try:
from google.auth.aio.transport.sessions import AsyncAuthorizedSession # type: ignore
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError as e: # pragma: NO COVER
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
raise ImportError("async rest transport requires google.auth >= 2.x.x") from e
Expand Down Expand Up @@ -35,11 +43,10 @@ try:
except AttributeError: # pragma: NO COVER
OptionalRetry = Union[retries.AsyncRetry, object, None] # type: ignore

{# TODO (https://github.com/googleapis/gapic-generator-python/issues/2128): Update `rest_version` to include the transport dependency version. #}
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version,
grpc_version=None,
rest_version=None,
rest_version=google.auth.__version__
)

{# TODO: Add an `_interceptor` property once implemented #}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ from google.api_core import api_core_version
from proto.marshal.rules.dates import DurationRule, TimestampRule
from proto.marshal.rules import wrappers
{% if 'rest' in opts.transport %}
{% if rest_async_io_enabled %}
try:
import aiohttp # type: ignore
HAS_AIOHTTP_INSTALLED = True
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError: # pragma: NO COVER
HAS_AIOHTTP_INSTALLED = False
{% endif %}{# if rest_async_io_enabled #}
from requests import Response
from requests import Request, PreparedRequest
from requests.sessions import Session
Expand All @@ -43,6 +51,7 @@ try:
from google.auth.aio.transport.sessions import AsyncAuthorizedSession
{% endif %}
HAS_GOOGLE_AUTH_AIO = True
{# NOTE: `pragma: NO COVER` is needed since the coverage for presubmits isn't combined. #}
except ImportError: # pragma: NO COVER
HAS_GOOGLE_AUTH_AIO = False

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1861,6 +1861,8 @@ def test_transport_kind_{{ transport_name }}():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")
elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")
{% endif %}
transport = {{ get_client(service, is_async) }}.get_transport_class("{{ transport_name }}")(
credentials={{get_credentials(is_async)}}
Expand All @@ -1884,6 +1886,8 @@ def test_transport_kind_{{ transport_name }}():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")
elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")
{% endif %}
client = {{ get_client(service, is_async) }}(
credentials={{get_credentials(is_async)}},
Expand All @@ -1902,6 +1906,8 @@ def test_unsupported_parameter_rest_asyncio():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")
elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")
options = client_options.ClientOptions(quota_project_id="octopus")
{# TODO(https://github.com/googleapis/gapic-generator-python/issues/2137): Remove `type: ignore` once we add a version check for google-api-core. #}
with pytest.raises(core_exceptions.AsyncRestUnsupportedParameterError, match="google.api_core.client_options.ClientOptions.quota_project_id") as exc: # type: ignore
Expand Down Expand Up @@ -1987,6 +1993,8 @@ def test_unsupported_parameter_rest_asyncio():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")
elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")
{% endif %}

client = {{ get_client(service, is_async) }}(
Expand Down Expand Up @@ -2015,6 +2023,8 @@ def test_initialize_client_w_{{transport_name}}():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")
elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")
{% endif %}
client = {{ get_client(service, is_async) }}(
credentials={{get_credentials(is_async)}},
Expand Down Expand Up @@ -2044,7 +2054,8 @@ def test_initialize_client_w_{{transport_name}}():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")

elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")
{% endif %}
client = {{ get_client(service, is_async) }}(
credentials={{get_credentials(is_async)}},
Expand Down Expand Up @@ -2110,6 +2121,8 @@ def test_initialize_client_w_{{transport_name}}():
if not HAS_GOOGLE_AUTH_AIO:
{# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged. #}
pytest.skip("google-auth > 2.x.x is required for async rest transport.")
elif not HAS_AIOHTTP_INSTALLED:
pytest.skip("aiohttp is required for async rest transport.")

{% endif %}
client = {{ get_client(service, is_async) }}(
Expand Down
33 changes: 33 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,39 @@ def showcase(
env=env,
)

@nox.session(python=ALL_PYTHON)
def showcase_w_rest_async(
session,
templates="DEFAULT",
other_opts: typing.Iterable[str] = (),
env: typing.Optional[typing.Dict[str, str]] = {},
):
"""Run the Showcase test suite."""

with showcase_library(session, templates=templates, other_opts=other_opts, rest_async_io_enabled=True):
session.install("aiohttp")
session.install("pytest", "pytest-asyncio")
test_directory = Path("tests", "system")
ignore_file = env.get("IGNORE_FILE")
pytest_command = [
"py.test",
"--quiet",
*(session.posargs or [str(test_directory)]),
]
if ignore_file:
ignore_path = test_directory / ignore_file
pytest_command.extend(["--ignore", str(ignore_path)])

# Note: google-api-core and google-auth are re-installed here to override the version installed in constraints.
# TODO(https://github.com/googleapis/python-api-core/pull/694): Update the version of google-api-core once the linked PR is merged.
session.install('--no-cache-dir', '--force-reinstall', "google-api-core[grpc]@git+https://github.com/googleapis/python-api-core.git@7dea20d73878eca93b61bb82ae6ddf335fb3a8ca")
# TODO(https://github.com/googleapis/google-auth-library-python/pull/1577): Update the version of google-auth once the linked PR is merged.
session.install('--no-cache-dir', '--force-reinstall', "google-auth@git+https://github.com/googleapis/google-auth-library-python.git")
session.run(
*pytest_command,
env=env,
)


@nox.session(python=NEWEST_PYTHON)
def showcase_mtls(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
HAS_GOOGLE_AUTH_AIO = False
GOOGLE_AUTH_AIO_EXCEPTION = e

try:
import aiohttp # type: ignore
HAS_AIOHTTP_INSTALLED = True
except ImportError as e: # pragma: NO COVER
HAS_AIOHTTP_INSTALLED = False


class CloudRedisClientMeta(type):
"""Metaclass for the CloudRedis client.
Expand All @@ -68,7 +74,7 @@ class CloudRedisClientMeta(type):
_transport_registry["grpc"] = CloudRedisGrpcTransport
_transport_registry["grpc_asyncio"] = CloudRedisGrpcAsyncIOTransport
_transport_registry["rest"] = CloudRedisRestTransport
if HAS_GOOGLE_AUTH_AIO: # pragma: NO COVER
if HAS_GOOGLE_AUTH_AIO and HAS_AIOHTTP_INSTALLED: # pragma: NO COVER
_transport_registry["rest_asyncio"] = AsyncCloudRedisRestTransport

def get_transport_class(cls,
Expand All @@ -86,6 +92,8 @@ def get_transport_class(cls,
# If a specific transport is requested, return that one.
if label == "rest_asyncio" and not HAS_GOOGLE_AUTH_AIO: # pragma: NO COVER
raise GOOGLE_AUTH_AIO_EXCEPTION
elif label == "rest_asyncio" and not HAS_AIOHTTP_INSTALLED: # pragma: NO COVER
raise ImportError("async rest transport requires aiohttp external package.")
if label:
return cls._transport_registry[label]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,35 @@
# limitations under the License.
#
from collections import OrderedDict
from typing import Dict, Type
from typing import Dict, Type, Tuple

from .base import CloudRedisTransport
from .grpc import CloudRedisGrpcTransport
from .grpc_asyncio import CloudRedisGrpcAsyncIOTransport
from .rest import CloudRedisRestTransport
from .rest import CloudRedisRestInterceptor
ASYNC_REST_CLASSES: Tuple[str, ...]
try:
from .rest_asyncio import AsyncCloudRedisRestTransport
ASYNC_REST_CLASSES = ('AsyncCloudRedisRestTransport',)
HAS_REST_ASYNC = True
except ImportError: # pragma: NO COVER
ASYNC_REST_CLASSES = ()
HAS_REST_ASYNC = False


# Compile a registry of transports.
_transport_registry = OrderedDict() # type: Dict[str, Type[CloudRedisTransport]]
_transport_registry['grpc'] = CloudRedisGrpcTransport
_transport_registry['grpc_asyncio'] = CloudRedisGrpcAsyncIOTransport
_transport_registry['rest'] = CloudRedisRestTransport
if HAS_REST_ASYNC: # pragma: NO COVER
_transport_registry['rest_asyncio'] = AsyncCloudRedisRestTransport

__all__ = (
'CloudRedisTransport',
'CloudRedisGrpcTransport',
'CloudRedisGrpcAsyncIOTransport',
'CloudRedisRestTransport',
'CloudRedisRestInterceptor',
)
) + ASYNC_REST_CLASSES
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
try:
import aiohttp # type: ignore
except ImportError as e: # pragma: NO COVER
raise ImportError("async rest transport requires aiohttp external package.") from e

import google.auth
try:
from google.auth.aio.transport.sessions import AsyncAuthorizedSession # type: ignore
except ImportError as e: # pragma: NO COVER
Expand Down Expand Up @@ -48,7 +54,7 @@
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version,
grpc_version=None,
rest_version=None,
rest_version=google.auth.__version__
)

@dataclasses.dataclass
Expand Down
Loading