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

add: test line probe expression language support alongside methods DEBUG-3379 #3877

Merged
merged 8 commits into from
Jan 30, 2025
124 changes: 92 additions & 32 deletions tests/debugger/test_debugger_expression_language.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ def _validate_expression_language_messages(self, expected_message_map):
############ test ############
############ access variables ############
def setup_expression_language_access_variables(self):
language, method = self.get_tracer()["language"], "Expression"
message_map, probes = self._create_expression_probes(
methodName="Expression",
methodName=method,
expressions=[
["Accessing input", "asd", Dsl("ref", "inputValue")],
["Accessing return", ".*Great success number 3", Dsl("ref", "@return")],
["Accessing local", 3, Dsl("ref", "localValue")],
["Accessing complex object int", 1, Dsl("getmember", [Dsl("ref", "testStruct"), "IntValue"])],
["Accessing complex object double", 1.1, Dsl("getmember", [Dsl("ref", "testStruct"), "DoubleValue"])],
Expand All @@ -90,8 +90,8 @@ def setup_expression_language_access_variables(self):
2,
Dsl("index", [Dsl("getmember", [Dsl("ref", "testStruct"), "Dictionary"]), "two"]),
],
["Accessing duration", r"\d+(\.\d+)?", Dsl("ref", "@duration")],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -100,11 +100,30 @@ def setup_expression_language_access_variables(self):
def test_expression_language_access_variables(self):
self._assert(expected_response=200)

def setup_expression_language_contextual_variables(self):
message_map, probes = self._create_expression_probes(
methodName="Expression",
expressions=[
["Accessing return", ".*Great success number 3", Dsl("ref", "@return")],
["Accessing duration", r"\d+(\.\d+)?", Dsl("ref", "@duration")],
],
# We only capture @return and @duration in the context of a method probe.
lines=[],
)

self.message_map = message_map
self._setup(probes, "/debugger/expression?inputValue=asd")

def test_expression_language_contextual_variables(self):
self._assert(expected_response=200)

############ access exception ############
def setup_expression_language_access_exception(self):
language, method = self.get_tracer()["language"], "ExpressionException"
message_map, probes = self._create_expression_probes(
methodName="ExpressionException",
methodName=method,
expressions=[["Accessing exception", ".*Hello from exception", Dsl("ref", "@exception")]],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -115,8 +134,9 @@ def test_expression_language_access_exception(self):

############ comparison operators ############
def setup_expression_language_comparison_operators(self):
language, method = self.get_tracer()["language"], "ExpressionOperators"
message_map, probes = self._create_expression_probes(
methodName="ExpressionOperators",
methodName=method,
expressions=[
["intValue eq 5", True, Dsl("eq", [Dsl("ref", "intValue"), 5])],
["intValue ne 0", True, Dsl("ne", [Dsl("ref", "intValue"), 0])],
Expand Down Expand Up @@ -166,6 +186,7 @@ def setup_expression_language_comparison_operators(self):
["strValue le a", False, Dsl("le", [Dsl("ref", "strValue"), "a"])],
["strValue ge z", False, Dsl("ge", [Dsl("ref", "strValue"), "z"])],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -176,8 +197,9 @@ def test_expression_language_comparison_operators(self):

############ intance of ############
def setup_expression_language_instance_of(self):
language, method = self.get_tracer()["language"], "ExpressionOperators"
message_map, probes = self._create_expression_probes(
methodName="ExpressionOperators",
methodName=method,
expressions=[
["intValue instanceof int", True, Dsl("instanceof", [Dsl("ref", "intValue"), self._get_type("int")])],
[
Expand Down Expand Up @@ -217,6 +239,7 @@ def setup_expression_language_instance_of(self):
],
["pii instanceof string", False, Dsl("instanceof", [Dsl("ref", "pii"), self._get_type("string")])],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -228,8 +251,9 @@ def test_expression_language_instance_of(self):

############ logical operators ############
def setup_expression_language_logical_operators(self):
language, method = self.get_tracer()["language"], "ExpressionOperators"
message_map, probes = self._create_expression_probes(
methodName="ExpressionOperators",
methodName=method,
expressions=[
[
"intValue eq 5 and strValue ne 5",
Expand All @@ -254,6 +278,7 @@ def setup_expression_language_logical_operators(self):
],
["not intValue eq 10", False, Dsl("not", Dsl("eq", [Dsl("ref", "intValue"), 5]))],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -265,8 +290,9 @@ def test_expression_language_logical_operators(self):

############ string operations ############
def setup_expression_language_string_operations(self):
language, method = self.get_tracer()["language"], "StringOperations"
message_map, probes = self._create_expression_probes(
methodName="StringOperations",
methodName=method,
expressions=[
##### isempty
["strValue isEmpty", False, Dsl("isEmpty", Dsl("ref", "strValue"))],
Expand Down Expand Up @@ -300,6 +326,7 @@ def setup_expression_language_string_operations(self):
["emptyString matches empty", True, Dsl("matches", [Dsl("ref", "emptyString"), ""])],
["emptyString matches some", False, Dsl("matches", [Dsl("ref", "emptyString"), "foo"])],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -315,8 +342,9 @@ def test_expression_language_string_operations(self):
## all collection are filled with incremented number values (e.g at the [0] = 0; [1] = 1)

def setup_expression_language_collection_operations(self):
language, method = self.get_tracer()["language"], "CollectionOperations"
message_map, probes = self._create_expression_probes(
methodName="CollectionOperations",
methodName=method,
expressions=[
##### len
["Array0 len", 0, Dsl("len", Dsl("ref", "a0"))],
Expand Down Expand Up @@ -374,6 +402,7 @@ def setup_expression_language_collection_operations(self):
Dsl("len", Dsl("filter", [Dsl("ref", "l5"), Dsl("lt", [Dsl("ref", "@it"), 2])])),
],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -384,8 +413,9 @@ def test_expression_language_collection_operations(self):
self._assert(expected_response=200)

def setup_expression_language_hash_operations(self):
language, method = self.get_tracer()["language"], "CollectionOperations"
message_map, probes = self._create_expression_probes(
methodName="CollectionOperations",
methodName=method,
expressions=[
## at the app there are 3 types of collections are created - array, list and hash.
## the number at the end of variable means the length of the collection
Expand Down Expand Up @@ -517,6 +547,7 @@ def setup_expression_language_hash_operations(self):
),
],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -529,13 +560,15 @@ def test_expression_language_hash_operations(self):

############ nulls ############
def setup_expression_language_nulls_true(self):
language, method = self.get_tracer()["language"], "Nulls"
message_map, probes = self._create_expression_probes(
methodName="Nulls",
methodName=method,
expressions=[
["intValue eq null", True, Dsl("eq", [Dsl("ref", "intValue"), None])],
["strValue eq null", True, Dsl("eq", [Dsl("ref", "strValue"), None])],
["pii eq null", True, Dsl("eq", [Dsl("ref", "pii"), None])],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand All @@ -546,13 +579,15 @@ def test_expression_language_nulls_true(self):
self._assert(expected_response=200)

def setup_expression_language_nulls_false(self):
language, method = self.get_tracer()["language"], "Nulls"
message_map, probes = self._create_expression_probes(
methodName="Nulls",
methodName=method,
expressions=[
["intValue eq null", False, Dsl("eq", [Dsl("ref", "intValue"), None])],
["strValue eq null", False, Dsl("eq", [Dsl("ref", "strValue"), None])],
["pii eq null", False, Dsl("eq", [Dsl("ref", "pii"), None])],
],
lines=self._method_and_language_to_line_number(method, language),
)

self.message_map = message_map
Expand Down Expand Up @@ -614,28 +649,53 @@ def _get_hash_value_property_name(self):
else:
return "value"

def _create_expression_probes(self, methodName, expressions):
def _method_and_language_to_line_number(self, method, language):
"""
_method_and_language_to_line_number returns the respective line number given the method and language
"""
return {
"Expression": {"java": [71], "dotnet": [74], "python": [72]},
# The `@exception` variable is not available in the context of line probes.
"ExpressionException": {},
"ExpressionOperators": {"java": [82], "dotnet": [90], "python": [87]},
"StringOperations": {"java": [87], "dotnet": [97], "python": [96]},
"CollectionOperations": {"java": [114], "dotnet": [114], "python": [123]},
"Nulls": {"java": [130], "dotnet": [127], "python": [136]},
}.get(method, {}).get(language, [])

def _create_expression_probes(self, methodName, expressions, lines=[]):
probes = []
expected_message_map = {}

for expression in expressions:
expression_to_test, expected_result, dsl = expression
message = f"Expression to test: '{expression_to_test}'. Result is: "

if isinstance(expected_result, bool):
expected_result = "[Tt]rue" if expected_result else "[Ff]alse"
elif isinstance(expected_result, str) and expected_result and expected_result != "":
expected_result = f"[']?{expected_result}[']?"
else:
expected_result = str(expected_result)

probe = debugger.read_probes("expression_probe_base")[0]
probe["id"] = debugger.generate_probe_id("log")
probe["where"]["methodName"] = methodName
probe["segments"] = Segment().add_str(message).add_dsl(dsl).to_dict()
probes.append(probe)

expected_message_map[probe["id"]] = message + expected_result
prob_types = ["method"]
if len(lines) > 0:
prob_types.append("line")

for probe_type in prob_types:
for expression in expressions:
expression_to_test, expected_result, dsl = expression
message = f"Expression to test: '{expression_to_test}'. Result is: "

if isinstance(expected_result, bool):
expected_result = "[Tt]rue" if expected_result else "[Ff]alse"
elif isinstance(expected_result, str) and expected_result and expected_result != "":
expected_result = f"[']?{expected_result}[']?"
else:
expected_result = str(expected_result)

probe = debugger.read_probes("expression_probe_base")[0]
probe["id"] = debugger.generate_probe_id("log")
if probe_type == "method":
probe["where"]["methodName"] = methodName
if probe_type == "line":
del probe["where"]["methodName"]
probe["where"]["lines"] = lines
probe["where"]["sourceFile"] = "ACTUAL_SOURCE_FILE"
probe["where"]["typeName"] = None

probe["segments"] = Segment().add_str(message).add_dsl(dsl).to_dict()
probes.append(probe)

expected_message_map[probe["id"]] = message + expected_result

return expected_message_map, probes

Expand Down
Loading