package units import ( "context" "errors" "strings" "testing" "time" "github.com/novox/mesh-host/internal/declaration" ) // The reading of failed units (novox/hq issue 315, "how it is checked"): a failed unit a module states, // writes or installs is that module's, in either manager; one no module places is the machine's; a unit // liveness judges is left to it; the two-look rule holds both ways; a manager that cannot be read is // unread, never healthy; and only reads are asked. type fakeReader struct { failed map[string][]Listed // by "system" or "user:" shown map[string]Shown // by unit owners map[string]string // by path unread map[string]error ownerQs int } func mgr(scope, user string) string { if scope == ScopeUser { return "user:" + user } return "system" } func (f *fakeReader) Failed(_ context.Context, scope, user string) ([]Listed, error) { if err := f.unread[mgr(scope, user)]; err != nil { return nil, err } return f.failed[mgr(scope, user)], nil } func (f *fakeReader) Show(_ context.Context, _, _ string, units []string) (map[string]Shown, error) { out := map[string]Shown{} for _, u := range units { out[u] = f.shown[u] } return out, nil } func (f *fakeReader) PackageOwning(_ context.Context, path string) (string, bool, error) { f.ownerQs++ p, ok := f.owners[path] return p, ok, nil } // shanks is the desktop as found on 2026-10-08: two mounts of the machine's own mount table, the // Razer daemon's packaged user unit, and a unit a removed package left behind. func shanks() *fakeReader { return &fakeReader{ failed: map[string][]Listed{ "system": {{Unit: "mnt-recalbox.mount", Load: "loaded"}, {Unit: "storage-media.mount", Load: "loaded"}}, "user:operator": {{Unit: "greenclip.service", Load: "not-found"}, {Unit: "openrazer-daemon.service", Load: "loaded"}}, }, shown: map[string]Shown{ "mnt-recalbox.mount": {FragmentPath: "/run/systemd/generator/mnt-recalbox.mount", Result: "exit-code"}, "storage-media.mount": {FragmentPath: "/run/systemd/generator/storage-media.mount", Result: "timeout"}, "greenclip.service": {}, "openrazer-daemon.service": {FragmentPath: "/usr/lib/systemd/user/openrazer-daemon.service", Result: "exit-code"}, }, owners: map[string]string{"/usr/lib/systemd/user/openrazer-daemon.service": "openrazer-daemon"}, } } func declared() *declaration.Declaration { return &declaration.Declaration{Resources: []declaration.Resource{ &declaration.Package{ID: "openrazer.daemon", Type: declaration.TypePackage, Package: "openrazer-daemon"}, &declaration.Package{ID: "clipmenu.greenclip", Type: declaration.TypePackage, Package: "rofi-greenclip", Absent: true}, &declaration.User{ID: "zsh.account", Type: declaration.TypeUser, Name: "operator"}, &declaration.Service{ID: "sshd.run", Type: declaration.TypeService, Unit: "sshd.service", State: "running"}, &declaration.Service{ID: "power.after-boot", Type: declaration.TypeService, Unit: "mesh-power-after-boot.service"}, &declaration.File{ID: "watcher.unit", Type: declaration.TypeFile, Path: "/home/operator/.config/systemd/user/watcher.service"}, }} } var t0 = time.Date(2026, 10, 8, 12, 0, 0, 0, time.UTC) func lookTwice(t *testing.T, j *Judge) Statement { t.Helper() now := t0 j.Now = func() time.Time { return now } first, _ := j.Look(context.Background()) if len(first.Failed) != 0 { t.Fatalf("a unit was said failed on its first look: %+v", first.Failed) } now = now.Add(15 * time.Second) st, _ := j.Look(context.Background()) return st } func TestTheModulesAndTheMachinesFailures(t *testing.T) { r := shanks() j := New(r) j.Set(OwnedBy(declared(), nil)) st := lookTwice(t, j) if st.State != Degraded { t.Fatalf("state %q, want degraded", st.State) } owned := st.Owned() if len(owned) != 1 || owned[0].Unit != "openrazer-daemon.service" || owned[0].Module != "openrazer" || owned[0].Resource != "openrazer.daemon" || owned[0].Via != ViaPackage || owned[0].Scope != ScopeUser { t.Fatalf("the Razer daemon's packaged user unit is openrazer's: %+v", owned) } if owned[0].Since != t0 || owned[0].Streak != 2 || owned[0].Result != "exit-code" { t.Fatalf("since the first look that found it, two in a row, how it failed: %+v", owned[0]) } var machine []string for _, f := range st.Unowned() { machine = append(machine, f.Scope+"/"+f.Unit) } want := "system/mnt-recalbox.mount system/storage-media.mount user/greenclip.service" if strings.Join(machine, " ") != want { t.Fatalf("the machine's own: %v, want %s", machine, want) } } func TestADeclaredUnitAndAWrittenFileAreTheirModules(t *testing.T) { r := &fakeReader{ failed: map[string][]Listed{ "system": {{Unit: "mesh-power-after-boot.service", Load: "loaded"}, {Unit: "sshd.service", Load: "loaded"}}, "user:operator": {{Unit: "watcher.service", Load: "loaded"}}, }, shown: map[string]Shown{ "watcher.service": {FragmentPath: "/home/operator/.config/systemd/user/watcher.service"}, }, } j := New(r) j.Set(OwnedBy(declared(), nil)) st := lookTwice(t, j) got := map[string]string{} for _, f := range st.Failed { got[f.Unit] = f.Module + " " + f.Via } if got["mesh-power-after-boot.service"] != "power unit" { t.Errorf("a stateless service the declaration names is its module's: %q", got["mesh-power-after-boot.service"]) } if got["watcher.service"] != "watcher file" { t.Errorf("a user unit the mesh wrote is its module's: %q", got["watcher.service"]) } if _, said := got["sshd.service"]; said { t.Errorf("a service stated running is liveness's to judge, and said once: %v", got) } if r.ownerQs != 0 { t.Errorf("the package database was asked %d time(s) for units the declaration already names", r.ownerQs) } } func TestTwoLooksEachWay(t *testing.T) { r := shanks() j := New(r) j.Set(OwnedBy(declared(), nil)) now := t0 j.Now = func() time.Time { return now } st, changed := j.Look(context.Background()) if len(st.Failed) != 0 || !changed { t.Fatalf("first look: nothing said failed, the state said: %+v %v", st.Failed, changed) } now = now.Add(15 * time.Second) if st, changed = j.Look(context.Background()); len(st.Failed) != 4 || !changed { t.Fatalf("second look: four said failed: %+v %v", st.Failed, changed) } now = now.Add(15 * time.Second) if _, changed = j.Look(context.Background()); changed { t.Fatal("a third look the same is no change") } // The operator mounts the media library again: no longer failed on the first look that says so. r.failed["system"] = r.failed["system"][:1] now = now.Add(15 * time.Second) st, changed = j.Look(context.Background()) if len(st.Failed) != 3 || !changed { t.Fatalf("a unit no longer failed is no longer said: %+v", st.Failed) } // Every manager clean: running. r.failed = map[string][]Listed{} now = now.Add(15 * time.Second) if st, _ = j.Look(context.Background()); st.State != Running || len(st.Failed) != 0 { t.Fatalf("no failed unit is running: %+v", st) } } func TestAManagerThatCannotBeReadIsUnread(t *testing.T) { r := shanks() j := New(r) j.Set(OwnedBy(declared(), nil)) lookTwice(t, j) r.unread = map[string]error{"user:operator": errors.New("Failed to connect to bus: No medium found")} st, _ := j.Look(context.Background()) if len(st.Unread) != 1 || !strings.Contains(st.Unread[0], "operator") { t.Fatalf("the account manager is said unread: %v", st.Unread) } // Its failures are not counted while unread, and not forgotten either: back on the next read, said // at once, from when they were first found. r.unread = nil st, _ = j.Look(context.Background()) for _, f := range st.Failed { if f.Unit == "openrazer-daemon.service" && f.Since == t0 { return } } t.Fatalf("a manager read again says what it held, from when it was first found: %+v", st.Failed) } func TestNoManagerReadIsUnknown(t *testing.T) { r := &fakeReader{unread: map[string]error{"system": errors.New("systemctl: not found"), "user:operator": errors.New("systemctl: not found")}} j := New(r) j.Set(OwnedBy(declared(), nil)) if st, _ := j.Look(context.Background()); st.State != Unknown { t.Fatalf("no manager read is unknown, never running: %q", st.State) } } func TestAnAdoptedMachinesHoldingIsTheMachines(t *testing.T) { d := &declaration.Declaration{Resources: []declaration.Resource{ &declaration.Service{ID: "found.cups", Type: declaration.TypeService, Unit: "cups.service"}, }} o := OwnedBy(d, map[string]bool{"found.cups": true}) if _, ok := o.Units["system/cups.service"]; ok { t.Fatal("a unit an adopted machine holds as found is the machine's, not a module's") } } func TestTheReaderOnlyReads(t *testing.T) { var asked []string run := func(_ context.Context, name string, args ...string) (string, error) { asked = append(asked, name+" "+strings.Join(args, " ")) switch { case name == "systemctl" && contains(args, "list-units"): return "● greenclip.service not-found failed failed greenclip.service\n" + "openrazer-daemon.service loaded failed failed Daemon to manage razer devices in userspace\n", nil case name == "systemctl" && contains(args, "show"): return "Id=greenclip.service\nFragmentPath=\nResult=start-limit-hit\n\n" + "Id=openrazer-daemon.service\nFragmentPath=/usr/lib/systemd/user/openrazer-daemon.service\nResult=exit-code\n", nil case name == "pacman" && contains(args, "-Qqo"): return "openrazer-daemon\n", nil } return "", nil } e := Exec{Run: run, System: "arch"} listed, err := e.Failed(context.Background(), ScopeUser, "operator") if err != nil || len(listed) != 2 || listed[0].Unit != "greenclip.service" || listed[0].Load != "not-found" { t.Fatalf("the list, its mark skipped: %+v %v", listed, err) } shown, err := e.Show(context.Background(), ScopeUser, "operator", []string{"greenclip.service", "openrazer-daemon.service"}) if err != nil || shown["openrazer-daemon.service"].FragmentPath == "" || shown["greenclip.service"].Result != "start-limit-hit" { t.Fatalf("the show: %+v %v", shown, err) } if pkg, ok, err := e.PackageOwning(context.Background(), "/usr/lib/systemd/user/openrazer-daemon.service"); !ok || pkg != "openrazer-daemon" || err != nil { t.Fatalf("the owner: %q %v %v", pkg, ok, err) } for _, a := range asked { if !strings.Contains(a, "list-units") && !strings.Contains(a, " show ") && !strings.HasPrefix(a, "pacman -Q") { t.Errorf("asked something that is not a read: %q", a) } if !strings.HasPrefix(a, "pacman") && !strings.Contains(a, "--machine=operator@") { t.Errorf("an account's manager is asked as that account's: %q", a) } } } func contains(args []string, s string) bool { for _, a := range args { if a == s { return true } } return false } func TestNothingIsReadBeforeADeclaration(t *testing.T) { r := shanks() j := New(r) if st, changed := j.Look(context.Background()); st.State != "" || changed { t.Fatalf("before a declaration every unit would read as the machine's: %+v", st) } }