Skip to content
Draft
5 changes: 5 additions & 0 deletions manifests/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,11 @@ manifest:
'*': missing_feature (Not yet implemented)
poc: v3.44.0
uds: v3.44.0
? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions_dictionary_value
: - weblog_declaration:
'*': missing_feature (Not yet implemented)
poc: v3.44.0
uds: v3.44.0
tests/debugger/test_debugger_capture_expressions_errors.py::Test_Debugger_Filter_Rejected_Capture_Expression_Error: # ProbeProcessor skips captureExpressions when `when` is false; #8725 rate-limits eval-error snapshots to 1/5min
- weblog_declaration:
'*': missing_feature (Not yet implemented)
Expand Down
2 changes: 2 additions & 0 deletions manifests/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1898,6 +1898,8 @@ manifest:
rails80: v2.38.0
uds-rails: v2.38.0
tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions: missing_feature (Local variable capture not implemented for method probes)
? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions_dictionary_value
: missing_feature (Local variable capture not implemented for method probes)
? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_method_local_capture_expressions
: missing_feature (Local variable capture not implemented for method probes)
? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_method_parameter_capture_expressions
Expand Down
18 changes: 18 additions & 0 deletions tests/debugger/test_debugger_capture_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,24 @@ def test_complex_capture_expressions(self):

self._validate_capture_expressions(expected_captures)

def setup_complex_capture_expressions_dictionary_value(self):
self._setup("probe_capture_expressions_complex", "/debugger/expression?inputValue=testValue", "log", lines=None)

def test_complex_capture_expressions_dictionary_value(self):
"""``testStruct.Dictionary['two']`` names an existing key, so it must capture 2, not a not-captured marker."""
self._assert()

expected_captures = {
probe_id: {
"dictionary_value": lambda v: (
isinstance(v, dict) and "notCapturedReason" not in v and str(v.get("value")) == "2"
),
}
for probe_id in self.probe_ids
}

self._validate_capture_expressions(expected_captures)


@features.debugger_line_probe
@scenarios.debugger_probes_snapshot
Expand Down
72 changes: 72 additions & 0 deletions tests/debugger/test_debugger_go_expression_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.

"""Go expression errors that the system-probe can detect, because Go types are fixed at compile time."""

import tests.debugger.utils as debugger
from utils import context, features, irrelevant, scenarios


class _GoExpressionTestBase(debugger.BaseDebuggerTest):
def _setup_probes(self, probes_name: str, install_statuses: list[debugger.ProbeStatus]) -> None:
self.initialize_weblog_remote_config()

probes = debugger.read_probes(probes_name)
for probe in probes:
probe["id"] = debugger.generate_probe_id("log")

self.set_probes(probes)
self.send_rc_probes()
self.wait_for_all_probes(statuses=install_statuses, timeout=30)
self.send_weblog_request("/debugger/expression?inputValue=asd")
self.wait_for_all_snapshots(timeout=10)


@features.debugger_expression_language
@scenarios.debugger_probes_snapshot
@irrelevant(context.library != "golang", reason="Only Go checks expression types at install time")
class Test_Debugger_Go_Static_Template_Error(_GoExpressionTestBase):
"""A template the system-probe already knows can never evaluate must be rejected, like the same condition is."""

def setup_static_template_error_probe_rejected(self) -> None:
self._setup_probes("probe_static_template_error", ["INSTALLED", "ERROR"])

def test_static_template_error_probe_rejected(self) -> None:
"""Reject log templates with an invalid map member, unknown variable, or missing struct field."""
self.collect()
self.assert_setup_ok()

for probe_id in self.probe_ids:
diag = self.probe_diagnostics.get(probe_id)
assert diag is not None, "The probe did not receive any diagnostic."
assert diag["status"] == "ERROR", (
f"Probe reached status {diag['status']!r}; its template can never evaluate, so it must be "
f"rejected with status=ERROR like the equivalent condition."
)


