Skip to content

Commit 42793eb

Browse files
committed
add tests for using seer during grouping
1 parent db8287e commit 42793eb

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
from dataclasses import asdict
2+
from typing import Any
3+
from unittest.mock import MagicMock, patch
4+
5+
from sentry.conf.server import SEER_SIMILARITY_MODEL_VERSION
6+
from sentry.grouping.ingest.seer import get_seer_similar_issues, should_call_seer_for_grouping
7+
from sentry.seer.utils import SeerSimilarIssueData
8+
from sentry.testutils.cases import TestCase
9+
from sentry.testutils.helpers import Feature
10+
from sentry.testutils.helpers.eventprocessing import save_new_event
11+
from sentry.testutils.helpers.features import with_feature
12+
from sentry.testutils.pytest.mocking import capture_results
13+
from sentry.utils.types import NonNone
14+
15+
16+
class SeerEventManagerGroupingTest(TestCase):
17+
"""Test whether Seer is called during ingest and if so, how the results are used"""
18+
19+
def test_obeys_seer_similarity_flags(self):
20+
existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
21+
seer_result_data = SeerSimilarIssueData(
22+
parent_hash=existing_event.get_primary_hash(),
23+
parent_group_id=NonNone(existing_event.group_id),
24+
stacktrace_distance=0.01,
25+
message_distance=0.05,
26+
should_group=True,
27+
)
28+
metadata_base = {
29+
"similarity_model_version": SEER_SIMILARITY_MODEL_VERSION,
30+
"results": [asdict(seer_result_data)],
31+
}
32+
33+
get_seer_similar_issues_return_values: list[Any] = []
34+
35+
with (
36+
patch(
37+
"sentry.event_manager.should_call_seer_for_grouping",
38+
wraps=should_call_seer_for_grouping,
39+
) as should_call_seer_spy,
40+
patch(
41+
"sentry.event_manager.get_seer_similar_issues",
42+
wraps=capture_results(
43+
get_seer_similar_issues, get_seer_similar_issues_return_values
44+
),
45+
) as get_seer_similar_issues_spy,
46+
patch(
47+
"sentry.grouping.ingest.seer.get_similarity_data_from_seer",
48+
return_value=[seer_result_data],
49+
),
50+
):
51+
52+
with Feature(
53+
{
54+
"projects:similarity-embeddings-metadata": False,
55+
"projects:similarity-embeddings-grouping": False,
56+
}
57+
):
58+
new_event = save_new_event({"message": "Adopt don't shop"}, self.project)
59+
60+
# We checked whether to make the call, but didn't go through with it
61+
assert should_call_seer_spy.call_count == 1
62+
assert get_seer_similar_issues_spy.call_count == 0
63+
64+
# No metadata stored, parent group not used (even though `should_group` is True)
65+
assert "seer_similarity" not in NonNone(new_event.group).data["metadata"]
66+
assert "seer_similarity" not in new_event.data
67+
assert new_event.group_id != existing_event.group_id
68+
69+
should_call_seer_spy.reset_mock()
70+
get_seer_similar_issues_spy.reset_mock()
71+
72+
with Feature(
73+
{
74+
"projects:similarity-embeddings-metadata": True,
75+
"projects:similarity-embeddings-grouping": False,
76+
}
77+
):
78+
new_event = save_new_event({"message": "Maisey is silly"}, self.project)
79+
expected_metadata = {**metadata_base, "request_hash": new_event.get_primary_hash()}
80+
81+
# We checked whether to make the call, and then made it
82+
assert should_call_seer_spy.call_count == 1
83+
assert get_seer_similar_issues_spy.call_count == 1
84+
85+
# Metadata returned and stored
86+
assert get_seer_similar_issues_return_values[0][0] == expected_metadata
87+
assert (
88+
NonNone(new_event.group).data["metadata"]["seer_similarity"]
89+
== expected_metadata
90+
)
91+
assert new_event.data["seer_similarity"] == expected_metadata
92+
93+
# No parent group returned or used (even though `should_group` is True)
94+
assert get_seer_similar_issues_return_values[0][1] is None
95+
assert new_event.group_id != existing_event.group_id
96+
97+
should_call_seer_spy.reset_mock()
98+
get_seer_similar_issues_spy.reset_mock()
99+
get_seer_similar_issues_return_values.pop()
100+
101+
with Feature(
102+
{
103+
"projects:similarity-embeddings-metadata": False,
104+
"projects:similarity-embeddings-grouping": True,
105+
}
106+
):
107+
new_event = save_new_event({"message": "Charlie is goofy"}, self.project)
108+
expected_metadata = {**metadata_base, "request_hash": new_event.get_primary_hash()}
109+
110+
# We checked whether to make the call, and then made it
111+
assert should_call_seer_spy.call_count == 1
112+
assert get_seer_similar_issues_spy.call_count == 1
113+
114+
# Metadata returned and stored (metadata flag being off doesn't matter because
115+
# grouping flag takes precedence)
116+
assert get_seer_similar_issues_return_values[0][0] == expected_metadata
117+
assert new_event.data["seer_similarity"] == expected_metadata
118+
119+
# Parent group returned and used
120+
assert get_seer_similar_issues_return_values[0][1] == existing_event.group
121+
assert new_event.group_id == existing_event.group_id
122+
123+
should_call_seer_spy.reset_mock()
124+
get_seer_similar_issues_spy.reset_mock()
125+
get_seer_similar_issues_return_values.pop()
126+
127+
with Feature(
128+
{
129+
"projects:similarity-embeddings-metadata": True,
130+
"projects:similarity-embeddings-grouping": True,
131+
}
132+
):
133+
new_event = save_new_event(
134+
{"message": "Cori and Bodhi are ridiculous"}, self.project
135+
)
136+
expected_metadata = {**metadata_base, "request_hash": new_event.get_primary_hash()}
137+
138+
# We checked whether to make the call, and then made it
139+
assert should_call_seer_spy.call_count == 1
140+
assert get_seer_similar_issues_spy.call_count == 1
141+
142+
# Metadata returned and stored
143+
assert get_seer_similar_issues_return_values[0][0] == expected_metadata
144+
assert new_event.data["seer_similarity"] == expected_metadata
145+
146+
# Parent group returned and used
147+
assert get_seer_similar_issues_return_values[0][1] == existing_event.group
148+
assert new_event.group_id == existing_event.group_id
149+
150+
@with_feature("projects:similarity-embeddings-metadata")
151+
@patch("sentry.event_manager.get_seer_similar_issues", return_value=({}, None))
152+
def test_calls_seer_if_no_group_found(self, mock_get_seer_similar_issues: MagicMock):
153+
save_new_event({"message": "Dogs are great!"}, self.project)
154+
assert mock_get_seer_similar_issues.call_count == 1
155+
156+
@with_feature("projects:similarity-embeddings-metadata")
157+
@patch("sentry.event_manager.get_seer_similar_issues", return_value=({}, None))
158+
def test_bypasses_seer_if_group_found(self, mock_get_seer_similar_issues: MagicMock):
159+
existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
160+
assert mock_get_seer_similar_issues.call_count == 1
161+
162+
new_event = save_new_event({"message": "Dogs are great!"}, self.project)
163+
assert existing_event.group_id == new_event.group_id
164+
assert mock_get_seer_similar_issues.call_count == 1 # didn't get called again
165+
166+
@with_feature("projects:similarity-embeddings-metadata")
167+
def test_stores_seer_results_in_metadata(self):
168+
existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
169+
170+
seer_result_data = SeerSimilarIssueData(
171+
parent_hash=existing_event.get_primary_hash(),
172+
parent_group_id=NonNone(existing_event.group_id),
173+
stacktrace_distance=0.01,
174+
message_distance=0.05,
175+
should_group=True,
176+
)
177+
178+
with patch(
179+
"sentry.grouping.ingest.seer.get_similarity_data_from_seer",
180+
return_value=[seer_result_data],
181+
):
182+
new_event = save_new_event({"message": "Adopt don't shop"}, self.project)
183+
expected_metadata = {
184+
"similarity_model_version": SEER_SIMILARITY_MODEL_VERSION,
185+
"request_hash": new_event.get_primary_hash(),
186+
"results": [asdict(seer_result_data)],
187+
}
188+
189+
assert NonNone(new_event.group).data["metadata"]["seer_similarity"] == expected_metadata
190+
assert new_event.data["seer_similarity"] == expected_metadata
191+
192+
@with_feature("projects:similarity-embeddings-grouping")
193+
def test_assigns_event_to_neighbor_group_if_found(self):
194+
existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
195+
196+
seer_result_data = SeerSimilarIssueData(
197+
parent_hash=existing_event.get_primary_hash(),
198+
parent_group_id=NonNone(existing_event.group_id),
199+
stacktrace_distance=0.01,
200+
message_distance=0.05,
201+
should_group=True,
202+
)
203+
204+
with patch(
205+
"sentry.grouping.ingest.seer.get_similarity_data_from_seer",
206+
return_value=[seer_result_data],
207+
):
208+
new_event = save_new_event({"message": "Adopt don't shop"}, self.project)
209+
210+
assert existing_event.group_id == new_event.group_id
211+
212+
@with_feature("projects:similarity-embeddings-grouping")
213+
def test_creates_new_group_if_no_neighbor_found(self):
214+
existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
215+
216+
with patch("sentry.grouping.ingest.seer.get_similarity_data_from_seer", return_value=[]):
217+
new_event = save_new_event({"message": "Adopt don't shop"}, self.project)
218+
219+
assert existing_event.group_id != new_event.group_id
220+
221+
@with_feature("projects:similarity-embeddings-grouping")
222+
def test_creates_new_group_if_too_far_neighbor_found(self):
223+
existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
224+
225+
no_cigar_data = SeerSimilarIssueData(
226+
parent_hash=existing_event.get_primary_hash(),
227+
parent_group_id=NonNone(existing_event.group_id),
228+
stacktrace_distance=0.10,
229+
message_distance=0.05,
230+
should_group=False,
231+
)
232+
233+
with patch(
234+
"sentry.grouping.ingest.seer.get_similarity_data_from_seer",
235+
return_value=[no_cigar_data],
236+
):
237+
new_event = save_new_event({"message": "Adopt don't shop"}, self.project)
238+
239+
assert existing_event.group_id != new_event.group_id

0 commit comments

Comments
 (0)