@@ -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
89115class 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' )
0 commit comments