diff options
Diffstat (limited to 'tests/installer-steps/test_install_cpu_microcode.py')
| -rw-r--r-- | tests/installer-steps/test_install_cpu_microcode.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/tests/installer-steps/test_install_cpu_microcode.py b/tests/installer-steps/test_install_cpu_microcode.py new file mode 100644 index 0000000..20f1820 --- /dev/null +++ b/tests/installer-steps/test_install_cpu_microcode.py @@ -0,0 +1,110 @@ +"""Test install_cpu_microcode — vendor-detected microcode package install. + +archsetup never installed intel-ucode/amd-ucode (found on velox 2026-04-10: +CPU running old microcode, hand-fixed). The step reads vendor_id from +/proc/cpuinfo and installs the matching package. It must run before +configure_grub in boot_ux: grub-mkconfig detects /boot/<vendor>-ucode.img for +its initrd lines, and mkinitcpio's microcode hook embeds it, so the package +has to exist before either generates. + +Method: sed-extract install_cpu_microcode from the real `archsetup`, point it +at a fixture cpuinfo, fake pacman_install / display / error_warn. + +Run from repo root: + python3 -m unittest tests.installer-steps.test_install_cpu_microcode +""" + +import os +import re +import subprocess +import tempfile +import textwrap +import unittest + +REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +ARCHSETUP = os.path.join(REPO_ROOT, "archsetup") + +INTEL = "vendor_id\t: GenuineIntel\n" +AMD = "vendor_id\t: AuthenticAMD\n" + + +def run(cpuinfo_body, missing=False): + with tempfile.TemporaryDirectory() as d: + cpuinfo = os.path.join(d, "cpuinfo") + if not missing: + with open(cpuinfo, "w") as f: + f.write(cpuinfo_body) + script = textwrap.dedent(f"""\ + logfile=/dev/null + action="" + display() {{ :; }} + pacman_install() {{ echo "INSTALL: $1"; }} + error_warn() {{ echo "WARN: $1"; return 1; }} + source <(sed -n '/^install_cpu_microcode() {{/,/^}}/p' "{ARCHSETUP}") + install_cpu_microcode "{cpuinfo}" + echo "RC=$?" + exit 0 + """) + return subprocess.run( + ["bash", "-c", script], capture_output=True, text=True, timeout=10, + ) + + +def rc_of(r): + m = re.search(r"^RC=(\d+)$", r.stdout, re.M) + assert m, "no RC line in output: %r / %r" % (r.stdout, r.stderr) + return int(m.group(1)) + + +class InstallCpuMicrocode(unittest.TestCase): + # ------------------------------------------------------------ normal ---- + def test_intel_vendor_installs_intel_ucode(self): + r = run(f"processor\t: 0\n{INTEL}model name\t: whatever\n") + self.assertIn("INSTALL: intel-ucode", r.stdout) + self.assertNotIn("amd-ucode", r.stdout) + self.assertEqual(rc_of(r), 0) + + def test_amd_vendor_installs_amd_ucode(self): + r = run(f"processor\t: 0\n{AMD}") + self.assertIn("INSTALL: amd-ucode", r.stdout) + self.assertNotIn("intel-ucode", r.stdout) + self.assertEqual(rc_of(r), 0) + + # ---------------------------------------------------------- boundary ---- + def test_multicore_cpuinfo_installs_exactly_once(self): + # /proc/cpuinfo repeats vendor_id per logical CPU. + body = "".join(f"processor\t: {i}\n{AMD}\n" for i in range(16)) + r = run(body) + self.assertEqual(r.stdout.count("INSTALL:"), 1, + "one package install, not one per core") + + def test_space_separated_vendor_line_parses(self): + # Some kernels/arches pad with spaces rather than a tab. + r = run("vendor_id : GenuineIntel\n") + self.assertIn("INSTALL: intel-ucode", r.stdout) + + def test_vendor_id_substring_elsewhere_does_not_confuse(self): + # A flags line or model name mentioning a vendor string must not win + # over the real vendor_id line. + body = "model name\t: AuthenticAMD emulator\n" + INTEL + r = run(body) + self.assertIn("INSTALL: intel-ucode", r.stdout) + self.assertNotIn("amd-ucode", r.stdout) + + # ------------------------------------------------------------- error ---- + def test_unknown_vendor_warns_and_installs_nothing(self): + r = run("vendor_id\t: CentaurHauls\n") + self.assertNotIn("INSTALL:", r.stdout) + self.assertIn("WARN:", r.stdout) + self.assertEqual(rc_of(r), 1) + + def test_missing_cpuinfo_warns_and_installs_nothing(self): + r = run("", missing=True) + self.assertNotIn("INSTALL:", r.stdout) + self.assertIn("WARN:", r.stdout) + self.assertEqual(rc_of(r), 1) + self.assertEqual(r.returncode, 0) + + +if __name__ == "__main__": + unittest.main() |
