test(auto-theme): #79 V2 — simulate sunset in a VM (was mis-framed V3)
All checks were successful
Check / eval (push) Successful in 3m53s
All checks were successful
Check / eval (push) Successful in 3m53s
Bernardo rightly pushed back on deferring #79 to a real session: a simulated sunset IS VM-testable. Add checks.auto-theme, a runNixOSTest that installs nomarchy-theme-sync, points NOMARCHY_DEFAULT_THEMES at the presets, stubs the rebuild via NOMARCHY_REBUILD (a marker), configures the day/night pair + schedule, then WALKS THE VM CLOCK across the boundary: 19:55 -> 20:05 -> 20:06 -> next-day 07:30, asserting the active theme goes summer-day -> night (1 rebuild) -> night (idempotent, still 1) -> day (2 rebuilds). This isolates the auto decision + apply + rebuild-trigger; the actual home-manager switch is stubbed (that generic apply path is exercised by every manual theme change). The only on-hardware residual is the user timer firing on its OnCalendar schedule, which systemd-analyze validates. #79 drops its [blocked:hw] tag — it's V2-verified. ROADMAP updated; lesson recorded in MEMORY (don't default timer/session features to V3: stub the generic step, simulate the clock). Verification: V2 PASS (nix build .#checks.x86_64-linux.auto-theme, fresh, exit 0); V0 flake check green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
72
flake.nix
72
flake.nix
@@ -752,6 +752,78 @@
|
||||
'';
|
||||
};
|
||||
|
||||
# Auto time-of-day theme (#79, VISION § D): simulate crossing
|
||||
# sunset and sunrise by moving the VM clock, and assert
|
||||
# `nomarchy-theme-sync auto` switches the active theme accordingly
|
||||
# — day stays day (no needless rebuild), sunset flips to night,
|
||||
# a later tick is idempotent, sunrise flips back. The actual
|
||||
# `home-manager switch` is stubbed via NOMARCHY_REBUILD (that
|
||||
# generic apply path is exercised by every manual theme change);
|
||||
# this isolates the auto decision + apply + rebuild-trigger.
|
||||
auto-theme = pkgs.testers.runNixOSTest {
|
||||
name = "nomarchy-auto-theme";
|
||||
nodes.machine = { pkgs, ... }: {
|
||||
environment.systemPackages = [ pkgs.nomarchy-theme-sync ];
|
||||
time.timeZone = "UTC"; # naive HH:MM == the clock we set
|
||||
};
|
||||
testScript = ''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.succeed("timedatectl set-ntp false || true")
|
||||
|
||||
# Writable flake state (start on the day theme) + a rebuild stub
|
||||
# that records each invocation instead of running home-manager.
|
||||
machine.succeed("mkdir -p /root/.nomarchy")
|
||||
machine.succeed(
|
||||
"echo '{\"slug\":\"summer-day\"}' > /root/.nomarchy/theme-state.json"
|
||||
)
|
||||
machine.succeed(
|
||||
"printf '#!/bin/sh\\necho switch >> /root/rebuilds\\n' > /root/rebuild"
|
||||
" && chmod +x /root/rebuild"
|
||||
)
|
||||
|
||||
env = ("NOMARCHY_PATH=/root/.nomarchy "
|
||||
"NOMARCHY_DEFAULT_THEMES=${./themes} "
|
||||
"NOMARCHY_REBUILD=/root/rebuild ")
|
||||
|
||||
# Pair + schedule (setup writes only, no rebuild).
|
||||
for kv in ["settings.autoTheme.enable true",
|
||||
"settings.autoTheme.day summer-day",
|
||||
"settings.autoTheme.night summer-night",
|
||||
"settings.autoTheme.sunrise 07:00",
|
||||
"settings.autoTheme.sunset 20:00"]:
|
||||
machine.succeed(env + "nomarchy-theme-sync --quiet set " + kv + " --no-switch")
|
||||
|
||||
def slug():
|
||||
return machine.succeed(env + "nomarchy-theme-sync get slug").strip()
|
||||
def rebuilds():
|
||||
return int(machine.succeed("wc -l < /root/rebuilds 2>/dev/null || echo 0").strip())
|
||||
|
||||
# Before sunset: already the day theme → no switch, no rebuild.
|
||||
machine.succeed("date -s '2026-01-02 19:55:00'")
|
||||
machine.succeed(env + "nomarchy-theme-sync auto")
|
||||
assert slug() == "summer-day", f"pre-sunset should stay day, got {slug()}"
|
||||
assert rebuilds() == 0, f"no needless rebuild, got {rebuilds()}"
|
||||
|
||||
# Cross sunset → night theme, exactly one rebuild triggered.
|
||||
machine.succeed("date -s '2026-01-02 20:05:00'")
|
||||
machine.succeed(env + "nomarchy-theme-sync auto")
|
||||
assert slug() == "summer-night", f"post-sunset should be night, got {slug()}"
|
||||
assert rebuilds() == 1, f"sunset should trigger one rebuild, got {rebuilds()}"
|
||||
|
||||
# Another tick still after sunset → idempotent, no extra rebuild.
|
||||
machine.succeed("date -s '2026-01-02 20:06:00'")
|
||||
machine.succeed(env + "nomarchy-theme-sync auto")
|
||||
assert slug() == "summer-night"
|
||||
assert rebuilds() == 1, f"idempotent tick must not rebuild, got {rebuilds()}"
|
||||
|
||||
# Cross sunrise the next morning → back to day, second rebuild.
|
||||
machine.succeed("date -s '2026-01-03 07:30:00'")
|
||||
machine.succeed(env + "nomarchy-theme-sync auto")
|
||||
assert slug() == "summer-day", f"post-sunrise should be day, got {slug()}"
|
||||
assert rebuilds() == 2, f"sunrise should trigger a rebuild, got {rebuilds()}"
|
||||
'';
|
||||
};
|
||||
|
||||
# Snapshot GUI canary: btrfs-assistant crashes in libbtrfsutil's
|
||||
# UNPRIVILEGED subvolume iteration (btrfs-progs 6.17.1, fixed
|
||||
# upstream after 6.17.1) but runs fine as root — which is how the
|
||||
|
||||
Reference in New Issue
Block a user