Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Debugger] Add mix log test scenario + refactor #1632

Merged
merged 4 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ jobs:
run: ./run.sh DEBUGGER_LINE_PROBES_SNAPSHOT
env:
DD_API_KEY: ${{ secrets.DD_API_KEY }}
- name: Run DEBUGGER_MIX_LOG_PROBE scenario
if: always() && steps.build.outcome == 'success' && needs.scenarios.outputs.run_debugger == 'true'
run: ./run.sh DEBUGGER_MIX_LOG_PROBE
env:
DD_API_KEY: ${{ secrets.DD_API_KEY }}
- name: Run all scenarios in replay mode
if: always() && steps.build.outcome == 'success' && needs.scenarios.outputs.run_all == 'true'
run: |
Expand Down Expand Up @@ -508,6 +513,7 @@ jobs:
# ./run.sh DEBUGGER_METHOD_PROBES_SNAPSHOT --replay # currently not working on replay mode
./run.sh DEBUGGER_LINE_PROBES_STATUS --replay
# ./run.sh DEBUGGER_LINE_PROBES_SNAPSHOT --replay # currently not working on replay mode
# ./run.sh DEBUGGER_MIX_LOG_PROBE --replay # currently not working on replay mode
env:
DD_API_KEY: ${{ secrets.DD_API_KEY }}
DD_APPLICATION_KEY: ${{ secrets.DD_APPLICATION_KEY }}
Expand Down
1 change: 1 addition & 0 deletions manifests/cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ tests/:
Test_Debugger_Line_Probe_Statuses: missing_feature
Test_Debugger_Method_Probe_Snaphots: irrelevant
Test_Debugger_Method_Probe_Statuses: missing_feature
Test_Debugger_Mix_Log_Probe: irrelevant
integrations/:
test_db_integrations_sql.py:
Test_Agent_Mssql_db_integration: missing_feature
Expand Down
1 change: 1 addition & 0 deletions manifests/golang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ tests/:
Test_Debugger_Line_Probe_Statuses: missing_feature
Test_Debugger_Method_Probe_Snaphots: irrelevant
Test_Debugger_Method_Probe_Statuses: missing_feature
Test_Debugger_Mix_Log_Probe: irrelevant
integrations/:
test_db_integrations_sql.py:
Test_Agent_Mssql_db_integration: missing_feature
Expand Down
4 changes: 4 additions & 0 deletions manifests/java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,10 @@ tests/:
'*': missing_feature
spring-boot: v0.1 # real version not known
uds-spring-boot: v0.1 # real version not known
Test_Debugger_Mix_Log_Probe:
'*': missing_feature
spring-boot: v0.1 # real version not known
uds-spring-boot: v0.1 # real version not known
integrations/:
test_cassandra.py:
Test_Cassandra: bug (Endpoint is probably improperly implemented on weblog)
Expand Down
1 change: 1 addition & 0 deletions manifests/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ tests/:
Test_Debugger_Line_Probe_Statuses: missing_feature
Test_Debugger_Method_Probe_Snaphots: irrelevant
Test_Debugger_Method_Probe_Statuses: missing_feature
Test_Debugger_Mix_Log_Probe: irrelevant
integrations/:
test_db_integrations_sql.py:
Test_Agent_Mssql_db_integration:
Expand Down
1 change: 1 addition & 0 deletions manifests/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ tests/:
Test_Debugger_Line_Probe_Statuses: irrelevant
Test_Debugger_Method_Probe_Snaphots: irrelevant
Test_Debugger_Method_Probe_Statuses: irrelevant
Test_Debugger_Mix_Log_Probe: irrelevant
integrations/:
test_db_integrations_sql.py:
Test_Agent_Mssql_db_integration: missing_feature
Expand Down
1 change: 1 addition & 0 deletions manifests/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ tests/:
Test_Debugger_Line_Probe_Statuses: missing_feature
Test_Debugger_Method_Probe_Snaphots: missing_feature
Test_Debugger_Method_Probe_Statuses: missing_feature
Test_Debugger_Mix_Log_Probe: missing_feature
integrations/:
test_db_integrations_sql.py:
Test_Agent_Mssql_db_integration:
Expand Down
1 change: 1 addition & 0 deletions manifests/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ tests/:
Test_Debugger_Line_Probe_Statuses: missing_feature
Test_Debugger_Method_Probe_Snaphots: irrelevant
Test_Debugger_Method_Probe_Statuses: missing_feature
Test_Debugger_Mix_Log_Probe: irrelevant
integrations/:
test_db_integrations_sql.py:
Test_Agent_Mssql_db_integration: missing_feature
Expand Down
1 change: 1 addition & 0 deletions scenario_groups.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ DEBUGGER_SCENARIOS:
- DEBUGGER_METHOD_PROBES_SNAPSHOT
- DEBUGGER_LINE_PROBES_STATUS
- DEBUGGER_LINE_PROBES_SNAPSHOT
- DEBUGGER_MIX_LOG_PROBE
256 changes: 148 additions & 108 deletions tests/debugger/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,114 +5,122 @@
from utils import scenarios, interfaces, weblog


