Event ingestion now uses the source syslog PRI and an explicit-offset timezone timeline instead of assuming host-local time. CPU PPIN is exported as the source-backed CPU serial, and an active NVMe fault SEL event promotes the matching drive's storage status. See ADL-056, ADL-057. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
72 lines
2.5 KiB
Go
72 lines
2.5 KiB
Go
package inspur
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
func TestApplyStorageStatusFromEventsMarksOnlyFaultyNVMeCritical(t *testing.T) {
|
|
hw := &models.HardwareConfig{}
|
|
for i := 1; i <= 7; i++ {
|
|
hw.Storage = append(hw.Storage, models.Storage{Slot: fmt.Sprintf("OB%02d", i), Type: "NVMe", Present: true})
|
|
}
|
|
ts := time.Date(2026, 7, 23, 23, 20, 32, 0, time.UTC)
|
|
fault := models.Event{
|
|
ID: "0DFF0702",
|
|
Timestamp: ts,
|
|
Source: "BMC",
|
|
EventType: "Assert",
|
|
Severity: models.SeverityCritical,
|
|
Description: "NVME BP:Front0 NvmeIndex:6 drive fault: Status_Flags error.",
|
|
}
|
|
|
|
applyStorageStatusFromEvents(hw, []models.Event{fault}, []models.Event{fault}, true)
|
|
|
|
for i := range hw.Storage {
|
|
if hw.Storage[i].Slot == "OB07" {
|
|
if hw.Storage[i].Status != "Critical" || hw.Storage[i].ErrorDescription == "" {
|
|
t.Fatalf("expected OB07 critical with details, got %+v", hw.Storage[i])
|
|
}
|
|
if len(hw.Storage[i].StatusHistory) != 1 || hw.Storage[i].StatusChangedAt == nil {
|
|
t.Fatalf("expected one source-backed status transition, got %+v", hw.Storage[i])
|
|
}
|
|
continue
|
|
}
|
|
if hw.Storage[i].Status != "" {
|
|
t.Fatalf("unaffected %s must remain unknown/unset, got %q", hw.Storage[i].Slot, hw.Storage[i].Status)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestApplyStorageStatusFromEventsDeassertClearsCriticalToUnknown(t *testing.T) {
|
|
hw := &models.HardwareConfig{Storage: []models.Storage{{Slot: "OB07", Type: "NVMe", Present: true}}}
|
|
asserted := models.Event{
|
|
ID: "0DFF0702", Timestamp: time.Date(2026, 7, 23, 23, 20, 32, 0, time.UTC),
|
|
EventType: "Assert", Severity: models.SeverityCritical,
|
|
Description: "NVME BP:Front0 NvmeIndex:6 drive fault: Status_Flags error.",
|
|
}
|
|
deasserted := asserted
|
|
deasserted.Timestamp = asserted.Timestamp.Add(time.Hour)
|
|
deasserted.EventType = "Deassert"
|
|
deasserted.Severity = models.SeverityInfo
|
|
|
|
applyStorageStatusFromEvents(hw, []models.Event{asserted, deasserted}, nil, true)
|
|
|
|
if hw.Storage[0].Status != "Unknown" || hw.Storage[0].ErrorDescription != "" {
|
|
t.Fatalf("expected cleared drive fault to become Unknown, got %+v", hw.Storage[0])
|
|
}
|
|
if len(hw.Storage[0].StatusHistory) != 2 {
|
|
t.Fatalf("expected assert/deassert history, got %+v", hw.Storage[0].StatusHistory)
|
|
}
|
|
}
|
|
|
|
func TestStorageFaultIndexIgnoresNVMeInventoryChange(t *testing.T) {
|
|
event := models.Event{Description: "PCIE Device #NVME6 Device ID changed; Vendor ID changed"}
|
|
if _, ok := storageFaultIndex(event); ok {
|
|
t.Fatalf("inventory change must not be treated as an active drive fault")
|
|
}
|
|
}
|