19
19
)
20
20
from sentry .issues .ingest import (
21
21
_create_issue_kwargs ,
22
+ hash_fingerprint ,
22
23
materialize_metadata ,
23
24
save_issue_from_occurrence ,
24
25
save_issue_occurrence ,
28
29
from sentry .models .group import Group
29
30
from sentry .models .groupassignee import GroupAssignee
30
31
from sentry .models .groupenvironment import GroupEnvironment
32
+ from sentry .models .grouphash import GroupHash
31
33
from sentry .models .grouprelease import GroupRelease
32
34
from sentry .models .release import Release
33
35
from sentry .models .releaseprojectenvironment import ReleaseProjectEnvironment
@@ -213,6 +215,21 @@ def test_new_group(self) -> None:
213
215
},
214
216
)
215
217
218
+ def test_new_group_multiple_fingerprint (self ) -> None :
219
+ fingerprint = ["hi" , "bye" ]
220
+ occurrence = self .build_occurrence (type = ErrorGroupType .type_id , fingerprint = fingerprint )
221
+ event = self .store_event (project_id = self .project .id , data = {})
222
+
223
+ group_info = save_issue_from_occurrence (occurrence , event , None )
224
+ assert group_info is not None
225
+ assert group_info .is_new
226
+ assert not group_info .is_regression
227
+
228
+ group = group_info .group
229
+ assert group .title == occurrence .issue_title
230
+ grouphashes = set (GroupHash .objects .filter (group = group ).values_list ("hash" , flat = True ))
231
+ assert set (hash_fingerprint (fingerprint )) == grouphashes
232
+
216
233
def test_existing_group (self ) -> None :
217
234
event = self .store_event (data = {}, project_id = self .project .id )
218
235
occurrence = self .build_occurrence (fingerprint = ["some-fingerprint" ])
@@ -237,6 +254,77 @@ def test_existing_group(self) -> None:
237
254
assert updated_group .times_seen == 2
238
255
assert updated_group .message == "<unlabeled event> new title new subtitle api/123"
239
256
257
+ def test_existing_group_multiple_fingerprints (self ) -> None :
258
+ fingerprint = ["some-fingerprint" ]
259
+ event = self .store_event (data = {}, project_id = self .project .id )
260
+ occurrence = self .build_occurrence (fingerprint = fingerprint )
261
+ group_info = save_issue_from_occurrence (occurrence , event , None )
262
+ assert group_info is not None
263
+ assert group_info .is_new
264
+ grouphashes = set (
265
+ GroupHash .objects .filter (group = group_info .group ).values_list ("hash" , flat = True )
266
+ )
267
+ assert set (hash_fingerprint (fingerprint )) == grouphashes
268
+
269
+ fingerprint = ["some-fingerprint" , "another-fingerprint" ]
270
+ new_event = self .store_event (data = {}, project_id = self .project .id )
271
+ new_occurrence = self .build_occurrence (fingerprint = fingerprint )
272
+ with self .tasks ():
273
+ updated_group_info = save_issue_from_occurrence (new_occurrence , new_event , None )
274
+ assert updated_group_info is not None
275
+ assert group_info .group .id == updated_group_info .group .id
276
+ assert not updated_group_info .is_new
277
+ assert not updated_group_info .is_regression
278
+ grouphashes = set (
279
+ GroupHash .objects .filter (group = group_info .group ).values_list ("hash" , flat = True )
280
+ )
281
+ assert set (hash_fingerprint (fingerprint )) == grouphashes
282
+
283
+ def test_existing_group_multiple_fingerprints_overlap (self ) -> None :
284
+ fingerprint = ["some-fingerprint" ]
285
+ group_info = save_issue_from_occurrence (
286
+ self .build_occurrence (fingerprint = fingerprint ),
287
+ self .store_event (data = {}, project_id = self .project .id ),
288
+ None ,
289
+ )
290
+ assert group_info is not None
291
+ assert group_info .is_new
292
+ grouphashes = set (
293
+ GroupHash .objects .filter (group = group_info .group ).values_list ("hash" , flat = True )
294
+ )
295
+ assert set (hash_fingerprint (fingerprint )) == grouphashes
296
+ other_fingerprint = ["another-fingerprint" ]
297
+ other_group_info = save_issue_from_occurrence (
298
+ self .build_occurrence (fingerprint = other_fingerprint ),
299
+ self .store_event (data = {}, project_id = self .project .id ),
300
+ None ,
301
+ )
302
+ assert other_group_info is not None
303
+ assert other_group_info .is_new
304
+ grouphashes = set (
305
+ GroupHash .objects .filter (group = other_group_info .group ).values_list ("hash" , flat = True )
306
+ )
307
+ assert set (hash_fingerprint (other_fingerprint )) == grouphashes
308
+
309
+ # Should process the in order, and not join an already used fingerprint
310
+ overlapping_fingerprint = ["another-fingerprint" , "some-fingerprint" ]
311
+ new_event = self .store_event (data = {}, project_id = self .project .id )
312
+ new_occurrence = self .build_occurrence (fingerprint = overlapping_fingerprint )
313
+ with self .tasks ():
314
+ overlapping_group_info = save_issue_from_occurrence (new_occurrence , new_event , None )
315
+ assert overlapping_group_info is not None
316
+ assert other_group_info .group .id == overlapping_group_info .group .id
317
+ assert not overlapping_group_info .is_new
318
+ assert not overlapping_group_info .is_regression
319
+ grouphashes = set (
320
+ GroupHash .objects .filter (group = group_info .group ).values_list ("hash" , flat = True )
321
+ )
322
+ assert set (hash_fingerprint (fingerprint )) == grouphashes
323
+ other_grouphashes = set (
324
+ GroupHash .objects .filter (group = other_group_info .group ).values_list ("hash" , flat = True )
325
+ )
326
+ assert set (hash_fingerprint (other_fingerprint )) == other_grouphashes
327
+
240
328
def test_existing_group_different_category (self ) -> None :
241
329
event = self .store_event (data = {}, project_id = self .project .id )
242
330
occurrence = self .build_occurrence (fingerprint = ["some-fingerprint" ])
0 commit comments