def validate_data(expected_probes, expected_snapshots, expected_traces):
check_info_endpoint()

log_map = get_debugger_log_map()
for expected_probe in expected_probes:
check_probe_status(expected_probe, log_map["probes"])

def validate_probes(expected_probes):
def get_probes_map():
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v2/logs"))
probe_hash = {}

for request in agent_logs_endpoint_requests:
content = request["request"]["content"]
if content is not None:
for content in content:
debugger = content["debugger"]
if "diagnostics" in debugger:
probe_id = debugger["diagnostics"]["probeId"]
probe_hash[probe_id] = debugger["diagnostics"]

return probe_hash

def check_probe_status(expected_id, expected_status, probe_status_map):
if expected_id not in probe_status_map:
raise ValueError("Probe " + expected_id + " was not received.")

actual_status = probe_status_map[expected_id]["status"]
if actual_status != expected_status:
raise ValueError(
"Received probe "
+ expected_id
+ " with status "
+ actual_status
+ ", but expected for "
+ expected_status
)

probe_map = get_probes_map()
for expected_id, expected_status in expected_probes.items():
check_probe_status(expected_id, expected_status, probe_map)


def validate_snapshots(expected_snapshots):
def get_snapshot_map():
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v2/logs"))
snapshot_hash = {}

for request in agent_logs_endpoint_requests:
content = request["request"]["content"]
if content is not None:
for content in content:
debugger = content["debugger"]
if "snapshot" in debugger:
probe_id = debugger["snapshot"]["probe"]["id"]
snapshot_hash[probe_id] = debugger["snapshot"]

return snapshot_hash

def check_snapshot(expected_id, snapshot_status_map):
if expected_id not in snapshot_status_map:
raise ValueError("Snapshot " + expected_id + " was not received.")

snapshot_map = get_snapshot_map()
for expected_snapshot in expected_snapshots:
check_snapshot(expected_snapshot, log_map["snapshots"])

trace_map = get_debugger_tracer_map()
for expected_trace in expected_traces:
check_trace(expected_trace, trace_map)


def get_debugger_log_map():
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v2/logs"))
log_hash = {"probes": {}, "snapshots": {}}

for request in agent_logs_endpoint_requests:
content = request["request"]["content"]
if content is not None:
for content in content:
debugger = content["debugger"]

if "diagnostics" in debugger:
probe_id = debugger["diagnostics"]["probeId"]
log_hash["probes"][probe_id] = debugger["diagnostics"]
elif "snapshot" in debugger:
probe_id = debugger["snapshot"]["probe"]["id"]
log_hash["snapshots"][probe_id] = debugger["snapshot"]

return log_hash