@features.debugger_expression_language
@scenarios.debugger_probes_snapshot
@irrelevant(context.library != "golang", reason="Go-specific repro for map index conditions")
class Test_Debugger_Go_Missing_Map_Key_Condition(_GoExpressionTestBase):
"""A condition on a key that isn't in the map must not fire."""

def setup_missing_map_key_condition_does_not_fire(self) -> None:
self._setup_probes("probe_missing_map_key_condition", ["INSTALLED"])

def test_missing_map_key_condition_does_not_fire(self) -> None:
"""A missing Go map key reads as 0, so this condition must not capture data."""
self.collect()
self.assert_setup_ok()

for probe_id in self.probe_ids:
diag = self.probe_diagnostics.get(probe_id)
assert diag is not None, f"Probe {probe_id} received no install diagnostic"
assert diag["status"] in ("INSTALLED", "EMITTING"), f"Probe {probe_id} did not install: {diag['status']!r}"
for envelope in self.probe_snapshots.get(probe_id, []):
snap = envelope.get("debugger", {}).get("snapshot") or envelope.get("debugger.snapshot") or {}
assert not debugger.captures_contain_data(snap.get("captures")), (
"The probe emitted a snapshot with captured data, so the condition fired as if true. "
"A missing key in a map[string]int reads as 0, and 0 == 1 is false."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[
{
"language": "",
"type": "",
"id": "",
"version": 0,
"where": {
"typeName": "ACTUAL_TYPE_NAME",
"methodName": "Expression",
"sourceFile": null
},
"when": {
"dsl": "testStruct.Dictionary['nope'] == 1",
"json": {
"eq": [
{
"index": [
{"getmember": [{"ref": "testStruct"}, "Dictionary"]},
"nope"
]
},
1
]
}
},
"captureSnapshot": true,
"segments": [
{"str": "missing-map-key condition fired"}
]
}
]
86 changes: 86 additions & 0 deletions tests/debugger/utils/probes/probe_static_template_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[
{
"language": "",
"type": "",
"id": "",
"version": 0,
"where": {
"typeName": "ACTUAL_TYPE_NAME",
"methodName": "Expression",
"sourceFile": null
},
"captureSnapshot": false,
"segments": [
{
"str": "dot on map: "
},
{
"dsl": "testStruct.Dictionary.two",
"json": {
"getmember": [
{
"getmember": [
{
"ref": "testStruct"
},
"Dictionary"
]
},
"two"
]
}
}
]
},
{
"language": "",
"type": "",
"id": "",
"version": 0,
"where": {
"typeName": "ACTUAL_TYPE_NAME",
"methodName": "Expression",
"sourceFile": null
},
"captureSnapshot": false,
"segments": [
{
"str": "unknown variable: "
},
{
"dsl": "definitelyDoesNotExist",
"json": {
"ref": "definitelyDoesNotExist"
}
}
]
},
{
"language": "",
"type": "",
"id": "",
"version": 0,
"where": {
"typeName": "ACTUAL_TYPE_NAME",
"methodName": "Expression",
"sourceFile": null
},
"captureSnapshot": false,
"segments": [
{
"str": "missing struct field: "
},
{
"dsl": "testStruct.DefinitelyDoesNotExist",
"json": {
"getmember": [
{
"ref": "testStruct"
},
"DefinitelyDoesNotExist"
]
}
}
]
}
]
2 changes: 1 addition & 1 deletion utils/build/docker/golang/app/chi/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
2 changes: 1 addition & 1 deletion utils/build/docker/golang/app/echo/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
2 changes: 1 addition & 1 deletion utils/build/docker/golang/app/gin/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
2 changes: 1 addition & 1 deletion utils/build/docker/golang/app/net-http/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct {
StringValue: "one",
BoolValue: true,
Collection: []string{"one", "two", "three"},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10},
}
}

Expand Down
Loading