126 lines
5.0 KiB
Go
126 lines
5.0 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-controller/internal/conditions"
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
func TestAFailedUnitIsTheModulesConditionAndTheMachinesOwnAreOneFinding(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
inv, k := open.inventory, conditionsFrom
|
|
openConditions := func() map[string]conditions.Condition {
|
|
t.Helper()
|
|
list, err := k.Open(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := map[string]conditions.Condition{}
|
|
for _, c := range list {
|
|
out[c.Key] = c
|
|
}
|
|
return out
|
|
}
|
|
say := func(at time.Time, h link.Health) {
|
|
t.Helper()
|
|
if err := stateHealth(ctx, inv, k, "laptop", h, at); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
say(h0, desktop(h0))
|
|
got := openConditions()
|
|
machine, raised := got["machine.laptop.units"]
|
|
if !raised || len(got) != 1 {
|
|
t.Fatalf("the machine's own failed units are one finding at once (the engine looked twice): %v", got)
|
|
}
|
|
for _, unit := range []string{"mnt-recalbox.mount", "storage-media.mount", "greenclip.service"} {
|
|
if !strings.Contains(machine.Summary, unit) {
|
|
t.Errorf("the finding names %s: %s", unit, machine.Summary)
|
|
}
|
|
}
|
|
if strings.Contains(machine.Summary, "openrazer") || machine.Severity != conditions.Warning {
|
|
t.Errorf("the module's unit is the module's, and the machine's a warning: %+v", machine)
|
|
}
|
|
|
|
say(h0.Add(time.Minute), desktop(h0.Add(time.Minute)))
|
|
got = openConditions()
|
|
module, raised := got["module.openrazer.laptop.unhealthy"]
|
|
if !raised || !strings.Contains(module.Summary, "openrazer-daemon.service") ||
|
|
!strings.Contains(module.Summary, "account's own service manager") {
|
|
t.Fatalf("the module's failed unit raises its condition on the second statement, naming the unit: %+v", got)
|
|
}
|
|
|
|
kept, had, err := inv.HealthOf(ctx, "laptop")
|
|
if err != nil || !had || kept.Units == nil || len(kept.Units.Failed) != 3 {
|
|
t.Fatalf("the statement's units were not kept: %+v %v", kept.Units, err)
|
|
}
|
|
lines := strings.Join(unitsLines(kept, had, h0), "\n")
|
|
for _, want := range []string{"degraded", "storage-media.mount (system) — no module places it",
|
|
"openrazer-daemon.service — openrazer's"} {
|
|
if !strings.Contains(lines, want) {
|
|
t.Errorf("node show does not say %q:\n%s", want, lines)
|
|
}
|
|
}
|
|
|
|
// An older engine says nothing of its units: nothing cleared on its word.
|
|
older := desktop(h0.Add(2 * time.Minute))
|
|
older.Units = nil
|
|
say(h0.Add(2*time.Minute), older)
|
|
if _, still := openConditions()["machine.laptop.units"]; !still {
|
|
t.Fatal("a statement saying nothing of units cleared the machine's finding")
|
|
}
|
|
|
|
// The operator mends the mounts and removes the leftover link; the module's unit still fails.
|
|
mended := desktop(h0.Add(3 * time.Minute))
|
|
mended.Units.Failed = []link.FailedUnit{}
|
|
say(h0.Add(3*time.Minute), mended)
|
|
got = openConditions()
|
|
if _, still := got["machine.laptop.units"]; still {
|
|
t.Fatalf("no failed unit of the machine's own, still open: %v", got)
|
|
}
|
|
if _, still := got["module.openrazer.laptop.unhealthy"]; !still {
|
|
t.Fatalf("the module's unit still fails, and its condition stands: %v", got)
|
|
}
|
|
|
|
// And the module's unit mended: running, nothing open.
|
|
well := link.Health{Contract: link.ReadinessContract, At: h0.Add(4 * time.Minute),
|
|
Units: &link.UnitsHealth{State: link.UnitsRunning, Failed: []link.FailedUnit{}}}
|
|
say(h0.Add(4*time.Minute), well)
|
|
if got = openConditions(); len(got) != 0 {
|
|
t.Fatalf("a running service manager leaves nothing open: %v", got)
|
|
}
|
|
}
|
|
|
|
// desktop is the workstation as found on 2026-10-08, with the mesh's names: the Razer daemon's packaged
|
|
// user unit, the module's; two mounts of the machine's own table and a unit a removed package left
|
|
// behind, the machine's.
|
|
func desktop(at time.Time) link.Health {
|
|
return link.Health{Contract: link.ReadinessContract, At: at,
|
|
Resources: []link.ResourceHealth{{Module: "openrazer", Resource: "openrazer.daemon", Kind: link.KindUnit,
|
|
Target: "openrazer-daemon.service", State: link.StateUnhealthy,
|
|
Reason: "failed in the account's own service manager (exit-code)", Since: h0, Streak: 2}},
|
|
Units: &link.UnitsHealth{State: link.UnitsDegraded, Failed: []link.FailedUnit{
|
|
{Unit: "mnt-recalbox.mount", Scope: "system", Load: "loaded", Result: "exit-code", Since: h0},
|
|
{Unit: "storage-media.mount", Scope: "system", Load: "loaded", Result: "timeout", Since: h0},
|
|
{Unit: "greenclip.service", Scope: "user", Load: "not-found", Result: "start-limit-hit", Since: h0},
|
|
}}}
|
|
}
|
|
|
|
func TestTheGateNeverHoldsASendOnTheMachinesOwnUnits(t *testing.T) {
|
|
since := h0
|
|
units := conditions.Condition{Key: "machine.laptop.units", Kind: kindMachineUnits,
|
|
Subject: conditions.Subject{Scope: conditions.ScopeMachine, ID: "laptop", Machine: "laptop"},
|
|
Summary: "laptop's service manager is degraded", Raised: since.Add(time.Minute), Source: sourceUnits}
|
|
if w := aboutTheMachine("laptop", []string{"openrazer"}, since, gateFacts{judged: true,
|
|
open: []conditions.Condition{units}}); w.whole != "" || w.waiting != "" || len(w.on) != 0 {
|
|
t.Fatalf("the machine's own failed units held a send: %+v", w)
|
|
}
|
|
}
|