@@ -269,6 +269,47 @@ def test_error_stream_stream(self):
269269 trace .StatusCode .ERROR ,
270270 )
271271
272+ def test_client_interceptor_falsy_response (
273+ self ,
274+ ): # pylint: disable=no-self-use
275+ """ensure that client interceptor closes the span only once even if the response is falsy."""
276+
277+ span_end_count = 0
278+ tracer_provider , _exporter = self .create_tracer_provider ()
279+ tracer = tracer_provider .get_tracer (__name__ )
280+ original_start_span = tracer .start_span
281+
282+ def counting_span_end (original_end ):
283+ def wrapper (* args , ** kwargs ):
284+ nonlocal span_end_count
285+ span_end_count += 1
286+ return original_end (* args , ** kwargs )
287+
288+ return wrapper
289+
290+ def patched_start_span (* args , ** kwargs ):
291+ span = original_start_span (* args , ** kwargs )
292+ span .end = counting_span_end (span .end )
293+ return span
294+
295+ tracer .start_span = patched_start_span
296+ interceptor = OpenTelemetryClientInterceptor (tracer )
297+
298+ def invoker (_request , _metadata ):
299+ return {}
300+
301+ request = Request (client_id = 1 , request_data = "data" )
302+ interceptor .intercept_unary (
303+ request ,
304+ {},
305+ _UnaryClientInfo (
306+ full_method = "/GRPCTestServer/SimpleMethod" ,
307+ timeout = None ,
308+ ),
309+ invoker = invoker ,
310+ )
311+ assert span_end_count == 1
312+
272313 def test_client_interceptor_trace_context_propagation (
273314 self ,
274315 ): # pylint: disable=no-self-use
0 commit comments