Skip to content

Commit 644025c

Browse files
feat: add tests rollup seeding for integration tests
1 parent 918756f commit 644025c

3 files changed

Lines changed: 196 additions & 0 deletions

File tree

backend/kernelCI_app/management/commands/seed_test_data.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
Builds,
1919
Checkouts,
2020
Incidents,
21+
TestsRollup,
22+
StatusChoices,
2123
)
2224
from kernelCI_app.tests.factories.mocks import Build, Issue, Test
2325
from 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

backend/kernelCI_app/tests/factories/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .test_factory import TestFactory
88
from .issue_factory import IssueFactory
99
from .incident_factory import IncidentFactory
10+
from .tests_rollup_factory import TestsRollupFactory
1011

1112
from .mocks import Checkout, Build, Test, Issue
1213

@@ -16,6 +17,7 @@
1617
"TestFactory",
1718
"IssueFactory",
1819
"IncidentFactory",
20+
"TestsRollupFactory",
1921
"Checkout",
2022
"Build",
2123
"Test",
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""
2+
Factory for generating TestsRollup test data.
3+
"""
4+
5+
import factory
6+
from factory.django import DjangoModelFactory
7+
from kernelCI_app.models import TestsRollup
8+
9+
10+
class TestsRollupFactory(DjangoModelFactory):
11+
"""Factory for creating TestsRollup instances with realistic test data."""
12+
13+
class Meta:
14+
model = TestsRollup
15+
16+
origin = factory.Faker("word")
17+
tree_name = factory.Faker("word")
18+
git_repository_branch = factory.Faker("word")
19+
git_repository_url = factory.Faker("url")
20+
git_commit_hash = factory.Faker("sha1")
21+
22+
path_group = factory.Faker("word")
23+
build_config_name = "defconfig"
24+
build_architecture = "x86_64"
25+
build_compiler = "gcc-12"
26+
hardware_key = factory.Faker("word")
27+
28+
test_platform = None
29+
test_lab = None
30+
test_origin = None
31+
32+
issue_id = None
33+
issue_version = None
34+
issue_uncategorized = False
35+
36+
is_boot = False
37+
38+
pass_tests = 0
39+
fail_tests = 0
40+
skip_tests = 0
41+
error_tests = 0
42+
miss_tests = 0
43+
done_tests = 0
44+
null_tests = 0
45+
total_tests = factory.LazyAttribute(
46+
lambda obj: (
47+
obj.pass_tests
48+
+ obj.fail_tests
49+
+ obj.skip_tests
50+
+ obj.error_tests
51+
+ obj.miss_tests
52+
+ obj.done_tests
53+
+ obj.null_tests
54+
)
55+
)
56+
57+
duration_min = None
58+
duration_max = None

0 commit comments

Comments
 (0)