Skip to content

Commit

Permalink
Add 'client_info' support to Client. (#7903)
Browse files Browse the repository at this point in the history
  • Loading branch information
tseaver committed May 8, 2019
1 parent d613b57 commit a9bcc27
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 49 deletions.
11 changes: 3 additions & 8 deletions error_reporting/google/cloud/error_reporting/_gapic.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,10 @@

"""GAX wrapper for Error Reporting API requests."""

from google.api_core.gapic_v1 import client_info

from google.cloud.error_reporting import __version__
from google.cloud.errorreporting_v1beta1.gapic import report_errors_service_client
from google.cloud.errorreporting_v1beta1.proto import report_errors_service_pb2
from google.protobuf.json_format import ParseDict

_CLIENT_INFO = client_info.ClientInfo(client_library_version=__version__)


def make_report_error_api(client):
"""Create an instance of the gapic Logging API.
Expand All @@ -33,10 +28,10 @@ def make_report_error_api(client):
:rtype: :class:_ErrorReportingGapicApi
:returns: An Error Reporting API instance.
"""
gax_client = report_errors_service_client.ReportErrorsServiceClient(
credentials=client._credentials, client_info=_CLIENT_INFO
gapic_api = report_errors_service_client.ReportErrorsServiceClient(
credentials=client._credentials, client_info=client._client_info
)
return _ErrorReportingGapicApi(gax_client, client.project)
return _ErrorReportingGapicApi(gapic_api, client.project)


class _ErrorReportingGapicApi(object):
Expand Down
13 changes: 11 additions & 2 deletions error_reporting/google/cloud/error_reporting/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,20 @@ class _ErrorReportingLoggingAPI(object):
``credentials`` for the current object.
This parameter should be considered private, and could
change in the future.
:type client_info:
:class:`google.api_core.client_info.ClientInfo` or
:class:`google.api_core.gapic_v1.client_info.ClientInfo`
:param client_info:
The client info used to send a user-agent string along with API
requests. If ``None``, then default info will be used. Generally,
you only need to set this if you're developing your own library
or partner tool.
"""

def __init__(self, project, credentials=None, _http=None):
def __init__(self, project, credentials=None, _http=None, client_info=None):
self.logging_client = google.cloud.logging.client.Client(
project, credentials, _http=_http
project, credentials, _http=_http, client_info=client_info
)

def report_error_event(self, error_report):
Expand Down
28 changes: 23 additions & 5 deletions error_reporting/google/cloud/error_reporting/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,27 @@
import os
import traceback

import six

try:
from google.cloud.error_reporting._gapic import make_report_error_api

_HAVE_GRPC = True
except ImportError: # pragma: NO COVER
from google.api_core import ciient_info # noqa

_HAVE_GRPC = False
else:
from google.api_core.gapic_v1 import client_info

_HAVE_GRPC = True

from google.cloud.client import ClientWithProject
from google.cloud.error_reporting import __version__
from google.cloud.error_reporting._logging import _ErrorReportingLoggingAPI
from google.cloud.environment_vars import DISABLE_GRPC

import six

_DISABLE_GRPC = os.getenv(DISABLE_GRPC, False)
_USE_GRPC = _HAVE_GRPC and not _DISABLE_GRPC
_CLIENT_INFO = client_info.ClientInfo(client_library_version=__version__)


class HTTPContext(object):
Expand Down Expand Up @@ -128,6 +134,15 @@ class Client(ClientWithProject):
This parameter should be considered private, and could
change in the future.
:type client_info:
:class:`google.api_core.client_info.ClientInfo` or
:class:`google.api_core.gapic_v1.client_info.ClientInfo`
:param client_info:
The client info used to send a user-agent string along with API
requests. If ``None``, then default info will be used. Generally,
you only need to set this if you're developing your own library
or partner tool.
:raises: :class:`ValueError` if the project is neither passed in nor
set in the environment.
"""
Expand All @@ -142,6 +157,7 @@ def __init__(
_http=None,
service=None,
version=None,
client_info=_CLIENT_INFO,
_use_grpc=None,
):
super(Client, self).__init__(
Expand All @@ -151,6 +167,8 @@ def __init__(

self.service = service if service else self.DEFAULT_SERVICE
self.version = version
self._client_info = client_info

if _use_grpc is None:
self._use_grpc = _USE_GRPC
else:
Expand All @@ -177,7 +195,7 @@ def report_errors_api(self):
self._report_errors_api = make_report_error_api(self)
else:
self._report_errors_api = _ErrorReportingLoggingAPI(
self.project, self._credentials, self._http
self.project, self._credentials, self._http, self._client_info
)
return self._report_errors_api

Expand Down
38 changes: 16 additions & 22 deletions error_reporting/tests/unit/test__gapic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,31 @@


class Test_make_report_error_api(unittest.TestCase):
def test_make_report_error_api(self):
from google.cloud.errorreporting_v1beta1.gapic import (
report_errors_service_client,
)

@staticmethod
def _call_fut(client):
from google.cloud.error_reporting._gapic import make_report_error_api

client = mock.Mock(
_credentials=mock.sentinel.credentials,
project="prahj-ekt",
spec=["project", "_credentials"],
)
return make_report_error_api(client)

# Mock out the constructor for the GAPIC client.
ServiceClient = report_errors_service_client.ReportErrorsServiceClient
with mock.patch.object(ServiceClient, "__init__") as resc:
resc.return_value = None
def test_make_report_error_api(self):
client = mock.Mock(spec=["project", "_credentials", "_client_info"])

# Call the function being tested.
report_error_client = make_report_error_api(client)
# Call the function being tested.
patch = mock.patch(
"google.cloud.errorreporting_v1beta1."
"gapic.report_errors_service_client.ReportErrorsServiceClient"
)

# Assert that the arguments to the GAPIC constructor appear
# to be correct.
resc.assert_called_once()
_, _, kwargs = resc.mock_calls[0]
self.assertEqual(kwargs["credentials"], mock.sentinel.credentials)
self.assertIsNotNone(kwargs["client_info"])
with patch as patched:
report_error_client = self._call_fut(client)

# Assert that the final error client has the project in
# the expected location.
self.assertIs(report_error_client._project, client.project)
self.assertIs(report_error_client._gapic_api, patched.return_value)
patched.assert_called_once_with(
credentials=client._credentials, client_info=client._client_info
)


class Test_ErrorReportingGapicApi(unittest.TestCase):
Expand Down
31 changes: 23 additions & 8 deletions error_reporting/tests/unit/test__logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,41 @@ class Test_ErrorReportingLoggingAPI(unittest.TestCase):

PROJECT = "PROJECT"

def _make_one(self, project, credentials):
def _make_one(self, project, credentials, **kw):
from google.cloud.error_reporting._logging import _ErrorReportingLoggingAPI

return _ErrorReportingLoggingAPI(project, credentials)
return _ErrorReportingLoggingAPI(project, credentials, **kw)

def test_constructor(self):
@mock.patch("google.cloud.logging.client.Client")
def test_ctor_defaults(self, mocked_cls):
credentials = _make_credentials()

logging_api = self._make_one(self.PROJECT, credentials)

self.assertEqual(
logging_api.logging_client._connection.credentials, credentials
self.assertIs(logging_api.logging_client, mocked_cls.return_value)
mocked_cls.assert_called_once_with(
self.PROJECT, credentials, _http=None, client_info=None
)

@mock.patch("google.cloud.logging.client.Client")
def test_ctor_explicit(self, mocked_cls):
credentials = _make_credentials()
http = mock.Mock()
client_info = mock.Mock()

logging_api = self._make_one(
self.PROJECT, credentials, _http=http, client_info=client_info
)

self.assertIs(logging_api.logging_client, mocked_cls.return_value)
mocked_cls.assert_called_once_with(
self.PROJECT, credentials, _http=http, client_info=client_info
)
self.assertEqual(logging_api.logging_client.project, self.PROJECT)

@mock.patch("google.cloud.logging.client.Client")
def test_report_error_event(self, mocked_cls):
credentials = _make_credentials()
logging_api = self._make_one(self.PROJECT, credentials)
mocked_cls.assert_called_once_with(self.PROJECT, credentials, _http=None)
self.assertIs(logging_api.logging_client, mocked_cls.return_value)

logger = mock.Mock(spec=["log_struct"])
logging_api.logging_client.logger.return_value = logger
Expand Down
54 changes: 50 additions & 4 deletions error_reporting/tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,26 +53,72 @@ def _get_report_payload(self, error_api):
return positional[0]

@mock.patch("google.cloud.client._determine_default_project")
def test_ctor_default(self, default_mock):
def test_ctor_defaults(self, default_mock):
from google.api_core.client_info import ClientInfo

credentials = _make_credentials()
default_mock.return_value = "foo"
client = self._make_one(credentials=credentials)
self.assertEqual(client.service, client.DEFAULT_SERVICE)
self.assertEqual(client.version, None)
self.assertIsInstance(client._client_info, ClientInfo)
default_mock.assert_called_once_with(None)

def test_ctor_params(self):
def test_ctor_explicit(self):
credentials = _make_credentials()
client_info = mock.Mock()
client = self._make_one(
project=self.PROJECT,
credentials=credentials,
service=self.SERVICE,
version=self.VERSION,
client_info=client_info,
)
self.assertEqual(client.service, self.SERVICE)
self.assertEqual(client.version, self.VERSION)
self.assertIs(client._client_info, client_info)

def test_report_errors_api_already(self):
credentials = _make_credentials()
client = self._make_one(project=self.PROJECT, credentials=credentials)
client._report_errors_api = already = mock.Mock()
self.assertIs(client.report_errors_api, already)

def test_report_errors_api_wo_grpc(self):
credentials = _make_credentials()
client_info = mock.Mock()
http = mock.Mock()
client = self._make_one(
project=self.PROJECT,
credentials=credentials,
client_info=client_info,
_http=http,
_use_grpc=False,
)
patch = mock.patch(
"google.cloud.error_reporting.client._ErrorReportingLoggingAPI"
)

with patch as patched:
api = client.report_errors_api

self.assertIs(api, patched.return_value)
patched.assert_called_once_with(self.PROJECT, credentials, http, client_info)

def test_report_errors_api_w_grpc(self):
credentials = _make_credentials()
client = self._make_one(
project=self.PROJECT, credentials=credentials, _use_grpc=True
)
patch = mock.patch("google.cloud.error_reporting.client.make_report_error_api")

with patch as patched:
api = client.report_errors_api

self.assertIs(api, patched.return_value)
patched.assert_called_once_with(client)

def test_report_exception_with_gax(self):
def test_report_exception_with_grpc(self):
credentials = _make_credentials()
client = self._make_one(project=self.PROJECT, credentials=credentials)

Expand All @@ -89,7 +135,7 @@ def test_report_exception_with_gax(self):
self.assertIn("test_report", payload["message"])
self.assertIn("test_client.py", payload["message"])

def test_report_exception_wo_gax(self):
def test_report_exception_wo_grpc(self):
credentials = _make_credentials()
client = self._make_one(
project=self.PROJECT, credentials=credentials, _use_grpc=False
Expand Down

0 comments on commit a9bcc27

Please sign in to comment.