1414
1515import pytest
1616import asyncio
17+ from grpc import RpcError
1718
1819from google .cloud .bigtable .data ._cross_sync import CrossSync
1920
@@ -158,7 +159,61 @@ async def test_unary_unary_interceptor_success(self):
158159
159160 @CrossSync .pytest
160161 async def test_unary_unary_interceptor_failure (self ):
161- """Test that interceptor handles failed unary-unary calls"""
162+ """test a failed RpcError with metadata"""
163+ from google .cloud .bigtable .data ._metrics .data_model import (
164+ OPERATION_INTERCEPTOR_METADATA_KEY ,
165+ )
166+
167+ instance = self ._make_one ()
168+ op = mock .Mock ()
169+ op .uuid = "test-uuid"
170+ op .state = 1 # ACTIVE_ATTEMPT
171+ instance .operation_map [op .uuid ] = op
172+ exc = RpcError ("test" )
173+ exc .trailing_metadata = CrossSync .Mock (return_value = [("a" , "b" )])
174+ exc .initial_metadata = CrossSync .Mock (return_value = [("c" , "d" )])
175+ continuation = CrossSync .Mock (side_effect = exc )
176+ call = continuation .return_value
177+ details = mock .Mock ()
178+ details .metadata = [(OPERATION_INTERCEPTOR_METADATA_KEY , op .uuid )]
179+ request = mock .Mock ()
180+ with pytest .raises (RpcError ) as e :
181+ await instance .intercept_unary_unary (continuation , details , request )
182+ assert e .value == exc
183+ continuation .assert_called_once_with (details , request )
184+ op .add_response_metadata .assert_called_once_with ([("a" , "b" ), ("c" , "d" )])
185+ op .end_attempt_with_status .assert_called_once_with (exc )
186+
187+ @CrossSync .pytest
188+ async def test_unary_unary_interceptor_failure_no_metadata (self ):
189+ """test with RpcError without without metadata attached"""
190+ from google .cloud .bigtable .data ._metrics .data_model import (
191+ OPERATION_INTERCEPTOR_METADATA_KEY ,
192+ )
193+
194+ instance = self ._make_one ()
195+ op = mock .Mock ()
196+ op .uuid = "test-uuid"
197+ op .state = 1 # ACTIVE_ATTEMPT
198+ instance .operation_map [op .uuid ] = op
199+ exc = RpcError ("test" )
200+ continuation = CrossSync .Mock (side_effect = exc )
201+ call = continuation .return_value
202+ call .trailing_metadata = CrossSync .Mock (return_value = [("a" , "b" )])
203+ call .initial_metadata = CrossSync .Mock (return_value = [("c" , "d" )])
204+ details = mock .Mock ()
205+ details .metadata = [(OPERATION_INTERCEPTOR_METADATA_KEY , op .uuid )]
206+ request = mock .Mock ()
207+ with pytest .raises (RpcError ) as e :
208+ await instance .intercept_unary_unary (continuation , details , request )
209+ assert e .value == exc
210+ continuation .assert_called_once_with (details , request )
211+ op .add_response_metadata .assert_not_called ()
212+ op .end_attempt_with_status .assert_called_once_with (exc )
213+
214+ @CrossSync .pytest
215+ async def test_unary_unary_interceptor_failure_generic (self ):
216+ """test generic exception"""
162217 from google .cloud .bigtable .data ._metrics .data_model import (
163218 OPERATION_INTERCEPTOR_METADATA_KEY ,
164219 )
@@ -180,9 +235,10 @@ async def test_unary_unary_interceptor_failure(self):
180235 await instance .intercept_unary_unary (continuation , details , request )
181236 assert e .value == exc
182237 continuation .assert_called_once_with (details , request )
183- op .add_response_metadata .assert_called_once_with ([( "a" , "b" ), ( "c" , "d" )] )
238+ op .add_response_metadata .assert_not_called ( )
184239 op .end_attempt_with_status .assert_called_once_with (exc )
185240
241+
186242 @CrossSync .pytest
187243 async def test_unary_stream_interceptor_op_not_found (self ):
188244 """Test that interceptor calls continuation if op is not found"""
@@ -263,7 +319,67 @@ async def mock_generator():
263319
264320 @CrossSync .pytest
265321 async def test_unary_stream_interceptor_failure_start_stream (self ):
266- """Test that interceptor handles failures at start of stream"""
322+ """Test that interceptor handles failures at start of stream with RpcError with metadata"""
323+ from google .cloud .bigtable .data ._metrics .data_model import (
324+ OPERATION_INTERCEPTOR_METADATA_KEY ,
325+ )
326+
327+ instance = self ._make_one ()
328+ op = mock .Mock ()
329+ op .uuid = "test-uuid"
330+ op .state = 1 # ACTIVE_ATTEMPT
331+ op .start_time_ns = 0
332+ op .first_response_latency = None
333+ instance .operation_map [op .uuid ] = op
334+ exc = RpcError ("test" )
335+ exc .trailing_metadata = CrossSync .Mock (return_value = [("a" , "b" )])
336+ exc .initial_metadata = CrossSync .Mock (return_value = [("c" , "d" )])
337+
338+ continuation = CrossSync .Mock ()
339+ continuation .side_effect = exc
340+ details = mock .Mock ()
341+ details .metadata = [(OPERATION_INTERCEPTOR_METADATA_KEY , op .uuid )]
342+ request = mock .Mock ()
343+ with pytest .raises (RpcError ) as e :
344+ await instance .intercept_unary_stream (continuation , details , request )
345+ assert e .value == exc
346+ continuation .assert_called_once_with (details , request )
347+ assert op .first_response_latency_ns is not None
348+ op .add_response_metadata .assert_called_once_with ([("a" , "b" ), ("c" , "d" )])
349+ op .end_attempt_with_status .assert_called_once_with (exc )
350+
351+ @CrossSync .pytest
352+ async def test_unary_stream_interceptor_failure_start_stream_no_metadata (self ):
353+ """Test that interceptor handles failures at start of stream with RpcError with no metadata"""
354+ from google .cloud .bigtable .data ._metrics .data_model import (
355+ OPERATION_INTERCEPTOR_METADATA_KEY ,
356+ )
357+
358+ instance = self ._make_one ()
359+ op = mock .Mock ()
360+ op .uuid = "test-uuid"
361+ op .state = 1 # ACTIVE_ATTEMPT
362+ op .start_time_ns = 0
363+ op .first_response_latency = None
364+ instance .operation_map [op .uuid ] = op
365+ exc = RpcError ("test" )
366+
367+ continuation = CrossSync .Mock ()
368+ continuation .side_effect = exc
369+ details = mock .Mock ()
370+ details .metadata = [(OPERATION_INTERCEPTOR_METADATA_KEY , op .uuid )]
371+ request = mock .Mock ()
372+ with pytest .raises (RpcError ) as e :
373+ await instance .intercept_unary_stream (continuation , details , request )
374+ assert e .value == exc
375+ continuation .assert_called_once_with (details , request )
376+ assert op .first_response_latency_ns is not None
377+ op .add_response_metadata .assert_not_called ()
378+ op .end_attempt_with_status .assert_called_once_with (exc )
379+
380+ @CrossSync .pytest
381+ async def test_unary_stream_interceptor_failure_start_stream_generic (self ):
382+ """Test that interceptor handles failures at start of stream with generic exception"""
267383 from google .cloud .bigtable .data ._metrics .data_model import (
268384 OPERATION_INTERCEPTOR_METADATA_KEY ,
269385 )
@@ -287,5 +403,5 @@ async def test_unary_stream_interceptor_failure_start_stream(self):
287403 assert e .value == exc
288404 continuation .assert_called_once_with (details , request )
289405 assert op .first_response_latency_ns is not None
290- op .add_response_metadata .assert_called_once_with ([( "a" , "b" ), ( "c" , "d" )] )
406+ op .add_response_metadata .assert_not_called ( )
291407 op .end_attempt_with_status .assert_called_once_with (exc )
0 commit comments