test: add unit tests for agent_debugger_sdk/telemetry (zero coverage) - #305
test: add unit tests for agent_debugger_sdk/telemetry (zero coverage)#305acailic wants to merge 2 commits into
Conversation
Covers both the no-op fallback paths (opentelemetry not installed, the only reachable branches in this environment) and the success paths (console export, otlp export with/without the otlp exporter package installed, get_tracer delegation) via injected fake modules in sys.modules. Brings telemetry/__init__.py from 0% to 100% coverage. Closes #304 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new unit test suite to raise coverage of the SDK’s optional OpenTelemetry telemetry shim (agent_debugger_sdk.telemetry) from 0% by exercising both the no-op fallback behavior and the “OTel installed” success paths via injected fake modules.
Changes:
- Introduces
tests/test_telemetry.pycoveringinit_telemetry(),get_tracer(), and the no-op tracer/context manager behavior. - Adds tests for console exporter setup and OTLP exporter setup/fallback by injecting fake
opentelemetry*modules intosys.modules.
Suppressed comments (1)
tests/test_telemetry.py:157
- In the OTLP success-path test, only the leaf module is injected into
sys.modules. Thefrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ...import ininit_telemetry()will still fail unless the parent packages (opentelemetry.exporter,...otlp,...proto,...grpc) also exist as packages. Create those package modules (with path) before setting the leaf exporter module.
otlp_exporter_mod = ModuleType(
"opentelemetry.exporter.otlp.proto.grpc.trace_exporter"
)
otlp_exporter_mod.OTLPSpanExporter = MagicMock()
monkeypatch.setitem(
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| trace_mod = ModuleType("opentelemetry.trace") | ||
| otel_mod = ModuleType("opentelemetry") | ||
| otel_mod.trace = trace_mod | ||
| trace_mod.set_tracer_provider = MagicMock() | ||
| trace_mod.get_tracer = MagicMock(return_value="real-tracer") | ||
|
|
||
| sdk_trace_mod = ModuleType("opentelemetry.sdk.trace") | ||
| sdk_trace_mod.TracerProvider = MagicMock( | ||
| return_value=MagicMock(add_span_processor=MagicMock()) | ||
| ) | ||
|
|
||
| export_mod = ModuleType("opentelemetry.sdk.trace.export") | ||
| export_mod.BatchSpanProcessor = MagicMock() | ||
| export_mod.ConsoleSpanExporter = MagicMock() | ||
|
|
||
| sdk_mod = ModuleType("opentelemetry.sdk") | ||
| sdk_mod.trace = sdk_trace_mod | ||
|
|
There was a problem hiding this comment.
Fixed — fake modules now get __path__ (marked as packages) and are wired onto their parents (otel_mod.sdk = sdk_mod, etc.). Verified this specific concern by running the suite against a venv with real opentelemetry installed: without __path__ on the fake opentelemetry stub, an unrelated test (the otlp-fallback one) fell through to the real opentelemetry.exporter namespace package on disk and crashed with AttributeError: module 'opentelemetry' has no attribute '__path__'. Empty __path__ on the fakes now makes unregistered submodule imports fail cleanly instead.
| def test_init_telemetry_noop_when_opentelemetry_not_installed(caplog): | ||
| """init_telemetry should no-op and log when opentelemetry-sdk is unavailable.""" | ||
| import agent_debugger_sdk.telemetry as telemetry |
There was a problem hiding this comment.
Confirmed and fixed. Ran this test against a venv with opentelemetry actually installed — it failed as predicted. Added a no_opentelemetry fixture that shadows sys.modules['opentelemetry'] with a bare, path-less dummy module, forcing the ImportError branch deterministically. Test now passes in both a no-otel venv and a real-otel venv.
| def test_init_telemetry_accepts_otlp_args_without_crashing(): | ||
| """init_telemetry should not raise when called with an otlp exporter/endpoint, | ||
| even though opentelemetry is not installed (falls back to the no-op path).""" | ||
| import agent_debugger_sdk.telemetry as telemetry | ||
|
|
There was a problem hiding this comment.
Confirmed and fixed — same no_opentelemetry fixture applied here. Verified failing before the fix (against a venv with opentelemetry installed) and passing after.
| def test_get_tracer_returns_noop_tracer_when_opentelemetry_not_installed(): | ||
| """get_tracer should fall back to _NoOpTracer when opentelemetry is unavailable.""" | ||
| from agent_debugger_sdk.telemetry import _NoOpTracer, get_tracer | ||
|
|
There was a problem hiding this comment.
Confirmed and fixed — same no_opentelemetry fixture applied here. Verified failing before the fix (against a venv with opentelemetry installed) and passing after.
Fake opentelemetry package modules in the fake_opentelemetry fixture now get __path__ and are wired onto their parents, so unregistered submodule imports (e.g. opentelemetry.exporter.*) fail cleanly against an empty search path instead of falling through to whatever otel packages happen to be installed on the machine running the tests. Added a no_opentelemetry fixture that shadows sys.modules['opentelemetry'] with a bare, path-less dummy module so the no-op-path tests deterministically exercise the ImportError branch regardless of whether opentelemetry is actually installed in the test environment. Verified against a venv with opentelemetry installed: 4 tests (test_init_telemetry_noop_when_opentelemetry_not_installed, test_init_telemetry_accepts_otlp_args_without_crashing, test_get_tracer_returns_noop_tracer_when_opentelemetry_not_installed, test_init_telemetry_otlp_export_falls_back_to_console_when_exporter_missing) failed before this fix and pass after. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Summary
tests/test_telemetry.pycoveringagent_debugger_sdk/telemetry/__init__.py, previously at 0% coverageget_tracerdelegation) via injected fake modules insys.modulesCloses #304
Test plan
ruff check .cleanpytest -q tests/test_telemetry.py --cov=agent_debugger_sdk.telemetry --cov-report=term-missing→ 12 passed, 100% coveragepytest -q→ 3035 passed, 19 skipped, 0 failed (up from 3023 passed on main)🤖 Generated with Amplifier