From ff1d5cbc2155f3f969d2059a50b88858f16aedbb Mon Sep 17 00:00:00 2001 From: Ben Copeland Date: Fri, 25 Sep 2026 11:28:52 +0100 Subject: [PATCH 1/2] kbuild: never enable kselftest for dtbs_check builds dtbs_check builds do not build kselftest, but _kselftest stayed True for them unless the job also set kselftest: disable, which the arm64 dtbscheck job does not. The build steps guarded against this by pairing it with not _dtbs_check, while submit() did not, so those builds published a -kselftest child node: skip when the check failed, and fail (no kselftest tarball) when it passed. Resolve the flag once when parsing params and use plain self._kselftest in the tuxmake build. submit() runs on the object reloaded from the serialised state, which carries the resolved value. Signed-off-by: Ben Copeland --- kernelci/kbuild.py | 12 +++++------ tests/test_kbuild.py | 49 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/kernelci/kbuild.py b/kernelci/kbuild.py index 66c2e3f4ec..fae58c09e7 100644 --- a/kernelci/kbuild.py +++ b/kernelci/kbuild.py @@ -217,10 +217,9 @@ def __init__( self._dtbs_check = params["dtbs_check"] else: self._dtbs_check = False - if params.get("kselftest") == "disable": - self._kselftest = False - else: - self._kselftest = True + self._kselftest = ( + not self._dtbs_check and params.get("kselftest") != "disable" + ) self._extra_targets = params.get("extra_targets", []) self._apijobname = jobname self._steps = [] @@ -878,7 +877,6 @@ def _build_with_tuxmake(self): if not self._dtbs_check: self._fetch_firmware() - build_kselftest = not self._dtbs_check and self._kselftest kernel_build_dir = f"{self._workspace}/kernel_build" self.startjob("build_tuxmake") @@ -900,7 +898,7 @@ def _build_with_tuxmake(self): cmd_parts = self._tuxmake_base( self._af_dir, defconfig, extra_defconfigs ) - if build_kselftest: + if self._kselftest: cmd_parts.append(f"--build-dir={kernel_build_dir}") # Build targets depend on mode. kselftest is built in a separate @@ -972,7 +970,7 @@ def _build_with_tuxmake(self): self.addcmd("cd ..") - if build_kselftest: + if self._kselftest: self._build_kselftest_tuxmake( defconfig, extra_defconfigs, kernel_build_dir ) diff --git a/tests/test_kbuild.py b/tests/test_kbuild.py index 0f2444cd64..599201922e 100644 --- a/tests/test_kbuild.py +++ b/tests/test_kbuild.py @@ -22,6 +22,7 @@ def _kbuild(tmp_path, compiler="clang-21", arch="x86_64"): kbuild._config_full = "" kbuild._backend = "tuxmake" kbuild._dtbs_check = True + kbuild._kselftest = False kbuild._steps = [] kbuild._artifacts = [] kbuild._current_job = None @@ -211,13 +212,59 @@ def test_no_kept_kernel_tree_without_kselftest(self, tmp_path, monkeypatch): def test_no_kselftest_build_for_dtbs_check(self, tmp_path, monkeypatch): (kernel,) = _tuxmake_invocations( - tmp_path, monkeypatch, True, dtbs_check=True + tmp_path, monkeypatch, False, dtbs_check=True ) assert "--build-dir" not in kernel assert kernel.split()[-1] == "dtbs_check" +def _kbuild_from_params(monkeypatch, **params): + monkeypatch.setenv("KCI_API_TOKEN", "test-token") + params = { + "arch": "arm64", + "compiler": "gcc-14", + "defconfig": "defconfig", + "fragments": [], + **params, + } + return KBuild( + node={"artifacts": {"tarball": "https://storage.test/linux.tar.gz"}}, + jobname="kbuild-gcc-14-arm64", + params=params, + apiconfig="url: https://api.test\n", + ) + + +def _kbuild_from_json(tmp_path, monkeypatch, **params): + kbuild = _kbuild_from_params(monkeypatch, **params) + kbuild._storage_config = None + kbuild._fragments_dir = None + path = tmp_path / "kbuild.json" + kbuild.serialize(str(path)) + return KBuild.from_json(str(path)) + + +class TestKselftestFlag: + def test_enabled_by_default(self, monkeypatch): + assert _kbuild_from_params(monkeypatch)._kselftest is True + + def test_disabled_by_param(self, monkeypatch): + kbuild = _kbuild_from_params(monkeypatch, kselftest="disable") + assert kbuild._kselftest is False + + def test_disabled_for_dtbs_check(self, monkeypatch): + kbuild = _kbuild_from_params(monkeypatch, dtbs_check=True) + assert kbuild._kselftest is False + + def test_reload_keeps_enabled(self, tmp_path, monkeypatch): + assert _kbuild_from_json(tmp_path, monkeypatch)._kselftest is True + + def test_reload_keeps_disabled_for_dtbs_check(self, tmp_path, monkeypatch): + kbuild = _kbuild_from_json(tmp_path, monkeypatch, dtbs_check=True) + assert kbuild._kselftest is False + + class FakeStorage: def __init__(self): self.single_uploads = [] From 914953a5eb03eee6d38f76c8fbe2aad2fc81cde8 Mon Sep 17 00:00:00 2001 From: Ben Copeland Date: Fri, 25 Sep 2026 11:28:52 +0100 Subject: [PATCH 2/2] kbuild: drop the kfselftest fallback when loading serialised state The kbuild job serialises and reloads _build.json within the same run, so no state written before the _kfselftest rename (e8b8ea588) can reach the JSON loading path. Read the kselftest key like the other fields. Signed-off-by: Ben Copeland --- kernelci/kbuild.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernelci/kbuild.py b/kernelci/kbuild.py index fae58c09e7..a7b97767e9 100644 --- a/kernelci/kbuild.py +++ b/kernelci/kbuild.py @@ -276,9 +276,7 @@ def __init__( ) self._full_artifacts = jsonobj["full_artifacts"] self._dtbs_check = jsonobj["dtbs_check"] - self._kselftest = jsonobj.get( - "kselftest", jsonobj.get("kfselftest") - ) + self._kselftest = jsonobj["kselftest"] self._coverage = jsonobj.get("coverage", False) self._extra_targets = jsonobj.get("extra_targets", []) return