Skip to content

Commit a75b579

Browse files
mabdinurrobertomonteromiguel
authored andcommitted
telemetry: fix flaky configuration tests (#4283)
1 parent ebfd151 commit a75b579

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
lines changed

tests/parametric/conftest.py

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -376,21 +376,61 @@ def wait_for_telemetry_event(self, event_name: str, *, clear: bool = False, wait
376376
pass
377377
else:
378378
for event in events:
379-
if event["request_type"] == "message-batch":
380-
for message in event["payload"]:
381-
if message["request_type"] == event_name:
382-
if message.get("application", {}).get("language_version") != "SIDECAR":
383-
if clear:
384-
self.clear()
385-
return message
386-
elif event["request_type"] == event_name:
387-
if event.get("application", {}).get("language_version") != "SIDECAR":
388-
if clear:
389-
self.clear()
390-
return event
379+
e = self._get_telemetry_event(event, event_name)
380+
if e:
381+
if clear:
382+
self.clear()
383+
return e
391384
time.sleep(0.01)
392385
raise AssertionError(f"Telemetry event {event_name} not found")
393386

387+
def wait_for_telemetry_configurations(self, *, clear: bool = False) -> dict[str, str]:
388+
"""Waits for and returns the latest configurations captured in telemetry events.
389+
390+
Telemetry events can be found in `app-started` or `app-client-configuration-change` events.
391+
The function ensures that at least one telemetry event is captured before processing.
392+
"""
393+
events = []
394+
configurations = {}
395+
# Allow time for telemetry events to be captured
396+
time.sleep(1)
397+
# Attempt to retrieve telemetry events, suppressing request-related exceptions
398+
with contextlib.suppress(requests.exceptions.RequestException):
399+
events += self.telemetry(clear=False)
400+
if not events:
401+
raise AssertionError("No telemetry events were found. Ensure the application is sending telemetry events.")
402+
403+
# Sort events by tracer_time to ensure configurations are processed in order
404+
events.sort(key=lambda r: r["tracer_time"])
405+
# Extract configuration data from relevant telemetry events
406+
for event in events:
407+
for event_type in ["app-started", "app-client-configuration-change"]:
408+
telemetry_event = self._get_telemetry_event(event, event_type)
409+
if telemetry_event:
410+
for config in telemetry_event.get("payload", {}).get("configuration", []):
411+
# Store only the latest configuration for each name. This is the configuration
412+
# that should be used by the application.
413+
configurations[config["name"]] = config
414+
if clear:
415+
self.clear()
416+
return configurations
417+
418+
def _get_telemetry_event(self, event, request_type):
419+
"""Extracts telemetry events from a message batch or returns the telemetry event if it
420+
matches the expected request_type and was not emitted from a sidecar.
421+
"""
422+
if not event:
423+
return None
424+
elif event["request_type"] == "message-batch":
425+
for message in event["payload"]:
426+
if message["request_type"] == request_type:
427+
if message.get("application", {}).get("language_version") != "SIDECAR":
428+
return message
429+
elif event["request_type"] == request_type:
430+
if event.get("application", {}).get("language_version") != "SIDECAR":
431+
return event
432+
return None
433+
394434
def wait_for_rc_apply_state(
395435
self,
396436
product: str,

tests/parametric/test_telemetry.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,8 @@ class Test_Defaults:
7878
def test_library_settings(self, library_env, test_agent, test_library):
7979
with test_library.dd_start_span("test"):
8080
pass
81-
event = test_agent.wait_for_telemetry_event("app-started", wait_loops=400)
82-
configuration = event["payload"]["configuration"]
8381

84-
configuration_by_name = {item["name"]: item for item in configuration}
82+
configuration_by_name = test_agent.wait_for_telemetry_configurations()
8583
for apm_telemetry_name, value in [
8684
("trace_sample_rate", (1.0, None, "1.0")),
8785
("logs_injection_enabled", ("false", False, "true", True)),
@@ -152,10 +150,8 @@ class Test_Consistent_Configs:
152150
def test_library_settings(self, library_env, test_agent, test_library):
153151
with test_library.dd_start_span("test"):
154152
pass
155-
event = test_agent.wait_for_telemetry_event("app-started", wait_loops=400)
156-
configuration = event["payload"]["configuration"]
157-
configuration_by_name = {item["name"]: item for item in configuration}
158153

154+
configuration_by_name = test_agent.wait_for_telemetry_configurations()
159155
# # Check that the tags name match the expected value
160156
assert configuration_by_name.get("DD_ENV", {}).get("value") == "dev"
161157
assert configuration_by_name.get("DD_SERVICE", {}).get("value") == "service_test"
@@ -189,10 +185,8 @@ def test_library_settings(self, library_env, test_agent, test_library):
189185
def test_library_settings_2(self, library_env, test_agent, test_library):
190186
with test_library.dd_start_span("test"):
191187
pass
192-
event = test_agent.wait_for_telemetry_event("app-started", wait_loops=400)
193-
configuration = event["payload"]["configuration"]
194-
configuration_by_name = {item["name"]: item for item in configuration}
195188

189+
configuration_by_name = test_agent.wait_for_telemetry_configurations()
196190
assert configuration_by_name.get("DD_TRACE_LOG_DIRECTORY", {}).get("value") == "/some/temporary/directory"
197191
assert configuration_by_name.get("DD_TRACE_HTTP_CLIENT_ERROR_STATUSES", {}).get("value") == "200-250"
198192
assert configuration_by_name.get("DD_TRACE_HTTP_SERVER_ERROR_STATUSES", {}).get("value") == "250-200"
@@ -230,10 +224,8 @@ class Test_Environment:
230224
def test_library_settings(self, library_env, test_agent, test_library):
231225
with test_library.dd_start_span("test"):
232226
pass
233-
event = test_agent.wait_for_telemetry_event("app-started", wait_loops=400)
234-
configuration = event["payload"]["configuration"]
235227

236-
configuration_by_name = {item["name"]: item for item in configuration}
228+
configuration_by_name = test_agent.wait_for_telemetry_configurations()
237229
for apm_telemetry_name, environment_value in [
238230
("trace_sample_rate", ("0.3", 0.3)),
239231
("logs_injection_enabled", ("true", True)),
@@ -496,9 +488,8 @@ def test_stable_configuration_origin(
496488
)
497489
test_library.container_restart()
498490
test_library.dd_start_span("test")
499-
event = test_agent.wait_for_telemetry_event("app-started", wait_loops=400)
500-
configuration = {c["name"]: c for c in event["payload"]["configuration"]}
501491

492+
configuration = test_agent.wait_for_telemetry_configurations()
502493
for cfg_name, origin in expected_origin.items():
503494
apm_telemetry_name = _mapped_telemetry_name(context, cfg_name)
504495
telemetry_item = configuration[apm_telemetry_name]

0 commit comments

Comments
 (0)