@@ -204,6 +204,51 @@ def test_issue_closing_event(self):
204204 self .assertEqual (event_closing .closing_reason ,
205205 events .ClosingReason .TESTCASE_FIXED )
206206
207+ def test_testcase_grouping_event (self ):
208+ """Test testcase grouping event class."""
209+ event_type = events .EventTypes .TESTCASE_GROUPING
210+ source = 'events_test'
211+ testcase = test_utils .create_generic_testcase ()
212+ similar_testcase_id = 2
213+
214+ # Testcase is similar to another one.
215+ event_grouping = events .TestcaseGroupingEvent (
216+ source = source ,
217+ testcase = testcase ,
218+ group_id = 10 ,
219+ previous_group_id = 0 ,
220+ similar_testcase_id = similar_testcase_id ,
221+ grouping_reason = events .GroupingReason .SIMILAR_CRASH )
222+ self ._assert_event_common_fields (event_grouping , event_type , source )
223+ self ._assert_testcase_fields (event_grouping , testcase )
224+ self ._assert_task_fields (event_grouping )
225+ self .assertEqual (event_grouping .group_id , 10 )
226+ self .assertEqual (event_grouping .previous_group_id , 0 )
227+ self .assertEqual (event_grouping .similar_testcase_id , similar_testcase_id )
228+ self .assertEqual (event_grouping .grouping_reason ,
229+ events .GroupingReason .SIMILAR_CRASH )
230+ self .assertEqual (event_grouping .group_merge_reason , None )
231+
232+ # Testcase's group is being merged.
233+ event_grouping = events .TestcaseGroupingEvent (
234+ source = source ,
235+ testcase = testcase ,
236+ group_id = 10 ,
237+ previous_group_id = 5 ,
238+ similar_testcase_id = similar_testcase_id ,
239+ grouping_reason = events .GroupingReason .GROUP_MERGE ,
240+ group_merge_reason = events .GroupingReason .SAME_ISSUE )
241+ self ._assert_event_common_fields (event_grouping , event_type , source )
242+ self ._assert_testcase_fields (event_grouping , testcase )
243+ self ._assert_task_fields (event_grouping )
244+ self .assertEqual (event_grouping .group_id , 10 )
245+ self .assertEqual (event_grouping .previous_group_id , 5 )
246+ self .assertEqual (event_grouping .similar_testcase_id , similar_testcase_id )
247+ self .assertEqual (event_grouping .grouping_reason ,
248+ events .GroupingReason .GROUP_MERGE )
249+ self .assertEqual (event_grouping .group_merge_reason ,
250+ events .GroupingReason .SAME_ISSUE )
251+
207252 def test_task_execution_event (self ):
208253 """Test task execution events."""
209254 job_type = 'job_test'
@@ -465,6 +510,40 @@ def test_serialize_issue_closing_event(self):
465510 self .assertEqual (event_entity .closing_reason ,
466511 events .ClosingReason .TESTCASE_FIXED )
467512
513+ def test_serialize_testcase_grouping_event (self ):
514+ """Test serializing a testcase grouping event."""
515+ testcase = test_utils .create_generic_testcase ()
516+ event = events .TestcaseGroupingEvent (
517+ source = 'events_test' ,
518+ testcase = testcase ,
519+ group_id = 10 ,
520+ previous_group_id = 5 ,
521+ similar_testcase_id = 2 ,
522+ grouping_reason = events .GroupingReason .GROUP_MERGE ,
523+ group_merge_reason = events .GroupingReason .IDENTICAL_VARIANT )
524+ event_type = event .event_type
525+ timestamp = event .timestamp
526+
527+ event_entity = self .repository ._serialize_event (event ) # pylint: disable=protected-access
528+
529+ # BaseTestcaseEvent and BaseTaskEvent general assertions
530+ self .assertIsNotNone (event_entity )
531+ self .assertIsInstance (event_entity , data_types .TestcaseLifecycleEvent )
532+ self .assertEqual (event_entity .event_type , event_type )
533+ self .assertEqual (event_entity .timestamp , timestamp )
534+ self ._assert_common_event_fields (event_entity )
535+ self ._assert_testcase_fields (event_entity , testcase .key .id ())
536+ self ._assert_task_fields (event_entity )
537+
538+ # TestcaseGroupingEvent specific assertions
539+ self .assertEqual (event_entity .group_id , 10 )
540+ self .assertEqual (event_entity .previous_group_id , 5 )
541+ self .assertEqual (event_entity .similar_testcase_id , 2 )
542+ self .assertEqual (event_entity .grouping_reason ,
543+ events .GroupingReason .GROUP_MERGE )
544+ self .assertEqual (event_entity .group_merge_reason ,
545+ events .GroupingReason .IDENTICAL_VARIANT )
546+
468547 def test_serialize_task_execution_event (self ):
469548 """Test serializing a task execution event into a datastore entity."""
470549 source = 'events_test'
@@ -712,6 +791,52 @@ def test_deserialize_issue_closing_event(self):
712791 self .assertEqual (event .issue_id , '13579' )
713792 self .assertEqual (event .closing_reason , events .ClosingReason .TESTCASE_FIXED )
714793
794+ def test_deserialize_testcase_grouping_event (self ):
795+ """Test deserializing a testcase grouping event."""
796+ event_type = events .EventTypes .TESTCASE_GROUPING
797+ date_now = datetime .datetime (2025 , 1 , 1 , 10 , 30 , 15 )
798+
799+ event_entity = data_types .TestcaseLifecycleEvent (event_type = event_type )
800+ event_entity .timestamp = date_now
801+ event_entity .source = 'events_test'
802+ self ._set_common_event_fields (event_entity )
803+ event_entity .task_id = 'f61826c3-ca9a-4b97-9c1e-9e6f4e4f8868'
804+ event_entity .task_name = 'triage'
805+ event_entity .testcase_id = 1
806+ event_entity .fuzzer = 'fuzzer1'
807+ event_entity .job = 'test_job'
808+ event_entity .crash_revision = 2
809+ event_entity .group_id = 10
810+ event_entity .previous_group_id = 5
811+ event_entity .similar_testcase_id = 2
812+ event_entity .grouping_reason = events .GroupingReason .GROUP_MERGE
813+ event_entity .group_merge_reason = events .GroupingReason .SIMILAR_CRASH
814+ event_entity .put ()
815+
816+ event = self .repository ._deserialize_event (event_entity ) # pylint: disable=protected-access
817+ self .assertIsNotNone (event )
818+ self .assertIsInstance (event , events .TestcaseGroupingEvent )
819+
820+ # BaseTestcaseEvent and BaseTaskEvent general assertions.
821+ self .assertEqual (event .event_type , event_type )
822+ self .assertEqual (event .source , 'events_test' )
823+ self .assertEqual (event .timestamp , date_now )
824+ self ._assert_common_event_fields (event )
825+ self .assertEqual (event .task_id , 'f61826c3-ca9a-4b97-9c1e-9e6f4e4f8868' )
826+ self .assertEqual (event .task_name , 'triage' )
827+ self .assertEqual (event .testcase_id , 1 )
828+ self .assertEqual (event .fuzzer , 'fuzzer1' )
829+ self .assertEqual (event .job , 'test_job' )
830+ self .assertEqual (event .crash_revision , 2 )
831+
832+ # TestcaseGroupingEvent specific assertions
833+ self .assertEqual (event .group_id , 10 )
834+ self .assertEqual (event .previous_group_id , 5 )
835+ self .assertEqual (event .similar_testcase_id , 2 )
836+ self .assertEqual (event .grouping_reason , events .GroupingReason .GROUP_MERGE )
837+ self .assertEqual (event .group_merge_reason ,
838+ events .GroupingReason .SIMILAR_CRASH )
839+
715840 def test_deserialize_task_execution_event (self ):
716841 """Test deserializing a datastore event into a task execution event."""
717842 event_type = events .EventTypes .TASK_EXECUTION
0 commit comments