diff --git a/.coveragerc b/.coveragerc index 10cb72e8..9a9b9f3e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,27 +1,11 @@ -# -*- 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 -# -# https://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. - -# Generated by synthtool. DO NOT EDIT! [run] branch = True [report] fail_under = 100 show_missing = True -omit = google/cloud/errorreporting/__init__.py, .nox/* +omit = + google/cloud/errorreporting/__init__.py exclude_lines = # Re-enable the standard pragma pragma: NO COVER @@ -31,4 +15,4 @@ exclude_lines = # 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 \ No newline at end of file + except pkg_resources.DistributionNotFound diff --git a/docs/errorreporting_v1beta1/error_group_service.rst b/docs/errorreporting_v1beta1/error_group_service.rst new file mode 100644 index 00000000..dd213525 --- /dev/null +++ b/docs/errorreporting_v1beta1/error_group_service.rst @@ -0,0 +1,6 @@ +ErrorGroupService +----------------------------------- + +.. automodule:: google.cloud.errorreporting_v1beta1.services.error_group_service + :members: + :inherited-members: diff --git a/docs/errorreporting_v1beta1/error_stats_service.rst b/docs/errorreporting_v1beta1/error_stats_service.rst new file mode 100644 index 00000000..30d29e69 --- /dev/null +++ b/docs/errorreporting_v1beta1/error_stats_service.rst @@ -0,0 +1,11 @@ +ErrorStatsService +----------------------------------- + +.. automodule:: google.cloud.errorreporting_v1beta1.services.error_stats_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.errorreporting_v1beta1.services.error_stats_service.pagers + :members: + :inherited-members: diff --git a/docs/errorreporting_v1beta1/report_errors_service.rst b/docs/errorreporting_v1beta1/report_errors_service.rst new file mode 100644 index 00000000..ccddb8b0 --- /dev/null +++ b/docs/errorreporting_v1beta1/report_errors_service.rst @@ -0,0 +1,6 @@ +ReportErrorsService +------------------------------------- + +.. automodule:: google.cloud.errorreporting_v1beta1.services.report_errors_service + :members: + :inherited-members: diff --git a/docs/errorreporting_v1beta1/services.rst b/docs/errorreporting_v1beta1/services.rst index a5ec3b92..e888027f 100644 --- a/docs/errorreporting_v1beta1/services.rst +++ b/docs/errorreporting_v1beta1/services.rst @@ -1,12 +1,8 @@ Services for Google Cloud Errorreporting v1beta1 API ==================================================== +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.errorreporting_v1beta1.services.error_group_service - :members: - :inherited-members: -.. automodule:: google.cloud.errorreporting_v1beta1.services.error_stats_service - :members: - :inherited-members: -.. automodule:: google.cloud.errorreporting_v1beta1.services.report_errors_service - :members: - :inherited-members: + error_group_service + error_stats_service + report_errors_service diff --git a/docs/errorreporting_v1beta1/types.rst b/docs/errorreporting_v1beta1/types.rst index 08851dbe..179256c7 100644 --- a/docs/errorreporting_v1beta1/types.rst +++ b/docs/errorreporting_v1beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Errorreporting v1beta1 API .. automodule:: google.cloud.errorreporting_v1beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/google/cloud/errorreporting_v1beta1/__init__.py b/google/cloud/errorreporting_v1beta1/__init__.py index 8db40bd7..8ced2656 100644 --- a/google/cloud/errorreporting_v1beta1/__init__.py +++ b/google/cloud/errorreporting_v1beta1/__init__.py @@ -22,6 +22,7 @@ from .types.common import ErrorEvent from .types.common import ErrorGroup from .types.common import HttpRequestContext +from .types.common import ResolutionStatus from .types.common import ServiceContext from .types.common import SourceLocation from .types.common import TrackingIssue @@ -51,6 +52,7 @@ "ErrorEvent", "ErrorGroup", "ErrorGroupOrder", + "ErrorGroupServiceClient", "ErrorGroupStats", "ErrorStatsServiceClient", "GetGroupRequest", @@ -62,8 +64,8 @@ "QueryTimeRange", "ReportErrorEventRequest", "ReportErrorEventResponse", - "ReportErrorsServiceClient", "ReportedErrorEvent", + "ResolutionStatus", "ServiceContext", "ServiceContextFilter", "SourceLocation", @@ -71,5 +73,5 @@ "TimedCountAlignment", "TrackingIssue", "UpdateGroupRequest", - "ErrorGroupServiceClient", + "ReportErrorsServiceClient", ) diff --git a/google/cloud/errorreporting_v1beta1/proto/common.proto b/google/cloud/errorreporting_v1beta1/proto/common.proto index 7a1d2003..e9bb321e 100644 --- a/google/cloud/errorreporting_v1beta1/proto/common.proto +++ b/google/cloud/errorreporting_v1beta1/proto/common.proto @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,9 +16,9 @@ syntax = "proto3"; package google.devtools.clouderrorreporting.v1beta1; -import "google/api/annotations.proto"; import "google/api/resource.proto"; import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; option cc_enable_arenas = true; option csharp_namespace = "Google.Cloud.ErrorReporting.V1Beta1"; @@ -37,7 +37,7 @@ message ErrorGroup { }; // The group resource name. - // Example: projects/my-project-123/groups/my-groupid + // Example: projects/my-project-123/groups/CNSgkpnppqKCUw string name = 1; // Group IDs are unique for a given project. If the same kind of error @@ -46,6 +46,10 @@ message ErrorGroup { // Associated tracking issues. repeated TrackingIssue tracking_issues = 3; + + // Error group's resolution status. + // An unspecified resolution status will be interpreted as OPEN + ResolutionStatus resolution_status = 5; } // Information related to tracking the progress on resolving the error. @@ -169,3 +173,24 @@ message SourceLocation { // For example, `my.package.MyClass.method` in case of Java. string function_name = 4; } + +// Resolution status of an error group. +enum ResolutionStatus { + // Status is unknown. When left unspecified in requests, it is treated like + // OPEN. + RESOLUTION_STATUS_UNSPECIFIED = 0; + + // The error group is not being addressed. This is the default for + // new groups. It is also used for errors re-occurring after marked RESOLVED. + OPEN = 1; + + // Error Group manually acknowledged, it can have an issue link attached. + ACKNOWLEDGED = 2; + + // Error Group manually resolved, more events for this group are not expected + // to occur. + RESOLVED = 3; + + // The error group is muted and excluded by default on group stats requests. + MUTED = 4; +} diff --git a/google/cloud/errorreporting_v1beta1/proto/error_group_service.proto b/google/cloud/errorreporting_v1beta1/proto/error_group_service.proto index 18182729..0104b62d 100644 --- a/google/cloud/errorreporting_v1beta1/proto/error_group_service.proto +++ b/google/cloud/errorreporting_v1beta1/proto/error_group_service.proto @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,7 +11,6 @@ // 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. -// syntax = "proto3"; @@ -58,7 +57,7 @@ service ErrorGroupService { // A request to return an individual group. message GetGroupRequest { - // The group resource name. Written as + // Required. The group resource name. Written as // `projects/{projectID}/groups/{group_name}`. Call // [`groupStats.list`](https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.groupStats/list) // to return a list of groups belonging to this project. diff --git a/google/cloud/errorreporting_v1beta1/proto/error_stats_service.proto b/google/cloud/errorreporting_v1beta1/proto/error_stats_service.proto index 0773f488..6c62edd9 100644 --- a/google/cloud/errorreporting_v1beta1/proto/error_stats_service.proto +++ b/google/cloud/errorreporting_v1beta1/proto/error_stats_service.proto @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,7 +11,6 @@ // 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. -// syntax = "proto3"; @@ -68,11 +67,11 @@ service ErrorStatsService { // Specifies a set of `ErrorGroupStats` to return. message ListGroupStatsRequest { // Required. The resource name of the Google Cloud Platform project. Written - // as projects/ plus the - // Google Cloud - // Platform project ID. + // as `projects/{projectID}` or `projects/{projectNumber}`, where `{projectID}` + // and `{projectNumber}` can be found in the + // [Google Cloud Console](https://support.google.com/cloud/answer/6158840). // - // Example: projects/my-project-123. + // Examples: `projects/my-project-123`, `projects/5551234`. string project_name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = { @@ -258,9 +257,10 @@ enum ErrorGroupOrder { // Specifies a set of error events to return. message ListEventsRequest { // Required. The resource name of the Google Cloud Platform project. Written - // as `projects/` plus the + // as `projects/{projectID}`, where `{projectID}` is the // [Google Cloud Platform project // ID](https://support.google.com/cloud/answer/6158840). + // // Example: `projects/my-project-123`. string project_name = 1 [ (google.api.field_behavior) = REQUIRED, @@ -357,9 +357,10 @@ message ServiceContextFilter { // Deletes all events in the project. message DeleteEventsRequest { // Required. The resource name of the Google Cloud Platform project. Written - // as `projects/` plus the + // as `projects/{projectID}`, where `{projectID}` is the // [Google Cloud Platform project // ID](https://support.google.com/cloud/answer/6158840). + // // Example: `projects/my-project-123`. string project_name = 1 [ (google.api.field_behavior) = REQUIRED, diff --git a/google/cloud/errorreporting_v1beta1/proto/report_errors_service.proto b/google/cloud/errorreporting_v1beta1/proto/report_errors_service.proto index f46f546d..cd1e5100 100644 --- a/google/cloud/errorreporting_v1beta1/proto/report_errors_service.proto +++ b/google/cloud/errorreporting_v1beta1/proto/report_errors_service.proto @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,7 +11,6 @@ // 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. -// syntax = "proto3"; @@ -38,7 +37,7 @@ service ReportErrorsService { option (google.api.default_host) = "clouderrorreporting.googleapis.com"; option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; - // Report an individual error event. + // Report an individual error event and record the event to a log. // // This endpoint accepts **either** an OAuth token, // **or** an [API key](https://support.google.com/cloud/answer/6158862) @@ -46,7 +45,15 @@ service ReportErrorsService { // a `key` parameter. For example: // // `POST - // https://clouderrorreporting.googleapis.com/v1beta1/projects/example-project/events:report?key=123ABC456` + // https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456` + // + // **Note:** [Error Reporting](/error-reporting) is a global service built + // on Cloud Logging and doesn't analyze logs stored + // in regional log buckets or logs routed to other Google Cloud projects. + // + // For more information, see + // [Using Error Reporting with regionalized + // logs](/error-reporting/docs/regionalization). rpc ReportErrorEvent(ReportErrorEventRequest) returns (ReportErrorEventResponse) { option (google.api.http) = { post: "/v1beta1/{project_name=projects/*}/events:report" @@ -59,10 +66,11 @@ service ReportErrorsService { // A request for reporting an individual error event. message ReportErrorEventRequest { // Required. The resource name of the Google Cloud Platform project. Written - // as `projects/` plus the + // as `projects/{projectId}`, where `{projectId}` is the // [Google Cloud Platform project - // ID](https://support.google.com/cloud/answer/6158840). Example: - // `projects/my-project-123`. + // ID](https://support.google.com/cloud/answer/6158840). + // + // Example: // `projects/my-project-123`. string project_name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = { diff --git a/google/cloud/errorreporting_v1beta1/services/error_group_service/async_client.py b/google/cloud/errorreporting_v1beta1/services/error_group_service/async_client.py index 26c03996..e2af4bb2 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_group_service/async_client.py +++ b/google/cloud/errorreporting_v1beta1/services/error_group_service/async_client.py @@ -78,7 +78,36 @@ class ErrorGroupServiceAsyncClient: ErrorGroupServiceClient.parse_common_location_path ) - from_service_account_file = ErrorGroupServiceClient.from_service_account_file + @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: + ErrorGroupServiceAsyncClient: The constructed client. + """ + return ErrorGroupServiceClient.from_service_account_info.__func__(ErrorGroupServiceAsyncClient, 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: + ErrorGroupServiceAsyncClient: The constructed client. + """ + return ErrorGroupServiceClient.from_service_account_file.__func__(ErrorGroupServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -154,16 +183,17 @@ async def get_group( r"""Get the specified group. Args: - request (:class:`~.error_group_service.GetGroupRequest`): + request (:class:`google.cloud.errorreporting_v1beta1.types.GetGroupRequest`): The request object. A request to return an individual group. group_name (:class:`str`): - The group resource name. Written as + Required. The group resource name. Written as ``projects/{projectID}/groups/{group_name}``. Call ```groupStats.list`` `__ to return a list of groups belonging to this project. Example: ``projects/my-project-123/groups/my-group`` + This corresponds to the ``group_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -175,7 +205,7 @@ async def get_group( sent along with the request as metadata. Returns: - ~.common.ErrorGroup: + google.cloud.errorreporting_v1beta1.types.ErrorGroup: Description of a group of similar error events. @@ -233,12 +263,13 @@ async def update_group( Fails if the group does not exist. Args: - request (:class:`~.error_group_service.UpdateGroupRequest`): + request (:class:`google.cloud.errorreporting_v1beta1.types.UpdateGroupRequest`): The request object. A request to replace the existing data for the given group. - group (:class:`~.common.ErrorGroup`): + group (:class:`google.cloud.errorreporting_v1beta1.types.ErrorGroup`): Required. The group which replaces the resource on the server. + This corresponds to the ``group`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -250,7 +281,7 @@ async def update_group( sent along with the request as metadata. Returns: - ~.common.ErrorGroup: + google.cloud.errorreporting_v1beta1.types.ErrorGroup: Description of a group of similar error events. diff --git a/google/cloud/errorreporting_v1beta1/services/error_group_service/client.py b/google/cloud/errorreporting_v1beta1/services/error_group_service/client.py index d1656df2..db374a93 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_group_service/client.py +++ b/google/cloud/errorreporting_v1beta1/services/error_group_service/client.py @@ -112,6 +112,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + ErrorGroupServiceClient: 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 @@ -124,7 +140,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + ErrorGroupServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -227,10 +243,10 @@ def __init__( 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, ~.ErrorGroupServiceTransport]): The + transport (Union[str, ErrorGroupServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -266,21 +282,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -323,7 +335,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -340,16 +352,17 @@ def get_group( r"""Get the specified group. Args: - request (:class:`~.error_group_service.GetGroupRequest`): + request (google.cloud.errorreporting_v1beta1.types.GetGroupRequest): The request object. A request to return an individual group. - group_name (:class:`str`): - The group resource name. Written as + group_name (str): + Required. The group resource name. Written as ``projects/{projectID}/groups/{group_name}``. Call ```groupStats.list`` `__ to return a list of groups belonging to this project. Example: ``projects/my-project-123/groups/my-group`` + This corresponds to the ``group_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -361,7 +374,7 @@ def get_group( sent along with the request as metadata. Returns: - ~.common.ErrorGroup: + google.cloud.errorreporting_v1beta1.types.ErrorGroup: Description of a group of similar error events. @@ -420,12 +433,13 @@ def update_group( Fails if the group does not exist. Args: - request (:class:`~.error_group_service.UpdateGroupRequest`): + request (google.cloud.errorreporting_v1beta1.types.UpdateGroupRequest): The request object. A request to replace the existing data for the given group. - group (:class:`~.common.ErrorGroup`): + group (google.cloud.errorreporting_v1beta1.types.ErrorGroup): Required. The group which replaces the resource on the server. + This corresponds to the ``group`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -437,7 +451,7 @@ def update_group( sent along with the request as metadata. Returns: - ~.common.ErrorGroup: + google.cloud.errorreporting_v1beta1.types.ErrorGroup: Description of a group of similar error events. diff --git a/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc.py b/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc.py index 102cdd39..b6a71e1f 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc.py +++ b/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc.py @@ -58,6 +58,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -88,6 +89,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -104,6 +109,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: # Sanity check: Ensure that channel and credentials are not both # provided. @@ -113,11 +123,6 @@ def __init__( self._grpc_channel = channel self._ssl_channel_credentials = None elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -161,12 +166,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + # create a new channel. The provided one is ignored. self._grpc_channel = type(self).create_channel( host, credentials=credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc_asyncio.py b/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc_asyncio.py index f6ed3855..6fd73663 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc_asyncio.py +++ b/google/cloud/errorreporting_v1beta1/services/error_group_service/transports/grpc_asyncio.py @@ -102,6 +102,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -133,6 +134,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -149,6 +154,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: # Sanity check: Ensure that channel and credentials are not both # provided. @@ -158,11 +168,6 @@ def __init__( self._grpc_channel = channel self._ssl_channel_credentials = None elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -206,12 +211,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + # create a new channel. The provided one is ignored. self._grpc_channel = type(self).create_channel( host, credentials=credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/errorreporting_v1beta1/services/error_stats_service/async_client.py b/google/cloud/errorreporting_v1beta1/services/error_stats_service/async_client.py index 20e91256..ca116141 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_stats_service/async_client.py +++ b/google/cloud/errorreporting_v1beta1/services/error_stats_service/async_client.py @@ -81,7 +81,36 @@ class ErrorStatsServiceAsyncClient: ErrorStatsServiceClient.parse_common_location_path ) - from_service_account_file = ErrorStatsServiceClient.from_service_account_file + @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: + ErrorStatsServiceAsyncClient: The constructed client. + """ + return ErrorStatsServiceClient.from_service_account_info.__func__(ErrorStatsServiceAsyncClient, 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: + ErrorStatsServiceAsyncClient: The constructed client. + """ + return ErrorStatsServiceClient.from_service_account_file.__func__(ErrorStatsServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -158,22 +187,23 @@ async def list_group_stats( r"""Lists the specified groups. Args: - request (:class:`~.error_stats_service.ListGroupStatsRequest`): + request (:class:`google.cloud.errorreporting_v1beta1.types.ListGroupStatsRequest`): The request object. Specifies a set of `ErrorGroupStats` to return. project_name (:class:`str`): - Required. The resource name of the - Google Cloud Platform project. Written - as projects/ plus the Google - Cloud Platform project ID. - - Example: projects/my- - project-123. + Required. The resource name of the Google Cloud Platform + project. Written as ``projects/{projectID}`` or + ``projects/{projectNumber}``, where ``{projectID}`` and + ``{projectNumber}`` can be found in the `Google Cloud + Console `__. + + Examples: ``projects/my-project-123``, + ``projects/5551234``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - time_range (:class:`~.error_stats_service.QueryTimeRange`): + time_range (:class:`google.cloud.errorreporting_v1beta1.types.QueryTimeRange`): Optional. List data for the given time range. If not set, a default time range is used. The field time_range_begin in the response will specify the @@ -182,6 +212,7 @@ async def list_group_stats( unless the request contains an explicit group_id list. If a group_id list is given, also ErrorGroupStats with zero occurrences are returned. + This corresponds to the ``time_range`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -193,7 +224,7 @@ async def list_group_stats( sent along with the request as metadata. Returns: - ~.pagers.ListGroupStatsAsyncPager: + google.cloud.errorreporting_v1beta1.services.error_stats_service.pagers.ListGroupStatsAsyncPager: Contains a set of requested error group stats. Iterating over this object will yield @@ -262,21 +293,24 @@ async def list_events( r"""Lists the specified events. Args: - request (:class:`~.error_stats_service.ListEventsRequest`): + request (:class:`google.cloud.errorreporting_v1beta1.types.ListEventsRequest`): The request object. Specifies a set of error events to return. project_name (:class:`str`): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectID}``, where + ``{projectID}`` is the `Google Cloud Platform project ID `__. + Example: ``projects/my-project-123``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. group_id (:class:`str`): Required. The group for which events shall be returned. + This corresponds to the ``group_id`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -288,7 +322,7 @@ async def list_events( sent along with the request as metadata. Returns: - ~.pagers.ListEventsAsyncPager: + google.cloud.errorreporting_v1beta1.services.error_stats_service.pagers.ListEventsAsyncPager: Contains a set of requested error events. Iterating over this object will yield @@ -356,14 +390,16 @@ async def delete_events( r"""Deletes all error events of a given project. Args: - request (:class:`~.error_stats_service.DeleteEventsRequest`): + request (:class:`google.cloud.errorreporting_v1beta1.types.DeleteEventsRequest`): The request object. Deletes all events in the project. project_name (:class:`str`): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectID}``, where + ``{projectID}`` is the `Google Cloud Platform project ID `__. + Example: ``projects/my-project-123``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -375,7 +411,7 @@ async def delete_events( sent along with the request as metadata. Returns: - ~.error_stats_service.DeleteEventsResponse: + google.cloud.errorreporting_v1beta1.types.DeleteEventsResponse: Response message for deleting error events. diff --git a/google/cloud/errorreporting_v1beta1/services/error_stats_service/client.py b/google/cloud/errorreporting_v1beta1/services/error_stats_service/client.py index f04fbfef..7178412c 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_stats_service/client.py +++ b/google/cloud/errorreporting_v1beta1/services/error_stats_service/client.py @@ -115,6 +115,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + ErrorStatsServiceClient: 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 @@ -127,7 +143,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + ErrorStatsServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -230,10 +246,10 @@ def __init__( 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, ~.ErrorStatsServiceTransport]): The + transport (Union[str, ErrorStatsServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -269,21 +285,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -326,7 +338,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -344,22 +356,23 @@ def list_group_stats( r"""Lists the specified groups. Args: - request (:class:`~.error_stats_service.ListGroupStatsRequest`): + request (google.cloud.errorreporting_v1beta1.types.ListGroupStatsRequest): The request object. Specifies a set of `ErrorGroupStats` to return. - project_name (:class:`str`): - Required. The resource name of the - Google Cloud Platform project. Written - as projects/ plus the Google - Cloud Platform project ID. - - Example: projects/my- - project-123. + project_name (str): + Required. The resource name of the Google Cloud Platform + project. Written as ``projects/{projectID}`` or + ``projects/{projectNumber}``, where ``{projectID}`` and + ``{projectNumber}`` can be found in the `Google Cloud + Console `__. + + Examples: ``projects/my-project-123``, + ``projects/5551234``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - time_range (:class:`~.error_stats_service.QueryTimeRange`): + time_range (google.cloud.errorreporting_v1beta1.types.QueryTimeRange): Optional. List data for the given time range. If not set, a default time range is used. The field time_range_begin in the response will specify the @@ -368,6 +381,7 @@ def list_group_stats( unless the request contains an explicit group_id list. If a group_id list is given, also ErrorGroupStats with zero occurrences are returned. + This corresponds to the ``time_range`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -379,7 +393,7 @@ def list_group_stats( sent along with the request as metadata. Returns: - ~.pagers.ListGroupStatsPager: + google.cloud.errorreporting_v1beta1.services.error_stats_service.pagers.ListGroupStatsPager: Contains a set of requested error group stats. Iterating over this object will yield @@ -449,21 +463,24 @@ def list_events( r"""Lists the specified events. Args: - request (:class:`~.error_stats_service.ListEventsRequest`): + request (google.cloud.errorreporting_v1beta1.types.ListEventsRequest): The request object. Specifies a set of error events to return. - project_name (:class:`str`): + project_name (str): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectID}``, where + ``{projectID}`` is the `Google Cloud Platform project ID `__. + Example: ``projects/my-project-123``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - group_id (:class:`str`): + group_id (str): Required. The group for which events shall be returned. + This corresponds to the ``group_id`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -475,7 +492,7 @@ def list_events( sent along with the request as metadata. Returns: - ~.pagers.ListEventsPager: + google.cloud.errorreporting_v1beta1.services.error_stats_service.pagers.ListEventsPager: Contains a set of requested error events. Iterating over this object will yield @@ -544,14 +561,16 @@ def delete_events( r"""Deletes all error events of a given project. Args: - request (:class:`~.error_stats_service.DeleteEventsRequest`): + request (google.cloud.errorreporting_v1beta1.types.DeleteEventsRequest): The request object. Deletes all events in the project. - project_name (:class:`str`): + project_name (str): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectID}``, where + ``{projectID}`` is the `Google Cloud Platform project ID `__. + Example: ``projects/my-project-123``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -563,7 +582,7 @@ def delete_events( sent along with the request as metadata. Returns: - ~.error_stats_service.DeleteEventsResponse: + google.cloud.errorreporting_v1beta1.types.DeleteEventsResponse: Response message for deleting error events. diff --git a/google/cloud/errorreporting_v1beta1/services/error_stats_service/pagers.py b/google/cloud/errorreporting_v1beta1/services/error_stats_service/pagers.py index 02a4faa4..a5d6c02f 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_stats_service/pagers.py +++ b/google/cloud/errorreporting_v1beta1/services/error_stats_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.errorreporting_v1beta1.types import common from google.cloud.errorreporting_v1beta1.types import error_stats_service @@ -25,7 +34,7 @@ class ListGroupStatsPager: """A pager for iterating through ``list_group_stats`` requests. This class thinly wraps an initial - :class:`~.error_stats_service.ListGroupStatsResponse` object, and + :class:`google.cloud.errorreporting_v1beta1.types.ListGroupStatsResponse` object, and provides an ``__iter__`` method to iterate through its ``error_group_stats`` field. @@ -34,7 +43,7 @@ class ListGroupStatsPager: through the ``error_group_stats`` field on the corresponding responses. - All the usual :class:`~.error_stats_service.ListGroupStatsResponse` + All the usual :class:`google.cloud.errorreporting_v1beta1.types.ListGroupStatsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.error_stats_service.ListGroupStatsRequest`): + request (google.cloud.errorreporting_v1beta1.types.ListGroupStatsRequest): The initial request object. - response (:class:`~.error_stats_service.ListGroupStatsResponse`): + response (google.cloud.errorreporting_v1beta1.types.ListGroupStatsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListGroupStatsAsyncPager: """A pager for iterating through ``list_group_stats`` requests. This class thinly wraps an initial - :class:`~.error_stats_service.ListGroupStatsResponse` object, and + :class:`google.cloud.errorreporting_v1beta1.types.ListGroupStatsResponse` object, and provides an ``__aiter__`` method to iterate through its ``error_group_stats`` field. @@ -96,7 +105,7 @@ class ListGroupStatsAsyncPager: through the ``error_group_stats`` field on the corresponding responses. - All the usual :class:`~.error_stats_service.ListGroupStatsResponse` + All the usual :class:`google.cloud.errorreporting_v1beta1.types.ListGroupStatsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.error_stats_service.ListGroupStatsRequest`): + request (google.cloud.errorreporting_v1beta1.types.ListGroupStatsRequest): The initial request object. - response (:class:`~.error_stats_service.ListGroupStatsResponse`): + response (google.cloud.errorreporting_v1beta1.types.ListGroupStatsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -153,7 +162,7 @@ class ListEventsPager: """A pager for iterating through ``list_events`` requests. This class thinly wraps an initial - :class:`~.error_stats_service.ListEventsResponse` object, and + :class:`google.cloud.errorreporting_v1beta1.types.ListEventsResponse` object, and provides an ``__iter__`` method to iterate through its ``error_events`` field. @@ -162,7 +171,7 @@ class ListEventsPager: through the ``error_events`` field on the corresponding responses. - All the usual :class:`~.error_stats_service.ListEventsResponse` + All the usual :class:`google.cloud.errorreporting_v1beta1.types.ListEventsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -180,9 +189,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.error_stats_service.ListEventsRequest`): + request (google.cloud.errorreporting_v1beta1.types.ListEventsRequest): The initial request object. - response (:class:`~.error_stats_service.ListEventsResponse`): + response (google.cloud.errorreporting_v1beta1.types.ListEventsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -215,7 +224,7 @@ class ListEventsAsyncPager: """A pager for iterating through ``list_events`` requests. This class thinly wraps an initial - :class:`~.error_stats_service.ListEventsResponse` object, and + :class:`google.cloud.errorreporting_v1beta1.types.ListEventsResponse` object, and provides an ``__aiter__`` method to iterate through its ``error_events`` field. @@ -224,7 +233,7 @@ class ListEventsAsyncPager: through the ``error_events`` field on the corresponding responses. - All the usual :class:`~.error_stats_service.ListEventsResponse` + All the usual :class:`google.cloud.errorreporting_v1beta1.types.ListEventsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -242,9 +251,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.error_stats_service.ListEventsRequest`): + request (google.cloud.errorreporting_v1beta1.types.ListEventsRequest): The initial request object. - response (:class:`~.error_stats_service.ListEventsResponse`): + response (google.cloud.errorreporting_v1beta1.types.ListEventsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc.py b/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc.py index f9595d23..6a5328c5 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc.py +++ b/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc.py @@ -58,6 +58,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -88,6 +89,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -104,6 +109,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: # Sanity check: Ensure that channel and credentials are not both # provided. @@ -113,11 +123,6 @@ def __init__( self._grpc_channel = channel self._ssl_channel_credentials = None elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -161,12 +166,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + # create a new channel. The provided one is ignored. self._grpc_channel = type(self).create_channel( host, credentials=credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc_asyncio.py b/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc_asyncio.py index 4c687c11..336e180a 100644 --- a/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc_asyncio.py +++ b/google/cloud/errorreporting_v1beta1/services/error_stats_service/transports/grpc_asyncio.py @@ -102,6 +102,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -133,6 +134,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -149,6 +154,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: # Sanity check: Ensure that channel and credentials are not both # provided. @@ -158,11 +168,6 @@ def __init__( self._grpc_channel = channel self._ssl_channel_credentials = None elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -206,12 +211,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + # create a new channel. The provided one is ignored. self._grpc_channel = type(self).create_channel( host, credentials=credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/errorreporting_v1beta1/services/report_errors_service/async_client.py b/google/cloud/errorreporting_v1beta1/services/report_errors_service/async_client.py index 3b7c6fcf..61f223b6 100644 --- a/google/cloud/errorreporting_v1beta1/services/report_errors_service/async_client.py +++ b/google/cloud/errorreporting_v1beta1/services/report_errors_service/async_client.py @@ -72,7 +72,36 @@ class ReportErrorsServiceAsyncClient: ReportErrorsServiceClient.parse_common_location_path ) - from_service_account_file = ReportErrorsServiceClient.from_service_account_file + @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: + ReportErrorsServiceAsyncClient: The constructed client. + """ + return ReportErrorsServiceClient.from_service_account_info.__func__(ReportErrorsServiceAsyncClient, 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: + ReportErrorsServiceAsyncClient: The constructed client. + """ + return ReportErrorsServiceClient.from_service_account_file.__func__(ReportErrorsServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -147,31 +176,42 @@ async def report_error_event( timeout: float = None, metadata: Sequence[Tuple[str, str]] = (), ) -> report_errors_service.ReportErrorEventResponse: - r"""Report an individual error event. + r"""Report an individual error event and record the event to a log. This endpoint accepts **either** an OAuth token, **or** an `API key `__ for authentication. To use an API key, append it to the URL as the value of a ``key`` parameter. For example: - ``POST https://clouderrorreporting.googleapis.com/v1beta1/projects/example-project/events:report?key=123ABC456`` + ``POST https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456`` + + **Note:** `Error Reporting `__ is a global + service built on Cloud Logging and doesn't analyze logs stored + in regional log buckets or logs routed to other Google Cloud + projects. + + For more information, see `Using Error Reporting with + regionalized logs `__. Args: - request (:class:`~.report_errors_service.ReportErrorEventRequest`): + request (:class:`google.cloud.errorreporting_v1beta1.types.ReportErrorEventRequest`): The request object. A request for reporting an individual error event. project_name (:class:`str`): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectId}``, where + ``{projectId}`` is the `Google Cloud Platform project ID `__. - Example: ``projects/my-project-123``. + + Example: // ``projects/my-project-123``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - event (:class:`~.report_errors_service.ReportedErrorEvent`): + event (:class:`google.cloud.errorreporting_v1beta1.types.ReportedErrorEvent`): Required. The error event to be reported. + This corresponds to the ``event`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -183,7 +223,7 @@ async def report_error_event( sent along with the request as metadata. Returns: - ~.report_errors_service.ReportErrorEventResponse: + google.cloud.errorreporting_v1beta1.types.ReportErrorEventResponse: Response for reporting an individual error event. Data may be added to this message in the future. diff --git a/google/cloud/errorreporting_v1beta1/services/report_errors_service/client.py b/google/cloud/errorreporting_v1beta1/services/report_errors_service/client.py index b10ecca4..840e449f 100644 --- a/google/cloud/errorreporting_v1beta1/services/report_errors_service/client.py +++ b/google/cloud/errorreporting_v1beta1/services/report_errors_service/client.py @@ -111,6 +111,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + ReportErrorsServiceClient: 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 @@ -123,7 +139,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + ReportErrorsServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -215,10 +231,10 @@ def __init__( 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, ~.ReportErrorsServiceTransport]): The + transport (Union[str, ReportErrorsServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -254,21 +270,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -311,7 +323,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -326,31 +338,42 @@ def report_error_event( timeout: float = None, metadata: Sequence[Tuple[str, str]] = (), ) -> report_errors_service.ReportErrorEventResponse: - r"""Report an individual error event. + r"""Report an individual error event and record the event to a log. This endpoint accepts **either** an OAuth token, **or** an `API key `__ for authentication. To use an API key, append it to the URL as the value of a ``key`` parameter. For example: - ``POST https://clouderrorreporting.googleapis.com/v1beta1/projects/example-project/events:report?key=123ABC456`` + ``POST https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456`` + + **Note:** `Error Reporting `__ is a global + service built on Cloud Logging and doesn't analyze logs stored + in regional log buckets or logs routed to other Google Cloud + projects. + + For more information, see `Using Error Reporting with + regionalized logs `__. Args: - request (:class:`~.report_errors_service.ReportErrorEventRequest`): + request (google.cloud.errorreporting_v1beta1.types.ReportErrorEventRequest): The request object. A request for reporting an individual error event. - project_name (:class:`str`): + project_name (str): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectId}``, where + ``{projectId}`` is the `Google Cloud Platform project ID `__. - Example: ``projects/my-project-123``. + + Example: // ``projects/my-project-123``. + This corresponds to the ``project_name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - event (:class:`~.report_errors_service.ReportedErrorEvent`): + event (google.cloud.errorreporting_v1beta1.types.ReportedErrorEvent): Required. The error event to be reported. + This corresponds to the ``event`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -362,7 +385,7 @@ def report_error_event( sent along with the request as metadata. Returns: - ~.report_errors_service.ReportErrorEventResponse: + google.cloud.errorreporting_v1beta1.types.ReportErrorEventResponse: Response for reporting an individual error event. Data may be added to this message in the future. diff --git a/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc.py b/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc.py index f2c84d92..f7eea171 100644 --- a/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc.py +++ b/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc.py @@ -57,6 +57,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -87,6 +88,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -103,6 +108,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: # Sanity check: Ensure that channel and credentials are not both # provided. @@ -112,11 +122,6 @@ def __init__( self._grpc_channel = channel self._ssl_channel_credentials = None elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -160,12 +165,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + # create a new channel. The provided one is ignored. self._grpc_channel = type(self).create_channel( host, credentials=credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -246,14 +257,22 @@ def report_error_event( ]: r"""Return a callable for the report error event method over gRPC. - Report an individual error event. + Report an individual error event and record the event to a log. This endpoint accepts **either** an OAuth token, **or** an `API key `__ for authentication. To use an API key, append it to the URL as the value of a ``key`` parameter. For example: - ``POST https://clouderrorreporting.googleapis.com/v1beta1/projects/example-project/events:report?key=123ABC456`` + ``POST https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456`` + + **Note:** `Error Reporting `__ is a global + service built on Cloud Logging and doesn't analyze logs stored + in regional log buckets or logs routed to other Google Cloud + projects. + + For more information, see `Using Error Reporting with + regionalized logs `__. Returns: Callable[[~.ReportErrorEventRequest], diff --git a/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc_asyncio.py b/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc_asyncio.py index 39465e57..80327fd8 100644 --- a/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc_asyncio.py +++ b/google/cloud/errorreporting_v1beta1/services/report_errors_service/transports/grpc_asyncio.py @@ -101,6 +101,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -132,6 +133,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -148,6 +153,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + if channel: # Sanity check: Ensure that channel and credentials are not both # provided. @@ -157,11 +167,6 @@ def __init__( self._grpc_channel = channel self._ssl_channel_credentials = None elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -205,12 +210,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + # create a new channel. The provided one is ignored. self._grpc_channel = type(self).create_channel( host, credentials=credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -250,14 +261,22 @@ def report_error_event( ]: r"""Return a callable for the report error event method over gRPC. - Report an individual error event. + Report an individual error event and record the event to a log. This endpoint accepts **either** an OAuth token, **or** an `API key `__ for authentication. To use an API key, append it to the URL as the value of a ``key`` parameter. For example: - ``POST https://clouderrorreporting.googleapis.com/v1beta1/projects/example-project/events:report?key=123ABC456`` + ``POST https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456`` + + **Note:** `Error Reporting `__ is a global + service built on Cloud Logging and doesn't analyze logs stored + in regional log buckets or logs routed to other Google Cloud + projects. + + For more information, see `Using Error Reporting with + regionalized logs `__. Returns: Callable[[~.ReportErrorEventRequest], diff --git a/google/cloud/errorreporting_v1beta1/types/__init__.py b/google/cloud/errorreporting_v1beta1/types/__init__.py index fc7243be..8819a78f 100644 --- a/google/cloud/errorreporting_v1beta1/types/__init__.py +++ b/google/cloud/errorreporting_v1beta1/types/__init__.py @@ -23,6 +23,7 @@ ErrorContext, HttpRequestContext, SourceLocation, + ResolutionStatus, ) from .error_group_service import ( GetGroupRequest, @@ -56,6 +57,7 @@ "ErrorContext", "HttpRequestContext", "SourceLocation", + "ResolutionStatus", "GetGroupRequest", "UpdateGroupRequest", "ListGroupStatsRequest", diff --git a/google/cloud/errorreporting_v1beta1/types/common.py b/google/cloud/errorreporting_v1beta1/types/common.py index 779aa453..e0d1a7eb 100644 --- a/google/cloud/errorreporting_v1beta1/types/common.py +++ b/google/cloud/errorreporting_v1beta1/types/common.py @@ -24,6 +24,7 @@ __protobuf__ = proto.module( package="google.devtools.clouderrorreporting.v1beta1", manifest={ + "ResolutionStatus", "ErrorGroup", "TrackingIssue", "ErrorEvent", @@ -35,6 +36,15 @@ ) +class ResolutionStatus(proto.Enum): + r"""Resolution status of an error group.""" + RESOLUTION_STATUS_UNSPECIFIED = 0 + OPEN = 1 + ACKNOWLEDGED = 2 + RESOLVED = 3 + MUTED = 4 + + class ErrorGroup(proto.Message): r"""Description of a group of similar error events. @@ -42,14 +52,18 @@ class ErrorGroup(proto.Message): name (str): The group resource name. Example: projects/my- - project-123/groups/my-groupid + project-123/groups/CNSgkpnppqKCUw group_id (str): Group IDs are unique for a given project. If the same kind of error occurs in different service contexts, it will receive the same group ID. - tracking_issues (Sequence[~.common.TrackingIssue]): + tracking_issues (Sequence[google.cloud.errorreporting_v1beta1.types.TrackingIssue]): Associated tracking issues. + resolution_status (google.cloud.errorreporting_v1beta1.types.ResolutionStatus): + Error group's resolution status. + An unspecified resolution status will be + interpreted as OPEN """ name = proto.Field(proto.STRING, number=1) @@ -60,6 +74,8 @@ class ErrorGroup(proto.Message): proto.MESSAGE, number=3, message="TrackingIssue", ) + resolution_status = proto.Field(proto.ENUM, number=5, enum="ResolutionStatus",) + class TrackingIssue(proto.Message): r"""Information related to tracking the progress on resolving the @@ -80,17 +96,17 @@ class ErrorEvent(proto.Message): system. Attributes: - event_time (~.timestamp.Timestamp): + event_time (google.protobuf.timestamp_pb2.Timestamp): Time when the event occurred as provided in the error report. If the report did not contain a timestamp, the time the error was received by the Error Reporting system is used. - service_context (~.common.ServiceContext): + service_context (google.cloud.errorreporting_v1beta1.types.ServiceContext): The ``ServiceContext`` for which this error was reported. message (str): The stack trace that was reported or logged by the service. - context (~.common.ErrorContext): + context (google.cloud.errorreporting_v1beta1.types.ErrorContext): Data about the context in which the error occurred. """ @@ -149,7 +165,7 @@ class ErrorContext(proto.Message): Engine logs. Attributes: - http_request (~.common.HttpRequestContext): + http_request (google.cloud.errorreporting_v1beta1.types.HttpRequestContext): The HTTP request which was processed when the error was triggered. user (str): @@ -160,7 +176,7 @@ class ErrorContext(proto.Message): this case the Error Reporting system will use other data, such as remote IP address, to distinguish affected users. See ``affected_users_count`` in ``ErrorGroupStats``. - report_location (~.common.SourceLocation): + report_location (google.cloud.errorreporting_v1beta1.types.SourceLocation): The location in the source code where the decision was made to report the error, usually the place where it was logged. For a logged diff --git a/google/cloud/errorreporting_v1beta1/types/error_group_service.py b/google/cloud/errorreporting_v1beta1/types/error_group_service.py index 70aa92a8..e36854b6 100644 --- a/google/cloud/errorreporting_v1beta1/types/error_group_service.py +++ b/google/cloud/errorreporting_v1beta1/types/error_group_service.py @@ -32,7 +32,7 @@ class GetGroupRequest(proto.Message): Attributes: group_name (str): - The group resource name. Written as + Required. The group resource name. Written as ``projects/{projectID}/groups/{group_name}``. Call ```groupStats.list`` `__ to return a list of groups belonging to this project. @@ -47,7 +47,7 @@ class UpdateGroupRequest(proto.Message): r"""A request to replace the existing data for the given group. Attributes: - group (~.common.ErrorGroup): + group (google.cloud.errorreporting_v1beta1.types.ErrorGroup): Required. The group which replaces the resource on the server. """ diff --git a/google/cloud/errorreporting_v1beta1/types/error_stats_service.py b/google/cloud/errorreporting_v1beta1/types/error_stats_service.py index 51a14e89..3973ca04 100644 --- a/google/cloud/errorreporting_v1beta1/types/error_stats_service.py +++ b/google/cloud/errorreporting_v1beta1/types/error_stats_service.py @@ -65,23 +65,23 @@ class ListGroupStatsRequest(proto.Message): Attributes: project_name (str): - Required. The resource name of the Google - Cloud Platform project. Written as - projects/ plus the Google - Cloud Platform project ID. + Required. The resource name of the Google Cloud Platform + project. Written as ``projects/{projectID}`` or + ``projects/{projectNumber}``, where ``{projectID}`` and + ``{projectNumber}`` can be found in the `Google Cloud + Console `__. - Example: projects/my-project-123. + Examples: ``projects/my-project-123``, ``projects/5551234``. group_id (Sequence[str]): Optional. List all ErrorGroupStats with these IDs. - service_filter (~.error_stats_service.ServiceContextFilter): + service_filter (google.cloud.errorreporting_v1beta1.types.ServiceContextFilter): Optional. List only ErrorGroupStats which belong to a service context that matches the filter. Data for all service contexts is returned if this field is not specified. - time_range (~.error_stats_service.QueryTimeRange): + time_range (google.cloud.errorreporting_v1beta1.types.QueryTimeRange): Optional. List data for the given time range. If not set, a default time range is used. The field time_range_begin in the response will specify the beginning of this time range. @@ -89,17 +89,17 @@ class ListGroupStatsRequest(proto.Message): range are returned, unless the request contains an explicit group_id list. If a group_id list is given, also ErrorGroupStats with zero occurrences are returned. - timed_count_duration (~.duration.Duration): + timed_count_duration (google.protobuf.duration_pb2.Duration): Optional. The preferred duration for a single returned ``TimedCount``. If not set, no timed counts are returned. - alignment (~.error_stats_service.TimedCountAlignment): + alignment (google.cloud.errorreporting_v1beta1.types.TimedCountAlignment): Optional. The alignment of the timed counts to be returned. Default is ``ALIGNMENT_EQUAL_AT_END``. - alignment_time (~.timestamp.Timestamp): + alignment_time (google.protobuf.timestamp_pb2.Timestamp): Optional. Time where the timed counts shall be aligned if rounded alignment is chosen. Default is 00:00 UTC. - order (~.error_stats_service.ErrorGroupOrder): + order (google.cloud.errorreporting_v1beta1.types.ErrorGroupOrder): Optional. The sort order in which the results are returned. Default is ``COUNT_DESC``. page_size (int): @@ -140,7 +140,7 @@ class ListGroupStatsResponse(proto.Message): r"""Contains a set of requested error group stats. Attributes: - error_group_stats (Sequence[~.error_stats_service.ErrorGroupStats]): + error_group_stats (Sequence[google.cloud.errorreporting_v1beta1.types.ErrorGroupStats]): The error group stats which match the given request. next_page_token (str): @@ -148,7 +148,7 @@ class ListGroupStatsResponse(proto.Message): Pass this token, along with the same query parameters as the first request, to view the next page of results. - time_range_begin (~.timestamp.Timestamp): + time_range_begin (google.protobuf.timestamp_pb2.Timestamp): The timestamp specifies the start time to which the request was restricted. The start time is set based on the requested time range. It may @@ -177,7 +177,7 @@ class ErrorGroupStats(proto.Message): criteria, such as a given time period and/or service filter. Attributes: - group (~.common.ErrorGroup): + group (google.cloud.errorreporting_v1beta1.types.ErrorGroup): Group data that is independent of the filter criteria. count (int): @@ -195,22 +195,22 @@ class ErrorGroupStats(proto.Message): provided in the error report. If more users are implicitly affected, such as due to a crash of the whole service, this is not reflected here. - timed_counts (Sequence[~.error_stats_service.TimedCount]): + timed_counts (Sequence[google.cloud.errorreporting_v1beta1.types.TimedCount]): Approximate number of occurrences over time. Timed counts returned by ListGroups are guaranteed to be: - Inside the requested time interval - Non-overlapping, and - Ordered by ascending time. - first_seen_time (~.timestamp.Timestamp): + first_seen_time (google.protobuf.timestamp_pb2.Timestamp): Approximate first occurrence that was ever seen for this group and which matches the given filter criteria, ignoring the time_range that was specified in the request. - last_seen_time (~.timestamp.Timestamp): + last_seen_time (google.protobuf.timestamp_pb2.Timestamp): Approximate last occurrence that was ever seen for this group and which matches the given filter criteria, ignoring the time_range that was specified in the request. - affected_services (Sequence[~.common.ServiceContext]): + affected_services (Sequence[google.cloud.errorreporting_v1beta1.types.ServiceContext]): Service contexts with a non-zero error count for the given filter criteria. This list can be truncated if multiple services are affected. Refer to ``num_affected_services`` @@ -218,7 +218,7 @@ class ErrorGroupStats(proto.Message): num_affected_services (int): The total number of services with a non-zero error count for the given filter criteria. - representative (~.common.ErrorEvent): + representative (google.cloud.errorreporting_v1beta1.types.ErrorEvent): An arbitrary event that is chosen as representative for the whole group. The representative event is intended to be used as a @@ -259,10 +259,10 @@ class TimedCount(proto.Message): count (int): Approximate number of occurrences in the given time period. - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Start of the time period to which ``count`` refers (included). - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End of the time period to which ``count`` refers (excluded). """ @@ -279,19 +279,20 @@ class ListEventsRequest(proto.Message): Attributes: project_name (str): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectID}``, where + ``{projectID}`` is the `Google Cloud Platform project ID `__. + Example: ``projects/my-project-123``. group_id (str): Required. The group for which events shall be returned. - service_filter (~.error_stats_service.ServiceContextFilter): + service_filter (google.cloud.errorreporting_v1beta1.types.ServiceContextFilter): Optional. List only ErrorGroups which belong to a service context that matches the filter. Data for all service contexts is returned if this field is not specified. - time_range (~.error_stats_service.QueryTimeRange): + time_range (google.cloud.errorreporting_v1beta1.types.QueryTimeRange): Optional. List only data for the given time range. If not set a default time range is used. The field time_range_begin in the response will specify the beginning of this time @@ -323,7 +324,7 @@ class ListEventsResponse(proto.Message): r"""Contains a set of requested error events. Attributes: - error_events (Sequence[~.common.ErrorEvent]): + error_events (Sequence[google.cloud.errorreporting_v1beta1.types.ErrorEvent]): The error events which match the given request. next_page_token (str): @@ -331,7 +332,7 @@ class ListEventsResponse(proto.Message): Pass this token, along with the same query parameters as the first request, to view the next page of results. - time_range_begin (~.timestamp.Timestamp): + time_range_begin (google.protobuf.timestamp_pb2.Timestamp): The timestamp specifies the start time to which the request was restricted. """ @@ -356,7 +357,7 @@ class QueryTimeRange(proto.Message): durations might be adjusted for lower durations. Attributes: - period (~.error_stats_service.QueryTimeRange.Period): + period (google.cloud.errorreporting_v1beta1.types.QueryTimeRange.Period): Restricts the query to the specified time range. """ @@ -404,9 +405,10 @@ class DeleteEventsRequest(proto.Message): Attributes: project_name (str): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectID}``, where + ``{projectID}`` is the `Google Cloud Platform project ID `__. + Example: ``projects/my-project-123``. """ diff --git a/google/cloud/errorreporting_v1beta1/types/report_errors_service.py b/google/cloud/errorreporting_v1beta1/types/report_errors_service.py index 1a66727b..bdba6ee8 100644 --- a/google/cloud/errorreporting_v1beta1/types/report_errors_service.py +++ b/google/cloud/errorreporting_v1beta1/types/report_errors_service.py @@ -38,11 +38,12 @@ class ReportErrorEventRequest(proto.Message): Attributes: project_name (str): Required. The resource name of the Google Cloud Platform - project. Written as ``projects/`` plus the `Google Cloud - Platform project + project. Written as ``projects/{projectId}``, where + ``{projectId}`` is the `Google Cloud Platform project ID `__. - Example: ``projects/my-project-123``. - event (~.report_errors_service.ReportedErrorEvent): + + Example: // ``projects/my-project-123``. + event (google.cloud.errorreporting_v1beta1.types.ReportedErrorEvent): Required. The error event to be reported. """ @@ -62,12 +63,12 @@ class ReportedErrorEvent(proto.Message): system. Attributes: - event_time (~.timestamp.Timestamp): + event_time (google.protobuf.timestamp_pb2.Timestamp): Optional. Time when the event occurred. If not provided, the time when the event was received by the Error Reporting system will be used. - service_context (~.common.ServiceContext): + service_context (google.cloud.errorreporting_v1beta1.types.ServiceContext): Required. The service context in which this error has occurred. message (str): @@ -96,7 +97,7 @@ class ReportedErrorEvent(proto.Message): ```(string)$exception`` `__. - **Go**: Must be the return value of ```runtime.Stack()`` `__. - context (~.common.ErrorContext): + context (google.cloud.errorreporting_v1beta1.types.ErrorContext): Optional. A description of the context in which the error occurred. """ diff --git a/synth.metadata b/synth.metadata index f49b243b..377f5974 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,15 +4,15 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-error-reporting.git", - "sha": "eaf4a5aebe9f3cee0af211defec7ff10d5bae4a4" + "sha": "c4b168d1f4e045d72487abba88e118a15b1c99ef" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "dd372aa22ded7a8ba6f0e03a80e06358a3fa0907", - "internalRef": "347055288" + "sha": "f6dd7e47620566925a4b3f1ce029e74e1b2f2516", + "internalRef": "359781040" } }, { @@ -42,6 +42,7 @@ } ], "generatedFiles": [ + ".coveragerc", ".flake8", ".github/CONTRIBUTING.md", ".github/ISSUE_TEMPLATE/bug_report.md", @@ -95,6 +96,9 @@ "docs/_static/custom.css", "docs/_templates/layout.html", "docs/conf.py", + "docs/errorreporting_v1beta1/error_group_service.rst", + "docs/errorreporting_v1beta1/error_stats_service.rst", + "docs/errorreporting_v1beta1/report_errors_service.rst", "docs/errorreporting_v1beta1/services.rst", "docs/errorreporting_v1beta1/types.rst", "docs/multiprocessing.rst", diff --git a/tests/unit/gapic/errorreporting_v1beta1/__init__.py b/tests/unit/gapic/errorreporting_v1beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/errorreporting_v1beta1/__init__.py +++ b/tests/unit/gapic/errorreporting_v1beta1/__init__.py @@ -1 +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/tests/unit/gapic/errorreporting_v1beta1/test_error_group_service.py b/tests/unit/gapic/errorreporting_v1beta1/test_error_group_service.py index da93c3df..814cefe8 100644 --- a/tests/unit/gapic/errorreporting_v1beta1/test_error_group_service.py +++ b/tests/unit/gapic/errorreporting_v1beta1/test_error_group_service.py @@ -90,7 +90,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [ErrorGroupServiceClient, ErrorGroupServiceAsyncClient] + "client_class", [ErrorGroupServiceClient, ErrorGroupServiceAsyncClient,] +) +def test_error_group_service_client_from_service_account_info(client_class): + creds = 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 == "clouderrorreporting.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [ErrorGroupServiceClient, ErrorGroupServiceAsyncClient,] ) def test_error_group_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -100,16 +117,21 @@ def test_error_group_service_client_from_service_account_file(client_class): 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 == "clouderrorreporting.googleapis.com:443" def test_error_group_service_client_get_transport_class(): transport = ErrorGroupServiceClient.get_transport_class() - assert transport == transports.ErrorGroupServiceGrpcTransport + available_transports = [ + transports.ErrorGroupServiceGrpcTransport, + ] + assert transport in available_transports transport = ErrorGroupServiceClient.get_transport_class("grpc") assert transport == transports.ErrorGroupServiceGrpcTransport @@ -160,7 +182,7 @@ def test_error_group_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -176,7 +198,7 @@ def test_error_group_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -192,7 +214,7 @@ def test_error_group_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -220,7 +242,7 @@ def test_error_group_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -281,29 +303,25 @@ def test_error_group_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -312,66 +330,53 @@ def test_error_group_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -397,7 +402,7 @@ def test_error_group_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -427,7 +432,7 @@ def test_error_group_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -446,7 +451,7 @@ def test_error_group_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -467,7 +472,9 @@ def test_get_group( with mock.patch.object(type(client.transport.get_group), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = common.ErrorGroup( - name="name_value", group_id="group_id_value", + name="name_value", + group_id="group_id_value", + resolution_status=common.ResolutionStatus.OPEN, ) response = client.get_group(request) @@ -486,11 +493,29 @@ def test_get_group( assert response.group_id == "group_id_value" + assert response.resolution_status == common.ResolutionStatus.OPEN + def test_get_group_from_dict(): test_get_group(request_type=dict) +def test_get_group_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 = ErrorGroupServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_group), "__call__") as call: + client.get_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == error_group_service.GetGroupRequest() + + @pytest.mark.asyncio async def test_get_group_async( transport: str = "grpc_asyncio", request_type=error_group_service.GetGroupRequest @@ -507,7 +532,11 @@ async def test_get_group_async( with mock.patch.object(type(client.transport.get_group), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - common.ErrorGroup(name="name_value", group_id="group_id_value",) + common.ErrorGroup( + name="name_value", + group_id="group_id_value", + resolution_status=common.ResolutionStatus.OPEN, + ) ) response = await client.get_group(request) @@ -525,6 +554,8 @@ async def test_get_group_async( assert response.group_id == "group_id_value" + assert response.resolution_status == common.ResolutionStatus.OPEN + @pytest.mark.asyncio async def test_get_group_async_from_dict(): @@ -666,7 +697,9 @@ def test_update_group( with mock.patch.object(type(client.transport.update_group), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = common.ErrorGroup( - name="name_value", group_id="group_id_value", + name="name_value", + group_id="group_id_value", + resolution_status=common.ResolutionStatus.OPEN, ) response = client.update_group(request) @@ -685,11 +718,29 @@ def test_update_group( assert response.group_id == "group_id_value" + assert response.resolution_status == common.ResolutionStatus.OPEN + def test_update_group_from_dict(): test_update_group(request_type=dict) +def test_update_group_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 = ErrorGroupServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_group), "__call__") as call: + client.update_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == error_group_service.UpdateGroupRequest() + + @pytest.mark.asyncio async def test_update_group_async( transport: str = "grpc_asyncio", request_type=error_group_service.UpdateGroupRequest @@ -706,7 +757,11 @@ async def test_update_group_async( with mock.patch.object(type(client.transport.update_group), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - common.ErrorGroup(name="name_value", group_id="group_id_value",) + common.ErrorGroup( + name="name_value", + group_id="group_id_value", + resolution_status=common.ResolutionStatus.OPEN, + ) ) response = await client.update_group(request) @@ -724,6 +779,8 @@ async def test_update_group_async( assert response.group_id == "group_id_value" + assert response.resolution_status == common.ResolutionStatus.OPEN + @pytest.mark.asyncio async def test_update_group_async_from_dict(): @@ -1014,6 +1071,53 @@ def test_error_group_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.ErrorGroupServiceGrpcTransport, + transports.ErrorGroupServiceGrpcAsyncIOTransport, + ], +) +def test_error_group_service_grpc_transport_client_cert_source_for_mtls( + transport_class, +): + cred = credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + 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_error_group_service_host_no_port(): client = ErrorGroupServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1035,7 +1139,7 @@ def test_error_group_service_host_with_port(): def test_error_group_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.ErrorGroupServiceGrpcTransport( @@ -1047,7 +1151,7 @@ def test_error_group_service_grpc_transport_channel(): def test_error_group_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.ErrorGroupServiceGrpcAsyncIOTransport( @@ -1058,6 +1162,8 @@ def test_error_group_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -1072,7 +1178,7 @@ def test_error_group_service_transport_channel_mtls_with_client_cert_source( "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -1110,6 +1216,8 @@ def test_error_group_service_transport_channel_mtls_with_client_cert_source( 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", [ @@ -1125,7 +1233,7 @@ def test_error_group_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/errorreporting_v1beta1/test_error_stats_service.py b/tests/unit/gapic/errorreporting_v1beta1/test_error_stats_service.py index 2ea69420..1966becb 100644 --- a/tests/unit/gapic/errorreporting_v1beta1/test_error_stats_service.py +++ b/tests/unit/gapic/errorreporting_v1beta1/test_error_stats_service.py @@ -93,7 +93,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [ErrorStatsServiceClient, ErrorStatsServiceAsyncClient] + "client_class", [ErrorStatsServiceClient, ErrorStatsServiceAsyncClient,] +) +def test_error_stats_service_client_from_service_account_info(client_class): + creds = 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 == "clouderrorreporting.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [ErrorStatsServiceClient, ErrorStatsServiceAsyncClient,] ) def test_error_stats_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -103,16 +120,21 @@ def test_error_stats_service_client_from_service_account_file(client_class): 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 == "clouderrorreporting.googleapis.com:443" def test_error_stats_service_client_get_transport_class(): transport = ErrorStatsServiceClient.get_transport_class() - assert transport == transports.ErrorStatsServiceGrpcTransport + available_transports = [ + transports.ErrorStatsServiceGrpcTransport, + ] + assert transport in available_transports transport = ErrorStatsServiceClient.get_transport_class("grpc") assert transport == transports.ErrorStatsServiceGrpcTransport @@ -163,7 +185,7 @@ def test_error_stats_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -179,7 +201,7 @@ def test_error_stats_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -195,7 +217,7 @@ def test_error_stats_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -223,7 +245,7 @@ def test_error_stats_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -284,29 +306,25 @@ def test_error_stats_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -315,66 +333,53 @@ def test_error_stats_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -400,7 +405,7 @@ def test_error_stats_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -430,7 +435,7 @@ def test_error_stats_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -449,7 +454,7 @@ def test_error_stats_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -492,6 +497,22 @@ def test_list_group_stats_from_dict(): test_list_group_stats(request_type=dict) +def test_list_group_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 = ErrorStatsServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_group_stats), "__call__") as call: + client.list_group_stats() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == error_stats_service.ListGroupStatsRequest() + + @pytest.mark.asyncio async def test_list_group_stats_async( transport: str = "grpc_asyncio", @@ -888,6 +909,22 @@ def test_list_events_from_dict(): test_list_events(request_type=dict) +def test_list_events_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 = ErrorStatsServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_events), "__call__") as call: + client.list_events() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == error_stats_service.ListEventsRequest() + + @pytest.mark.asyncio async def test_list_events_async( transport: str = "grpc_asyncio", request_type=error_stats_service.ListEventsRequest @@ -1247,6 +1284,22 @@ def test_delete_events_from_dict(): test_delete_events(request_type=dict) +def test_delete_events_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 = ErrorStatsServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_events), "__call__") as call: + client.delete_events() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == error_stats_service.DeleteEventsRequest() + + @pytest.mark.asyncio async def test_delete_events_async( transport: str = "grpc_asyncio", @@ -1575,6 +1628,53 @@ def test_error_stats_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.ErrorStatsServiceGrpcTransport, + transports.ErrorStatsServiceGrpcAsyncIOTransport, + ], +) +def test_error_stats_service_grpc_transport_client_cert_source_for_mtls( + transport_class, +): + cred = credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + 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_error_stats_service_host_no_port(): client = ErrorStatsServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1596,7 +1696,7 @@ def test_error_stats_service_host_with_port(): def test_error_stats_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.ErrorStatsServiceGrpcTransport( @@ -1608,7 +1708,7 @@ def test_error_stats_service_grpc_transport_channel(): def test_error_stats_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.ErrorStatsServiceGrpcAsyncIOTransport( @@ -1619,6 +1719,8 @@ def test_error_stats_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -1633,7 +1735,7 @@ def test_error_stats_service_transport_channel_mtls_with_client_cert_source( "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -1671,6 +1773,8 @@ def test_error_stats_service_transport_channel_mtls_with_client_cert_source( 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", [ @@ -1686,7 +1790,7 @@ def test_error_stats_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/errorreporting_v1beta1/test_report_errors_service.py b/tests/unit/gapic/errorreporting_v1beta1/test_report_errors_service.py index f84d267f..98a83947 100644 --- a/tests/unit/gapic/errorreporting_v1beta1/test_report_errors_service.py +++ b/tests/unit/gapic/errorreporting_v1beta1/test_report_errors_service.py @@ -93,7 +93,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [ReportErrorsServiceClient, ReportErrorsServiceAsyncClient] + "client_class", [ReportErrorsServiceClient, ReportErrorsServiceAsyncClient,] +) +def test_report_errors_service_client_from_service_account_info(client_class): + creds = 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 == "clouderrorreporting.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [ReportErrorsServiceClient, ReportErrorsServiceAsyncClient,] ) def test_report_errors_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -103,16 +120,21 @@ def test_report_errors_service_client_from_service_account_file(client_class): 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 == "clouderrorreporting.googleapis.com:443" def test_report_errors_service_client_get_transport_class(): transport = ReportErrorsServiceClient.get_transport_class() - assert transport == transports.ReportErrorsServiceGrpcTransport + available_transports = [ + transports.ReportErrorsServiceGrpcTransport, + ] + assert transport in available_transports transport = ReportErrorsServiceClient.get_transport_class("grpc") assert transport == transports.ReportErrorsServiceGrpcTransport @@ -167,7 +189,7 @@ def test_report_errors_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -183,7 +205,7 @@ def test_report_errors_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -199,7 +221,7 @@ def test_report_errors_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -227,7 +249,7 @@ def test_report_errors_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -288,29 +310,25 @@ def test_report_errors_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -319,66 +337,53 @@ def test_report_errors_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -408,7 +413,7 @@ def test_report_errors_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -442,7 +447,7 @@ def test_report_errors_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -461,7 +466,7 @@ def test_report_errors_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -502,6 +507,24 @@ def test_report_error_event_from_dict(): test_report_error_event(request_type=dict) +def test_report_error_event_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 = ReportErrorsServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.report_error_event), "__call__" + ) as call: + client.report_error_event() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == report_errors_service.ReportErrorEventRequest() + + @pytest.mark.asyncio async def test_report_error_event_async( transport: str = "grpc_asyncio", @@ -860,6 +883,53 @@ def test_report_errors_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.ReportErrorsServiceGrpcTransport, + transports.ReportErrorsServiceGrpcAsyncIOTransport, + ], +) +def test_report_errors_service_grpc_transport_client_cert_source_for_mtls( + transport_class, +): + cred = credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + 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_report_errors_service_host_no_port(): client = ReportErrorsServiceClient( credentials=credentials.AnonymousCredentials(), @@ -881,7 +951,7 @@ def test_report_errors_service_host_with_port(): def test_report_errors_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.ReportErrorsServiceGrpcTransport( @@ -893,7 +963,7 @@ def test_report_errors_service_grpc_transport_channel(): def test_report_errors_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.ReportErrorsServiceGrpcAsyncIOTransport( @@ -904,6 +974,8 @@ def test_report_errors_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -918,7 +990,7 @@ def test_report_errors_service_transport_channel_mtls_with_client_cert_source( "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -956,6 +1028,8 @@ def test_report_errors_service_transport_channel_mtls_with_client_cert_source( 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", [ @@ -971,7 +1045,7 @@ def test_report_errors_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel