Skip to content

Commit 73947fd

Browse files
committed
Updating unit tests for GAPIC commit in datastore.
1 parent b92e796 commit 73947fd

File tree

5 files changed

+360
-297
lines changed

5 files changed

+360
-297
lines changed

datastore/unit_tests/test__gax.py

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ def _fake_method(exc, result=None):
3434
else:
3535
raise exc
3636

37+
@staticmethod
38+
def _make_rendezvous(status_code, details):
39+
from grpc._channel import _RPCState
40+
from google.cloud.exceptions import GrpcRendezvous
41+
42+
exc_state = _RPCState((), None, None, status_code, details)
43+
return GrpcRendezvous(exc_state, None, None, None)
44+
3745
def test_success(self):
3846
expected = object()
3947
with self._call_fut():
@@ -42,39 +50,30 @@ def test_success(self):
4250

4351
def test_failure_aborted(self):
4452
from grpc import StatusCode
45-
from grpc._channel import _RPCState
4653
from google.cloud.exceptions import Conflict
47-
from google.cloud.exceptions import GrpcRendezvous
4854

4955
details = 'Bad things.'
50-
exc_state = _RPCState((), None, None, StatusCode.ABORTED, details)
51-
exc = GrpcRendezvous(exc_state, None, None, None)
56+
exc = self._make_rendezvous(StatusCode.ABORTED, details)
5257
with self.assertRaises(Conflict):
5358
with self._call_fut():
5459
self._fake_method(exc)
5560

5661
def test_failure_invalid_argument(self):
5762
from grpc import StatusCode
58-
from grpc._channel import _RPCState
5963
from google.cloud.exceptions import BadRequest
60-
from google.cloud.exceptions import GrpcRendezvous
6164

6265
details = ('Cannot have inequality filters on multiple '
6366
'properties: [created, priority]')
64-
exc_state = _RPCState((), None, None,
65-
StatusCode.INVALID_ARGUMENT, details)
66-
exc = GrpcRendezvous(exc_state, None, None, None)
67+
exc = self._make_rendezvous(StatusCode.INVALID_ARGUMENT, details)
6768
with self.assertRaises(BadRequest):
6869
with self._call_fut():
6970
self._fake_method(exc)
7071

7172
def test_failure_cancelled(self):
72-
from grpc import StatusCode
73-
from grpc._channel import _RPCState
7473
from google.cloud.exceptions import GrpcRendezvous
74+
from grpc import StatusCode
7575

76-
exc_state = _RPCState((), None, None, StatusCode.CANCELLED, None)
77-
exc = GrpcRendezvous(exc_state, None, None, None)
76+
exc = self._make_rendezvous(StatusCode.CANCELLED, None)
7877
with self.assertRaises(GrpcRendezvous):
7978
with self._call_fut():
8079
self._fake_method(exc)
@@ -85,6 +84,33 @@ def test_commit_failure_non_grpc_err(self):
8584
with self._call_fut():
8685
self._fake_method(exc)
8786

87+
def test_gax_error(self):
88+
from google.gax.errors import GaxError
89+
from grpc import StatusCode
90+
from google.cloud.exceptions import Forbidden
91+
92+
# First, create low-level GrpcRendezvous exception.
93+
details = 'Some error details.'
94+
cause = self._make_rendezvous(StatusCode.PERMISSION_DENIED, details)
95+
# Then put it into a high-level GaxError.
96+
msg = 'GAX Error content.'
97+
exc = GaxError(msg, cause=cause)
98+
99+
with self.assertRaises(Forbidden):
100+
with self._call_fut():
101+
self._fake_method(exc)
102+
103+
def test_gax_error_not_mapped(self):
104+
from google.gax.errors import GaxError
105+
from grpc import StatusCode
106+
107+
cause = self._make_rendezvous(StatusCode.CANCELLED, None)
108+
exc = GaxError(None, cause=cause)
109+
110+
with self.assertRaises(GaxError):
111+
with self._call_fut():
112+
self._fake_method(exc)
113+
88114

89115
class Test_DatastoreAPIOverGRPC(unittest.TestCase):
90116

@@ -228,45 +254,38 @@ def test_begin_transaction(self):
228254
stub.method_calls,
229255
[(request_pb, 'BeginTransaction')])
230256

231-
def test_commit_success(self):
232-
return_val = object()
233-
stub = _GRPCStub(return_val)
234-
datastore_api, _ = self._make_one(stub=stub)
235257

