export: align reanimator contract v2.7
This commit is contained in:
@@ -210,7 +210,7 @@ func TestConvertCPUs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
result := convertCPUs(cpus, "2026-02-10T15:30:00Z", "BOARD-001")
|
||||
result := convertCPUs(cpus, "2026-02-10T15:30:00Z")
|
||||
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("expected 2 CPUs, got %d", len(result))
|
||||
@@ -227,8 +227,8 @@ func TestConvertCPUs(t *testing.T) {
|
||||
if result[0].Status != "Unknown" {
|
||||
t.Errorf("expected Unknown status, got %q", result[0].Status)
|
||||
}
|
||||
if result[0].SerialNumber != "BOARD-001-CPU-0" {
|
||||
t.Errorf("expected generated CPU serial, got %q", result[0].SerialNumber)
|
||||
if result[0].SerialNumber != "" {
|
||||
t.Errorf("expected empty CPU serial when source serial is absent, got %q", result[0].SerialNumber)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +259,158 @@ func TestConvertMemory(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_CPUSerialIsNotSynthesizedAndSocketIsDeduped(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "cpu-dedupe.json",
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
Devices: []models.HardwareDevice{
|
||||
{
|
||||
Kind: models.DeviceKindCPU,
|
||||
Slot: "CPU1",
|
||||
Model: "Xeon Platinum",
|
||||
Cores: 56,
|
||||
Status: "OK",
|
||||
Details: map[string]any{
|
||||
"socket": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
CPUs: []models.CPU{
|
||||
{Socket: 1, Model: "Xeon Platinum", Cores: 56, Status: "OK"},
|
||||
{Socket: 2, Model: "Xeon Platinum", Cores: 56, Status: "OK"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.CPUs) != 2 {
|
||||
t.Fatalf("expected exactly two CPUs after socket dedupe, got %d", len(out.Hardware.CPUs))
|
||||
}
|
||||
for _, cpu := range out.Hardware.CPUs {
|
||||
if cpu.SerialNumber != "" {
|
||||
t.Fatalf("expected CPU serial to stay empty when source serial is absent, got %q", cpu.SerialNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_ExportsEventLogsAndOmitsPCIeBDFJSON(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "events.json",
|
||||
CollectedAt: time.Date(2026, 3, 15, 12, 0, 0, 0, time.UTC),
|
||||
Events: []models.Event{
|
||||
{
|
||||
ID: "0x0042",
|
||||
Timestamp: time.Date(2026, 3, 15, 11, 59, 0, 0, time.UTC),
|
||||
Source: "SEL",
|
||||
SensorName: "CPU0_C0D0",
|
||||
Severity: models.SeverityWarning,
|
||||
Description: "Correctable ECC error threshold exceeded",
|
||||
RawData: "sel_record_id=42",
|
||||
},
|
||||
{
|
||||
Source: "LOGPile",
|
||||
Severity: models.SeverityWarning,
|
||||
Description: "internal warning should not leak to event_logs",
|
||||
},
|
||||
},
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
Devices: []models.HardwareDevice{
|
||||
{
|
||||
Kind: models.DeviceKindPCIe,
|
||||
Slot: "",
|
||||
BDF: "0000:18:00.0",
|
||||
DeviceClass: "NetworkController",
|
||||
Manufacturer: "Mellanox",
|
||||
Model: "ConnectX-6",
|
||||
Status: "OK",
|
||||
Details: map[string]any{
|
||||
"manufactured_year_week": "2024-W07",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.EventLogs) != 1 {
|
||||
t.Fatalf("expected 1 exported event log, got %d", len(out.Hardware.EventLogs))
|
||||
}
|
||||
log := out.Hardware.EventLogs[0]
|
||||
if log.Source != "bmc" {
|
||||
t.Fatalf("expected SEL source to map to bmc, got %#v", log)
|
||||
}
|
||||
if log.ComponentRef != "CPU0_C0D0" {
|
||||
t.Fatalf("expected sensor name to map to component_ref, got %#v", log)
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 1 {
|
||||
t.Fatalf("expected 1 pcie device, got %d", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
if out.Hardware.PCIeDevices[0].Slot != "0000:18:00.0" {
|
||||
t.Fatalf("expected slot to fall back to BDF, got %#v", out.Hardware.PCIeDevices[0])
|
||||
}
|
||||
if out.Hardware.PCIeDevices[0].ManufacturedYearWeek != "2024-W07" {
|
||||
t.Fatalf("expected manufactured_year_week to be exported, got %#v", out.Hardware.PCIeDevices[0])
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(out)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal() failed: %v", err)
|
||||
}
|
||||
if strings.Contains(string(payload), `"bdf"`) {
|
||||
t.Fatalf("expected pcie bdf field to stay out of JSON payload: %s", payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_EventLogSourceMappingSupportsDellAndHostSyslog(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "event-source-map.json",
|
||||
CollectedAt: time.Date(2026, 3, 15, 12, 0, 0, 0, time.UTC),
|
||||
Events: []models.Event{
|
||||
{
|
||||
ID: "SYS1001",
|
||||
Timestamp: time.Date(2026, 3, 15, 11, 58, 0, 0, time.UTC),
|
||||
Source: "iDRAC",
|
||||
SensorName: "NIC.Slot.1-1-1",
|
||||
Severity: models.SeverityWarning,
|
||||
Description: "Link is down",
|
||||
},
|
||||
{
|
||||
ID: "syslog_1",
|
||||
Timestamp: time.Date(2026, 3, 15, 11, 59, 0, 0, time.UTC),
|
||||
Source: "syslog",
|
||||
SensorName: "systemd[1]",
|
||||
Severity: models.SeverityInfo,
|
||||
Description: "Started Example Service",
|
||||
},
|
||||
},
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.EventLogs) != 2 {
|
||||
t.Fatalf("expected 2 event logs, got %d", len(out.Hardware.EventLogs))
|
||||
}
|
||||
if out.Hardware.EventLogs[0].Source != "bmc" {
|
||||
t.Fatalf("expected iDRAC event to map to bmc, got %#v", out.Hardware.EventLogs[0])
|
||||
}
|
||||
if out.Hardware.EventLogs[1].Source != "host" {
|
||||
t.Fatalf("expected syslog event to map to host, got %#v", out.Hardware.EventLogs[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertStorage(t *testing.T) {
|
||||
storage := []models.Storage{
|
||||
{
|
||||
@@ -288,6 +440,46 @@ func TestConvertStorage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_SkipsAMIVirtualStorageDevices(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "virtual-media.json",
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
Storage: []models.Storage{
|
||||
{
|
||||
Slot: "USB_Device1_Port4",
|
||||
Type: "HDD",
|
||||
Model: "Virtual Cdrom Device",
|
||||
SerialNumber: "AAAABBBBCCCC1",
|
||||
Manufacturer: "American Megatrends Inc.",
|
||||
Interface: "USB",
|
||||
Present: true,
|
||||
},
|
||||
{
|
||||
Slot: "OB01",
|
||||
Type: "NVMe",
|
||||
Model: "Memblaze PBlaze7",
|
||||
SerialNumber: "REAL-NVME-001",
|
||||
Manufacturer: "Memblaze",
|
||||
Interface: "NVMe",
|
||||
Present: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.Storage) != 1 {
|
||||
t.Fatalf("expected only one real storage device to remain, got %d", len(out.Hardware.Storage))
|
||||
}
|
||||
if out.Hardware.Storage[0].SerialNumber != "REAL-NVME-001" {
|
||||
t.Fatalf("expected virtual AMI storage to be skipped, got %#v", out.Hardware.Storage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertStorage_RemainingEndurance(t *testing.T) {
|
||||
pct100 := 100
|
||||
pct3 := 3
|
||||
@@ -370,16 +562,16 @@ func TestConvertPCIeDevices(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z", "BOARD-001")
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z")
|
||||
|
||||
// Should have: 2 PCIe devices + 1 GPU + 1 NIC = 4 total
|
||||
if len(result) != 4 {
|
||||
t.Fatalf("expected 4 PCIe devices total, got %d", len(result))
|
||||
}
|
||||
|
||||
// Check that serial is generated for second PCIe device
|
||||
if result[1].SerialNumber != "BOARD-001-PCIE-PCIeCard2" {
|
||||
t.Errorf("expected generated serial for missing device serial, got %q", result[1].SerialNumber)
|
||||
// Missing serials must remain absent.
|
||||
if result[1].SerialNumber != "" {
|
||||
t.Errorf("expected empty serial for missing device serial, got %q", result[1].SerialNumber)
|
||||
}
|
||||
|
||||
// Check GPU was included
|
||||
@@ -416,20 +608,71 @@ func TestConvertPCIeDevices_NVSwitchWithoutSerialRemainsEmpty(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z", "BOARD-001")
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z")
|
||||
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("expected 1 PCIe device, got %d", len(result))
|
||||
}
|
||||
|
||||
if result[0].SerialNumber != "BOARD-001-PCIE-NVSWITCH1" {
|
||||
t.Fatalf("expected generated NVSwitch serial, got %q", result[0].SerialNumber)
|
||||
if result[0].SerialNumber != "" {
|
||||
t.Fatalf("expected empty NVSwitch serial, got %q", result[0].SerialNumber)
|
||||
}
|
||||
if result[0].Firmware != "96.10.6D.00.01" {
|
||||
t.Fatalf("expected NVSwitch firmware 96.10.6D.00.01, got %q", result[0].Firmware)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_MapsHGXNVSwitchFirmwareToPCIeDevice(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
Firmware: []models.FirmwareInfo{
|
||||
{DeviceName: "HGX_FW_ERoT_NVSwitch_0", Version: "00.02.0192.0000_n00"},
|
||||
{DeviceName: "HGX_FW_NVSwitch_0", Version: "96.10.73.00.01"},
|
||||
},
|
||||
PCIeDevices: []models.PCIeDevice{
|
||||
{
|
||||
Slot: "NVSwitch_0",
|
||||
DeviceClass: "NVSwitch",
|
||||
Manufacturer: "NVIDIA",
|
||||
Details: map[string]any{
|
||||
"temperature_c": 31.59375,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 1 {
|
||||
t.Fatalf("expected one NVSwitch PCIe device, got %d", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
got := out.Hardware.PCIeDevices[0]
|
||||
if got.Firmware != "96.10.73.00.01" {
|
||||
t.Fatalf("expected HGX NVSwitch firmware to map to device, got %#v", got)
|
||||
}
|
||||
if got.TemperatureC != 31.59375 {
|
||||
t.Fatalf("expected NVSwitch temperature to be exported, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNVSwitchFirmwareBySlot_SkipsERoTFirmware(t *testing.T) {
|
||||
got := buildNVSwitchFirmwareBySlot([]models.FirmwareInfo{
|
||||
{DeviceName: "HGX_FW_ERoT_NVSwitch_0", Version: "00.02.0192.0000_n00"},
|
||||
{DeviceName: "HGX_FW_NVSwitch_0", Version: "96.10.73.00.01"},
|
||||
})
|
||||
|
||||
if len(got) != 1 {
|
||||
t.Fatalf("expected only main NVSwitch firmware to remain, got %#v", got)
|
||||
}
|
||||
if got["NVSWITCH_0"] != "96.10.73.00.01" {
|
||||
t.Fatalf("expected main NVSwitch firmware, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertPCIeDevices_SkipsDisplayControllerDuplicates(t *testing.T) {
|
||||
hw := &models.HardwareConfig{
|
||||
PCIeDevices: []models.PCIeDevice{
|
||||
@@ -449,7 +692,7 @@ func TestConvertPCIeDevices_SkipsDisplayControllerDuplicates(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z", "BOARD-001")
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z")
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("expected only dedicated GPU record without duplicate display PCIe, got %d", len(result))
|
||||
}
|
||||
@@ -482,7 +725,7 @@ func TestConvertPCIeDevices_MapsGPUStatusHistory(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z", "BOARD-001")
|
||||
result := convertPCIeDevices(hw, "2026-02-10T15:30:00Z")
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("expected 1 converted GPU, got %d", len(result))
|
||||
}
|
||||
@@ -667,11 +910,11 @@ func TestConvertToReanimator_DeduplicatesAllSections(t *testing.T) {
|
||||
if len(out.Hardware.Firmware) != 1 {
|
||||
t.Fatalf("expected deduped firmware len=1, got %d", len(out.Hardware.Firmware))
|
||||
}
|
||||
if len(out.Hardware.CPUs) != 2 {
|
||||
t.Fatalf("expected cpus len=2 (no serial/bdf dedupe), got %d", len(out.Hardware.CPUs))
|
||||
if len(out.Hardware.CPUs) != 1 {
|
||||
t.Fatalf("expected cpus len=1 after socket dedupe, got %d", len(out.Hardware.CPUs))
|
||||
}
|
||||
if len(out.Hardware.Memory) != 2 {
|
||||
t.Fatalf("expected memory len=2 (different serials), got %d", len(out.Hardware.Memory))
|
||||
if len(out.Hardware.Memory) != 1 {
|
||||
t.Fatalf("expected memory len=1 after slot dedupe, got %d", len(out.Hardware.Memory))
|
||||
}
|
||||
if len(out.Hardware.Storage) != 1 {
|
||||
t.Fatalf("expected deduped storage len=1, got %d", len(out.Hardware.Storage))
|
||||
@@ -679,8 +922,8 @@ func TestConvertToReanimator_DeduplicatesAllSections(t *testing.T) {
|
||||
if len(out.Hardware.PowerSupplies) != 1 {
|
||||
t.Fatalf("expected deduped psu len=1, got %d", len(out.Hardware.PowerSupplies))
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 4 {
|
||||
t.Fatalf("expected pcie len=4 with serial->bdf dedupe, got %d", len(out.Hardware.PCIeDevices))
|
||||
if len(out.Hardware.PCIeDevices) != 2 {
|
||||
t.Fatalf("expected pcie len=2 after final pcie-class dedupe, got %d", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
|
||||
gpuCount := 0
|
||||
@@ -689,8 +932,8 @@ func TestConvertToReanimator_DeduplicatesAllSections(t *testing.T) {
|
||||
gpuCount++
|
||||
}
|
||||
}
|
||||
if gpuCount != 2 {
|
||||
t.Fatalf("expected two #GPU0 records (pcie+gpu kinds), got %d", gpuCount)
|
||||
if gpuCount != 1 {
|
||||
t.Fatalf("expected one merged #GPU0 record, got %d", gpuCount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,6 +1157,143 @@ func TestConvertToReanimator_MergesCanonicalAndLegacyDevices(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_DoesNotMergeStorageIntoPCIeBySharedSerial(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "nvme-redfish.json",
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
Storage: []models.Storage{
|
||||
{
|
||||
Slot: "Disk.Bay.0",
|
||||
Type: "NVMe",
|
||||
Model: "MZQL21T9HCJR-00A07",
|
||||
SerialNumber: "S64GNNFX612200",
|
||||
Manufacturer: "Samsung",
|
||||
Firmware: "GDC5A02Q",
|
||||
Present: true,
|
||||
},
|
||||
},
|
||||
PCIeDevices: []models.PCIeDevice{
|
||||
{
|
||||
Slot: "NVMeSSD1",
|
||||
BDF: "0000:81:00.0",
|
||||
DeviceClass: "MassStorageController",
|
||||
Description: "MZQL21T9HCJR-00A07",
|
||||
SerialNumber: "S64GNNFX612200",
|
||||
Manufacturer: "Samsung",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.Storage) != 1 {
|
||||
t.Fatalf("expected storage record to survive shared-serial canonical merge, got %d", len(out.Hardware.Storage))
|
||||
}
|
||||
if out.Hardware.Storage[0].Slot != "Disk.Bay.0" {
|
||||
t.Fatalf("expected storage slot Disk.Bay.0, got %q", out.Hardware.Storage[0].Slot)
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 0 {
|
||||
t.Fatalf("expected NVMe storage endpoint to be excluded from pcie export, got %d records", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_LeavesStorageControllersInPCIe(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-123"},
|
||||
PCIeDevices: []models.PCIeDevice{
|
||||
{
|
||||
Slot: "PCIe Slot 3",
|
||||
BDF: "0000:5e:00.0",
|
||||
DeviceClass: "MassStorageController",
|
||||
Description: "MegaRAID Controller",
|
||||
PartNumber: "PERC H755",
|
||||
SerialNumber: "RAID-001",
|
||||
Manufacturer: "Dell",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 1 {
|
||||
t.Fatalf("expected RAID controller to remain in pcie export, got %d", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_PCIePlaceholderModelFallsBackToPCIIDs(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-123"},
|
||||
Devices: []models.HardwareDevice{
|
||||
{
|
||||
Kind: models.DeviceKindNetwork,
|
||||
Slot: "NIC1",
|
||||
Model: "Network Device View",
|
||||
VendorID: 0x15b3,
|
||||
DeviceID: 0x101d,
|
||||
Manufacturer: "Mellanox",
|
||||
Present: boolPtr(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 1 {
|
||||
t.Fatalf("expected one pcie export, got %d", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
if strings.EqualFold(out.Hardware.PCIeDevices[0].Model, "Network Device View") {
|
||||
t.Fatalf("expected placeholder model to be replaced, got %q", out.Hardware.PCIeDevices[0].Model)
|
||||
}
|
||||
if out.Hardware.PCIeDevices[0].SerialNumber != "" {
|
||||
t.Fatalf("expected missing pcie serial to stay empty, got %q", out.Hardware.PCIeDevices[0].SerialNumber)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_SkipsPlaceholderNetworkPCIeRecords(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-123"},
|
||||
Devices: []models.HardwareDevice{
|
||||
{
|
||||
Kind: models.DeviceKindNetwork,
|
||||
Slot: "1",
|
||||
Status: "Unknown",
|
||||
},
|
||||
{
|
||||
Kind: models.DeviceKindNetwork,
|
||||
Slot: "NIC2",
|
||||
Model: "ConnectX-7",
|
||||
Manufacturer: "NVIDIA",
|
||||
Present: boolPtr(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if len(out.Hardware.PCIeDevices) != 1 {
|
||||
t.Fatalf("expected only one meaningful pcie-class device, got %d", len(out.Hardware.PCIeDevices))
|
||||
}
|
||||
if out.Hardware.PCIeDevices[0].Slot != "NIC2" {
|
||||
t.Fatalf("expected placeholder numeric-slot NIC to be skipped, got %+v", out.Hardware.PCIeDevices)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_ExportsSensorsAndPSUTelemetry(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "vitals.json",
|
||||
@@ -987,6 +1367,60 @@ func TestConvertToReanimator_ExportsSensorsAndPSUTelemetry(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_SkipsSensorsWithoutNumericReadings(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "sensor-gaps.json",
|
||||
Sensors: []models.SensorReading{
|
||||
{Name: "CPU0 Temp", Type: "temperature", Status: "OK", RawValue: "N/A"},
|
||||
{Name: "PSU1 Power", Type: "power", Status: "OK", RawValue: ""},
|
||||
{Name: "Fan1", Type: "fan", Status: "OK", RawValue: "not present"},
|
||||
{Name: "Humidity", Type: "humidity", Status: "OK", RawValue: "unknown"},
|
||||
},
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if out.Hardware.Sensors != nil {
|
||||
t.Fatalf("expected sensors to be omitted when all readings are non-numeric, got %+v", out.Hardware.Sensors)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_MergesSiblingPowerSensors(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "power-sensors.json",
|
||||
Sensors: []models.SensorReading{
|
||||
{Name: "Power Supply Bay 8_InputPower", Type: "power", Value: 231, Unit: "W", Status: "OK"},
|
||||
{Name: "Power Supply Bay 8_InputVoltage", Type: "voltage", Value: 228, Unit: "V", Status: "OK"},
|
||||
},
|
||||
Hardware: &models.HardwareConfig{
|
||||
BoardInfo: models.BoardInfo{SerialNumber: "BOARD-001"},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ConvertToReanimator(input)
|
||||
if err != nil {
|
||||
t.Fatalf("ConvertToReanimator() failed: %v", err)
|
||||
}
|
||||
if out.Hardware.Sensors == nil || len(out.Hardware.Sensors.Power) != 1 {
|
||||
t.Fatalf("expected one merged power sensor, got %#v", out.Hardware.Sensors)
|
||||
}
|
||||
got := out.Hardware.Sensors.Power[0]
|
||||
if got.Name != "Power Supply Bay 8" {
|
||||
t.Fatalf("expected merged sensor name, got %q", got.Name)
|
||||
}
|
||||
if got.PowerW != 231 || got.VoltageV != 228 {
|
||||
t.Fatalf("expected merged power/voltage readings, got %#v", got)
|
||||
}
|
||||
if got.Location != "" {
|
||||
t.Fatalf("expected sensor location to be omitted, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToReanimator_PreservesCanonicalDedupWithoutDeviceVitals(t *testing.T) {
|
||||
input := &models.AnalysisResult{
|
||||
Filename: "dedup-vitals.json",
|
||||
@@ -1336,6 +1770,7 @@ func TestIsDeviceBoundFirmwareName(t *testing.T) {
|
||||
{"NVMe Drive", true},
|
||||
// HGX FW ID patterns (in case Id is used as name)
|
||||
{"HGX_FW_GPU_SXM_1", true},
|
||||
{"HGX_FW_ERoT_NVSwitch_0", true},
|
||||
{"HGX_InfoROM_GPU_SXM_2", true},
|
||||
// System-level firmware — must NOT be excluded
|
||||
{"BIOS", false},
|
||||
|
||||
Reference in New Issue
Block a user