2026-03-31 14:52:50 -03:00
|
|
|
package facts
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"metis/pkg/inventory"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestAggregateGroupsByClass(t *testing.T) {
|
|
|
|
|
inv := &inventory.Inventory{
|
|
|
|
|
Classes: []inventory.NodeClass{{Name: "c1"}, {Name: "c2"}},
|
|
|
|
|
Nodes: []inventory.NodeSpec{
|
2026-04-11 01:08:08 -03:00
|
|
|
{Name: "n1", Class: "c1", USBScratch: &inventory.USBScratchDisk{Mountpoint: "/mnt/scratch", Label: "scratch-1", BindTargets: []string{"/var/lib/rancher"}}},
|
2026-03-31 14:52:50 -03:00
|
|
|
{Name: "n2", Class: "c2"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
snaps := []Snapshot{
|
2026-04-11 01:08:08 -03:00
|
|
|
{Hostname: "n1", Kernel: "k1", PackageSample: map[string]string{"containerd": "2.0"}, USBScratch: &USBScratch{Mountpoint: "/mnt/scratch", Label: "scratch-1", MountHealthy: true, LabelHealthy: true, BindHealthy: true, BindTargets: []USBBindTarget{{Path: "/var/lib/rancher", Healthy: true}}}},
|
2026-03-31 14:52:50 -03:00
|
|
|
{Hostname: "n2", Kernel: "k2", PackageSample: map[string]string{"containerd": "1.7"}},
|
|
|
|
|
{Hostname: "n1", Kernel: "k1"},
|
|
|
|
|
}
|
|
|
|
|
sum := Aggregate(inv, snaps)
|
|
|
|
|
if len(sum) != 2 {
|
|
|
|
|
t.Fatalf("expected 2 classes, got %d", len(sum))
|
|
|
|
|
}
|
|
|
|
|
c1 := sum["c1"]
|
|
|
|
|
if c1 == nil || c1.Kernels["k1"] != 2 {
|
|
|
|
|
t.Fatalf("expected k1 count 2, got %#v", c1)
|
|
|
|
|
}
|
|
|
|
|
if c1.PackageStats["containerd"]["2.0"] != 1 {
|
|
|
|
|
t.Fatalf("package stats not tallied: %#v", c1.PackageStats)
|
|
|
|
|
}
|
2026-04-11 01:08:08 -03:00
|
|
|
if c1.USBMountHealth["ok"] != 1 || c1.USBLabelHealth["ok"] != 1 || c1.USBBindHealth["ok"] != 1 {
|
|
|
|
|
t.Fatalf("usb health not tallied: %#v", c1)
|
|
|
|
|
}
|
2026-03-31 14:52:50 -03:00
|
|
|
}
|
2026-04-11 00:17:10 -03:00
|
|
|
|
|
|
|
|
func TestAggregateKeepsUnknownHostnames(t *testing.T) {
|
|
|
|
|
sum := Aggregate(nil, []Snapshot{{Hostname: "ghost", Kernel: "k"}})
|
|
|
|
|
if sum["unknown"].Nodes[0] != "ghost" {
|
|
|
|
|
t.Fatalf("unexpected unknown aggregate: %#v", sum["unknown"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestChooseTargetsHandlesTiesAndEmptyValues(t *testing.T) {
|
|
|
|
|
sum := &ClassSummary{
|
|
|
|
|
Kernels: map[string]int{"k1": 2, "k2": 2},
|
|
|
|
|
OSImages: map[string]int{
|
|
|
|
|
"img": 1,
|
|
|
|
|
},
|
|
|
|
|
PackageStats: map[string]map[string]int{
|
|
|
|
|
"p": {"": 3, "1": 1},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
targets := ChooseTargets(sum)
|
|
|
|
|
if targets.Kernel != "" {
|
|
|
|
|
t.Fatalf("expected kernel tie to return empty, got %q", targets.Kernel)
|
|
|
|
|
}
|
|
|
|
|
if targets.OSImage != "img" {
|
|
|
|
|
t.Fatalf("expected OS image img, got %q", targets.OSImage)
|
|
|
|
|
}
|
|
|
|
|
if _, ok := targets.Packages["p"]; ok {
|
|
|
|
|
t.Fatalf("expected empty package version to be skipped: %+v", targets.Packages)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-11 03:12:59 -03:00
|
|
|
|
|
|
|
|
func TestUSBHealthHelpersCoverAllStates(t *testing.T) {
|
|
|
|
|
addUSBHealth(nil, nil, nil)
|
|
|
|
|
|
|
|
|
|
sum := &ClassSummary{
|
|
|
|
|
USBMountHealth: map[string]int{},
|
|
|
|
|
USBUUIDHealth: map[string]int{},
|
|
|
|
|
USBLabelHealth: map[string]int{},
|
|
|
|
|
USBBindHealth: map[string]int{},
|
|
|
|
|
}
|
|
|
|
|
desired := &inventory.USBScratchDisk{
|
|
|
|
|
Mountpoint: "/mnt/scratch",
|
|
|
|
|
UUID: "usb-1",
|
|
|
|
|
Label: "scratch-a",
|
|
|
|
|
BindTargets: []string{"/var/lib/rancher"},
|
|
|
|
|
}
|
|
|
|
|
addUSBHealth(sum, desired, nil)
|
|
|
|
|
if sum.USBMountHealth["missing"] != 1 || sum.USBUUIDHealth["missing"] != 1 || sum.USBLabelHealth["missing"] != 1 || sum.USBBindHealth["missing"] != 1 {
|
|
|
|
|
t.Fatalf("expected missing usb health entries: %#v", sum)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addUSBHealth(sum, desired, &USBScratch{
|
|
|
|
|
MountHealthy: true,
|
|
|
|
|
UUIDHealthy: true,
|
|
|
|
|
LabelHealthy: false,
|
|
|
|
|
BindHealthy: false,
|
|
|
|
|
})
|
|
|
|
|
if sum.USBMountHealth["ok"] != 1 || sum.USBUUIDHealth["ok"] != 1 || sum.USBLabelHealth["bad"] != 1 || sum.USBBindHealth["bad"] != 1 {
|
|
|
|
|
t.Fatalf("expected healthy/bad usb health entries: %#v", sum)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if got := usbStatus(nil, true); got != "missing" {
|
|
|
|
|
t.Fatalf("usbStatus missing = %q", got)
|
|
|
|
|
}
|
|
|
|
|
if got := usbStatus(&USBScratch{}, true); got != "ok" {
|
|
|
|
|
t.Fatalf("usbStatus ok = %q", got)
|
|
|
|
|
}
|
|
|
|
|
if got := usbStatus(&USBScratch{}, false); got != "bad" {
|
|
|
|
|
t.Fatalf("usbStatus bad = %q", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestAggregateCoversMissingClassAndEmptyFields(t *testing.T) {
|
|
|
|
|
inv := &inventory.Inventory{
|
|
|
|
|
Nodes: []inventory.NodeSpec{
|
|
|
|
|
{
|
|
|
|
|
Name: "ghost",
|
|
|
|
|
Class: "missing",
|
|
|
|
|
USBScratch: &inventory.USBScratchDisk{Mountpoint: "/mnt/scratch", Label: "ghost-scratch"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
sums := Aggregate(inv, []Snapshot{{Hostname: "ghost"}})
|
|
|
|
|
sum := sums["unknown"]
|
|
|
|
|
if sum == nil {
|
|
|
|
|
t.Fatal("expected unknown summary")
|
|
|
|
|
}
|
|
|
|
|
if len(sum.Nodes) != 1 || sum.Nodes[0] != "ghost" {
|
|
|
|
|
t.Fatalf("unexpected aggregate nodes: %#v", sum.Nodes)
|
|
|
|
|
}
|
|
|
|
|
if sum.USBLabelHealth["missing"] != 1 || sum.USBMountHealth["missing"] != 1 {
|
|
|
|
|
t.Fatalf("expected missing usb health from class-missing node: %#v", sum)
|
|
|
|
|
}
|
|
|
|
|
}
|