From fca837883b0b79793ea81d223d6e08a8ee2b2248 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sat, 8 Aug 2026 04:55:52 -0500 Subject: feat: automate microcode, TLP radio enable, and ZFS tmp.mount mask The 2026-04 velox setup left three manual fixes behind. All three now happen at install time. - The TLP config sets DEVICES_TO_ENABLE_ON_STARTUP="bluetooth wifi". systemd-rfkill is masked on laptops because it fights TLP, so TLP is the only thing left that can restore radio state. Without this a fresh install can boot with both radios soft-blocked. - mask_tmp_mount_for_zfs masks systemd's tmp.mount when the pool carries a dataset mounted at /tmp, so tmpfs can't shadow the dataset and break systemd-tmpfiles. - install_cpu_microcode installs intel-ucode or amd-ucode by vendor_id, first in boot_ux so grub-mkconfig and mkinitcpio's microcode hook both see the ucode image. New tests cover each function across normal, boundary, and error cases. The boot_ux and snapshot-dispatch sequence pins include the new calls. --- tests/installer-steps/test_configure_tlp_power.py | 110 ++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/installer-steps/test_configure_tlp_power.py (limited to 'tests/installer-steps/test_configure_tlp_power.py') diff --git a/tests/installer-steps/test_configure_tlp_power.py b/tests/installer-steps/test_configure_tlp_power.py new file mode 100644 index 0000000..c88e0c2 --- /dev/null +++ b/tests/installer-steps/test_configure_tlp_power.py @@ -0,0 +1,110 @@ +"""Test configure_tlp_power's radio-enable line and laptop gating. + +systemd-rfkill is masked on laptops because it fights TLP's radio handling — +which means nothing restores radio state at boot unless TLP is told to. The +velox 2026-04-10 setup found wifi and bluetooth soft-blocked on first boot for +exactly this reason. The conf written here must carry +DEVICES_TO_ENABLE_ON_STARTUP so a fresh install comes up with radios on. + +Method: sed-extract configure_tlp_power from the real `archsetup`, point it at +a temp tlp.d dir and a temp power-supply dir, and fake pacman_install / +run_task / display / error_warn / systemctl. + +Run from repo root: + python3 -m unittest tests.installer-steps.test_configure_tlp_power +""" + +import os +import stat +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") + + +def run(battery=True, bat_name="BAT0", unwritable_tlpd=False): + with tempfile.TemporaryDirectory() as d: + psdir = os.path.join(d, "power_supply") + os.makedirs(psdir) + if battery: + open(os.path.join(psdir, bat_name), "w").close() + tlpd = os.path.join(d, "tlp.d") + if unwritable_tlpd: + os.makedirs(tlpd) + os.chmod(tlpd, stat.S_IRUSR | stat.S_IXUSR) + # The real mask call redirects stdout into $logfile, so the fake + # systemctl records to a side file the test reads back instead. + script = textwrap.dedent(f"""\ + logfile=/dev/null + action="" + display() {{ :; }} + pacman_install() {{ echo "INSTALL: $1"; }} + run_task() {{ echo "TASK: $1"; }} + systemctl() {{ echo "SYSTEMCTL: $*" >> "{d}/systemctl.log"; }} + error_warn() {{ echo "WARN: $1"; return 1; }} + source <(sed -n '/^configure_tlp_power() {{/,/^}}/p' "{ARCHSETUP}") + configure_tlp_power "{tlpd}" "{psdir}" + echo "RC=$?" + echo "CONF:[$(cat "{tlpd}/01-custom.conf" 2>/dev/null)]" + [ -f "{d}/systemctl.log" ] && cat "{d}/systemctl.log" + exit 0 + """) + r = subprocess.run( + ["bash", "-c", script], capture_output=True, text=True, timeout=10, + ) + if unwritable_tlpd: + os.chmod(tlpd, stat.S_IRWXU) + return r + + +class ConfigureTlpPower(unittest.TestCase): + # ------------------------------------------------------------ normal ---- + def test_laptop_gets_tlp_with_radio_enable_line(self): + r = run(battery=True) + self.assertIn("INSTALL: tlp", r.stdout) + conf = r.stdout.split("CONF:[")[1] + self.assertIn('DEVICES_TO_ENABLE_ON_STARTUP="bluetooth wifi"', conf, + "radios must be re-enabled at boot: systemd-rfkill is " + "masked, so TLP is the only thing that can do it") + self.assertIn("CPU_ENERGY_PERF_POLICY_ON_AC", conf) + self.assertIn("SYSTEMCTL: mask systemd-rfkill.service systemd-rfkill.socket", + r.stdout) + self.assertIn("TASK: enabling TLP service", r.stdout) + + def test_radio_line_is_active_not_commented(self): + r = run(battery=True) + conf = r.stdout.split("CONF:[")[1].split("]")[0] + for line in conf.splitlines(): + if "DEVICES_TO_ENABLE_ON_STARTUP" in line: + self.assertFalse(line.lstrip().startswith("#"), + "the radio-enable line must not be commented out") + break + else: + self.fail("DEVICES_TO_ENABLE_ON_STARTUP line missing from conf") + + # ---------------------------------------------------------- boundary ---- + def test_desktop_without_battery_is_a_no_op(self): + r = run(battery=False) + self.assertNotIn("INSTALL:", r.stdout) + self.assertNotIn("SYSTEMCTL:", r.stdout) + self.assertIn("CONF:[]", r.stdout, "no conf may be written on a desktop") + + def test_second_battery_index_still_counts_as_laptop(self): + r = run(battery=True, bat_name="BAT1") + self.assertIn("INSTALL: tlp", r.stdout) + self.assertIn('DEVICES_TO_ENABLE_ON_STARTUP', r.stdout) + + # ------------------------------------------------------------- error ---- + @unittest.skipUnless(os.geteuid() != 0, "root ignores directory write bits") + def test_unwritable_tlpd_warns_and_does_not_crash(self): + r = run(battery=True, unwritable_tlpd=True) + self.assertIn("WARN:", r.stdout, + "a failed conf write must surface through error_warn") + self.assertEqual(r.returncode, 0) + + +if __name__ == "__main__": + unittest.main() -- cgit v1.2.3