Skip to content

Commit 80d7ce6

Browse files
committed
feat: Change queries to use lab column information
* For analysis queries we are going for lab column information first, and coalescing to json misc information. * All COALESCE expressions are marked with TODO comments for removal after the lab_id backfill is complete. Closes #1948 Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
1 parent ec84431 commit 80d7ce6

10 files changed

Lines changed: 186 additions & 99 deletions

File tree

backend/kernelCI_app/helpers/hardwareDetails.py

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,6 @@ def handle_test_history(
290290
full_environment_misc: bool = False,
291291
) -> None:
292292
create_record_test_platform(record=record)
293-
record_misc = sanitize_dict(record.get("misc"))
294-
295293
environment_misc_dict = get_environment_misc_value(
296294
full_environment_misc=full_environment_misc,
297295
parsed_environment_misc=record.get("parsed_environment_misc"),
@@ -313,11 +311,7 @@ def handle_test_history(
313311
environment_misc=environment_misc,
314312
tree_name=record["build__checkout__tree_name"],
315313
git_repository_branch=record["build__checkout__git_repository_branch"],
316-
lab=(
317-
record_misc.get("runtime", UNKNOWN_STRING)
318-
if record_misc
319-
else UNKNOWN_STRING
320-
),
314+
lab=record.get("lab") or UNKNOWN_STRING,
321315
)
322316

323317
task.append(test_history_item)
@@ -380,16 +374,14 @@ def handle_test_summary(
380374
getattr(task.origins[origin], status) + 1,
381375
)
382376

383-
misc = sanitize_dict(record.get("misc")) or {}
384-
lab = misc.get("runtime", UNKNOWN_STRING)
385-
if lab:
386-
if task.labs.get(lab) is None:
387-
task.labs[lab] = StatusCount()
388-
setattr(
389-
task.labs[lab],
390-
status,
391-
getattr(task.labs[lab], status) + 1,
392-
)
377+
lab = record.get("lab") or UNKNOWN_STRING
378+
if task.labs.get(lab) is None:
379+
task.labs[lab] = StatusCount()
380+
setattr(
381+
task.labs[lab],
382+
status,
383+
getattr(task.labs[lab], status) + 1,
384+
)
393385

394386

395387
def handle_build_history(
@@ -458,18 +450,16 @@ def handle_build_summary(
458450
getattr(builds_summary.origins[origin], status_key) + 1,
459451
)
460452

461-
misc = sanitize_dict(build.misc) or {}
462-
lab = misc.get("lab", UNKNOWN_STRING)
463-
if lab:
464-
build_lab_summary = builds_summary.labs.get(lab)
465-
if not build_lab_summary:
466-
build_lab_summary = StatusCount()
467-
builds_summary.labs[lab] = build_lab_summary
468-
setattr(
469-
builds_summary.labs[lab],
470-
status_key,
471-
getattr(builds_summary.labs[lab], status_key) + 1,
472-
)
453+
lab = record.get("build_lab") or UNKNOWN_STRING
454+
build_lab_summary = builds_summary.labs.get(lab)
455+
if not build_lab_summary:
456+
build_lab_summary = StatusCount()
457+
builds_summary.labs[lab] = build_lab_summary
458+
setattr(
459+
builds_summary.labs[lab],
460+
status_key,
461+
getattr(builds_summary.labs[lab], status_key) + 1,
462+
)
473463

474464
process_issue(record=record, task_issues_dict=issue_dict, issue_from="build")
475465

@@ -579,8 +569,7 @@ def decide_if_is_full_record_filtered_out(
579569
if not is_current_tree_selected:
580570
return True
581571

582-
misc = sanitize_dict(record.get("misc")) or {}
583-
lab = misc.get("runtime", UNKNOWN_STRING)
572+
lab = record.get("lab") or UNKNOWN_STRING
584573

585574
is_record_filtered_out_result = instance.filters.is_record_filtered_out(
586575
hardwares=record["environment_compatible"],
@@ -730,10 +719,8 @@ def process_filters(*, instance, record: Dict) -> None:
730719

731720
instance.unfiltered_origins["build"].add(record["build__origin"])
732721

733-
build_misc = sanitize_dict(record.get("build__misc")) or {}
734-
build_lab = build_misc.get("lab")
735-
if build_lab:
736-
instance.unfiltered_labs["build"].add(build_lab)
722+
if record.get("build_lab"):
723+
instance.unfiltered_labs["build"].add(record["build_lab"])
737724

738725
if record["id"] is not None:
739726
if is_boot(record["path"]):
@@ -771,10 +758,8 @@ def process_filters(*, instance, record: Dict) -> None:
771758
platform_set.add(test_platform)
772759
origin_set.add(record["test_origin"])
773760

774-
test_misc = sanitize_dict(record.get("misc")) or {}
775-
test_lab = test_misc.get("runtime")
776-
if test_lab:
777-
instance.unfiltered_labs[flag_tab].add(test_lab)
761+
if record.get("lab"):
762+
instance.unfiltered_labs[flag_tab].add(record["lab"])
778763

779764

780765
def is_record_tree_selected(*, record, tree: Tree, is_all_selected: bool) -> bool:

backend/kernelCI_app/helpers/treeDetails.py

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
create_issue_typed,
2626
extract_error_message,
2727
is_boot,
28-
sanitize_dict,
2928
)
3029

3130

@@ -87,42 +86,41 @@ def get_current_row_data(
8786
"test_number_value": current_row[10],
8887
"test_misc": current_row[11],
8988
"test_environment_compatible": current_row[tmp_test_env_comp_key],
90-
"build_id": current_row[13],
91-
"build_origin": current_row[14],
92-
"build_comment": current_row[15],
93-
"build_start_time": current_row[16],
94-
"build_duration": current_row[17],
95-
"build_architecture": current_row[18],
96-
"build_command": current_row[19],
97-
"build_compiler": current_row[20],
98-
"build_config_name": current_row[21],
99-
"build_config_url": current_row[22],
100-
"build_log_url": current_row[23],
101-
"build_status": current_row[24],
102-
"build_misc": current_row[25],
103-
"checkout_id": current_row[26],
104-
"checkout_git_repository_url": current_row[27],
105-
"checkout_git_repository_branch": current_row[28],
106-
"checkout_git_commit_tags": current_row[29],
107-
"checkout_origin": current_row[30],
108-
"incident_id": current_row[31],
109-
"incident_test_id": current_row[32],
110-
"incident_present": current_row[33],
111-
"issue_id": current_row[34],
112-
"issue_version": current_row[35],
113-
"issue_comment": current_row[36],
114-
"issue_report_url": current_row[37],
89+
"test_lab": current_row[13],
90+
"build_id": current_row[14],
91+
"build_origin": current_row[15],
92+
"build_comment": current_row[16],
93+
"build_start_time": current_row[17],
94+
"build_duration": current_row[18],
95+
"build_architecture": current_row[19],
96+
"build_command": current_row[20],
97+
"build_compiler": current_row[21],
98+
"build_config_name": current_row[22],
99+
"build_config_url": current_row[23],
100+
"build_log_url": current_row[24],
101+
"build_status": current_row[25],
102+
"build_misc": current_row[26],
103+
"build_lab": current_row[27],
104+
"checkout_id": current_row[28],
105+
"checkout_git_repository_url": current_row[29],
106+
"checkout_git_repository_branch": current_row[30],
107+
"checkout_git_commit_tags": current_row[31],
108+
"checkout_origin": current_row[32],
109+
"incident_id": current_row[33],
110+
"incident_test_id": current_row[34],
111+
"incident_present": current_row[35],
112+
"issue_id": current_row[36],
113+
"issue_version": current_row[37],
114+
"issue_comment": current_row[38],
115+
"issue_report_url": current_row[39],
115116
}
116117

117118
parsed_environment_misc = handle_misc(
118119
misc_value_or_default(current_row_data["test_environment_misc"])
119120
)
120121
current_row_data["test_platform"] = parsed_environment_misc.get("platform")
121122
current_row_data["parsed_environment_misc"] = parsed_environment_misc
122-
test_misc = sanitize_dict(current_row_data["test_misc"])
123-
test_runtime_lab = UNKNOWN_STRING
124-
if test_misc is not None:
125-
test_runtime_lab = test_misc.get("runtime", UNKNOWN_STRING)
123+
test_runtime_lab = current_row_data["test_lab"] or UNKNOWN_STRING
126124

127125
if current_row_data["test_status"] is None:
128126
current_row_data["test_status"] = NULL_STATUS
@@ -495,8 +493,9 @@ def process_filters(instance, row_data: dict, skip_build_filters: bool = False)
495493
instance.global_architectures.add(row_data["build_architecture"])
496494
instance.global_compilers.add(row_data["build_compiler"])
497495
instance.unfiltered_origins["build"].add(row_data["build_origin"])
498-
if (build_misc := row_data["build_misc"]) is not None:
499-
instance.unfiltered_labs["build"].add(build_misc.get("lab", UNKNOWN_STRING))
496+
instance.unfiltered_labs["build"].add(
497+
row_data.get("build_lab") or UNKNOWN_STRING
498+
)
500499

501500
build_issue_id, build_issue_version, is_build_issue = (
502501
should_increment_build_issue(

backend/kernelCI_app/management/commands/notifications.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ def generate_hardware_summary_report(
706706
continue
707707
hardware_id = environment_misc.get("platform")
708708
raw["job_id"] = environment_misc.get("job_id")
709-
raw["runtime"] = misc.get("runtime")
709+
raw["runtime"] = raw.get("lab") or misc.get("runtime")
710710
origin = raw.get("test_origin")
711711
key = (hardware_id, origin)
712712
tree = raw.get("tree_name")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Generated by Django 5.2.11 on 2026-06-29 20:25
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("kernelCI_app", "0018_hardwareregistryplatformvendor_and_more"),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name="Labs",
15+
fields=[
16+
("id", models.AutoField(primary_key=True, serialize=False)),
17+
("name", models.TextField(unique=True)),
18+
],
19+
options={
20+
"db_table": "labs",
21+
},
22+
),
23+
migrations.AddField(
24+
model_name="builds",
25+
name="lab",
26+
field=models.ForeignKey(
27+
db_constraint=False,
28+
null=True,
29+
on_delete=django.db.models.deletion.DO_NOTHING,
30+
to="kernelCI_app.labs",
31+
),
32+
),
33+
migrations.AddField(
34+
model_name="tests",
35+
name="lab",
36+
field=models.ForeignKey(
37+
db_constraint=False,
38+
null=True,
39+
on_delete=django.db.models.deletion.DO_NOTHING,
40+
to="kernelCI_app.labs",
41+
),
42+
),
43+
]

backend/kernelCI_app/queries/build.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from typing import Optional
22

3+
from django.db.models import TextField
34
from django.db.models.expressions import F
5+
from django.db.models.functions import Cast, Coalesce
46
from querybuilder.query import Query
57

68
from kernelCI_app.models import Builds, Tests
@@ -51,7 +53,13 @@ def get_build_details(build_id: str) -> Optional[list[dict]]:
5153
def get_build_tests(build_id: str) -> Optional[list[dict]]:
5254
result = (
5355
Tests.objects.filter(build_id=build_id)
54-
.annotate(lab=F("misc__runtime"))
56+
# TODO remove misc__runtime fallback after lab backfill
57+
.annotate(
58+
lab_name=Coalesce(
59+
F("lab__name"),
60+
Cast(F("misc__runtime"), output_field=TextField()),
61+
)
62+
)
5563
.values(
5664
"id",
5765
"duration",
@@ -61,7 +69,12 @@ def get_build_tests(build_id: str) -> Optional[list[dict]]:
6169
"environment_compatible",
6270
"environment_misc",
6371
"build__status",
64-
"lab",
72+
"lab_name",
6573
)
6674
)
67-
return list(result)
75+
tests = []
76+
for test in result:
77+
test["lab"] = test.pop("lab_name")
78+
tests.append(test)
79+
80+
return tests

backend/kernelCI_app/queries/hardware.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ def get_hardware_listing_data_bulk(
255255
FROM
256256
tests
257257
INNER JOIN builds b ON tests.build_id = b.id
258+
LEFT JOIN labs tl ON tests.lab_id = tl.id
258259
WHERE
259260
"tests"."environment_misc" ->> 'platform' IS NOT NULL
260261
AND "tests"."start_time" >= %(start_date)s
@@ -267,7 +268,8 @@ def get_hardware_listing_data_bulk(
267268
OR tests.environment_misc ->> 'platform' = key_list.hardware_id
268269
)
269270
AND tests.origin = key_list.origin
270-
AND tests.misc ->> 'runtime' = key_list.lab_name
271+
-- TODO remove misc->>'runtime' fallback after lab backfill
272+
AND COALESCE(tl.name, tests.misc ->> 'runtime') = key_list.lab_name
271273
)
272274
)
273275
SELECT
@@ -478,7 +480,8 @@ def get_hardware_details_summary(
478480
AS known_issues,
479481
array[builds.compiler, builds.architecture] AS compiler_arch,
480482
builds.config_name,
481-
builds.misc->>'lab' AS lab,
483+
-- TODO remove misc->>'lab' fallback after lab backfill
484+
COALESCE(bl.name, builds.misc->>'lab') AS lab,
482485
tests.environment_misc->>'platform' AS platform,
483486
tests.environment_compatible,
484487
checkouts.origin,
@@ -497,6 +500,7 @@ def get_hardware_details_summary(
497500
tests.build_id = builds.id
498501
INNER JOIN checkouts ON
499502
builds.checkout_id = checkouts.id
503+
LEFT JOIN labs bl ON builds.lab_id = bl.id
500504
LEFT OUTER JOIN incidents ON
501505
builds.id = incidents.build_id
502506
WHERE
@@ -522,7 +526,8 @@ def get_hardware_details_summary(
522526
as known_issues,
523527
array[builds.compiler, builds.architecture] AS compiler_arch,
524528
builds.config_name,
525-
tests.misc->>'runtime' AS lab,
529+
-- TODO remove misc->>'runtime' fallback after lab backfill
530+
COALESCE(tl.name, tests.misc->>'runtime') AS lab,
526531
tests.environment_misc->>'platform' AS platform,
527532
tests.environment_compatible,
528533
checkouts.origin,
@@ -541,6 +546,7 @@ def get_hardware_details_summary(
541546
tests.build_id = builds.id
542547
INNER JOIN checkouts ON
543548
builds.checkout_id = checkouts.id
549+
LEFT JOIN labs tl ON tests.lab_id = tl.id
544550
LEFT OUTER JOIN incidents ON
545551
tests.id = incidents.test_id
546552
WHERE
@@ -626,13 +632,21 @@ def query_records(
626632
issues.report_url AS incidents__issue__report_url,
627633
incidents.test_id AS incidents__test_id,
628634
T7.issue_id AS build__incidents__issue__id,
629-
T8.version AS build__incidents__issue__version
635+
T8.version AS build__incidents__issue__version,
636+
-- TODO remove misc->>'runtime' fallback after lab backfill
637+
COALESCE(tl.name, tests.misc->>'runtime') AS lab,
638+
-- TODO remove misc->>'lab' fallback after lab backfill
639+
COALESCE(bl.name, builds.misc->>'lab') AS build_lab
630640
FROM
631641
tests
632642
INNER JOIN builds ON
633643
tests.build_id = builds.id
634644
INNER JOIN checkouts ON
635645
builds.checkout_id = checkouts.id
646+
LEFT JOIN labs tl ON
647+
tests.lab_id = tl.id
648+
LEFT JOIN labs bl ON
649+
builds.lab_id = bl.id
636650
LEFT OUTER JOIN incidents ON
637651
tests.id = incidents.test_id
638652
LEFT OUTER JOIN issues ON
@@ -721,13 +735,16 @@ def get_hardware_summary_data(
721735
checkouts.git_commit_name,
722736
checkouts.git_commit_hash,
723737
checkouts.tree_name,
724-
checkouts.origin AS checkout_origin
738+
checkouts.origin AS checkout_origin,
739+
-- TODO remove misc->>'runtime' fallback after lab backfill
740+
COALESCE(tl.name, tests.misc->>'runtime') AS lab
725741
FROM
726742
tests
727743
INNER JOIN builds ON
728744
tests.build_id = builds.id
729745
INNER JOIN checkouts ON
730746
builds.checkout_id = checkouts.id
747+
LEFT JOIN labs tl ON tests.lab_id = tl.id
731748
WHERE
732749
tests.start_time >= %s
733750
AND tests.start_time <= %s
@@ -740,7 +757,8 @@ def get_hardware_summary_data(
740757
OR tests.environment_misc ->> 'platform' = key_list.hardware_id
741758
)
742759
AND tests.origin = key_list.origin
743-
AND tests.misc ->> 'runtime' = key_list.lab_name
760+
-- TODO remove misc->>'runtime' fallback after lab backfill
761+
AND COALESCE(tl.name, tests.misc ->> 'runtime') = key_list.lab_name
744762
)
745763
ORDER BY
746764
tests.start_time DESC

0 commit comments

Comments
 (0)