236-
request_pb = mock.Mock(project_id=None, spec=['project_id'])
237-
project = 'PROJECT'
238-
result = datastore_api.commit(project, request_pb)
239-
self.assertIs(result, return_val)
240-
self.assertEqual(request_pb.project_id, project)
241-
self.assertEqual(stub.method_calls,
242-
[(request_pb, 'Commit')])
258+
@unittest.skipUnless(_HAVE_GRPC, 'No gRPC')
259+
class TestGAPICDatastoreAPI(unittest.TestCase):
243260

244-
def test_rollback(self):
245-
return_val = object()
246-
stub = _GRPCStub(return_val)
247-
datastore_api, _ = self._make_one(stub=stub)
261+
@staticmethod
262+
def _get_target_class():
263+
from google.cloud.datastore._gax import GAPICDatastoreAPI
248264

249-
request_pb = mock.Mock(project_id=None, spec=['project_id'])
250-
project = 'PROJECT'
251-
result = datastore_api.rollback(project, request_pb)
252-
self.assertIs(result, return_val)
253-
self.assertEqual(request_pb.project_id, project)
254-
self.assertEqual(stub.method_calls,
255-
[(request_pb, 'Rollback')])
265+
return GAPICDatastoreAPI
256266

257-
def test_allocate_ids(self):
258-
return_val = object()
259-
stub = _GRPCStub(return_val)
260-
datastore_api, _ = self._make_one(stub=stub)
267+
def _make_one(self, *args, **kwargs):
268+
return self._get_target_class()(*args, **kwargs)
261269

262-
request_pb = mock.Mock(project_id=None, spec=['project_id'])
263-
project = 'PROJECT'
264-
result = datastore_api.allocate_ids(project, request_pb)
265-
self.assertIs(result, return_val)
266-
self.assertEqual(request_pb.project_id, project)
267-
self.assertEqual(
268-
stub.method_calls,
269-
[(request_pb, 'AllocateIds')])
270+
def test_commit(self):
271+
from google.cloud.gapic.datastore.v1 import datastore_client
272+
273+
patch1 = mock.patch.object(
274+
datastore_client.DatastoreClient, '__init__',
275+
return_value=None)
276+
patch2 = mock.patch.object(datastore_client.DatastoreClient, 'commit')
277+
patch3 = mock.patch(
278+
'google.cloud.datastore._gax._grpc_catch_rendezvous')
279+
280+
with patch1 as mock_constructor:
281+
ds_api = self._make_one()
282+
mock_constructor.assert_called_once_with()
283+
with patch2 as mock_commit:
284+
with patch3 as mock_catch_rendezvous:
285+
mock_catch_rendezvous.assert_not_called()
286+
ds_api.commit(1, 2, a=3)
287+
mock_commit.assert_called_once_with(1, 2, a=3)
288+
mock_catch_rendezvous.assert_called_once_with()
270289

271290

272291
@unittest.skipUnless(_HAVE_GRPC, 'No gRPC')
@@ -278,12 +297,12 @@ def _call_fut(self, client):
278297
return make_datastore_api(client)
279298

280299
@mock.patch(
281-
'google.cloud.gapic.datastore.v1.datastore_client.DatastoreClient',
282-
SERVICE_ADDRESS='datastore.mock.mock',
300+
'google.cloud.datastore._gax.GAPICDatastoreAPI',
283301
return_value=mock.sentinel.ds_client)
284302
@mock.patch('google.cloud.datastore._gax.make_secure_channel',
285303
return_value=mock.sentinel.channel)
286304
def test_it(self, make_chan, mock_klass):
305+
from google.cloud.gapic.datastore.v1 import datastore_client
287306
from google.cloud._http import DEFAULT_USER_AGENT
288307
from google.cloud.datastore import __version__
289308

@@ -294,7 +313,7 @@ def test_it(self, make_chan, mock_klass):
294313

295314
make_chan.assert_called_once_with(
296315
mock.sentinel.credentials, DEFAULT_USER_AGENT,
297-
mock_klass.SERVICE_ADDRESS)
316+
datastore_client.DatastoreClient.SERVICE_ADDRESS)
298317
mock_klass.assert_called_once_with(
299318
channel=mock.sentinel.channel, lib_name='gccl',
300319
lib_version=__version__)
@@ -322,12 +341,3 @@ def RunQuery(self, request_pb):
322341

323342
def BeginTransaction(self, request_pb):
324343
return self._method(request_pb, 'BeginTransaction')
325-
326-
def Commit(self, request_pb):
327-
return self._method(request_pb, 'Commit')
328-
329-
def Rollback(self, request_pb):
330-
return self._method(request_pb, 'Rollback')
331-
332-
def AllocateIds(self, request_pb):
333-
return self._method(request_pb, 'AllocateIds')

