package collector import ( "bee/audit/internal/schema" "testing" ) func TestParseIPMISELOutput(t *testing.T) { entries := parseIPMISELOutput(` 1 | 06/18/2026 | 14:23:45 | Temperature #0x30 | Upper Critical going high | Asserted 2 | 06/18/2026 | 14:24:45 | Voltage #0x21 | Upper Non-critical going high | Deasserted malformed `) if len(entries) != 2 { t.Fatalf("entries = %d, want 2", len(entries)) } first := entries[0] if first.Source != "ipmi-sel" || first.MessageID == nil || *first.MessageID != "1" { t.Fatalf("first entry identity = %#v", first) } if first.EventTime == nil || *first.EventTime != "06/18/2026 14:23:45" { t.Fatalf("first event time = %v", first.EventTime) } if first.ComponentRef == nil || *first.ComponentRef != "Temperature #0x30" { t.Fatalf("first component = %v", first.ComponentRef) } if first.Severity == nil || *first.Severity != statusCritical || first.IsActive == nil || !*first.IsActive { t.Fatalf("first severity/activity = %#v", first) } second := entries[1] if second.Message != "Upper Non-critical going high (Deasserted)" { t.Fatalf("second message = %q", second.Message) } if second.Severity == nil || *second.Severity != statusWarning || second.IsActive == nil || *second.IsActive { t.Fatalf("second severity/activity = %#v", second) } } func TestIPMISELSeverity(t *testing.T) { tests := []struct { event string want string }{ {event: "Upper Critical going high", want: statusCritical}, {event: "Non-recoverable fault", want: statusCritical}, {event: "Upper Non-critical going high", want: statusWarning}, {event: "Voltage degraded", want: statusWarning}, {event: "Device inserted", want: "info"}, } for _, tt := range tests { if got := ipmiSELSeverity(tt.event); got != tt.want { t.Errorf("ipmiSELSeverity(%q) = %q, want %q", tt.event, got, tt.want) } } } func TestParseIPMISensorOutput(t *testing.T) { sensors := parseIPMISensorOutput(` FAN1 | 4200 | RPM | ok | na | na | na | na | na | na CPU Temp | 92.5 | degrees C | ns | na | na | na | 80 | 90 | na CPU Temp | 80 | degrees C | ok | na | na | na | 80 | 90 | na PSU Input | 12.1 | Volts | ok | na | na | na | na | na | na System Power | 650 | Watts | cr | na | na | na | na | na | na Ambient | 44 | percent | nc | na | na | na | na | na | na Missing | na | RPM | ok Broken | not-a-number | RPM | ok `) if sensors == nil { t.Fatal("expected sensors") } if len(sensors.Fans) != 1 || sensors.Fans[0].RPM == nil || *sensors.Fans[0].RPM != 4200 { t.Fatalf("fans = %#v", sensors.Fans) } if len(sensors.Temperatures) != 1 { t.Fatalf("temperatures = %#v", sensors.Temperatures) } temp := sensors.Temperatures[0] if temp.ThresholdWarningCelsius == nil || *temp.ThresholdWarningCelsius != 80 || temp.ThresholdCriticalCelsius == nil || *temp.ThresholdCriticalCelsius != 90 || temp.Status == nil || *temp.Status != statusCritical { t.Fatalf("temperature = %#v", temp) } if len(sensors.Power) != 2 || sensors.Power[0].VoltageV == nil || sensors.Power[1].PowerW == nil || sensors.Power[1].Status == nil || *sensors.Power[1].Status != statusCritical { t.Fatalf("power = %#v", sensors.Power) } if len(sensors.Other) != 1 || sensors.Other[0].Unit == nil || *sensors.Other[0].Unit != "percent" || sensors.Other[0].Status == nil || *sensors.Other[0].Status != statusWarning { t.Fatalf("other = %#v", sensors.Other) } } func TestParseIPMIThresholdAndStatus(t *testing.T) { if got := parseIPMIThreshold(" 42.5 "); got == nil || *got != 42.5 { t.Fatalf("threshold = %v, want 42.5", got) } for _, raw := range []string{"", "na", "N/A", "not-a-number"} { if got := parseIPMIThreshold(raw); got != nil { t.Errorf("parseIPMIThreshold(%q) = %v, want nil", raw, got) } } for raw, want := range map[string]string{ "ok": statusOK, "cr": statusCritical, "unc": statusWarning, "na": "", "other": "", } { if got := normalizeIPMISensorStatus(raw); got != want { t.Errorf("normalizeIPMISensorStatus(%q) = %q, want %q", raw, got, want) } } } func TestMergeIPMISensors(t *testing.T) { existing := &schema.HardwareSensors{ Fans: []schema.HardwareFanSensor{{Name: "FAN1"}}, } ipmi := &schema.HardwareSensors{ Fans: []schema.HardwareFanSensor{{Name: "FAN1"}, {Name: "FAN2"}}, Temperatures: []schema.HardwareTemperatureSensor{{Name: "CPU Temp"}}, } merged := mergeIPMISensors(existing, ipmi) if merged != existing || len(merged.Fans) != 2 || len(merged.Temperatures) != 1 { t.Fatalf("merged = %#v", merged) } if got := mergeIPMISensors(existing, nil); got != existing { t.Fatal("nil IPMI sensors should preserve existing sensors") } if got := mergeIPMISensors(nil, ipmi); got != ipmi { t.Fatal("nil existing sensors should return IPMI sensors") } }