This document provides a comprehensive overview of all validation methods available in the AgentInterfaceValidator class. The agent interface validates messages intercepted between the Datadog Agent and the Datadog Backend.
The AgentInterfaceValidator is instantiated as a singleton in utils/interfaces/__init__.py and can be accessed as interfaces.agent in your test cases. It intercepts and validates JSON messages stored in the logs_<scenario_name>/interfaces/agent folder.
from utils import interfaces, weblog
from utils import scenarios
@scenarios.scenario
class MyTestClass:
def setup_my_test(self):
# Generate traces by making requests
self.r = weblog.get("/endpoint")
def test_my_validation(self):
# Use validation methods to verify intercepted data
interfaces.agent.assert_trace_exists(self.r)
# Validate custom span data
def span_validator(span):
return span.get("service") == "my-service"
spans = list(interfaces.agent.get_spans(self.r))
assert any(span_validator(span) for _, span in spans)get_spans(request=None)- Get spans submitted to backend, optionally filtered by requestget_spans_list(request)- Get spans for a specific request as a listget_telemetry_data(*, flatten_message_batches=True)- Get telemetry data sent to backendget_profiling_data()- Get profiling data from/api/v2/profileendpointget_metrics()- Get metrics submitted to/api/v2/seriesendpointget_sketches()- Get distribution sketches from/api/beta/sketchesendpointget_stats(resource="")- Get APM stats from/api/v0.2/stats, optionally filtered by resourceget_dsm_data()- Get Data Streams Monitoring data from/api/v0.1/pipeline_stats
assert_trace_exists(request)- Assert at least one trace exists for requestvalidate_appsec(request, validator)- Validate AppSec data using custom validator function
assert_headers_presence(path_filter, request_headers=(), response_headers=(), check_condition=None)- Validate presence of HTTP headers in agent communicationsassert_headers_match(path_filter, request_headers=None, response_headers=None, check_condition=None)- Validate HTTP headers match expected values
The agent interface differs from the library interface in several important ways:
- Data Source: Validates data after it has been processed by the agent, not raw tracer output
- Endpoints: Monitors backend API endpoints (
/api/v0.2/traces,/api/v2/series, etc.) - Data Structure: Works with agent-formatted payloads including
tracerPayloads,chunks, and aggregated data - Scope: Focuses on agent-to-backend communication rather than tracer-to-agent
- Use request filtering: Always filter by specific requests when possible to avoid interference from other tests
- Understand data flow: Agent interface data represents what reaches the backend, which may be sampled, aggregated, or modified by the agent
- Combine with library validation: Use both library and agent interfaces together to validate the complete data pipeline
- Check data transformation: Verify that data transformations performed by the agent are correct
- Validate aggregations: Use stats and metrics methods to ensure proper aggregation by the agent
def test_agent_trace_forwarding(self):
r = weblog.get("/")
interfaces.agent.assert_trace_exists(r)
# Verify spans reach the backend with correct structure
spans = list(interfaces.agent.get_spans(r))
assert len(spans) > 0
for _, span in spans:
assert "trace_id" in span
assert "span_id" in spandef test_appsec_agent_forwarding(self):
r = weblog.get("/", headers={"X-Attack": "' OR 1=1--"})
appsec_spans = list(interfaces.agent.get_appsec_data(r))
assert len(appsec_spans) > 0
for data, span, appsec_data in appsec_spans:
assert "triggers" in appsec_datadef test_agent_metrics_collection(self):
r = weblog.get("/")
# Check that metrics are properly collected and forwarded
metrics = list(interfaces.agent.get_metrics())
assert len(metrics) > 0
for _, metric in metrics:
assert "metric" in metric
assert "points" in metricdef test_agent_stats_aggregation(self):
r = weblog.get("/")
# Verify stats are aggregated by resource
stats = list(interfaces.agent.get_stats(resource="/"))
assert len(stats) > 0
for stat in stats:
assert stat["Resource"] == "/"
assert "Hits" in stat
assert "Duration" in statdef test_agent_telemetry_forwarding(self):
def telemetry_validator(data):
content = data["request"]["content"]
return content.get("request_type") == "generate-metrics"
interfaces.agent.validate_telemetry(telemetry_validator)def test_custom_span_processing(self):
r = weblog.get("/")
def span_validator(data):
content = data["request"]["content"]
if "tracerPayloads" not in content:
return False
for payload in content["tracerPayloads"]:
for chunk in payload["chunks"]:
for span in chunk["spans"]:
if span.get("service") == "my-service":
return True
return False
interfaces.agent.add_traces_validation(span_validator)The agent interface sits in the middle of the data pipeline:
[Tracer] → [Agent] → [Backend]
↑
Agent Interface
(validates here)
This means:
- Data has been processed/transformed by the agent
- Sampling decisions have been applied
- Stats aggregation has occurred
- Rate limiting may have been applied
- End-to-End Validation: Ensure data flows completely through the system
- Agent Processing: Verify agent correctly processes and forwards data
- Sampling Verification: Check that sampling decisions are properly applied
- Aggregation Testing: Validate stats and metrics aggregation
- Performance Monitoring: Ensure profiling and metrics collection works
- Security Integration: Verify AppSec events are properly forwarded