test(power): VM check for battery charge-limit udev re-apply
Add checks.battery-charge-limit (runNixOSTest): the test_power module fakes a Mains adapter, toggling ac_online emits a real power_supply uevent, and the test asserts the udev rule restarts the oneshot (changed InvocationID). Verifies the re-apply *trigger* at runtime, beyond the earlier eval check; the sysfs write still needs real hardware. Also records the SSH_AUTH_SOCK rendered-artifact verification in the roadmap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -298,9 +298,11 @@ how to override it. Items marked ✓ are shipped.
|
|||||||
shell's copy — resolved with `gpgconf --list-dirs agent-ssh-socket` at
|
shell's copy — resolved with `gpgconf --list-dirs agent-ssh-socket` at
|
||||||
session-init (the same lookup the shell integration uses, so the two can't
|
session-init (the same lookup the shell integration uses, so the two can't
|
||||||
drift), reaching GUI apps via the login shell that starts Hyprland the same
|
drift), reaching GUI apps via the login shell that starts Hyprland the same
|
||||||
way `NIXOS_OZONE_WL` does. Eval-verified (the var resolves to the gpgconf
|
way `NIXOS_OZONE_WL` does. Verified by building the home generation and
|
||||||
substitution; home config builds). Pending an on-machine check that a GUI
|
inspecting the rendered `hm-session-vars.sh` — it carries
|
||||||
git/ssh client picks up the agent.
|
`export SSH_AUTH_SOCK="$(…/gpgconf --list-dirs agent-ssh-socket)"` with the
|
||||||
|
command substitution intact (unescaped, resolved at session-init). Pending
|
||||||
|
an on-machine check that a GUI git/ssh client picks up the agent.
|
||||||
- **Sanitize & organize the repo:** a housekeeping pass for consistency
|
- **Sanitize & organize the repo:** a housekeeping pass for consistency
|
||||||
and clarity.
|
and clarity.
|
||||||
- ✓ pruned now-redundant config: the installer no longer writes
|
- ✓ pruned now-redundant config: the installer no longer writes
|
||||||
@@ -361,10 +363,14 @@ how to override it. Items marked ✓ are shipped.
|
|||||||
unplug gap — the match is by adapter *type*, not kernel name
|
unplug gap — the match is by adapter *type*, not kernel name
|
||||||
(AC/AC0/ADP1/ACAD vary), and `restart` (not `try-restart`) re-applies
|
(AC/AC0/ADP1/ACAD vary), and `restart` (not `try-restart`) re-applies
|
||||||
even if the boot run was inactive. Eval-verified both ways (rule present
|
even if the boot run was inactive. Eval-verified both ways (rule present
|
||||||
with charge limit on / absent off). **Pending an on-hardware check** (a
|
with charge limit on / absent off), and **VM-verified the trigger**
|
||||||
`sudo nixos-rebuild` + a physical unplug to fire the udev event — the
|
(`checks.battery-charge-limit`: the `test_power` module fakes a Mains
|
||||||
dev box has both an `AC` Mains adapter and a `BAT0`
|
adapter, toggling `ac_online` emits a real `power_supply` uevent, and the
|
||||||
`charge_control_end_threshold`, so it can exercise it).
|
udev rule restarts the oneshot — confirmed by a changed `InvocationID`).
|
||||||
|
The sysfs *write* itself needs a real `charge_control_end_threshold`, so
|
||||||
|
a final on-hardware check (a `sudo nixos-rebuild` + a physical unplug)
|
||||||
|
remains — the dev box has both an `AC` Mains adapter and a `BAT0`
|
||||||
|
`charge_control_end_threshold`, so it can exercise it.
|
||||||
- ✓ **installer:** writes `power.laptop = true` (battery probe) and
|
- ✓ **installer:** writes `power.laptop = true` (battery probe) and
|
||||||
`power.thermal.enable` (Intel) into the generated `system.nix`.
|
`power.thermal.enable` (Intel) into the generated `system.nix`.
|
||||||
- ✓ **idle cohesion:** `modules/home/idle.nix` now suspends only on
|
- ✓ **idle cohesion:** `modules/home/idle.nix` now suspends only on
|
||||||
|
|||||||
47
flake.nix
47
flake.nix
@@ -159,6 +159,53 @@
|
|||||||
machine.succeed("grep -q pam_fprintd /etc/pam.d/sudo")
|
machine.succeed("grep -q pam_fprintd /etc/pam.d/sudo")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Runtime VM check for the battery-charge-limit re-apply: the udev
|
||||||
|
# rule must restart the oneshot on an AC state change (firmware can
|
||||||
|
# clear the threshold on unplug). The `test_power` module fakes a
|
||||||
|
# Mains adapter we can toggle to emit a real power_supply uevent —
|
||||||
|
# so this exercises the trigger, not just the config wiring. (The
|
||||||
|
# sysfs *write* needs a real charge_control_end_threshold and stays
|
||||||
|
# an on-hardware check.) Imports options.nix (where the power
|
||||||
|
# options live) + power.nix, so the VM stays minimal.
|
||||||
|
battery-charge-limit = pkgs.testers.runNixOSTest {
|
||||||
|
name = "nomarchy-battery-charge-limit";
|
||||||
|
nodes.machine = { ... }: {
|
||||||
|
imports = [ ./modules/nixos/options.nix ./modules/nixos/power.nix ];
|
||||||
|
boot.kernelModules = [ "test_power" ]; # fake Mains + battery
|
||||||
|
nomarchy.system.power = {
|
||||||
|
enable = true;
|
||||||
|
laptop = true;
|
||||||
|
batteryChargeLimit = 80;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testScript = ''
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
# The oneshot exists and the fake Mains adapter is present.
|
||||||
|
machine.succeed("systemctl cat nomarchy-battery-charge-limit.service")
|
||||||
|
machine.succeed("udevadm settle")
|
||||||
|
machine.succeed("grep -lx Mains /sys/class/power_supply/*/type")
|
||||||
|
|
||||||
|
# Let any add-event restart settle, then sample the invocation.
|
||||||
|
machine.succeed("sleep 2")
|
||||||
|
before = machine.succeed(
|
||||||
|
"systemctl show -p InvocationID --value "
|
||||||
|
"nomarchy-battery-charge-limit.service"
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
# Simulate an AC unplug → 'change' uevent on the Mains device.
|
||||||
|
machine.succeed("echo off > /sys/module/test_power/parameters/ac_online")
|
||||||
|
machine.succeed("udevadm settle")
|
||||||
|
|
||||||
|
# The udev rule must have restarted the oneshot (new InvocationID).
|
||||||
|
machine.wait_until_succeeds(
|
||||||
|
'test "$(systemctl show -p InvocationID --value '
|
||||||
|
'nomarchy-battery-charge-limit.service)" != "' + before + '"',
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# ─── Reference host ────────────────────────────────────────────
|
# ─── Reference host ────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user