def get_debugger_tracer_map():
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v0.2/traces"))
span_hash = {}
for request in agent_logs_endpoint_requests:
content = request["request"]["content"]
if content is not None:
for payload in content["tracerPayloads"]:
for chunk in payload["chunks"]:
for span in chunk["spans"]:
if span["name"] == "dd.dynamic.span":
span_hash[span["meta"]["debugger.probeid"]] = span
else:
for key, value in span["meta"].items():
if key.startswith("_dd.di"):
span_hash[value] = span["meta"][key.split(".")[2]]

return span_hash


def check_probe_status(expected_id, probe_status_map):
expected_status = expected_id.split("-")[1].upper()

if expected_id not in probe_status_map:
raise ValueError("Probe " + expected_id + " was not received.")

actual_status = probe_status_map[expected_id]["status"]
if actual_status != expected_status:
raise ValueError(
"Received probe " + expected_id + " with status " + actual_status + ", but expected for " + expected_status
)

check_snapshot(expected_snapshot, snapshot_map)

def check_snapshot(expected_id, snapshot_status_map):
if expected_id not in snapshot_status_map:
raise ValueError("Snapshot " + expected_id + " was not received.")

def validate_spans(expected_spans):
def get_span_map():
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v0.2/traces"))
span_hash = {}
for request in agent_logs_endpoint_requests:
content = request["request"]["content"]
if content is not None:
for payload in content["tracerPayloads"]:
for chunk in payload["chunks"]:
for span in chunk["spans"]:
if span["name"] == "dd.dynamic.span":
span_hash[span["meta"]["debugger.probeid"]] = span
else:
for key, value in span["meta"].items():
if key.startswith("_dd.di"):
span_hash[value] = span["meta"][key.split(".")[2]]

def check_trace(expected_id, trace_map):
if expected_id not in trace_map:
raise ValueError("Trace " + expected_id + " was not received.")
return span_hash

def check_trace(expected_id, trace_map):
if expected_id not in trace_map:
raise ValueError("Trace " + expected_id + " was not received.")

def check_info_endpoint():
""" Check that agent exposes /v0.7/config endpoint """
for data in interfaces.library.get_data("/info"):
for endpoint in data["response"]["content"]["endpoints"]:
if endpoint == "/v0.7/config":
return

raise ValueError("Agent did not provide /v0.7/config endpoint")
span_map = get_span_map()
for expected_trace in expected_spans:
check_trace(expected_trace, span_map)


@scenarios.debugger_method_probes_status
class Test_Debugger_Method_Probe_Statuses:
def test_method_probe_status(self):
expected_data = [
"logProbe-received",
"logProbe-installed",
"metricProbe-received",
"metricProbe-installed",
"spanProbe-received",
"spanProbe-installed",
"spanDecorationProbe-received",
"spanDecorationProbe-installed",
]
validate_data(expected_data, [], [])
expected_probes = {
"loga0cf2-9e4e-45cf-9f39-591received": "RECEIVED",
"loga0cf2-9e4e-45cf-9f39-59installed": "INSTALLED",
"metricf2-9e4e-45cf-9f39-591received": "RECEIVED",
"metricf2-9e4e-45cf-9f39-59installed": "INSTALLED",
"span0cf2-9e4e-45cf-9f39-591received": "RECEIVED",
"span0cf2-9e4e-45cf-9f39-59installed": "INSTALLED",
"decorcf2-9e4e-45cf-9f39-591received": "RECEIVED",
"decorcf2-9e4e-45cf-9f39-59installed": "INSTALLED",
}

validate_probes(expected_probes)


@scenarios.debugger_line_probes_status
class Test_Debugger_Line_Probe_Statuses:
def test_line_probe_status(self):
expected_data = ["logProbe-installed", "metricProbe-installed", "spanDecorationProbe-installed"]
validate_data(expected_data, [], [])
expected_probes = {
"loga0cf2-9e4e-45cf-9f39-59installed": "INSTALLED",
"metricf2-9e4e-45cf-9f39-59installed": "INSTALLED",
"decorcf2-9e4e-45cf-9f39-59installed": "INSTALLED",
}

validate_probes(expected_probes)


