|
9 | 9 | recordings while leaving first-execution recordings intact. |
10 | 10 | """ |
11 | 11 |
|
| 12 | +import sys |
12 | 13 | import uuid |
13 | 14 | import warnings |
14 | 15 | from collections.abc import AsyncGenerator |
|
23 | 24 | from google.adk.runners import InMemoryRunner |
24 | 25 | from google.adk.utils.context_utils import Aclosing |
25 | 26 | from google.genai import types |
| 27 | +from opentelemetry.metrics import NoOpMeterProvider |
| 28 | +from opentelemetry.metrics._internal import _ProxyMeterProvider |
26 | 29 | from opentelemetry.sdk.metrics import MeterProvider |
27 | 30 | from opentelemetry.sdk.metrics.export import InMemoryMetricReader |
28 | 31 | from opentelemetry.sdk.trace import TracerProvider |
@@ -287,3 +290,63 @@ def test_plugin_does_not_warn_with_unset_providers( |
287 | 290 | warnings.simplefilter("always") |
288 | 291 | GoogleAdkPlugin().configure_worker(_worker_config()) |
289 | 292 | assert not [w for w in recorded if "replay-safe" in str(w.message)] |
| 293 | + |
| 294 | + |
| 295 | +def test_meter_provider_replay_safety_classification(monkeypatch: pytest.MonkeyPatch): |
| 296 | + from temporalio.contrib.google_adk_agents._plugin import ( |
| 297 | + _meter_provider_replay_safe, |
| 298 | + ) |
| 299 | + |
| 300 | + assert _meter_provider_replay_safe(ReplaySafeMeterProvider(MeterProvider())) is True |
| 301 | + assert _meter_provider_replay_safe(NoOpMeterProvider()) is True |
| 302 | + assert _meter_provider_replay_safe(_ProxyMeterProvider()) is True |
| 303 | + assert _meter_provider_replay_safe(MeterProvider()) is False |
| 304 | + |
| 305 | + # When the private proxy class cannot be imported, providers other than |
| 306 | + # the replay-safe/no-op ones are unclassifiable and must not warn. |
| 307 | + monkeypatch.setitem(sys.modules, "opentelemetry.metrics._internal", None) |
| 308 | + assert _meter_provider_replay_safe(MeterProvider()) is None |
| 309 | + assert _meter_provider_replay_safe(NoOpMeterProvider()) is True |
| 310 | + |
| 311 | + |
| 312 | +def test_plugin_does_not_warn_when_proxy_detection_unavailable( |
| 313 | + monkeypatch: pytest.MonkeyPatch, |
| 314 | + reset_otel_meter_provider, # type: ignore[reportUnusedParameter] |
| 315 | + reset_otel_tracer_provider, # type: ignore[reportUnusedParameter] |
| 316 | +): |
| 317 | + # A replay-unsafe provider is set, but with the private proxy class |
| 318 | + # unimportable it cannot be classified, so the plugin stays silent rather |
| 319 | + # than risking a false positive. |
| 320 | + opentelemetry.metrics.set_meter_provider(MeterProvider()) |
| 321 | + monkeypatch.setitem(sys.modules, "opentelemetry.metrics._internal", None) |
| 322 | + with warnings.catch_warnings(record=True) as recorded: |
| 323 | + warnings.simplefilter("always") |
| 324 | + GoogleAdkPlugin().configure_worker(_worker_config()) |
| 325 | + assert not [ |
| 326 | + w for w in recorded if "MeterProvider is not replay-safe" in str(w.message) |
| 327 | + ] |
| 328 | + |
| 329 | + |
| 330 | +async def test_plugin_warning_points_at_worker_construction( |
| 331 | + client: Client, |
| 332 | + reset_otel_meter_provider, # type: ignore[reportUnusedParameter] |
| 333 | + reset_otel_tracer_provider, # type: ignore[reportUnusedParameter] |
| 334 | +): |
| 335 | + # stacklevel on the warning must attribute it to the user's Worker(...) |
| 336 | + # call, i.e. this file, not SDK internals. |
| 337 | + opentelemetry.metrics.set_meter_provider(MeterProvider()) |
| 338 | + with warnings.catch_warnings(record=True) as recorded: |
| 339 | + warnings.simplefilter("always") |
| 340 | + Worker( |
| 341 | + client, |
| 342 | + task_queue=f"replay-metrics-{uuid.uuid4()}", |
| 343 | + activities=[replay_metrics_get_weather], |
| 344 | + workflows=[ReplayMetricsAgent], |
| 345 | + plugins=[GoogleAdkPlugin()], |
| 346 | + ) |
| 347 | + warned = [ |
| 348 | + w for w in recorded if "MeterProvider is not replay-safe" in str(w.message) |
| 349 | + ] |
| 350 | + assert len(warned) == 1 |
| 351 | + assert warned[0].category is UserWarning |
| 352 | + assert warned[0].filename == __file__ |
0 commit comments