|
13 | 13 | # limitations under the License. |
14 | 14 | # pylint:disable=cyclic-import |
15 | 15 |
|
| 16 | +from unittest import mock |
| 17 | + |
16 | 18 | import grpc |
17 | 19 |
|
18 | 20 | import opentelemetry.instrumentation.grpc |
|
26 | 28 | ) |
27 | 29 | from opentelemetry.instrumentation.utils import suppress_instrumentation |
28 | 30 | from opentelemetry.propagate import get_global_textmap, set_global_textmap |
| 31 | +from opentelemetry.sdk.trace import Span as SdkSpan |
29 | 32 | from opentelemetry.semconv.trace import SpanAttributes |
30 | 33 | from opentelemetry.test.mock_textmap import MockTextMapPropagator |
31 | 34 | from opentelemetry.test.test_base import TestBase |
@@ -269,6 +272,32 @@ def test_error_stream_stream(self): |
269 | 272 | trace.StatusCode.ERROR, |
270 | 273 | ) |
271 | 274 |
|
| 275 | + def test_client_interceptor_falsy_response( |
| 276 | + self, |
| 277 | + ): |
| 278 | + """ensure that client interceptor closes the span only once even if the response is falsy.""" |
| 279 | + |
| 280 | + with mock.patch.object(SdkSpan, "end") as span_end_mock: |
| 281 | + tracer_provider, _exporter = self.create_tracer_provider() |
| 282 | + tracer = tracer_provider.get_tracer(__name__) |
| 283 | + |
| 284 | + interceptor = OpenTelemetryClientInterceptor(tracer) |
| 285 | + |
| 286 | + def invoker(_request, _metadata): |
| 287 | + return {} |
| 288 | + |
| 289 | + request = Request(client_id=1, request_data="data") |
| 290 | + interceptor.intercept_unary( |
| 291 | + request, |
| 292 | + {}, |
| 293 | + _UnaryClientInfo( |
| 294 | + full_method="/GRPCTestServer/SimpleMethod", |
| 295 | + timeout=None, |
| 296 | + ), |
| 297 | + invoker=invoker, |
| 298 | + ) |
| 299 | + self.assertEqual(span_end_mock.call_count, 1) |
| 300 | + |
272 | 301 | def test_client_interceptor_trace_context_propagation( |
273 | 302 | self, |
274 | 303 | ): # pylint: disable=no-self-use |
|
0 commit comments