diff --git a/trace/google/cloud/trace/_gapic.py b/trace/google/cloud/trace/_gapic.py index dbcbecabdf43..435d9fcc6c17 100644 --- a/trace/google/cloud/trace/_gapic.py +++ b/trace/google/cloud/trace/_gapic.py @@ -14,10 +14,8 @@ """Wrapper for interacting with the Stackdriver Trace API.""" -from google.api_core.gapic_v1 import client_info from google.api_core.gapic_v1 import method from google.cloud._helpers import _datetime_to_pb_timestamp -from google.cloud.trace import __version__ from google.cloud.trace_v2.gapic import trace_service_client from google.cloud.trace_v2.proto import trace_pb2 from google.protobuf.json_format import ParseDict @@ -25,9 +23,6 @@ from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -_CLIENT_INFO = client_info.ClientInfo(client_library_version=__version__) - - class _TraceAPI(object): """ Wrapper to help mapping trace-related APIs. @@ -319,6 +314,6 @@ def make_trace_api(client): proper configurations. """ generated = trace_service_client.TraceServiceClient( - credentials=client._credentials, client_info=_CLIENT_INFO + credentials=client._credentials, client_info=client._client_info ) return _TraceAPI(generated, client) diff --git a/trace/google/cloud/trace/client.py b/trace/google/cloud/trace/client.py index 577f79be098e..c4c9d5dd6840 100644 --- a/trace/google/cloud/trace/client.py +++ b/trace/google/cloud/trace/client.py @@ -14,8 +14,13 @@ """Client for interacting with the Stackdriver Trace API.""" -from google.cloud.trace._gapic import make_trace_api +from google.api_core.gapic_v1 import client_info from google.cloud.client import ClientWithProject +from google.cloud.trace import __version__ +from google.cloud.trace._gapic import make_trace_api + + +_CLIENT_INFO = client_info.ClientInfo(client_library_version=__version__) class Client(ClientWithProject): @@ -29,6 +34,11 @@ class Client(ClientWithProject): credentials (Optional[:class:`~google.auth.credentials.Credentials`]): The OAuth2 Credentials to use for this client. If not passed, falls back to the default inferred from the environment. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with API + requests. If ``None``, then default info will be used. Generally, + you only need to set this if you're developing your own library + or partner tool. """ SCOPE = ( @@ -39,8 +49,9 @@ class Client(ClientWithProject): _trace_api = None - def __init__(self, project=None, credentials=None): + def __init__(self, project=None, credentials=None, client_info=_CLIENT_INFO): super(Client, self).__init__(project=project, credentials=credentials) + self._client_info = client_info @property def trace_api(self): diff --git a/trace/google/cloud/trace/v1/_gapic.py b/trace/google/cloud/trace/v1/_gapic.py index 3289b95a5d6a..365f535eba5c 100644 --- a/trace/google/cloud/trace/v1/_gapic.py +++ b/trace/google/cloud/trace/v1/_gapic.py @@ -178,7 +178,7 @@ def make_trace_api(client): proper configurations. """ generated = trace_service_client.TraceServiceClient( - credentials=client._credentials, client_info=_CLIENT_INFO + credentials=client._credentials, client_info=client._client_info ) return _TraceAPI(generated, client) diff --git a/trace/google/cloud/trace/v1/client.py b/trace/google/cloud/trace/v1/client.py index 806ff7b8351c..266158933294 100644 --- a/trace/google/cloud/trace/v1/client.py +++ b/trace/google/cloud/trace/v1/client.py @@ -14,9 +14,14 @@ """Client for interacting with the Stackdriver Trace API.""" -from google.cloud.trace.v1._gapic import make_trace_api -from google.cloud.client import ClientWithProject +from google.api_core.gapic_v1 import client_info from google.cloud._helpers import _datetime_to_pb_timestamp +from google.cloud.client import ClientWithProject +from google.cloud.trace import __version__ +from google.cloud.trace.v1._gapic import make_trace_api + + +_CLIENT_INFO = client_info.ClientInfo(client_library_version=__version__) class Client(ClientWithProject): @@ -27,11 +32,15 @@ class Client(ClientWithProject): project (str): Required. The project which the client acts on behalf of. If not passed, falls back to the default inferred from the environment. - credentials (Optional[~google.auth.credentials.Credentials]): The OAuth2 Credentials to use for this client. If not passed, falls back to the default inferred from the environment. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with API + requests. If ``None``, then default info will be used. Generally, + you only need to set this if you're developing your own library + or partner tool. """ SCOPE = ( @@ -42,8 +51,9 @@ class Client(ClientWithProject): _trace_api = None - def __init__(self, project=None, credentials=None): + def __init__(self, project=None, credentials=None, client_info=_CLIENT_INFO): super(Client, self).__init__(project=project, credentials=credentials) + self._client_info = client_info @property def trace_api(self): diff --git a/trace/tests/unit/v1/test__gapic_v1.py b/trace/tests/unit/v1/test__gapic_v1.py index 76fdd9593b88..bd21f026d056 100644 --- a/trace/tests/unit/v1/test__gapic_v1.py +++ b/trace/tests/unit/v1/test__gapic_v1.py @@ -17,52 +17,43 @@ import mock -from google.api_core import grpc_helpers - -class _Base(object): +class Test__TraceAPI(unittest.TestCase): project = "PROJECT" + @staticmethod + def _get_target_class(): + from google.cloud.trace.v1._gapic import _TraceAPI + + return _TraceAPI + def _make_one(self, gapic_client=None, handwritten_client=None): from google.cloud.trace_v1.gapic import trace_service_client - channel = grpc_helpers.ChannelStub() if gapic_client is None: - gapic_client = trace_service_client.TraceServiceClient(channel=channel) + gapic_client = mock.create_autospec(trace_service_client.TraceServiceClient) if handwritten_client is None: handwritten_client = mock.Mock() api = self._get_target_class()(gapic_client, handwritten_client) - return channel, api - - -class Test__TraceAPI(_Base, unittest.TestCase): - @staticmethod - def _get_target_class(): - from google.cloud.trace.v1._gapic import _TraceAPI - - return _TraceAPI + return api def test_constructor(self): from google.cloud.trace_v1.gapic import trace_service_client - channel = grpc_helpers.ChannelStub() - gapic_client = trace_service_client.TraceServiceClient(channel=channel) - _, api = self._make_one(gapic_client, mock.sentinel.client) + gapic_client = mock.create_autospec(trace_service_client.TraceServiceClient) + api = self._make_one(gapic_client, mock.sentinel.client) self.assertIs(api._gapic_api, gapic_client) self.assertIs(api.client, mock.sentinel.client) def test_patch_traces(self): from google.cloud.trace_v1.gapic import trace_service_client - from google.cloud.trace_v1.proto.trace_pb2 import TraceSpan, Trace, Traces from google.cloud.trace.v1._gapic import _traces_mapping_to_pb - from google.cloud._helpers import _datetime_to_pb_timestamp trace_id = "test_trace_id" span_id = 1234 span_name = "test_span_name" start_time = datetime.datetime.utcnow() end_time = datetime.datetime.utcnow() - traces = { "traces": [ { @@ -79,220 +70,145 @@ def test_patch_traces(self): } ] } - traces_pb = _traces_mapping_to_pb(traces) + gapic_api = mock.create_autospec(trace_service_client.TraceServiceClient) + api = self._make_one(gapic_api, None) - gapic_api = mock.Mock(spec=trace_service_client.TraceServiceClient) - _, api = self._make_one(gapic_api, None) api.patch_traces(project_id=self.project, traces=traces) - gapic_api.patch_traces.assert_called_with(self.project, traces_pb) - - call_args = gapic_api.patch_traces.call_args[0] - self.assertEqual(len(call_args), 2) - traces_called = call_args[1] - self.assertEqual(len(traces_called.traces), 1) - trace = traces_called.traces[0] - - self.assertEqual(len(trace.spans), 1) - span = trace.spans[0] - - self.assertIsInstance(traces_called, Traces) - self.assertEqual(trace.project_id, self.project) - self.assertEqual(trace.trace_id, trace_id) - self.assertIsInstance(trace, Trace) - - self.assertEqual(span.span_id, span_id) - self.assertEqual(span.name, span_name) - self.assertEqual(span.start_time, _datetime_to_pb_timestamp(start_time)) - self.assertEqual(span.end_time, _datetime_to_pb_timestamp(end_time)) - self.assertIsInstance(span, TraceSpan) + gapic_api.patch_traces.assert_called_once_with(self.project, traces_pb) def test_get_trace(self): from google.cloud.trace_v1.gapic import trace_service_client + from google.cloud.trace_v1.proto.trace_pb2 import Trace trace_id = "test_trace_id" + trace_pb = Trace(project_id=self.project, trace_id=trace_id) - gapic_api = mock.Mock(spec=trace_service_client.TraceServiceClient) - _, api = self._make_one(gapic_api, None) - patch = mock.patch( - "google.cloud.trace.v1._gapic._parse_trace_pb", - return_value="fake_pb_result", - ) - - with patch: - api.get_trace(project_id=self.project, trace_id=trace_id) - - gapic_api.get_trace.assert_called_with(self.project, trace_id) + gapic_api = mock.create_autospec(trace_service_client.TraceServiceClient) + gapic_api.get_trace.return_value = trace_pb + api = self._make_one(gapic_api, None) - def _make_trace_pb( - self, - project, - trace_id, - span_id, - span_name, - start_time, - end_time, - parent_span_id, - labels, - ): - from google.cloud.trace.v1._gapic import _traces_mapping_to_pb + trace = api.get_trace(project_id=self.project, trace_id=trace_id) - span_kind = 2 + expected_trace = {"projectId": self.project, "traceId": trace_id} + self.assertEqual(trace, expected_trace) - traces = { - "traces": [ - { - "projectId": project, - "traceId": trace_id, - "spans": [ - { - "spanId": span_id, - "name": span_name, - "startTime": start_time, - "endTime": end_time, - "kind": span_kind, - "parentSpanId": parent_span_id, - "labels": labels, - } - ], - } - ] - } - - traces_pb = _traces_mapping_to_pb(traces) - trace_pb = traces_pb.traces - return trace_pb + gapic_api.get_trace.assert_called_with(self.project, trace_id) def test_list_traces(self): - from google.cloud._helpers import _rfc3339_to_datetime - from google.cloud._helpers import UTC + from google.api_core.page_iterator import GRPCIterator from google.cloud.trace_v1.gapic import trace_service_client from google.cloud.trace_v1.gapic.enums import ListTracesRequest as Enum - from google.cloud.trace_v1.proto import trace_pb2 + from google.cloud.trace.v1._gapic import _item_to_mapping - trace_id = "test_trace_id" - span_id = 1234 - span_name = "test_span_name" - span_kind = "RPC_CLIENT" - parent_span_id = 123 - start_ts = datetime.datetime.utcnow() - end_ts = datetime.datetime.utcnow() - labels = {"/http/status_code": "200", "/component": "HTTP load balancer"} - size = 10 + page_size = 10 view_type = Enum.ViewType.COMPLETE - token = "TOKEN" - - trace_pb = self._make_trace_pb( - self.project, - trace_id, - span_id, - span_name, - start_ts.isoformat() + "Z", - end_ts.isoformat() + "Z", - parent_span_id, - labels, - ) + page_token = "TOKEN" + gapic_api = mock.create_autospec(trace_service_client.TraceServiceClient) + response_iter = mock.create_autospec(GRPCIterator) + gapic_api.list_traces.return_value = response_iter + api = self._make_one(gapic_api) - gapic_api = mock.Mock(spec=trace_service_client.TraceServiceClient) - gapic_api.list_traces = mock.create_autospec(gapic_api.list_traces) - channel, api = self._make_one() - - channel.ListTraces.response = trace_pb2.ListTracesResponse(traces=[trace_pb[0]]) iterator = api.list_traces( - project_id=self.project, view=view_type, page_size=size, page_token=token + project_id=self.project, + view=view_type, + page_size=page_size, + page_token=page_token, ) - traces = list(iterator) - - self.assertEqual(len(traces), 1) - trace = traces[0] + self.assertIs(iterator, response_iter) + self.assertIs(iterator.item_to_value, _item_to_mapping) + self.assertEqual(iterator.next_page_token, page_token) + + gapic_api.list_traces.assert_called_once_with( + project_id=self.project, + view=view_type, + page_size=page_size, + start_time=None, + end_time=None, + filter_=None, + order_by=None, + ) - self.assertEqual(len(trace["spans"]), 1) - span = trace["spans"][0] - self.assertEqual(trace["projectId"], self.project) - self.assertEqual(trace["traceId"], trace_id) +class _TracePbBase(object): + project = u"PROJECT" + trace_id = u"test_trace_id" + span_id = 1234 + span_name = u"test_span_name" + start_time = "2017-06-24T00:12:50.369990Z" + end_time = "2017-06-24T00:13:39.633255Z" + start_seconds = 1498263170 + start_nanos = 369990000 + end_seconds = 1498263219 + end_nanos = 633255000 + + @classmethod + def _make_trace_pb(cls): + from google.cloud.trace_v1.proto.trace_pb2 import Trace + from google.cloud.trace_v1.proto.trace_pb2 import TraceSpan + from google.protobuf.timestamp_pb2 import Timestamp - self.assertEqual(span["spanId"], str(span_id)) - self.assertEqual(span["name"], span_name) + start_time_pb = Timestamp(seconds=cls.start_seconds, nanos=cls.start_nanos) + end_time_pb = Timestamp(seconds=cls.end_seconds, nanos=cls.end_nanos) - self.assertEqual( - _rfc3339_to_datetime(span["startTime"]), start_ts.replace(tzinfo=UTC) - ) - self.assertEqual( - _rfc3339_to_datetime(span["endTime"]), end_ts.replace(tzinfo=UTC) - ) - self.assertEqual(span["kind"], span_kind) - self.assertEqual(span["parentSpanId"], str(parent_span_id)) - self.assertEqual(span["labels"], labels) - - self.assertEqual(len(channel.ListTraces.requests), 1) - request = channel.ListTraces.requests[0] - - self.assertEqual(request.project_id, self.project) - self.assertEqual(request.view, view_type) - self.assertEqual(request.page_size, size) - self.assertEqual( - request.start_time.ToDatetime(), datetime.datetime(1970, 1, 1, 0, 0) - ) - self.assertEqual( - request.end_time.ToDatetime(), datetime.datetime(1970, 1, 1, 0, 0) + span_pb = TraceSpan( + span_id=cls.span_id, + name=cls.span_name, + start_time=start_time_pb, + end_time=end_time_pb, ) - self.assertEqual(request.filter, "") - self.assertEqual(request.order_by, "") + + return Trace(project_id=cls.project, trace_id=cls.trace_id, spans=[span_pb]) + + @classmethod + def _expected_json(cls): + return { + "projectId": cls.project, + "traceId": cls.trace_id, + "spans": [ + { + "spanId": str(cls.span_id), + "name": cls.span_name, + "startTime": cls.start_time, + "endTime": cls.end_time, + } + ], + } -class Test__parse_trace_pb(unittest.TestCase): +class Test__item_to_mapping(unittest.TestCase, _TracePbBase): @staticmethod def _call_fut(*args, **kwargs): - from google.cloud.trace.v1._gapic import _parse_trace_pb + from google.cloud.trace.v1._gapic import _item_to_mapping - return _parse_trace_pb(*args, **kwargs) + return _item_to_mapping(*args, **kwargs) def test_registered_type(self): - from google.cloud.trace_v1.proto.trace_pb2 import TraceSpan, Trace - from google.protobuf.timestamp_pb2 import Timestamp + iterator = object() + trace_pb = self._make_trace_pb() - project = u"PROJECT" - trace_id = u"test_trace_id" - span_id = 1234 - span_name = u"test_span_name" - start_time = "2017-06-24T00:12:50.369990Z" - end_time = "2017-06-24T00:13:39.633255Z" - start_seconds = 1498263170 - start_nanos = 369990000 - end_seconds = 1498263219 - end_nanos = 633255000 + parsed_json = self._call_fut(iterator, trace_pb) - start_time_pb = Timestamp(seconds=start_seconds, nanos=start_nanos) - end_time_pb = Timestamp(seconds=end_seconds, nanos=end_nanos) + expected_result = self._expected_json() + self.assertEqual(parsed_json, expected_result) - span_pb = TraceSpan( - span_id=span_id, - name=span_name, - start_time=start_time_pb, - end_time=end_time_pb, - ) - trace_pb = Trace(project_id=project, trace_id=trace_id, spans=[span_pb]) +class Test__parse_trace_pb(unittest.TestCase, _TracePbBase): + @staticmethod + def _call_fut(*args, **kwargs): + from google.cloud.trace.v1._gapic import _parse_trace_pb - parse_result = self._call_fut(trace_pb) + return _parse_trace_pb(*args, **kwargs) - expected_result = { - "projectId": project, - "traceId": trace_id, - "spans": [ - { - "spanId": str(span_id), - "name": span_name, - "startTime": start_time, - "endTime": end_time, - } - ], - } + def test_registered_type(self): + trace_pb = self._make_trace_pb() + + parsed_json = self._call_fut(trace_pb) - self.assertEqual(parse_result, expected_result) + expected_result = self._expected_json() + self.assertEqual(parsed_json, expected_result) @mock.patch("google.cloud.trace.v1._gapic.MessageToDict", side_effect=TypeError) def test_unregistered_type(self, msg_to_dict_mock): @@ -311,28 +227,19 @@ def _call_fut(self, client): def test_it(self): from google.cloud.trace.v1._gapic import _TraceAPI - credentials = object() - client = mock.Mock(_credentials=credentials, spec=["_credentials"]) - generated_api_kwargs = [] - generated = object() - - def generated_api(**kwargs): - generated_api_kwargs.append(kwargs) - return generated - - host = "foo.apis.invalid" - generated_api.SERVICE_ADDRESS = host + client = mock.Mock(spec=["_credentials", "_client_info"]) patch_api = mock.patch( - "google.cloud.trace.v1._gapic.trace_service_client." "TraceServiceClient", - new=generated_api, + "google.cloud.trace.v1._gapic.trace_service_client.TraceServiceClient" ) - with patch_api: + with patch_api as patched: trace_api = self._call_fut(client) - self.assertEqual(len(generated_api_kwargs), 1) + patched.assert_called_once_with( + credentials=client._credentials, client_info=client._client_info + ) self.assertIsInstance(trace_api, _TraceAPI) - self.assertIs(trace_api._gapic_api, generated) + self.assertIs(trace_api._gapic_api, patched.return_value) self.assertIs(trace_api.client, client) diff --git a/trace/tests/unit/v1/test_client_v1.py b/trace/tests/unit/v1/test_client_v1.py index ad8ebc24c794..d3e1c391592a 100644 --- a/trace/tests/unit/v1/test_client_v1.py +++ b/trace/tests/unit/v1/test_client_v1.py @@ -36,10 +36,22 @@ def _get_target_class(): def _make_one(self, *args, **kw): return self._get_target_class()(*args, **kw) - def test_constructor(self): + def test_constructor_defaults(self): + from google.api_core.gapic_v1.client_info import ClientInfo + credentials = _make_credentials() client = self._make_one(project=self.project, credentials=credentials) self.assertEqual(client.project, self.project) + self.assertIsInstance(client._client_info, ClientInfo) + + def test_constructor_explicit(self): + credentials = _make_credentials() + client_info = mock.Mock() + client = self._make_one( + project=self.project, credentials=credentials, client_info=client_info + ) + self.assertEqual(client.project, self.project) + self.assertIs(client._client_info, client_info) def test_trace_api(self): clients = [] diff --git a/trace/tests/unit/v2/test__gapic_v2.py b/trace/tests/unit/v2/test__gapic_v2.py index faa9b03ad722..e6859b5964ef 100644 --- a/trace/tests/unit/v2/test__gapic_v2.py +++ b/trace/tests/unit/v2/test__gapic_v2.py @@ -272,28 +272,19 @@ def _call_fut(self, client): def test_it(self): from google.cloud.trace._gapic import _TraceAPI - credentials = object() - client = mock.Mock(_credentials=credentials, spec=["_credentials"]) - generated_api_kwargs = [] - generated = object() - - def generated_api(**kwargs): - generated_api_kwargs.append(kwargs) - return generated - - host = "foo.apis.invalid" - generated_api.SERVICE_ADDRESS = host + client = mock.Mock(spec=["_credentials", "_client_info"]) patch_api = mock.patch( - "google.cloud.trace._gapic.trace_service_client." "TraceServiceClient", - new=generated_api, + "google.cloud.trace._gapic.trace_service_client.TraceServiceClient" ) - with patch_api: + with patch_api as patched: trace_api = self._call_fut(client) - self.assertEqual(len(generated_api_kwargs), 1) + patched.assert_called_once_with( + credentials=client._credentials, client_info=client._client_info + ) self.assertIsInstance(trace_api, _TraceAPI) - self.assertIs(trace_api._gapic_api, generated) + self.assertIs(trace_api._gapic_api, patched.return_value) self.assertIs(trace_api.client, client) diff --git a/trace/tests/unit/v2/test_client_v2.py b/trace/tests/unit/v2/test_client_v2.py index cd009c502623..d5a14aeb6c92 100644 --- a/trace/tests/unit/v2/test_client_v2.py +++ b/trace/tests/unit/v2/test_client_v2.py @@ -36,10 +36,21 @@ def _get_target_class(): def _make_one(self, *args, **kw): return self._get_target_class()(*args, **kw) - def test_constructor(self): + def test_constructor_defaults(self): + from google.api_core.gapic_v1.client_info import ClientInfo + credentials = _make_credentials() client = self._make_one(project=self.project, credentials=credentials) self.assertEqual(client.project, self.project) + self.assertIsInstance(client._client_info, ClientInfo) + + def test_constructor_explicit(self): + credentials = _make_credentials() + client_info = mock.Mock() + client = self._make_one( + project=self.project, credentials=credentials, client_info=client_info + ) + self.assertEqual(client.project, self.project) def test_trace_api(self): clients = []