|
3 | 3 | # Licensed under the MIT License. See License.txt in the project root for |
4 | 4 | # license information. |
5 | 5 | # -------------------------------------------------------------------------- |
| 6 | +import logging |
6 | 7 | from unittest.mock import patch |
7 | 8 | import pytest |
8 | | -from featuremanagement import EvaluationEvent, FeatureFlag, Variant, VariantAssignmentReason |
| 9 | +from featuremanagement import EvaluationEvent, FeatureFlag, Variant, VariantAssignmentReason, TargetingContext |
9 | 10 | import featuremanagement.azuremonitor._send_telemetry |
| 11 | +from featuremanagement.azuremonitor import TargetingSpanProcessor |
10 | 12 |
|
11 | 13 |
|
12 | 14 | @pytest.mark.usefixtures("caplog") |
13 | 15 | class TestSendTelemetryAppinsights: |
14 | 16 |
|
| 17 | + user_id = None |
| 18 | + |
15 | 19 | def test_send_telemetry_appinsights(self): |
16 | 20 | feature_flag = FeatureFlag.convert_from_json( |
17 | 21 | { |
@@ -211,3 +215,49 @@ def test_send_telemetry_appinsights_allocation(self): |
211 | 215 | assert mock_track_event.call_args[0][1]["VariantAssignmentReason"] == "Percentile" |
212 | 216 | assert mock_track_event.call_args[0][1]["VariantAssignmentPercentage"] == "25" |
213 | 217 | assert "DefaultWhenEnabled" not in mock_track_event.call_args[0][1] |
| 218 | + |
| 219 | + def test_targeting_span_processor(self, caplog): |
| 220 | + processor = TargetingSpanProcessor() |
| 221 | + processor.on_start(None) |
| 222 | + assert "" in caplog.text |
| 223 | + caplog.clear() |
| 224 | + |
| 225 | + processor = TargetingSpanProcessor(targeting_context_accessor="not callable") |
| 226 | + processor.on_start(None) |
| 227 | + assert "" in caplog.text |
| 228 | + caplog.clear() |
| 229 | + |
| 230 | + processor = TargetingSpanProcessor(targeting_context_accessor=self.bad_targeting_context_accessor) |
| 231 | + processor.on_start(None) |
| 232 | + assert ( |
| 233 | + "targeting_context_accessor did not return a TargetingContext. Received type <class 'str'>." in caplog.text |
| 234 | + ) |
| 235 | + caplog.clear() |
| 236 | + |
| 237 | + processor = TargetingSpanProcessor(targeting_context_accessor=self.async_targeting_context_accessor) |
| 238 | + processor.on_start(None) |
| 239 | + assert "Async targeting_context_accessor is not supported." in caplog.text |
| 240 | + caplog.clear() |
| 241 | + |
| 242 | + processor = TargetingSpanProcessor(targeting_context_accessor=self.accessor_callback) |
| 243 | + logging.getLogger().setLevel(logging.DEBUG) |
| 244 | + processor.on_start(None) |
| 245 | + assert "TargetingContext does not have a user ID." in caplog.text |
| 246 | + caplog.clear() |
| 247 | + |
| 248 | + with patch("opentelemetry.sdk.trace.Span") as mock_span: |
| 249 | + self.user_id = "test_user" |
| 250 | + processor.on_start(mock_span) |
| 251 | + assert mock_span.set_attribute.call_args[0][0] == "TargetingId" |
| 252 | + assert mock_span.set_attribute.call_args[0][1] == "test_user" |
| 253 | + |
| 254 | + self.user_id = None |
| 255 | + |
| 256 | + def bad_targeting_context_accessor(self): |
| 257 | + return "not targeting context" |
| 258 | + |
| 259 | + async def async_targeting_context_accessor(self): |
| 260 | + return TargetingContext(user_id=self.user_id) |
| 261 | + |
| 262 | + def accessor_callback(self): |
| 263 | + return TargetingContext(user_id=self.user_id) |
0 commit comments