Skip to content

Commit 4c9cf04

Browse files
committed
fixup! feat: Change queries to use lab column information
Keep lab as the standard Django FK field and resolve build test lab names via raw SQL, matching the hardware query pattern. Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
1 parent e2c753f commit 4c9cf04

4 files changed

Lines changed: 64 additions & 109 deletions

File tree

backend/kernelCI_app/migrations/0020_rename_builds_tests_lab_to_lab_id.py

Lines changed: 0 additions & 43 deletions
This file was deleted.

backend/kernelCI_app/models.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,8 @@ class Builds(models.Model):
132132
log_url = models.TextField(blank=True, null=True)
133133
log_excerpt = models.CharField(max_length=16384, blank=True, null=True)
134134
misc = models.JSONField(blank=True, null=True)
135-
lab_id = models.ForeignKey(
136-
Labs,
137-
db_column="lab_id",
138-
db_constraint=False,
139-
null=True,
140-
on_delete=models.DO_NOTHING,
135+
lab = models.ForeignKey(
136+
Labs, db_constraint=False, null=True, on_delete=models.DO_NOTHING
141137
)
142138
status = models.CharField(
143139
max_length=10, choices=StatusChoices.choices, blank=True, null=True
@@ -197,12 +193,8 @@ class UnitPrefix(models.TextChoices):
197193
input_files = models.JSONField(blank=True, null=True)
198194
output_files = models.JSONField(blank=True, null=True)
199195
misc = models.JSONField(blank=True, null=True)
200-
lab_id = models.ForeignKey(
201-
Labs,
202-
db_column="lab_id",
203-
db_constraint=False,
204-
null=True,
205-
on_delete=models.DO_NOTHING,
196+
lab = models.ForeignKey(
197+
Labs, db_constraint=False, null=True, on_delete=models.DO_NOTHING
206198
)
207199
number_value = models.FloatField(blank=True, null=True)
208200
environment_compatible = ArrayField(models.TextField(), blank=True, null=True)

backend/kernelCI_app/queries/build.py

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from typing import Optional
22

3-
from django.db.models import TextField
4-
from django.db.models.expressions import F
5-
from django.db.models.functions import Cast, Coalesce
3+
from django.db import connection
64
from querybuilder.query import Query
75

8-
from kernelCI_app.models import Builds, Tests
6+
from kernelCI_app.helpers.database import dict_fetchall
7+
from kernelCI_app.models import Builds
98

109

1110
def get_build_details(build_id: str) -> Optional[list[dict]]:
@@ -51,26 +50,24 @@ def get_build_details(build_id: str) -> Optional[list[dict]]:
5150

5251

5352
def get_build_tests(build_id: str) -> Optional[list[dict]]:
54-
result = (
55-
Tests.objects.filter(build_id=build_id)
56-
# TODO remove misc__runtime fallback after lab backfill
57-
.annotate(
58-
lab=Coalesce(
59-
F("lab_id__name"),
60-
Cast(F("misc__runtime"), output_field=TextField()),
61-
)
62-
)
63-
.values(
64-
"id",
65-
"duration",
66-
"status",
67-
"path",
68-
"start_time",
69-
"environment_compatible",
70-
"environment_misc",
71-
"build__status",
72-
"lab_id",
73-
"lab",
74-
)
75-
)
76-
return list(result)
53+
query = """
54+
SELECT
55+
tests.id,
56+
tests.duration,
57+
tests.status,
58+
tests.path,
59+
tests.start_time,
60+
tests.environment_compatible,
61+
tests.environment_misc,
62+
builds.status AS build__status,
63+
tests.lab_id,
64+
-- TODO remove misc->>'runtime' fallback after lab backfill
65+
COALESCE(labs.name, tests.misc->>'runtime') AS lab
66+
FROM tests
67+
INNER JOIN builds ON tests.build_id = builds.id
68+
LEFT JOIN labs ON tests.lab_id = labs.id
69+
WHERE tests.build_id = %s
70+
"""
71+
with connection.cursor() as cursor:
72+
cursor.execute(query, [build_id])
73+
return dict_fetchall(cursor)

backend/kernelCI_app/tests/unitTests/queries/build_test.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
from unittest.mock import patch
22

33
from kernelCI_app.queries.build import get_build_details, get_build_tests
4-
from kernelCI_app.tests.unitTests.queries.conftest import (
5-
setup_mock_filter_values_queryset,
6-
setup_mock_query_builder,
7-
)
4+
from kernelCI_app.tests.unitTests.queries.conftest import setup_mock_query_builder
85

96

107
class TestGetBuildDetails:
@@ -28,25 +25,35 @@ def test_get_build_details_empty_result(self, mock_query_class):
2825

2926

3027
class TestGetBuildTests:
31-
@patch("kernelCI_app.queries.build.Tests")
32-
def test_get_build_tests_success(self, mock_tests_model):
33-
setup_mock_filter_values_queryset(
34-
mock_tests_model,
35-
[
36-
{
37-
"id": "test",
38-
"duration": 30,
39-
"status": "PASS",
40-
"path": "test.path",
41-
"start_time": "2024-01-15T10:00:00Z",
42-
"environment_compatible": ["hardware1"],
43-
"environment_misc": {"platform": "x86_64"},
44-
"build__status": "PASS",
45-
"lab_id": 1,
46-
"lab": "lab-a",
47-
}
48-
],
49-
)
28+
@patch("kernelCI_app.queries.build.connection")
29+
def test_get_build_tests_success(self, mock_connection):
30+
mock_cursor = mock_connection.cursor.return_value.__enter__.return_value
31+
mock_cursor.fetchall.return_value = [
32+
(
33+
"test",
34+
30,
35+
"PASS",
36+
"test.path",
37+
"2024-01-15T10:00:00Z",
38+
["hardware1"],
39+
{"platform": "x86_64"},
40+
"PASS",
41+
1,
42+
"lab-a",
43+
)
44+
]
45+
mock_cursor.description = [
46+
("id",),
47+
("duration",),
48+
("status",),
49+
("path",),
50+
("start_time",),
51+
("environment_compatible",),
52+
("environment_misc",),
53+
("build__status",),
54+
("lab_id",),
55+
("lab",),
56+
]
5057

5158
result = get_build_tests("build")
5259

@@ -64,11 +71,13 @@ def test_get_build_tests_success(self, mock_tests_model):
6471
"lab": "lab-a",
6572
}
6673
]
67-
mock_tests_model.objects.filter.assert_called_once_with(build_id="build")
74+
mock_cursor.execute.assert_called_once()
6875

69-
@patch("kernelCI_app.queries.build.Tests")
70-
def test_get_build_tests_empty_result(self, mock_tests_model):
71-
setup_mock_filter_values_queryset(mock_tests_model, [])
76+
@patch("kernelCI_app.queries.build.connection")
77+
def test_get_build_tests_empty_result(self, mock_connection):
78+
mock_cursor = mock_connection.cursor.return_value.__enter__.return_value
79+
mock_cursor.fetchall.return_value = []
80+
mock_cursor.description = []
7281

7382
result = get_build_tests("build")
7483

0 commit comments

Comments
 (0)