datastore/unit_tests/test__http.py

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,23 @@ def test_begin_transaction(self):
662662
# The RPC-over-HTTP request does not set the project in the request.
663663
self.assertEqual(request.project_id, u'')
664664

665+
666+
class TestHTTPDatastoreAPI(unittest.TestCase):
667+
668+
@staticmethod
669+
def _get_target_class():
670+
from google.cloud.datastore._http import HTTPDatastoreAPI
671+
672+
return HTTPDatastoreAPI
673+
674+
def _make_one(self, *args, **kwargs):
675+
return self._get_target_class()(*args, **kwargs)
676+
677+
def test_constructor(self):
678+
client = object()
679+
ds_api = self._make_one(client)
680+
self.assertIs(ds_api.client, client)
681+
665682
def test_commit_wo_transaction(self):
666683
from google.cloud.proto.datastore.v1 import datastore_pb2
667684
from google.cloud.datastore.helpers import _new_value_pb
@@ -675,19 +692,23 @@ def test_commit_wo_transaction(self):
675692
insert.key.CopyFrom(key_pb)
676693
value_pb = _new_value_pb(insert, 'foo')
677694
value_pb.string_value = u'Foo'
695+
696+
# Create mock HTTP and client with response.
678697
http = Http({'status': '200'}, rsp_pb.SerializeToString())
679698
client = mock.Mock(
680699
_http=http, _base_url='test.invalid', spec=['_http', '_base_url'])
681-
conn = self._make_one(client)
682-
uri = _build_expected_url(conn.api_base_url, project, 'commit')
683700

684-
result = conn.commit(project, req_pb, None)
685-
self.assertEqual(result, rsp_pb)
701+
# Make request.
702+
rq_class = datastore_pb2.CommitRequest
703+
ds_api = self._make_one(client)
704+
mode = rq_class.NON_TRANSACTIONAL
705+
result = ds_api.commit(project, mode, [mutation])
686706

687-
# Verify the caller.
707+
# Check the result and verify the callers.
708+
self.assertEqual(result, rsp_pb)
709+
uri = _build_expected_url(client._base_url, project, 'commit')
688710
cw = http._called_with
689711
_verify_protobuf_call(self, cw, uri)
690-
rq_class = datastore_pb2.CommitRequest
691712
request = rq_class()
692713
request.ParseFromString(cw['body'])
693714
self.assertEqual(request.transaction, b'')
@@ -707,42 +728,29 @@ def test_commit_w_transaction(self):
707728
insert.key.CopyFrom(key_pb)
708729
value_pb = _new_value_pb(insert, 'foo')
709730
value_pb.string_value = u'Foo'
731+
732+
# Create mock HTTP and client with response.
710733
http = Http({'status': '200'}, rsp_pb.SerializeToString())
711734
client = mock.Mock(
712735
_http=http, _base_url='test.invalid', spec=['_http', '_base_url'])
713-
conn = self._make_one(client)
714-
uri = _build_expected_url(conn.api_base_url, project, 'commit')
715736

716-
result = conn.commit(project, req_pb, b'xact')
717-
self.assertEqual(result, rsp_pb)
737+
# Make request.
738+
rq_class = datastore_pb2.CommitRequest
739+
ds_api = self._make_one(client)
740+
mode = rq_class.TRANSACTIONAL
741+
result = ds_api.commit(project, mode, [mutation], transaction=b'xact')
718742

719-
# Verify the caller.
743+
# Check the result and verify the callers.
744+
self.assertEqual(result, rsp_pb)
745+
uri = _build_expected_url(client._base_url, project, 'commit')
720746
cw = http._called_with
721747
_verify_protobuf_call(self, cw, uri)
722-
rq_class = datastore_pb2.CommitRequest
723748
request = rq_class()
724749
request.ParseFromString(cw['body'])
725750
self.assertEqual(request.transaction, b'xact')
726751
self.assertEqual(list(request.mutations), [mutation])
727752
self.assertEqual(request.mode, rq_class.TRANSACTIONAL)
728753

729-
730-
class TestHTTPDatastoreAPI(unittest.TestCase):
731-
732-
@staticmethod
733-
def _get_target_class():
734-
from google.cloud.datastore._http import HTTPDatastoreAPI
735-
736-
return HTTPDatastoreAPI
737-
738-
def _make_one(self, *args, **kwargs):
739-
return self._get_target_class()(*args, **kwargs)
740-
741-
def test_constructor(self):
742-
client = object()
743-
ds_api = self._make_one(client)
744-
self.assertIs(ds_api.client, client)
745-
746754
def test_rollback_ok(self):
747755
from google.cloud.proto.datastore.v1 import datastore_pb2
748756

0 commit comments

Comments
 (0)