99 Agent365ExporterOptions ,
1010)
1111from 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
1417class 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
116228if __name__ == "__main__" :
117229 unittest .main ()
0 commit comments