class _Base_Debugger_Snapshot_Test:
Expand Down Expand Up @@ -166,16 +174,18 @@ def test_method_probe_snaphots(self):
assert self.span_probe_response.status_code == 200
assert self.span_decoration_probe_response.status_code == 200

expected_probes = [
"logProbe-installed",
"metricProbe-installed",
"spanProbe-installed",
"spanDecorationProbe-installed",
]
expected_snapshots = ["logProbe-installed"]
expected_traces = ["spanProbe-installed", "spanDecorationProbe-installed"]
expected_probes = {
"log170aa-acda-4453-9111-1478a6method": "INSTALLED",
"metricaa-acda-4453-9111-1478a6method": "INSTALLED",
"span70aa-acda-4453-9111-1478a6method": "INSTALLED",
"decor0aa-acda-4453-9111-1478a6method": "INSTALLED",
}
expected_snapshots = ["log170aa-acda-4453-9111-1478a6method"]
expected_spans = ["span70aa-acda-4453-9111-1478a6method", "decor0aa-acda-4453-9111-1478a6method"]

validate_data(expected_probes, expected_snapshots, expected_traces)
validate_probes(expected_probes)
validate_snapshots(expected_snapshots)
validate_spans(expected_spans)


@scenarios.debugger_line_probes_snapshot
Expand All @@ -199,12 +209,42 @@ def test_line_probe_snaphots(self):
assert self.metric_probe_response.status_code == 200
assert self.span_decoration_probe_response.status_code == 200

expected_probes = [
"logProbe-installed",
"metricProbe-installed",
"spanDecorationProbe-installed",
expected_probes = {
"log170aa-acda-4453-9111-1478a697line": "INSTALLED",
"metricaa-acda-4453-9111-1478a697line": "INSTALLED",
"decor0aa-acda-4453-9111-1478a697line": "INSTALLED",
}
expected_snapshots = ["log170aa-acda-4453-9111-1478a697line"]
expected_spans = ["decor0aa-acda-4453-9111-1478a697line"]

validate_probes(expected_probes)
validate_snapshots(expected_snapshots)
validate_spans(expected_spans)


@scenarios.debugger_mix_log_probe
class Test_Debugger_Mix_Log_Probe(_Base_Debugger_Snapshot_Test):
multi_probe_response = None

def setup_mix_probe(self):
interfaces.library.wait_for(self.wait_for_remote_config, timeout=30)
interfaces.agent.wait_for(self.wait_for_probe, timeout=30)
self.multi_probe_response = weblog.get("/debugger/mix/asd/1")

def test_mix_probe(self):
assert self.remote_config_is_sent is True
assert self.probe_installed is True
assert self.multi_probe_response.status_code == 200

expected_probes = {
"logfb5a-1974-4cdb-b1dd-77dba2method": "INSTALLED",
"logfb5a-1974-4cdb-b1dd-77dba2f1line": "INSTALLED",
}

expected_snapshots = [
"logfb5a-1974-4cdb-b1dd-77dba2method",
"logfb5a-1974-4cdb-b1dd-77dba2f1line",
]
expected_snapshots = ["logProbe-installed"]
expected_traces = ["spanDecorationProbe-installed"]

validate_data(expected_probes, expected_snapshots, expected_traces)
validate_probes(expected_probes)
validate_snapshots(expected_snapshots)
8 changes: 8 additions & 0 deletions utils/_context/_scenarios.py
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,14 @@ class scenarios:
doc="Test scenario for checking if debugger successfully generates snapshots for specific line probes",
)

debugger_mix_log_probe = EndToEndScenario(
"DEBUGGER_MIX_LOG_PROBE",
proxy_state={"mock_remote_config_backend": "DEBUGGER_MIX_LOG_PROBE"},
weblog_env={"DD_DYNAMIC_INSTRUMENTATION_ENABLED": "1", "DD_REMOTE_CONFIG_ENABLED": "true",},
library_interface_timeout=5,
doc="Set both method and line probes at the same code",
)

fuzzer = _DockerScenario("_FUZZER", doc="Fake scenario for fuzzing (launch without pytest)")


Expand Down
Loading