Skip to content

Commit f901f95

Browse files
committed
add tests
1 parent 4ba62ec commit f901f95

File tree

1 file changed

+132
-1
lines changed

1 file changed

+132
-1
lines changed

tests/sentry/stacktraces/test_in_app_normalization.py

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22

33
from typing import Any
44

5-
from sentry.grouping.api import get_default_grouping_config_dict, load_grouping_config
5+
from sentry.grouping.api import (
6+
get_default_grouping_config_dict,
7+
get_grouping_config_dict_for_project,
8+
load_grouping_config,
9+
)
610
from sentry.stacktraces.processing import normalize_stacktraces_for_grouping
711
from sentry.testutils.cases import TestCase
12+
from sentry.utils.safe import get_path
813

914

1015
def make_stacktrace(frame_0_in_app="not set", frame_1_in_app="not set") -> dict[str, Any]:
@@ -132,6 +137,132 @@ def test_detects_frame_mix_correctly_with_multiple_stacktraces(self):
132137
), f"Expected {expected_frame_mix}, got {frame_mix} with stacktrace `in-app` values {stacktrace_0_mix}, {stacktrace_1_mix}"
133138

134139

140+
class DynamicProjectRootRuleTest(TestCase):
141+
def test_simple(self):
142+
stacktrace = {
143+
"frames": [
144+
{
145+
"abs_path": "/path/to/app/root/some/in_app/path/app_file.py",
146+
"context_line": "do_app_stuff()",
147+
},
148+
{
149+
"abs_path": "/path/to/virtual/env/some/package/path/library_file.py",
150+
"context_line": "do_third_party_stuff()",
151+
},
152+
]
153+
}
154+
155+
event_with_project_root = make_event([stacktrace])
156+
# TODO: For now this has to be added separately, since normalization strips it out
157+
event_with_project_root["debug_meta"] = {"project_root": "/path/to/app/root"}
158+
159+
grouping_config = load_grouping_config(get_grouping_config_dict_for_project(self.project))
160+
normalize_stacktraces_for_grouping(event_with_project_root, grouping_config)
161+
162+
# Without the dynamic rule, both frames would be `in_app: False`, as that's the default when
163+
# no value is provided in the stacktrace.
164+
frames = event_with_project_root["exception"]["values"][0]["stacktrace"]["frames"]
165+
assert frames[0]["in_app"] is True
166+
assert frames[1]["in_app"] is False
167+
168+
def test_applies_rule_in_edge_cases(self):
169+
for project_root, frame_path in [
170+
# Trailing slash
171+
("/path/to/app/root/", "/path/to/app/root/some/in_app/path/app_file.py"),
172+
# Windows path
173+
("C:\\path\\to\\app\\root", "C:\\path\\to\\app\\root\\some\\in_app\\path\\app_file.py"),
174+
# Windows path with a trailing backslash
175+
(
176+
"C:\\path\\to\\app\\root\\",
177+
"C:\\path\\to\\app\\root\\some\\in_app\\path\\app_file.py",
178+
),
179+
]:
180+
stacktrace = {
181+
"frames": [
182+
{
183+
"abs_path": frame_path,
184+
"context_line": "do_app_stuff()",
185+
},
186+
]
187+
}
188+
189+
event_with_project_root = make_event([stacktrace])
190+
# TODO: For now this has to be added separately, since normalization strips it out
191+
event_with_project_root["debug_meta"] = {"project_root": project_root}
192+
193+
grouping_config = load_grouping_config(
194+
get_grouping_config_dict_for_project(self.project)
195+
)
196+
normalize_stacktraces_for_grouping(event_with_project_root, grouping_config)
197+
198+
# Without the dynamic rule, the frame would be `in_app: False`, as that's the default
199+
# when no value is provided in the stacktrace.
200+
frames = event_with_project_root["exception"]["values"][0]["stacktrace"]["frames"]
201+
assert frames[0]["in_app"] is True, f"Case with project root {project_root} failed"
202+
203+
def test_applies_default_if_no_project_root(self):
204+
stacktrace = {
205+
"frames": [
206+
{
207+
"abs_path": "/path/to/app/root/some/in_app/path/app_file.py",
208+
"context_line": "do_app_stuff()",
209+
},
210+
{
211+
"abs_path": "/path/to/virtual/env/some/package/path/library_file.py",
212+
"context_line": "do_third_party_stuff()",
213+
},
214+
]
215+
}
216+
217+
event_without_project_root = make_event([stacktrace])
218+
assert get_path(event_without_project_root, "debug_meta", "project_root") is None
219+
220+
grouping_config = load_grouping_config(get_grouping_config_dict_for_project(self.project))
221+
normalize_stacktraces_for_grouping(event_without_project_root, grouping_config)
222+
223+
# The default `in_app` value if none is provided in the stacktrace is False.
224+
frames = event_without_project_root["exception"]["values"][0]["stacktrace"]["frames"]
225+
assert frames[0]["in_app"] is False
226+
assert frames[1]["in_app"] is False
227+
228+
def test_custom_rule_takes_precedence(self):
229+
stacktrace = {
230+
"frames": [
231+
{
232+
"abs_path": "/path/to/app/root/some/in_app/path/app_file.py",
233+
"context_line": "do_app_stuff()",
234+
},
235+
{
236+
"abs_path": "/path/to/app/root/some/other/in_app/path/some_other_file.py",
237+
"context_line": "do_other_app_stuff()",
238+
},
239+
]
240+
}
241+
242+
event_with_project_root = make_event([stacktrace])
243+
# TODO: For now this has to be added separately, since normalization strips it out
244+
event_with_project_root["debug_meta"] = {"project_root": "/path/to/app/root"}
245+
246+
# First, normalize with no custom rules - both frames should come out as in-app because of
247+
# the dynamically-created rule
248+
grouping_config = load_grouping_config(get_grouping_config_dict_for_project(self.project))
249+
normalize_stacktraces_for_grouping(event_with_project_root, grouping_config)
250+
251+
frames = event_with_project_root["exception"]["values"][0]["stacktrace"]["frames"]
252+
assert frames[0]["in_app"] is True
253+
assert frames[1]["in_app"] is True
254+
255+
# Now, add a custom rule and normalize again
256+
self.project.update_option("sentry:grouping_enhancements", "path:**/app_file.py -app")
257+
grouping_config = load_grouping_config(get_grouping_config_dict_for_project(self.project))
258+
normalize_stacktraces_for_grouping(event_with_project_root, grouping_config)
259+
260+
# The first frame is now `in_app: False`, showing the custom rule won out
261+
frames = event_with_project_root["exception"]["values"][0]["stacktrace"]["frames"]
262+
assert frames[0]["in_app"] is False
263+
assert frames[1]["in_app"] is True
264+
265+
135266
class MacOSInAppDetectionTest(TestCase):
136267
def test_macos_package_in_app_detection(self):
137268
data: dict[str, Any] = {

0 commit comments

Comments
 (0)