Skip to content

Commit 4099769

Browse files
add tests
1 parent 140ce27 commit 4099769

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

tests/observability/core/test_agent365.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
Agent365ExporterOptions,
1010
)
1111
from microsoft_agents_a365.observability.core.trace_processor import SpanProcessor
12+
from opentelemetry import trace as otel_trace
13+
from opentelemetry.sdk.resources import Resource
14+
from opentelemetry.sdk.trace import TracerProvider
1215

1316

1417
class TestAgent365Configure(unittest.TestCase):
@@ -19,6 +22,16 @@ def setUp(self):
1922
self.mock_token_resolver = Mock()
2023
self.mock_token_resolver.return_value = "test_token_123"
2124

25+
def tearDown(self):
26+
"""Clean up after each test."""
27+
# Reset the telemetry manager singleton state
28+
from microsoft_agents_a365.observability.core.config import _telemetry_manager
29+
30+
_telemetry_manager._tracer_provider = None
31+
_telemetry_manager._span_processors = {}
32+
33+
otel_trace._TRACER_PROVIDER = None
34+
2235
def test_configure_basic_functionality(self):
2336
"""Test configure function with basic parameters and legacy parameters."""
2437
# Test basic configuration without exporter_options
@@ -112,6 +125,105 @@ def test_span_processor_creation(self):
112125
processor = SpanProcessor()
113126
self.assertIsNotNone(processor, "SpanProcessor should be created successfully")
114127

128+
def test_configure_prevents_duplicate_initialization(self):
129+
"""Test that calling configure() multiple times doesn't reinitialize."""
130+
result1 = configure(
131+
service_name="test-service-1",
132+
service_namespace="test-namespace-1",
133+
)
134+
self.assertTrue(result1)
135+
136+
with patch(
137+
"microsoft_agents_a365.observability.core.config._telemetry_manager._logger"
138+
) as mock_logger:
139+
result2 = configure(
140+
service_name="test-service-2",
141+
service_namespace="test-namespace-2",
142+
)
143+
self.assertTrue(result2)
144+
mock_logger.warning.assert_called_once()
145+
self.assertIn("already configured", mock_logger.warning.call_args[0][0].lower())
146+
147+
@patch("microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled")
148+
@patch("microsoft_agents_a365.observability.core.config.TracerProvider")
149+
def test_configure_creates_new_tracer_provider(self, mock_provider_class, mock_is_enabled):
150+
"""Test configure() creates new TracerProvider when none exists and adds processors."""
151+
mock_is_enabled.return_value = False
152+
153+
new_provider = TracerProvider(
154+
resource=Resource.create({
155+
"service.name": "test-service",
156+
"service.namespace": "test-namespace",
157+
})
158+
)
159+
mock_provider_class.return_value = new_provider
160+
161+
result = configure(service_name="test-service", service_namespace="test-namespace")
162+
self.assertTrue(result)
163+
164+
# Verify both processors were added by inspecting the MultiSpanProcessor
165+
166+
active_processor = new_provider._active_span_processor
167+
self.assertIsNotNone(active_processor)
168+
169+
# MultiSpanProcessor has a _span_processors list
170+
processors = active_processor._span_processors
171+
self.assertEqual(
172+
len(processors), 2, "Should have 2 processors: BatchSpanProcessor and SpanProcessor"
173+
)
174+
175+
# Verify types of processors
176+
processor_types = [type(p).__name__ for p in processors]
177+
self.assertIn("BatchSpanProcessor", processor_types)
178+
self.assertIn("SpanProcessor", processor_types)
179+
180+
@patch("microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled")
181+
@patch("microsoft_agents_a365.observability.core.config.trace.get_tracer_provider")
182+
def test_configure_uses_existing_tracer_provider(self, mock_get_provider, mock_is_enabled):
183+
"""Test configure() uses existing TracerProvider and adds processors without calling set_tracer_provider."""
184+
mock_is_enabled.return_value = False
185+
186+
existing_provider = TracerProvider(
187+
resource=Resource.create({"service.name": "existing-service"})
188+
)
189+
mock_get_provider.return_value = existing_provider
190+
191+
with patch(
192+
"microsoft_agents_a365.observability.core.config._telemetry_manager._logger"
193+
) as mock_logger:
194+
with patch(
195+
"microsoft_agents_a365.observability.core.config.trace.set_tracer_provider"
196+
) as mock_set:
197+
result = configure(service_name="new-service", service_namespace="new-namespace")
198+
self.assertTrue(result)
199+
200+
# Verify existing provider was detected
201+
info_calls = [call[0][0] for call in mock_logger.info.call_args_list]
202+
self.assertTrue(
203+
any("Detected existing TracerProvider" in msg for msg in info_calls)
204+
)
205+
206+
# Verify didn't call set_tracer_provider
207+
mock_set.assert_not_called()
208+
209+
# Verify both processors were added by inspecting the MultiSpanProcessor
210+
211+
active_processor = existing_provider._active_span_processor
212+
self.assertIsNotNone(active_processor)
213+
214+
# MultiSpanProcessor has a _span_processors list
215+
processors = active_processor._span_processors
216+
self.assertEqual(
217+
len(processors),
218+
2,
219+
"Should have 2 processors: BatchSpanProcessor and SpanProcessor",
220+
)
221+
222+
# Verify types of processors
223+
processor_types = [type(p).__name__ for p in processors]
224+
self.assertIn("BatchSpanProcessor", processor_types)
225+
self.assertIn("SpanProcessor", processor_types)
226+
115227

116228
if __name__ == "__main__":
117229
unittest.main()

tests/observability/core/test_agent365_exporter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,18 @@ def test_export_error_logging(self, mock_logger):
372372
"No spans with tenant/agent identity found; nothing exported."
373373
)
374374

375+
def test_exporter_is_internal(self):
376+
"""Test that _Agent365Exporter is marked as internal/private.
377+
378+
The underscore prefix convention indicates this class is internal to the SDK
379+
and should not be instantiated directly by developers.
380+
"""
381+
382+
self.assertTrue(
383+
_Agent365Exporter.__name__.startswith("_"),
384+
"Exporter class should be prefixed with underscore to indicate it's private/internal",
385+
)
386+
375387

376388
if __name__ == "__main__":
377389
unittest.main()

0 commit comments

Comments
 (0)