|
13 | 13 | # limitations under the License. |
14 | 14 |
|
15 | 15 | import datetime |
| 16 | +import sys |
16 | 17 | from unittest import mock |
17 | 18 |
|
18 | 19 | import pytest |
@@ -346,3 +347,102 @@ def test_wrap_method_with_call_not_supported(): |
346 | 347 | def test__deduplicate_metadata_tokens(headers, expected): |
347 | 348 | dedup = google.api_core.gapic_v1.method._deduplicate_metadata_tokens |
348 | 349 | assert dedup(*headers) == expected |
| 350 | + |
| 351 | + |
| 352 | +def test_wrap_method_otel_tracing_disabled(monkeypatch): |
| 353 | + """Proves that when OpenTelemetry tracing is disabled, no span is created.""" |
| 354 | + monkeypatch.setenv("GOOGLE_SDK_EXPERIMENTAL_PYTHON_TRACING_ENABLED", "false") |
| 355 | + mock_target = mock.Mock(return_value="success") |
| 356 | + wrapped = google.api_core.gapic_v1.method.wrap_method(mock_target) |
| 357 | + |
| 358 | + with mock.patch( |
| 359 | + "google.api_core._observability.is_otel_capabilities_enabled", |
| 360 | + return_value=False, |
| 361 | + ): |
| 362 | + assert wrapped() == "success" |
| 363 | + mock_target.assert_called_once() |
| 364 | + |
| 365 | + |
| 366 | +def test_wrap_method_otel_tracing_enabled_success(monkeypatch): |
| 367 | + """Proves that when OpenTelemetry tracing is enabled, a T3 client span is started.""" |
| 368 | + monkeypatch.setenv("GOOGLE_SDK_EXPERIMENTAL_PYTHON_TRACING_ENABLED", "true") |
| 369 | + mock_target = mock.Mock(return_value="success") |
| 370 | + mock_target._method = ( |
| 371 | + "/google.cloud.secretmanager.v1.SecretManagerService/ListSecrets" |
| 372 | + ) |
| 373 | + |
| 374 | + mock_span = mock.MagicMock() |
| 375 | + mock_tracer = mock.MagicMock() |
| 376 | + mock_tracer.start_as_current_span.return_value.__enter__.return_value = mock_span |
| 377 | + |
| 378 | + mock_trace = mock.Mock() |
| 379 | + mock_trace.get_tracer.return_value = mock_tracer |
| 380 | + mock_trace.SpanKind.CLIENT = "CLIENT" |
| 381 | + |
| 382 | + wrapped = google.api_core.gapic_v1.method.wrap_method(mock_target) |
| 383 | + |
| 384 | + with ( |
| 385 | + mock.patch( |
| 386 | + "google.api_core._observability.is_otel_capabilities_enabled", |
| 387 | + return_value=True, |
| 388 | + ), |
| 389 | + mock.patch.dict( |
| 390 | + sys.modules, |
| 391 | + { |
| 392 | + "opentelemetry": mock.Mock(trace=mock_trace), |
| 393 | + "opentelemetry.trace": mock_trace, |
| 394 | + }, |
| 395 | + ), |
| 396 | + ): |
| 397 | + result = wrapped() |
| 398 | + |
| 399 | + assert result == "success" |
| 400 | + mock_tracer.start_as_current_span.assert_called_once_with( |
| 401 | + "google.cloud.secretmanager.v1.SecretManagerService/ListSecrets", |
| 402 | + kind="CLIENT", |
| 403 | + attributes={ |
| 404 | + "rpc.system": "grpc", |
| 405 | + "rpc.service": "google.cloud.secretmanager.v1.SecretManagerService", |
| 406 | + "rpc.method": "ListSecrets", |
| 407 | + }, |
| 408 | + ) |
| 409 | + |
| 410 | + |
| 411 | +def test_wrap_method_otel_tracing_enabled_error(monkeypatch): |
| 412 | + """Proves that when an RPC fails, the T3 client span records the exception and error status.""" |
| 413 | + monkeypatch.setenv("GOOGLE_SDK_EXPERIMENTAL_PYTHON_TRACING_ENABLED", "true") |
| 414 | + err = RuntimeError("gRPC connection reset") |
| 415 | + mock_target = mock.Mock(side_effect=err) |
| 416 | + mock_target._method = ( |
| 417 | + "/google.cloud.secretmanager.v1.SecretManagerService/ListSecrets" |
| 418 | + ) |
| 419 | + |
| 420 | + mock_span = mock.MagicMock() |
| 421 | + mock_tracer = mock.MagicMock() |
| 422 | + mock_tracer.start_as_current_span.return_value.__enter__.return_value = mock_span |
| 423 | + |
| 424 | + mock_trace = mock.Mock() |
| 425 | + mock_trace.get_tracer.return_value = mock_tracer |
| 426 | + mock_trace.SpanKind.CLIENT = "CLIENT" |
| 427 | + mock_trace.StatusCode.ERROR = "ERROR" |
| 428 | + |
| 429 | + wrapped = google.api_core.gapic_v1.method.wrap_method(mock_target) |
| 430 | + |
| 431 | + with ( |
| 432 | + mock.patch( |
| 433 | + "google.api_core._observability.is_otel_capabilities_enabled", |
| 434 | + return_value=True, |
| 435 | + ), |
| 436 | + mock.patch.dict( |
| 437 | + sys.modules, |
| 438 | + { |
| 439 | + "opentelemetry": mock.Mock(trace=mock_trace), |
| 440 | + "opentelemetry.trace": mock_trace, |
| 441 | + }, |
| 442 | + ), |
| 443 | + ): |
| 444 | + with pytest.raises(RuntimeError): |
| 445 | + wrapped() |
| 446 | + |
| 447 | + mock_span.record_exception.assert_called_once_with(err) |
| 448 | + mock_span.set_status.assert_called_once_with("ERROR", str(err)) |
0 commit comments