4
4
from unittest .mock import MagicMock , patch
5
5
6
6
from sentry .issues .occurrence_consumer import _process_message
7
- from sentry .issues .status_change_consumer import bulk_get_groups_from_fingerprints
7
+ from sentry .issues .status_change_consumer import bulk_get_groups_from_fingerprints , update_status
8
+ from sentry .issues .status_change_message import StatusChangeMessageData
8
9
from sentry .models .activity import Activity
9
10
from sentry .models .group import Group , GroupStatus
10
11
from sentry .models .grouphistory import GroupHistory , GroupHistoryStatus
@@ -20,13 +21,15 @@ def get_test_message_status_change(
20
21
fingerprint : list [str ] | None = None ,
21
22
new_status : int = GroupStatus .RESOLVED ,
22
23
new_substatus : int | None = None ,
24
+ detector_id : int | None = None ,
23
25
) -> dict [str , Any ]:
24
26
payload = {
25
27
"project_id" : project_id ,
26
28
"fingerprint" : fingerprint or ["group-1" ],
27
29
"new_status" : new_status ,
28
30
"new_substatus" : new_substatus ,
29
31
"payload_type" : "status_change" ,
32
+ "detector_id" : detector_id ,
30
33
}
31
34
32
35
return payload
@@ -345,3 +348,119 @@ def test_bulk_get_single_project_multiple_hash(self) -> None:
345
348
tuple ([* other_occurrence .fingerprint , * self .occurrence .fingerprint ]),
346
349
): other_group
347
350
}
351
+
352
+
353
+ class TestStatusChangeRegistry (IssueOccurrenceTestBase ):
354
+ def setUp (self ) -> None :
355
+ super ().setUp ()
356
+ self .detector = self .create_detector ()
357
+ self .group = self .create_group (
358
+ project = self .project ,
359
+ status = GroupStatus .UNRESOLVED ,
360
+ substatus = GroupSubStatus .ESCALATING ,
361
+ )
362
+
363
+ status_change = get_test_message_status_change (
364
+ self .project .id ,
365
+ new_status = GroupStatus .RESOLVED ,
366
+ detector_id = self .detector .id ,
367
+ )
368
+
369
+ self .message = StatusChangeMessageData (
370
+ id = "test-id" ,
371
+ project_id = status_change ["project_id" ],
372
+ fingerprint = status_change ["fingerprint" ],
373
+ new_status = status_change ["new_status" ],
374
+ new_substatus = status_change .get ("new_substatus" ),
375
+ detector_id = status_change .get ("detector_id" ),
376
+ )
377
+
378
+ def get_latest_activity (self , activity_type : ActivityType ) -> Activity :
379
+ latest_activity = (
380
+ Activity .objects .filter (group_id = self .group .id , type = activity_type .value )
381
+ .order_by ("-datetime" )
382
+ .first ()
383
+ )
384
+
385
+ if latest_activity is None :
386
+ raise AssertionError (f"No activity found for type { activity_type } " )
387
+
388
+ return latest_activity
389
+
390
+ def test_handler_is_called__resolved (self ) -> None :
391
+ with patch (
392
+ "sentry.issues.status_change_consumer.group_status_update_registry" ,
393
+ ) as mock_registry :
394
+ mock_handler = MagicMock ()
395
+ mock_registry .registrations = {
396
+ "test_status_change" : mock_handler ,
397
+ }
398
+
399
+ update_status (self .group , self .message )
400
+ latest_activity = self .get_latest_activity (ActivityType .SET_RESOLVED )
401
+
402
+ mock_handler .assert_called_once_with (self .group , self .message , latest_activity )
403
+
404
+ def test_handler_is_not_called__unresolved_escalating (self ) -> None :
405
+ # There will be an issue occurrence that triggers this instead
406
+
407
+ self .message ["new_status" ] = GroupStatus .UNRESOLVED
408
+ self .message ["new_substatus" ] = GroupSubStatus .ESCALATING
409
+ with patch (
410
+ "sentry.issues.status_change_consumer.group_status_update_registry" ,
411
+ ) as mock_registry :
412
+ mock_handler = MagicMock ()
413
+ mock_registry .registrations = {
414
+ "test_status_change" : mock_handler ,
415
+ }
416
+
417
+ update_status (self .group , self .message )
418
+ assert mock_handler .call_count == 0
419
+
420
+ def test_handler_is_called_unresolved_ongoing (self ) -> None :
421
+ self .message ["new_status" ] = GroupStatus .UNRESOLVED
422
+ self .message ["new_substatus" ] = GroupSubStatus .ONGOING
423
+
424
+ with patch (
425
+ "sentry.issues.status_change_consumer.group_status_update_registry" ,
426
+ ) as mock_registry :
427
+ mock_handler = MagicMock ()
428
+ mock_registry .registrations = {
429
+ "test_status_change" : mock_handler ,
430
+ }
431
+
432
+ update_status (self .group , self .message )
433
+ latest_activity = self .get_latest_activity (ActivityType .AUTO_SET_ONGOING )
434
+ mock_handler .assert_called_once_with (self .group , self .message , latest_activity )
435
+
436
+ def test_handler_is_called__unresolved_regressed (self ) -> None :
437
+ self .message ["new_status" ] = GroupStatus .UNRESOLVED
438
+ self .message ["new_substatus" ] = GroupSubStatus .REGRESSED
439
+
440
+ with patch (
441
+ "sentry.issues.status_change_consumer.group_status_update_registry" ,
442
+ ) as mock_registry :
443
+ mock_handler = MagicMock ()
444
+ mock_registry .registrations = {
445
+ "test_status_change" : mock_handler ,
446
+ }
447
+
448
+ update_status (self .group , self .message )
449
+ latest_activity = self .get_latest_activity (ActivityType .SET_REGRESSION )
450
+ mock_handler .assert_called_once_with (self .group , self .message , latest_activity )
451
+
452
+ def test_handler_is_called__ignored (self ) -> None :
453
+ self .message ["new_status" ] = GroupStatus .IGNORED
454
+ self .message ["new_substatus" ] = GroupSubStatus .FOREVER
455
+
456
+ with patch (
457
+ "sentry.issues.status_change_consumer.group_status_update_registry" ,
458
+ ) as mock_registry :
459
+ mock_handler = MagicMock ()
460
+ mock_registry .registrations = {
461
+ "test_status_change" : mock_handler ,
462
+ }
463
+
464
+ update_status (self .group , self .message )
465
+ latest_activity = self .get_latest_activity (ActivityType .SET_IGNORED )
466
+ mock_handler .assert_called_once_with (self .group , self .message , latest_activity )
0 commit comments