Skip to content

Commit d0834e2

Browse files
Feat: move automatic labs to another field (#1717)
* feat: move automatic labs to another field Closes #1647 * refactor: remove lab column from builds table Removes lab from build table since all current build labs are k8s-all
1 parent b90f4ec commit d0834e2

4 files changed

Lines changed: 141 additions & 13 deletions

File tree

backend/kernelCI_app/constants/ingester.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import logging
5+
import re
56
from utils.validation import is_boolean_or_string_true
67

78
logger = logging.getLogger("ingester")
@@ -65,3 +66,8 @@
6566
except (ValueError, TypeError):
6667
logger.warning("Invalid INGEST_QUEUE_MAXSIZE, using default 5000")
6768
INGEST_QUEUE_MAXSIZE = 5000
69+
70+
AUTOMATIC_LABS = re.compile(r"^(shell|k8s.*)$")
71+
"""Regex pattern to find labs that were named automatically and should not be in the real lab/runtime field"""
72+
AUTOMATIC_LAB_FIELD = "automatic_lab"
73+
"""Field name where automatic lab names will be moved to"""

backend/kernelCI_app/management/commands/helpers/kcidbng_ingester.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from queue import Queue
99
from typing_extensions import Literal
1010
from kernelCI_app.constants.ingester import (
11+
AUTOMATIC_LAB_FIELD,
12+
AUTOMATIC_LABS,
1113
CONVERT_LOG_EXCERPT,
1214
INGEST_BATCH_SIZE,
1315
INGEST_FILES_BATCH_SIZE,
@@ -89,6 +91,26 @@ def standardize_tree_names(
8991
checkout["tree_name"] = correct_tree
9092

9193

94+
def standardize_labs(input_data: dict[str, Any]) -> None:
95+
"""
96+
Standardize labs in data, moving automatic lab names to AUTOMATIC_LAB_FIELD
97+
"""
98+
99+
builds: list[dict[str, Any]] = input_data.get("builds", [])
100+
for build in builds:
101+
lab = build.get("misc", {}).get("lab")
102+
if lab and AUTOMATIC_LABS.match(lab):
103+
build["misc"][AUTOMATIC_LAB_FIELD] = lab
104+
build["misc"].pop("lab", None)
105+
106+
tests: list[dict[str, Any]] = input_data.get("tests", [])
107+
for test in tests:
108+
lab = test.get("misc", {}).get("runtime")
109+
if lab and AUTOMATIC_LABS.match(lab):
110+
test["misc"][AUTOMATIC_LAB_FIELD] = lab
111+
test["misc"].pop("runtime", None)
112+
113+
92114
def prepare_file_data(
93115
file: SubmissionFileMetadata, tree_names: dict[str, str]
94116
) -> tuple[Optional[dict[str, Any]], Optional[dict[str, Any]]]:
@@ -121,6 +143,7 @@ def prepare_file_data(
121143
standardize_tree_names(data, tree_names)
122144
kcidb_io.schema.V5_3.validate(data)
123145
kcidb_io.schema.V5_3.upgrade(data)
146+
standardize_labs(data)
124147

125148
processing_time = time.time() - start_time
126149
return data, {

backend/kernelCI_app/tests/unitTests/commands/monitorSubmissions/kcidbng_ingester_test.py

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
SUBMISSION_FILE_DATA_MOCK,
1414
SUBMISSION_FILENAME_MOCK,
1515
)
16+
from kernelCI_app.constants.ingester import AUTOMATIC_LAB_FIELD
1617
import pytest
1718

1819
from kernelCI_app.management.commands.helpers.kcidbng_ingester import (
1920
SubmissionFileMetadata,
2021
standardize_tree_names,
22+
standardize_labs,
2123
prepare_file_data,
2224
consume_buffer,
2325
flush_buffers,
@@ -109,6 +111,111 @@ def test_standardize_tree_names_missing_tree_name(self):
109111
assert "tree_name" not in input_data["checkouts"][1]
110112

111113

114+
class TestStandardizeLabs:
115+
"""Test cases for standardize_labs function."""
116+
117+
# Test cases:
118+
# - builds/tests with missing misc field
119+
# - builds/tests with misc but not lab field
120+
# - empty builds/tests data
121+
# - builds/tests with real/automatic labs/runtimes
122+
123+
def test_standardize_labs_missing_misc(self):
124+
"""Test with builds/tests missing misc field."""
125+
input_data = {
126+
"builds": [
127+
{"id": "build1"},
128+
],
129+
"tests": [
130+
{"id": "test1"},
131+
],
132+
}
133+
134+
standardize_labs(input_data)
135+
136+
assert "misc" not in input_data["builds"][0]
137+
assert "misc" not in input_data["tests"][0]
138+
139+
def test_standardize_labs_missing_lab_runtime(self):
140+
"""Test with builds/tests having misc but missing lab/runtime field."""
141+
input_data = {
142+
"builds": [
143+
{
144+
"misc": {
145+
"other_field": "value",
146+
}
147+
},
148+
],
149+
"tests": [
150+
{
151+
"misc": {
152+
"platform": "x86",
153+
}
154+
},
155+
],
156+
}
157+
158+
standardize_labs(input_data)
159+
160+
assert "lab" not in input_data["builds"][0]["misc"]
161+
assert AUTOMATIC_LAB_FIELD not in input_data["builds"][0]["misc"]
162+
assert "runtime" not in input_data["tests"][0]["misc"]
163+
assert AUTOMATIC_LAB_FIELD not in input_data["tests"][0]["misc"]
164+
165+
def test_standardize_labs_empty_data(self):
166+
"""Test with empty builds and tests."""
167+
input_data = {
168+
"builds": [],
169+
"tests": [],
170+
}
171+
172+
standardize_labs(input_data)
173+
174+
assert input_data["builds"] == []
175+
assert input_data["tests"] == []
176+
177+
def test_standardize_labs_mixed_builds_and_tests(self):
178+
"""Test with a mix of automatic and real labs/runtimes."""
179+
input_data = {
180+
"builds": [
181+
{"misc": {"lab": "shell"}},
182+
{"misc": {"lab": "collabora"}},
183+
{"misc": {"lab": "k8s-cluster"}},
184+
],
185+
"tests": [
186+
{"misc": {"runtime": "shell"}},
187+
{"misc": {"runtime": "lava-lab"}},
188+
{"misc": {"runtime": "k8s"}},
189+
],
190+
}
191+
192+
standardize_labs(input_data)
193+
194+
# Build 0: shell -> automatic_lab
195+
assert "lab" not in input_data["builds"][0]["misc"]
196+
assert input_data["builds"][0]["misc"][AUTOMATIC_LAB_FIELD] == "shell"
197+
198+
# Build 1: real lab stays
199+
assert input_data["builds"][1]["misc"]["lab"] == "collabora"
200+
assert AUTOMATIC_LAB_FIELD not in input_data["builds"][1]["misc"]
201+
202+
# Build 2: k8s* -> automatic_lab
203+
assert "lab" not in input_data["builds"][2]["misc"]
204+
assert input_data["builds"][2]["misc"][AUTOMATIC_LAB_FIELD] == "k8s-cluster"
205+
206+
# Test 0: shell -> automatic_lab
207+
assert "runtime" not in input_data["tests"][0]["misc"]
208+
assert input_data["tests"][0]["misc"][AUTOMATIC_LAB_FIELD] == "shell"
209+
210+
# Test 1: real runtime stays
211+
assert input_data["tests"][1]["misc"]["runtime"] == "lava-lab"
212+
assert AUTOMATIC_LAB_FIELD not in input_data["tests"][1]["misc"]
213+
214+
# Test 2: k8s -> automatic_lab
215+
assert "runtime" not in input_data["tests"][2]["misc"]
216+
assert input_data["tests"][2]["misc"][AUTOMATIC_LAB_FIELD] == "k8s"
217+
218+
112219
class TestPrepareFileData:
113220
"""Test cases for prepare_file_data function."""
114221

@@ -145,6 +252,7 @@ def test_prepare_file_data_empty_file(self, mock_remove, mock_logger):
145252
@patch("kernelCI_app.management.commands.helpers.kcidbng_ingester.VERBOSE", False)
146253
@patch("kcidb_io.schema.V5_3.validate")
147254
@patch("kcidb_io.schema.V5_3.upgrade")
255+
@patch("kernelCI_app.management.commands.helpers.kcidbng_ingester.standardize_labs")
148256
@patch(
149257
"kernelCI_app.management.commands.helpers.kcidbng_ingester.standardize_tree_names"
150258
)
@@ -158,7 +266,8 @@ def test_prepare_file_data_success(
158266
mock_time,
159267
mock_file_open,
160268
mock_extract_log,
161-
mock_standardize,
269+
mock_standardize_tree,
270+
mock_standardize_labs,
162271
mock_upgrade,
163272
mock_validate,
164273
):
@@ -179,9 +288,10 @@ def test_prepare_file_data_success(
179288
assert result_metadata["processing_time"] == 1
180289
assert mock_time.call_count == 2
181290
mock_extract_log.assert_called_once_with(expected_data)
182-
mock_standardize.assert_called_once_with(expected_data, tree_names)
291+
mock_standardize_tree.assert_called_once_with(expected_data, tree_names)
183292
mock_validate.assert_called_once()
184293
mock_upgrade.assert_called_once()
294+
mock_standardize_labs.assert_called_once_with(expected_data)
185295
mock_file_open.assert_called_once_with(SUBMISSION_PATH_MOCK, "r")
186296

187297
@patch("kernelCI_app.management.commands.helpers.kcidbng_ingester.logger")

dashboard/src/components/BuildsTable/DefaultBuildsColumns.tsx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
MoreDetailsTableHeader,
1616
} from '@/components/Table/DetailsColumn';
1717
import { getBuildStatusGroup } from '@/utils/status';
18-
import { UNKNOWN_STRING } from '@/utils/constants/backend';
1918

2019
export const defaultBuildColumns: ColumnDef<AccordionItemBuilds>[] = [
2120
{
@@ -40,16 +39,6 @@ export const defaultBuildColumns: ColumnDef<AccordionItemBuilds>[] = [
4039
<TableHeader column={column} intlKey="global.compiler" />
4140
),
4241
},
43-
{
44-
id: 'lab',
45-
accessorKey: 'lab',
46-
header: ({ column }): JSX.Element => (
47-
<TableHeader column={column} intlKey="global.lab" />
48-
),
49-
cell: ({ row }): string => {
50-
return row.getValue('lab') || UNKNOWN_STRING;
51-
},
52-
},
5342
{
5443
accessorKey: 'date',
5544
header: ({ column }): JSX.Element => (

0 commit comments

Comments
 (0)