1818 Builds ,
1919 Checkouts ,
2020 Incidents ,
21+ TestsRollup ,
22+ StatusChoices ,
2123)
2224from kernelCI_app .tests .factories .mocks import Build , Issue , Test
2325from kernelCI_app .helpers .system import get_running_instance
@@ -64,6 +66,7 @@ def handle(self, *args, **options):
6466 tests = self .create_tests_and_boots (builds = builds )
6567 issues = self .create_issues (count = options ["issues" ])
6668 incidents = self .create_incidents (issues = issues , builds = builds , tests = tests )
69+ rollup_rows = self .create_tests_rollup (tests = tests , incidents = incidents )
6770
6871 self .stdout .write (
6972 self .style .SUCCESS (
@@ -73,6 +76,7 @@ def handle(self, *args, **options):
7376 f"- { len (tests )} tests\n "
7477 f"- { len (issues )} issues\n "
7578 f"- { len (incidents )} incidents\n "
79+ f"- { len (rollup_rows )} tests_rollup rows\n "
7680 )
7781 )
7882
@@ -101,6 +105,7 @@ def _validate_clear_operation(self, *, skip_confirmation: bool) -> None:
101105
102106 def clear_data (self ) -> None :
103107 """Clear existing test data."""
108+ TestsRollup .objects .all ().delete ()
104109 Incidents .objects .all ().delete ()
105110 Issues .objects .all ().delete ()
106111 Tests .objects .all ().delete ()
@@ -226,3 +231,134 @@ def create_incidents(
226231 incidents .append (incident )
227232
228233 return incidents
234+
235+ def create_tests_rollup (
236+ self , * , tests : list [Tests ], incidents : list [Incidents ]
237+ ) -> list [TestsRollup ]:
238+ """Aggregate seeded tests into tests_rollup rows.
239+
240+ Mirrors the logic of aggregate_tests_rollup() in process_pending_aggregations.py,
241+ operating on Tests model instances instead of PendingTest records.
242+ """
243+ self .stdout .write ("Creating tests_rollup aggregations..." )
244+
245+ status_to_counter = {
246+ StatusChoices .PASS : "pass_tests" ,
247+ StatusChoices .FAIL : "fail_tests" ,
248+ StatusChoices .SKIP : "skip_tests" ,
249+ StatusChoices .ERROR : "error_tests" ,
250+ StatusChoices .MISS : "miss_tests" ,
251+ StatusChoices .DONE : "done_tests" ,
252+ }
253+
254+ test_issue_map : dict [str , dict ] = {}
255+ for incident in incidents :
256+ if incident .test_id :
257+ test_issue_map .setdefault (
258+ incident .test_id ,
259+ {
260+ "issue_id" : incident .issue_id ,
261+ "issue_version" : incident .issue_version ,
262+ },
263+ )
264+
265+ rollup_data : dict [tuple , dict ] = {}
266+
267+ for test in tests :
268+ checkout = test .build .checkout
269+ path = test .path or ""
270+ path_group = path .split ("." , 1 )[0 ] if path else "-"
271+ path_group = path_group or "-"
272+
273+ compatible = test .environment_compatible
274+ platform = (
275+ (test .environment_misc or {}).get ("platform" )
276+ if test .environment_misc
277+ else None
278+ )
279+
280+ if compatible :
281+ hardware_key = compatible [0 ]
282+ elif platform :
283+ hardware_key = platform
284+ else :
285+ hardware_key = "Unknown"
286+
287+ issue_info = test_issue_map .get (test .id )
288+ issue_id = issue_info ["issue_id" ] if issue_info else None
289+ issue_version = issue_info ["issue_version" ] if issue_info else None
290+ issue_uncategorized = issue_id is None and test .status == StatusChoices .FAIL
291+
292+ arch = test .build .architecture or "Unknown"
293+ compiler = (
294+ test .build .compiler [0 ]
295+ if isinstance (test .build .compiler , list ) and test .build .compiler
296+ else test .build .compiler or "Unknown"
297+ )
298+ config = test .build .config_name or "Unknown"
299+ is_boot = bool (path ) and path .startswith ("boot" )
300+
301+ rollup_key = (
302+ checkout .origin ,
303+ checkout .tree_name ,
304+ checkout .git_repository_branch ,
305+ checkout .git_repository_url ,
306+ checkout .git_commit_hash ,
307+ path_group ,
308+ config ,
309+ arch ,
310+ compiler ,
311+ hardware_key ,
312+ platform ,
313+ None ,
314+ test .origin ,
315+ issue_id ,
316+ issue_version ,
317+ issue_uncategorized ,
318+ is_boot ,
319+ )
320+
321+ record = rollup_data .setdefault (
322+ rollup_key ,
323+ {
324+ "pass_tests" : 0 ,
325+ "fail_tests" : 0 ,
326+ "skip_tests" : 0 ,
327+ "error_tests" : 0 ,
328+ "miss_tests" : 0 ,
329+ "done_tests" : 0 ,
330+ "null_tests" : 0 ,
331+ "total_tests" : 0 ,
332+ },
333+ )
334+
335+ counter = status_to_counter .get (test .status , "null_tests" )
336+ record [counter ] += 1
337+ record ["total_tests" ] += 1
338+
339+ rollup_objects = [
340+ TestsRollup (
341+ origin = key [0 ],
342+ tree_name = key [1 ],
343+ git_repository_branch = key [2 ],
344+ git_repository_url = key [3 ],
345+ git_commit_hash = key [4 ],
346+ path_group = key [5 ],
347+ build_config_name = key [6 ],
348+ build_architecture = key [7 ],
349+ build_compiler = key [8 ],
350+ hardware_key = key [9 ],
351+ test_platform = key [10 ],
352+ test_lab = key [11 ],
353+ test_origin = key [12 ],
354+ issue_id = key [13 ],
355+ issue_version = key [14 ],
356+ issue_uncategorized = key [15 ],
357+ is_boot = key [16 ],
358+ ** counts ,
359+ )
360+ for key , counts in rollup_data .items ()
361+ ]
362+
363+ created = TestsRollup .objects .bulk_create (rollup_objects )
364+ return created
0 commit comments