Files
logpile/internal/collector/redfish_test.go
Mikhail Chusavitin becdca1d7e fix(redfish): read PCIeInterface link width for GPU PCIe devices
parseGPUWithSupplementalDocs did not read PCIeInterface from the device
doc, only from function docs. xFusion GPU PCIeCard entries carry link
width/speed in PCIeInterface (LanesInUse/Maxlanes/PCIeType/MaxPCIeType)
so GPU link width was always empty for xFusion servers.

Also apply the xFusion OEM function-level fallback for GPU function docs,
consistent with the NIC and PCIeDevice paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 13:35:29 +03:00

4268 lines
146 KiB
Go

package collector
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"git.mchus.pro/mchus/logpile/internal/collector/redfishprofile"
"git.mchus.pro/mchus/logpile/internal/models"
)
func testAnalysisPlan(d redfishprofile.AnalysisDirectives) redfishprofile.ResolvedAnalysisPlan {
return redfishprofile.ResolvedAnalysisPlan{Directives: d}
}
func TestRedfishConnectorCollect(t *testing.T) {
mux := http.NewServeMux()
register := func(path string, payload interface{}) {
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(payload)
})
}
register("/redfish/v1", map[string]interface{}{"Name": "ServiceRoot"})
register("/redfish/v1/Systems/1", map[string]interface{}{
"Manufacturer": "Supermicro",
"Model": "SYS-TEST",
"SerialNumber": "SYS123",
"BiosVersion": "2.1a",
})
register("/redfish/v1/Systems/1/Bios", map[string]interface{}{"Version": "2.1a"})
register("/redfish/v1/Systems/1/SecureBoot", map[string]interface{}{"SecureBootCurrentBoot": "Enabled"})
register("/redfish/v1/Systems/1/Processors", map[string]interface{}{
"Members": []map[string]string{
{"@odata.id": "/redfish/v1/Systems/1/Processors/CPU1"},
},
})
register("/redfish/v1/Systems/1/Processors/CPU1", map[string]interface{}{
"Name": "CPU1",
"Model": "Xeon Gold",
"TotalCores": 32,
"TotalThreads": 64,
"MaxSpeedMHz": 3600,
})
register("/redfish/v1/Systems/1/Memory", map[string]interface{}{
"Members": []map[string]string{
{"@odata.id": "/redfish/v1/Systems/1/Memory/DIMM1"},
},
})
register("/redfish/v1/Systems/1/Memory/DIMM1", map[string]interface{}{
"Name": "DIMM A1",
"CapacityMiB": 32768,
"MemoryDeviceType": "DDR5",
"OperatingSpeedMhz": 4800,
"Status": map[string]interface{}{
"Health": "OK",
},
})
register("/redfish/v1/Systems/1/Storage", map[string]interface{}{
"Members": []map[string]string{
{"@odata.id": "/redfish/v1/Systems/1/Storage/1"},
},
})
register("/redfish/v1/Systems/1/Storage/1", map[string]interface{}{
"Drives": []map[string]string{
{"@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"},
},
})
register("/redfish/v1/Systems/1/Storage/1/Drives/1", map[string]interface{}{
"Name": "Drive1",
"Model": "NVMe Test",
"MediaType": "SSD",
"Protocol": "NVMe",
"CapacityGB": 960,
"SerialNumber": "SN123",
})
register("/redfish/v1/Systems/1/PCIeDevices", map[string]interface{}{
"Members": []map[string]string{
{"@odata.id": "/redfish/v1/Systems/1/PCIeDevices/GPU1"},
},
})
register("/redfish/v1/Systems/1/PCIeDevices/GPU1", map[string]interface{}{
"Id": "GPU1",
"Name": "NVIDIA H100",
"Model": "NVIDIA H100 PCIe",
"Manufacturer": "NVIDIA",
"SerialNumber": "GPU-SN-001",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/PCIeDevices/GPU1/PCIeFunctions",
},
})
register("/redfish/v1/Systems/1/PCIeDevices/GPU1/PCIeFunctions", map[string]interface{}{
"Members": []map[string]string{
{"@odata.id": "/redfish/v1/Systems/1/PCIeFunctions/GPU1F0"},
},
})
register("/redfish/v1/Systems/1/PCIeFunctions/GPU1F0", map[string]interface{}{
"FunctionId": "0000:65:00.0",
"VendorId": "0x10DE",
"DeviceId": "0x2331",
"ClassCode": "0x030200",
"CurrentLinkWidth": 16,
"CurrentLinkSpeed": "16.0 GT/s",
"MaxLinkWidth": 16,
"MaxLinkSpeed": "16.0 GT/s",
})
register("/redfish/v1/Chassis/1/NetworkAdapters", map[string]interface{}{
"Members": []map[string]string{
{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/1"},
},
})
register("/redfish/v1/Chassis/1/Power", map[string]interface{}{
"PowerSupplies": []map[string]interface{}{
{
"MemberId": "PSU1",
"Name": "PSU Slot 1",
"Model": "PWS-2K01A-1R",
"Manufacturer": "Delta",
"PowerCapacityWatts": 2000,
"PowerInputWatts": 1600,
"LastPowerOutputWatts": 1200,
"LineInputVoltage": 230,
"Status": map[string]interface{}{
"Health": "OK",
"State": "Enabled",
},
},
},
})
register("/redfish/v1/Chassis/1/NetworkAdapters/1", map[string]interface{}{
"Name": "Mellanox",
"Model": "ConnectX-6",
"SerialNumber": "NIC123",
})
register("/redfish/v1/Managers/1", map[string]interface{}{
"FirmwareVersion": "1.25",
})
register("/redfish/v1/Managers/1/NetworkProtocol", map[string]interface{}{
"Id": "NetworkProtocol",
})
ts := httptest.NewServer(mux)
defer ts.Close()
c := NewRedfishConnector()
result, err := c.Collect(context.Background(), Request{
Host: ts.URL,
Port: 443,
Protocol: "redfish",
Username: "admin",
AuthType: "password",
Password: "secret",
TLSMode: "strict",
}, nil)
if err != nil {
t.Fatalf("collect failed: %v", err)
}
if result.Hardware == nil {
t.Fatalf("expected hardware config")
}
if result.Hardware.BoardInfo.ProductName != "SYS-TEST" {
t.Fatalf("unexpected board model: %q", result.Hardware.BoardInfo.ProductName)
}
if len(result.Hardware.CPUs) != 1 {
t.Fatalf("expected one CPU, got %d", len(result.Hardware.CPUs))
}
if len(result.Hardware.Memory) != 1 {
t.Fatalf("expected one DIMM, got %d", len(result.Hardware.Memory))
}
if len(result.Hardware.Storage) != 1 {
t.Fatalf("expected one drive, got %d", len(result.Hardware.Storage))
}
if len(result.Hardware.NetworkAdapters) != 1 {
t.Fatalf("expected one nic, got %d", len(result.Hardware.NetworkAdapters))
}
if len(result.Hardware.GPUs) != 1 {
t.Fatalf("expected one gpu, got %d", len(result.Hardware.GPUs))
}
if result.Hardware.GPUs[0].BDF != "0000:65:00.0" {
t.Fatalf("unexpected gpu BDF: %q", result.Hardware.GPUs[0].BDF)
}
if len(result.Hardware.PCIeDevices) != 1 {
t.Fatalf("expected one pcie device, got %d", len(result.Hardware.PCIeDevices))
}
if len(result.Hardware.PowerSupply) != 1 {
t.Fatalf("expected one psu, got %d", len(result.Hardware.PowerSupply))
}
if result.Hardware.PowerSupply[0].WattageW != 2000 {
t.Fatalf("unexpected psu wattage: %d", result.Hardware.PowerSupply[0].WattageW)
}
if len(result.Hardware.Firmware) == 0 {
t.Fatalf("expected firmware entries")
}
if result.RawPayloads == nil {
t.Fatalf("expected raw payloads")
}
treeAny, ok := result.RawPayloads["redfish_tree"]
if !ok {
t.Fatalf("expected redfish_tree in raw payloads")
}
tree, ok := treeAny.(map[string]interface{})
if !ok || len(tree) == 0 {
t.Fatalf("expected non-empty redfish_tree, got %#v", treeAny)
}
}
func TestRedfishConnectorProbe(t *testing.T) {
mux := http.NewServeMux()
register := func(path string, payload interface{}) {
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(payload)
})
}
register("/redfish/v1", map[string]interface{}{"Name": "ServiceRoot"})
register("/redfish/v1/Systems/1", map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1",
"PowerState": "Off",
"Actions": map[string]interface{}{
"#ComputerSystem.Reset": map[string]interface{}{
"target": "/redfish/v1/Systems/1/Actions/ComputerSystem.Reset",
"ResetType@Redfish.AllowableValues": []interface{}{"On", "ForceOff"},
},
},
})
ts := httptest.NewTLSServer(mux)
defer ts.Close()
connector := NewRedfishConnector()
port := 443
host := ""
if u, err := url.Parse(ts.URL); err == nil {
host = u.Hostname()
if p := u.Port(); p != "" {
fmt.Sscanf(p, "%d", &port)
}
}
got, err := connector.Probe(context.Background(), Request{
Host: host,
Protocol: "redfish",
Port: port,
Username: "admin",
AuthType: "password",
Password: "secret",
TLSMode: "insecure",
})
if err != nil {
t.Fatalf("probe failed: %v", err)
}
if got == nil || !got.Reachable {
t.Fatalf("expected reachable probe result, got %+v", got)
}
if got.HostPoweredOn {
t.Fatalf("expected powered off host")
}
if got.HostPowerState != "Off" {
t.Fatalf("expected power state Off, got %q", got.HostPowerState)
}
}
func TestRedfishConnectorProbe_FallsBackToPowerSummary(t *testing.T) {
mux := http.NewServeMux()
register := func(path string, payload interface{}) {
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(payload)
})
}
register("/redfish/v1", map[string]interface{}{"Name": "ServiceRoot"})
register("/redfish/v1/Systems", map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
})
register("/redfish/v1/Systems/1", map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1",
"PowerSummary": map[string]interface{}{
"PowerState": "On",
},
"Actions": map[string]interface{}{
"#ComputerSystem.Reset": map[string]interface{}{
"target": "/redfish/v1/Systems/1/Actions/ComputerSystem.Reset",
"ResetType@Redfish.AllowableValues": []interface{}{"On", "ForceOff"},
},
},
})
ts := httptest.NewTLSServer(mux)
defer ts.Close()
connector := NewRedfishConnector()
port := 443
host := ""
if u, err := url.Parse(ts.URL); err == nil {
host = u.Hostname()
if p := u.Port(); p != "" {
fmt.Sscanf(p, "%d", &port)
}
}
got, err := connector.Probe(context.Background(), Request{
Host: host,
Protocol: "redfish",
Port: port,
Username: "admin",
AuthType: "password",
Password: "secret",
TLSMode: "insecure",
})
if err != nil {
t.Fatalf("probe failed: %v", err)
}
if got == nil || !got.Reachable {
t.Fatalf("expected reachable probe result, got %+v", got)
}
if !got.HostPoweredOn {
t.Fatalf("expected powered on host from PowerSummary")
}
if got.HostPowerState != "On" {
t.Fatalf("expected power state On, got %q", got.HostPowerState)
}
}
func TestParsePCIeDeviceSlot_FromNestedRedfishSlotLocation(t *testing.T) {
doc := map[string]interface{}{
"Id": "NIC1",
"Slot": map[string]interface{}{
"Lanes": 16,
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"LocationOrdinalValue": 1,
"LocationType": "Slot",
"ServiceLabel": "PCIe Slot 1 (1)",
},
},
"PCIeType": "Gen5",
"SlotType": "FullLength",
},
}
got := parsePCIeDevice(doc, nil)
if got.Slot != "PCIe Slot 1 (1)" {
t.Fatalf("unexpected slot: %q", got.Slot)
}
}
func TestParsePCIeDeviceSlot_EmptyMapFallsBackToID(t *testing.T) {
doc := map[string]interface{}{
"Id": "NIC42",
"Slot": map[string]interface{}{},
}
got := parsePCIeDevice(doc, nil)
if got.Slot != "NIC42" {
t.Fatalf("unexpected slot fallback: %q", got.Slot)
}
if got.Slot == "map[]" {
t.Fatalf("slot should not stringify empty map")
}
}
func TestReplayRedfishFromRawPayloads_FallbackCollectionMembersByPrefix(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Supermicro",
"Model": "SYS-TEST",
"SerialNumber": "SYS123",
},
// Intentionally missing /redfish/v1/Systems/1/Processors collection.
"/redfish/v1/Systems/1/Processors/CPU1": map[string]interface{}{
"Id": "CPU1",
"Model": "Xeon Gold",
"TotalCores": 32,
"TotalThreads": 64,
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Id": "1",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
},
"redfish_fetch_errors": []map[string]interface{}{
{"path": "/redfish/v1/Systems/1/Processors", "error": "status 500"},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if got.Hardware == nil {
t.Fatalf("expected hardware")
}
if len(got.Hardware.CPUs) != 1 {
t.Fatalf("expected one CPU via prefix fallback, got %d", len(got.Hardware.CPUs))
}
if _, ok := got.RawPayloads["redfish_fetch_errors"]; !ok {
t.Fatalf("expected raw payloads to preserve redfish_fetch_errors")
}
}
func TestReplayRedfishFromRawPayloads_FallbackCollectionMembersSkipsPlaceholderNumericDocs(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Multillect",
"Model": "MLT-S06",
"SerialNumber": "430044262001626",
"Storage": map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage"},
},
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage",
"Members": []interface{}{},
"Members@odata.count": 0,
},
"/redfish/v1/Systems/1/Storage/1": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage/1",
"@odata.type": "#Storage.v1_7_1.Storage",
"Drives": []interface{}{},
"Drives@odata.count": "0",
"LogicalDisk": []interface{}{},
"PhysicalDisk": []interface{}{},
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Id": "1",
"NetworkAdapters": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters"},
"PCIeDevices": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices"},
},
"/redfish/v1/Chassis/1/NetworkAdapters": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters",
"Members": []interface{}{},
"Members@odata.count": 0,
},
"/redfish/v1/Chassis/1/NetworkAdapters/1": map[string]interface{}{
"@odata.context": "/redfish/v1/$metadata#Chassis/Members/1/NetworkAdapters/Members/$entity",
"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/1",
"@odata.type": "#NetworkAdapter.v1_0_0.Networkadapter",
"Id": "1",
"Name": "1",
},
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices",
"Members": []interface{}{},
"Members@odata.count": 0,
},
"/redfish/v1/Chassis/1/PCIeDevices/1": map[string]interface{}{
"@odata.context": "/redfish/v1/$metadata#PCIeDevice.PCIeDevice",
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/1",
"@odata.type": "#PCIeDevice.v1_4_0.PCIeDevice",
"Id": "1",
"Name": "PCIe Device",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if got.Hardware == nil {
t.Fatalf("expected hardware")
}
if len(got.Hardware.NetworkAdapters) != 0 {
t.Fatalf("expected placeholder network adapters to be skipped, got %d", len(got.Hardware.NetworkAdapters))
}
if len(got.Hardware.PCIeDevices) != 0 {
t.Fatalf("expected placeholder PCIe devices to be skipped, got %d", len(got.Hardware.PCIeDevices))
}
if len(got.Hardware.Storage) != 0 {
t.Fatalf("expected placeholder storage members to be skipped, got %d", len(got.Hardware.Storage))
}
}
func TestReplayRedfishFromRawPayloads_PrefersActiveBMCInterfaceForBoardMAC(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"}},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Multillect",
"Model": "MLT-S06",
"SerialNumber": "430044262001626",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"}},
},
"/redfish/v1/Chassis/1": map[string]interface{}{"Id": "1"},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"}},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
"/redfish/v1/Managers/1/EthernetInterfaces": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces/eth0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces/eth1"},
},
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"NcsiEnabled": true,
"LLDP": map[string]interface{}{
"LLDPMode": "Rx",
"Members": []interface{}{
map[string]interface{}{
"EthIndex": "eth1",
"ChassisName": "castor.netwell.local",
"PortDesc": "ge-0/0/17",
"PortId": "531",
"VlanId": 20,
},
},
},
},
},
},
"/redfish/v1/Managers/1/EthernetInterfaces/eth0": map[string]interface{}{
"Id": "eth0",
"MACAddress": "00:25:6c:70:00:13",
"LinkStatus": "NoLink",
"SpeedMbps": 65535,
},
"/redfish/v1/Managers/1/EthernetInterfaces/eth1": map[string]interface{}{
"Id": "eth1",
"MACAddress": "00:25:6c:70:00:12",
"LinkStatus": "LinkActive",
"SpeedMbps": 1000,
"IPv4Addresses": []interface{}{
map[string]interface{}{
"Address": "172.16.41.42",
"Gateway": "172.16.41.1",
"SubnetMask": "255.255.255.0",
},
},
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if got.Hardware == nil {
t.Fatalf("expected hardware")
}
if got.Hardware.BoardInfo.BMCMACAddress != "00:25:6C:70:00:12" {
t.Fatalf("expected active BMC MAC from eth1, got %q", got.Hardware.BoardInfo.BMCMACAddress)
}
summary, ok := got.RawPayloads["redfish_bmc_network_summary"].(map[string]any)
if !ok {
t.Fatalf("expected redfish_bmc_network_summary")
}
if summary["interface_id"] != "eth1" {
t.Fatalf("expected eth1 summary, got %#v", summary["interface_id"])
}
}
func TestReplayRedfishFromRawPayloads_AddsSensorsListHintSummary(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"}},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Multillect",
"Model": "MLT-S06",
"SerialNumber": "430044262001626",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"}},
},
"/redfish/v1/Chassis/1": map[string]interface{}{"Id": "1"},
"/redfish/v1/Chassis/1/SensorsList": map[string]interface{}{
"SensorsList": []interface{}{
map[string]interface{}{"SensorName": "DIMM000_Status", "SensorType": "Memory", "Status": "OK"},
map[string]interface{}{"SensorName": "DIMM001_Status", "SensorType": "Memory", "Status": "nop"},
map[string]interface{}{"SensorName": "DIMM100_Status", "SensorType": "Memory", "Status": "OK"},
map[string]interface{}{"SensorName": "HDD0_F_Status", "SensorType": "Drive Slot", "Status": "nop"},
map[string]interface{}{"SensorName": "NVME0_F_Status", "SensorType": "Drive Slot", "Status": "nop"},
map[string]interface{}{"SensorName": "Logical_Drive", "SensorType": "Drive Slot", "Status": "OK"},
},
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"}},
},
"/redfish/v1/Managers/1": map[string]interface{}{"Id": "1"},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
hints, ok := got.RawPayloads["redfish_sensor_hints"].(map[string]any)
if !ok {
t.Fatalf("expected redfish_sensor_hints")
}
memHints, ok := hints["memory_slots"].(map[string]any)
if !ok {
t.Fatalf("expected memory_slots hint")
}
if asInt(memHints["present_count"]) != 2 {
t.Fatalf("expected 2 present memory slot hints, got %#v", memHints["present_count"])
}
driveHints, ok := hints["drive_slots"].(map[string]any)
if !ok {
t.Fatalf("expected drive_slots hint")
}
if asInt(driveHints["physical_total"]) != 2 {
t.Fatalf("expected 2 physical drive slots, got %#v", driveHints["physical_total"])
}
if driveHints["logical_drive_status"] != "OK" {
t.Fatalf("expected logical drive status OK, got %#v", driveHints["logical_drive_status"])
}
foundMemoryEvent := false
foundDriveEvent := false
for _, ev := range got.Events {
if strings.Contains(ev.Description, "Memory slot sensors report 2 populated positions out of 3") {
foundMemoryEvent = true
}
if strings.Contains(ev.Description, "Drive slot sensors report 0 active physical slots out of 2") {
foundDriveEvent = true
}
}
if !foundMemoryEvent {
t.Fatalf("expected memory slot hint event")
}
if !foundDriveEvent {
t.Fatalf("expected drive slot hint event")
}
}
func TestReplayRedfishFromRawPayloads_PreservesSourceTimezoneAndUTCCollectedAt(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"}},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Inspur",
"Model": "NF5688M7",
"SerialNumber": "23E100051",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"}},
},
"/redfish/v1/Chassis/1": map[string]interface{}{"Id": "1"},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"}},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"DateTime": "2026-02-28T04:18:18+08:00",
"DateTimeLocalOffset": "+08:00",
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if got.SourceTimezone != "+08:00" {
t.Fatalf("expected source_timezone +08:00, got %q", got.SourceTimezone)
}
wantCollectedAt := time.Date(2026, 2, 27, 20, 18, 18, 0, time.UTC)
if !got.CollectedAt.Equal(wantCollectedAt) {
t.Fatalf("expected collected_at %s, got %s", wantCollectedAt, got.CollectedAt)
}
if got.RawPayloads["source_timezone"] != "+08:00" {
t.Fatalf("expected source_timezone in raw payloads, got %#v", got.RawPayloads["source_timezone"])
}
}
func TestReplayRedfishFromRawPayloads_ParsesInlineThresholdAndDiscreteSensors(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Id": "1",
"Manufacturer": "Inspur",
"Model": "NF5688M7",
"SerialNumber": "23E100051",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Id": "1",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
"/redfish/v1/Chassis/1/ThresholdSensors": map[string]interface{}{
"Sensors": []interface{}{
map[string]interface{}{
"Name": "Inlet_Temp",
"Reading": 16,
"ReadingUnits": "deg_c",
"State": "Enabled",
},
},
},
"/redfish/v1/Chassis/1/DiscreteSensors": map[string]interface{}{
"Sensors": []interface{}{
map[string]interface{}{
"Name": "PSU_Redundant",
"State": "Disabled",
},
},
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if len(got.Sensors) == 0 {
t.Fatalf("expected sensors from inline ThresholdSensors")
}
foundSensor := false
for _, s := range got.Sensors {
if s.Name == "Inlet_Temp" {
foundSensor = true
break
}
}
if !foundSensor {
t.Fatalf("expected Inlet_Temp sensor in replay output")
}
foundEvent := false
for _, ev := range got.Events {
if ev.EventType == "Discrete Sensor Status" && ev.SensorName == "PSU_Redundant" {
foundEvent = true
break
}
}
if !foundEvent {
t.Fatalf("expected discrete sensor warning event from inline DiscreteSensors")
}
}
func TestReplayRedfishFromRawPayloads_CollectsThermalAndPowerSensors(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Id": "1",
"Manufacturer": "Inspur",
"Model": "NF5688M7",
"SerialNumber": "23E100051",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Id": "1",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
"/redfish/v1/Chassis/1/Thermal": map[string]interface{}{
"Fans": []interface{}{
map[string]interface{}{
"Name": "FAN0_F_Speed",
"Reading": 9279,
"ReadingUnits": "RPM",
"Status": map[string]interface{}{
"Health": "OK",
"State": "Enabled",
},
},
},
"Temperatures": []interface{}{
map[string]interface{}{
"Name": "CPU0_Temp",
"ReadingCelsius": 44,
"Status": map[string]interface{}{
"Health": "OK",
"State": "Enabled",
},
},
},
},
"/redfish/v1/Chassis/1/Power": map[string]interface{}{
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"TotalPower": 1836,
"CurrentCPUPowerWatts": 304,
"CurrentMemoryPowerWatts": 75,
"CurrentFANPowerWatts": 180,
},
},
"PowerControl": []interface{}{
map[string]interface{}{
"Name": "System Power Control 1",
"PowerConsumedWatts": 1836,
"Status": map[string]interface{}{
"Health": "OK",
"State": "Enabled",
},
},
},
"PowerSupplies": []interface{}{
map[string]interface{}{
"Name": "Power Supply 1",
"PowerInputWatts": 180,
"LastPowerOutputWatts": 155,
"LineInputVoltage": 223.25,
"Status": map[string]interface{}{
"Health": "OK",
"State": "Enabled",
},
},
},
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if len(got.Sensors) == 0 {
t.Fatalf("expected non-empty sensors")
}
expected := map[string]bool{
"FAN0_F_Speed": false,
"CPU0_Temp": false,
"Total_Power": false,
"System Power Control 1_Consumed": false,
"Power Supply 1_InputPower": false,
}
for _, s := range got.Sensors {
if _, ok := expected[s.Name]; ok {
expected[s.Name] = true
}
}
for name, found := range expected {
if !found {
t.Fatalf("expected sensor %q in replay output", name)
}
}
}
func TestEnrichNICFromPCIeFunctions(t *testing.T) {
nic := parseNIC(map[string]interface{}{
"Id": "1",
"Model": "MCX75310AAS-NEAT",
"Manufacturer": "Supermicro",
"SerialNumber": "NIC-SN-1",
"Controllers": []interface{}{
map[string]interface{}{
"Links": map[string]interface{}{
"PCIeDevices": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/NIC1"},
},
},
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{"ServiceLabel": "PCIe Slot 1 (1)"},
},
},
},
})
pcieDoc := map[string]interface{}{
"Id": "NIC1",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/NIC1/PCIeFunctions",
},
}
functionDocs := []map[string]interface{}{
{
"FunctionId": "0000:17:00.0",
"VendorId": "0x15b3",
"DeviceId": "0x1021",
"SerialNumber": "MT-SN-0001",
"PartNumber": "MCX623106AC-CDAT",
"CurrentLinkWidth": 16,
"CurrentLinkSpeedGTs": "32 GT/s",
"MaxLinkWidth": 16,
"MaxLinkSpeedGTs": "32 GT/s",
},
}
enrichNICFromPCIe(&nic, pcieDoc, functionDocs, nil)
if nic.VendorID != 0x15b3 || nic.DeviceID != 0x1021 {
t.Fatalf("unexpected NIC IDs: vendor=%#x device=%#x", nic.VendorID, nic.DeviceID)
}
if nic.Location != "PCIe Slot 1 (1)" {
t.Fatalf("unexpected NIC location: %q", nic.Location)
}
if nic.BDF != "0000:17:00.0" {
t.Fatalf("unexpected NIC BDF: %q", nic.BDF)
}
if nic.SerialNumber != "NIC-SN-1" {
t.Fatalf("expected existing NIC serial to be preserved, got %q", nic.SerialNumber)
}
if nic.PartNumber != "MCX623106AC-CDAT" {
t.Fatalf("expected NIC part number from PCIe function, got %q", nic.PartNumber)
}
if nic.LinkWidth != 16 || nic.MaxLinkWidth != 16 {
t.Fatalf("unexpected NIC link width state: current=%d max=%d", nic.LinkWidth, nic.MaxLinkWidth)
}
if nic.LinkSpeed != "32 GT/s" || nic.MaxLinkSpeed != "32 GT/s" {
t.Fatalf("unexpected NIC link speed state: current=%q max=%q", nic.LinkSpeed, nic.MaxLinkSpeed)
}
}
func TestEnrichNICFromPCIeFunctions_FillsMissingIdentityFromFunctionDoc(t *testing.T) {
nic := parseNIC(map[string]interface{}{
"Id": "DevType7_NIC1",
"Controllers": []interface{}{
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 1,
},
},
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 1,
},
},
},
})
pcieDoc := map[string]interface{}{
"Slot": map[string]interface{}{
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"ServiceLabel": "RISER4",
},
},
},
}
functionDocs := []map[string]interface{}{
{
"FunctionId": "0000:0f:00.0",
"VendorId": "0x15b3",
"DeviceId": "0x101f",
"SerialNumber": "MT2412X00001",
"PartNumber": "MCX623432AC-GDA_Ax",
},
}
enrichNICFromPCIe(&nic, pcieDoc, functionDocs, nil)
if nic.Slot != "RISER4" {
t.Fatalf("expected slot from PCIe slot label, got %q", nic.Slot)
}
if nic.Location != "RISER4" {
t.Fatalf("expected location from PCIe slot label, got %q", nic.Location)
}
if nic.PortCount != 2 {
t.Fatalf("expected combined port count from controllers, got %d", nic.PortCount)
}
if nic.SerialNumber != "MT2412X00001" {
t.Fatalf("expected serial from PCIe function, got %q", nic.SerialNumber)
}
if nic.PartNumber != "MCX623432AC-GDA_Ax" {
t.Fatalf("expected part number from PCIe function, got %q", nic.PartNumber)
}
if nic.BDF != "0000:0f:00.0" {
t.Fatalf("expected BDF from PCIe function, got %q", nic.BDF)
}
}
func TestReplayCollectNICs_UsesNetworkDeviceFunctionPCIeFunctionLink(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/1/NetworkAdapters": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1"},
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1": map[string]interface{}{
"Id": "DevType7_NIC1",
"Name": "NetworkAdapter_1",
"Controllers": []interface{}{
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 2,
},
"Links": map[string]interface{}{
"PCIeDevices": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00"},
},
},
},
},
"NetworkDeviceFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions",
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function0"},
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function0": map[string]interface{}{
"Id": "Function0",
"Links": map[string]interface{}{
"PCIeFunction": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function0",
},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/00_0F_00": map[string]interface{}{
"Id": "00_0F_00",
"Name": "PCIeDevice_00_0F_00",
"Manufacturer": "Mellanox Technologies",
"FirmwareVersion": "26.43.25.66",
"Slot": map[string]interface{}{
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"ServiceLabel": "RISER4",
},
},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function0": map[string]interface{}{
"Id": "Function0",
"FunctionId": "0000:0f:00.0",
"VendorId": "0x15b3",
"DeviceId": "0x101f",
"SerialNumber": "MT2412X00001",
"PartNumber": "MCX623432AC-GDA_Ax",
},
}
r := redfishSnapshotReader{tree: tree}
nics := r.collectNICs([]string{"/redfish/v1/Chassis/1"})
if len(nics) != 1 {
t.Fatalf("expected one NIC, got %d", len(nics))
}
if nics[0].Slot != "RISER4" {
t.Fatalf("expected slot from PCIe device, got %q", nics[0].Slot)
}
if nics[0].SerialNumber != "MT2412X00001" {
t.Fatalf("expected serial from NetworkDeviceFunction PCIeFunction link, got %q", nics[0].SerialNumber)
}
if nics[0].PartNumber != "MCX623432AC-GDA_Ax" {
t.Fatalf("expected part number from linked PCIeFunction, got %q", nics[0].PartNumber)
}
if nics[0].BDF != "0000:0f:00.0" {
t.Fatalf("expected BDF from linked PCIeFunction, got %q", nics[0].BDF)
}
if nics[0].Model != "MT2894 Family [ConnectX-6 Lx]" {
t.Fatalf("expected model resolved from PCI IDs, got %q", nics[0].Model)
}
}
func TestReplayEnrichNICsFromNetworkInterfaces_DoesNotCreateGhostForLinkedAdapter(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/1/NetworkAdapters": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1"},
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1",
"Id": "DevType7_NIC1",
"Name": "NetworkAdapter_1",
"Controllers": []interface{}{
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 1,
},
"Links": map[string]interface{}{
"PCIeDevices": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00"},
},
},
},
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 1,
},
"Links": map[string]interface{}{
"PCIeDevices": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00"},
},
},
},
},
"NetworkDeviceFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions",
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function1"},
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function0": map[string]interface{}{
"Id": "Function0",
"Ethernet": map[string]interface{}{
"MACAddress": "CC:40:F3:D6:9E:DE",
"PermanentMACAddress": "CC:40:F3:D6:9E:DE",
},
"Links": map[string]interface{}{
"PCIeFunction": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function0",
},
},
},
"/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function1": map[string]interface{}{
"Id": "Function1",
"Ethernet": map[string]interface{}{
"MACAddress": "CC:40:F3:D6:9E:DF",
"PermanentMACAddress": "CC:40:F3:D6:9E:DF",
},
"Links": map[string]interface{}{
"PCIeFunction": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function1",
},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/00_0F_00": map[string]interface{}{
"Id": "00_0F_00",
"Name": "PCIeDevice_00_0F_00",
"Manufacturer": "Mellanox Technologies",
"FirmwareVersion": "26.43.25.66",
"Slot": map[string]interface{}{
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"ServiceLabel": "RISER4",
},
},
},
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function0": map[string]interface{}{
"FunctionId": "0000:0f:00.0",
"VendorId": "0x15b3",
"DeviceId": "0x101f",
"DeviceClass": "NetworkController",
"SerialNumber": "N/A",
},
"/redfish/v1/Chassis/1/PCIeDevices/00_0F_00/PCIeFunctions/Function1": map[string]interface{}{
"FunctionId": "0000:0f:00.1",
"VendorId": "0x15b3",
"DeviceId": "0x101f",
"DeviceClass": "NetworkController",
},
"/redfish/v1/Systems/1/NetworkInterfaces": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/NetworkInterfaces/DevType7_NIC1"},
},
},
"/redfish/v1/Systems/1/NetworkInterfaces/DevType7_NIC1": map[string]interface{}{
"Id": "DevType7_NIC1",
"Name": "NetworkAdapter_1",
"Links": map[string]interface{}{
"NetworkAdapter": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1",
},
},
"Status": map[string]interface{}{
"Health": "OK",
"State": "Disabled",
},
},
}
r := redfishSnapshotReader{tree: tree}
nics := r.collectNICs([]string{"/redfish/v1/Chassis/1"})
r.enrichNICsFromNetworkInterfaces(&nics, []string{"/redfish/v1/Systems/1"})
if len(nics) != 1 {
t.Fatalf("expected linked network interface to reuse existing NIC, got %d: %+v", len(nics), nics)
}
if nics[0].Slot != "RISER4" {
t.Fatalf("expected enriched slot to stay canonical, got %q", nics[0].Slot)
}
if nics[0].Model != "MT2894 Family [ConnectX-6 Lx]" {
t.Fatalf("expected resolved Mellanox model, got %q", nics[0].Model)
}
if len(nics[0].MACAddresses) != 2 {
t.Fatalf("expected both MACs to stay on one NIC, got %+v", nics[0].MACAddresses)
}
}
func TestParseNIC_PortCountFromControllerCapabilities(t *testing.T) {
nic := parseNIC(map[string]interface{}{
"Id": "1",
"Controllers": []interface{}{
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 2,
},
},
},
})
if nic.PortCount != 2 {
t.Fatalf("expected port_count=2, got %d", nic.PortCount)
}
}
func TestParseNIC_PrefersControllerSlotLabelAndPCIeInterface(t *testing.T) {
nic := parseNIC(map[string]interface{}{
"Id": "1",
"Model": "MCX75310AAS-NEAT",
"Manufacturer": "Supermicro",
"Controllers": []interface{}{
map[string]interface{}{
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"ServiceLabel": "PCIe Slot 1 (1)",
},
},
"PCIeInterface": map[string]interface{}{
"LanesInUse": 16,
"MaxLanes": 16,
"PCIeType": "Gen5",
"MaxPCIeType": "Gen5",
},
},
},
})
if nic.Slot != "PCIe Slot 1 (1)" {
t.Fatalf("expected slot from controller location, got %q", nic.Slot)
}
if nic.Location != "PCIe Slot 1 (1)" {
t.Fatalf("expected location from controller location, got %q", nic.Location)
}
if nic.LinkWidth != 16 || nic.MaxLinkWidth != 16 {
t.Fatalf("expected link widths from controller PCIeInterface, got current=%d max=%d", nic.LinkWidth, nic.MaxLinkWidth)
}
if nic.LinkSpeed != "Gen5" || nic.MaxLinkSpeed != "Gen5" {
t.Fatalf("expected link speeds from controller PCIeInterface, got current=%q max=%q", nic.LinkSpeed, nic.MaxLinkSpeed)
}
}
func TestParseNIC_xFusionMaxlanesAndOEMLinkWidth(t *testing.T) {
// xFusion uses "Maxlanes" (lowercase 'l') in PCIeInterface, not "MaxLanes".
// xFusion also stores per-function link width as Oem.xFusion.LinkWidth = "X8".
nic := parseNIC(map[string]interface{}{
"Id": "OCPCard1",
"Model": "ConnectX-6 Lx",
"Controllers": []interface{}{
map[string]interface{}{
"PCIeInterface": map[string]interface{}{
"LanesInUse": 8,
"Maxlanes": 8, // xFusion uses lowercase 'l'
"PCIeType": "Gen4",
"MaxPCIeType": "Gen4",
},
},
},
})
if nic.LinkWidth != 8 || nic.MaxLinkWidth != 8 {
t.Fatalf("expected link widths 8/8 from xFusion Maxlanes, got current=%d max=%d", nic.LinkWidth, nic.MaxLinkWidth)
}
// enrichNICFromPCIe: OEM xFusion LinkWidth on a PCIeFunction doc.
nic2 := models.NetworkAdapter{}
fnDoc := map[string]interface{}{
"Oem": map[string]interface{}{
"xFusion": map[string]interface{}{
"LinkWidth": "X8",
"LinkWidthAbility": "X8",
"LinkSpeed": "Gen4 (16.0GT/s)",
"LinkSpeedAbility": "Gen4 (16.0GT/s)",
},
},
}
enrichNICFromPCIe(&nic2, map[string]interface{}{}, []map[string]interface{}{fnDoc}, nil)
if nic2.LinkWidth != 8 || nic2.MaxLinkWidth != 8 {
t.Fatalf("expected link width 8 from xFusion OEM LinkWidth, got current=%d max=%d", nic2.LinkWidth, nic2.MaxLinkWidth)
}
if nic2.LinkSpeed != "Gen4 (16.0GT/s)" || nic2.MaxLinkSpeed != "Gen4 (16.0GT/s)" {
t.Fatalf("expected link speed from xFusion OEM LinkSpeed, got current=%q max=%q", nic2.LinkSpeed, nic2.MaxLinkSpeed)
}
}
func TestParseNIC_DropsUnrealisticPortCount(t *testing.T) {
nic := parseNIC(map[string]interface{}{
"Id": "1",
"Controllers": []interface{}{
map[string]interface{}{
"ControllerCapabilities": map[string]interface{}{
"NetworkPortCount": 825307750,
},
},
},
})
if nic.PortCount != 0 {
t.Fatalf("expected unrealistic port count to be dropped, got %d", nic.PortCount)
}
}
func TestParsePCIeDevice_PrefersFunctionClassOverDeviceType(t *testing.T) {
doc := map[string]interface{}{
"Id": "NIC1",
"DeviceType": "SingleFunction",
"Model": "MCX75310AAS-NEAT",
"PartNumber": "MCX75310AAS-NEAT",
}
functionDocs := []map[string]interface{}{
{
"DeviceClass": "NetworkController",
"VendorId": "0x15b3",
"DeviceId": "0x1021",
},
}
got := parsePCIeDevice(doc, functionDocs)
if got.DeviceClass == "SingleFunction" {
t.Fatalf("device class should not keep generic redfish DeviceType")
}
if got.DeviceClass == "" {
t.Fatalf("device class should be resolved")
}
}
func TestParsePCIeDevice_DoesNotPromotePartNumberToDeviceClass(t *testing.T) {
doc := map[string]interface{}{
"Id": "NIC1",
"DeviceType": "SingleFunction",
"Model": "MCX75310AAS-NEAT",
"PartNumber": "MCX75310AAS-NEAT",
}
got := parsePCIeDevice(doc, nil)
if got.DeviceClass != "PCIe device" {
t.Fatalf("expected generic PCIe class fallback, got %q", got.DeviceClass)
}
if got.PartNumber != "MCX75310AAS-NEAT" {
t.Fatalf("expected part number to stay intact, got %q", got.PartNumber)
}
}
func TestParsePCIeComponents_DoNotTreatNumericFunctionIDAsBDF(t *testing.T) {
pcieFn := parsePCIeFunction(map[string]interface{}{
"Id": "1",
"FunctionId": "1",
"DeviceClass": "NetworkController",
"VendorId": "0x15b3",
"DeviceId": "0x1021",
}, 1)
if pcieFn.BDF != "" {
t.Fatalf("expected empty BDF for numeric FunctionId, got %q", pcieFn.BDF)
}
gpu := parseGPU(map[string]interface{}{
"Id": "GPU1",
"Name": "GPU1",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions",
},
}, []map[string]interface{}{
{
"FunctionId": "1",
"VendorId": "0x10de",
"DeviceId": "0x2331",
},
}, 1)
if gpu.BDF != "" {
t.Fatalf("expected GPU BDF to stay empty when only numeric FunctionId exists, got %q", gpu.BDF)
}
nic := parseNIC(map[string]interface{}{"Id": "1"})
enrichNICFromPCIe(&nic, map[string]interface{}{}, []map[string]interface{}{
{
"FunctionId": "1",
"VendorId": "0x15b3",
"DeviceId": "0x1021",
},
}, nil)
if nic.BDF != "" {
t.Fatalf("expected NIC BDF to stay empty when only numeric FunctionId exists, got %q", nic.BDF)
}
}
func TestParseComponents_UseNestedSerialNumberFallback(t *testing.T) {
doc := map[string]interface{}{
"Name": "dev0",
"Id": "dev0",
"Model": "model0",
"Manufacturer": "vendor0",
"SerialNumber": "N/A",
"Oem": map[string]interface{}{
"VendorX": map[string]interface{}{
"SerialNumber": "SN-OK-001",
},
},
}
cpus := parseCPUs([]map[string]interface{}{doc})
if len(cpus) != 1 || cpus[0].SerialNumber != "SN-OK-001" {
t.Fatalf("expected CPU serial fallback, got %+v", cpus)
}
dimms := parseMemory([]map[string]interface{}{doc})
if len(dimms) != 1 || dimms[0].SerialNumber != "SN-OK-001" {
t.Fatalf("expected DIMM serial fallback, got %+v", dimms)
}
drive := parseDrive(doc)
if drive.SerialNumber != "SN-OK-001" {
t.Fatalf("expected drive serial fallback, got %q", drive.SerialNumber)
}
nic := parseNIC(doc)
if nic.SerialNumber != "SN-OK-001" {
t.Fatalf("expected NIC serial fallback, got %q", nic.SerialNumber)
}
psu := parsePSU(doc, 1)
if psu.SerialNumber != "SN-OK-001" {
t.Fatalf("expected PSU serial fallback, got %q", psu.SerialNumber)
}
pcie := parsePCIeDevice(doc, nil)
if pcie.SerialNumber != "SN-OK-001" {
t.Fatalf("expected PCIe device serial fallback, got %q", pcie.SerialNumber)
}
pcieFn := parsePCIeFunction(doc, 1)
if pcieFn.SerialNumber != "SN-OK-001" {
t.Fatalf("expected PCIe function serial fallback, got %q", pcieFn.SerialNumber)
}
}
func TestParseCPU_UsesPublicSerialAsPPINAndCurrentSpeedMHz(t *testing.T) {
cpus := parseCPUs([]map[string]interface{}{
{
"Id": "CPU0",
"Model": "Intel Xeon",
"TotalCores": 48,
"TotalThreads": 96,
"MaxSpeedMHz": 4000,
"OperatingSpeedMHz": 0,
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"SerialNumber": "6FB5241E81CECDFD",
"CurrentSpeedMHz": 2700,
},
},
},
})
if len(cpus) != 1 {
t.Fatalf("expected one CPU, got %d", len(cpus))
}
if cpus[0].PPIN != "6FB5241E81CECDFD" {
t.Fatalf("expected PPIN from Oem.Public.SerialNumber, got %+v", cpus[0])
}
if cpus[0].SerialNumber != "" {
t.Fatalf("expected empty CPU serial number when only Public serial exists, got %+v", cpus[0])
}
if cpus[0].FrequencyMHz != 2700 {
t.Fatalf("expected CPU frequency from Oem.Public.CurrentSpeedMHz, got %+v", cpus[0])
}
}
func TestParseCPUAndMemory_CollectOemDetails(t *testing.T) {
cpus := parseCPUs([]map[string]interface{}{
{
"Id": "CPU0",
"Model": "Intel Xeon",
"CorrectableErrors": 7,
"TemperatureCelsius": 63,
"Oem": map[string]interface{}{
"VendorX": map[string]interface{}{
"MicrocodeVersion": "0x2b000643",
"UncorrectableErrors": 1,
"ThermalThrottled": true,
},
},
},
})
if len(cpus) != 1 || cpus[0].Details == nil {
t.Fatalf("expected CPU details, got %+v", cpus)
}
if cpus[0].Details["microcode"] != "0x2b000643" {
t.Fatalf("expected CPU microcode detail, got %#v", cpus[0].Details)
}
if cpus[0].Details["correctable_error_count"] != int64(7) || cpus[0].Details["uncorrectable_error_count"] != int64(1) {
t.Fatalf("expected CPU error counters, got %#v", cpus[0].Details)
}
if cpus[0].Details["throttled"] != true || cpus[0].Details["temperature_c"] != 63.0 {
t.Fatalf("expected CPU thermal details, got %#v", cpus[0].Details)
}
dimms := parseMemory([]map[string]interface{}{
{
"Id": "DIMM0",
"DeviceLocator": "CPU0_C0D0",
"CapacityMiB": 32768,
"SerialNumber": "DIMM-001",
"Oem": map[string]interface{}{
"VendorX": map[string]interface{}{
"CorrectableECCErrorCount": 12,
"UncorrectableECCErrorCount": 2,
"TemperatureC": 41.5,
"SpareBlocksRemainingPercent": 88,
"PerformanceDegraded": true,
"DataLossDetected": false,
},
},
},
})
if len(dimms) != 1 || dimms[0].Details == nil {
t.Fatalf("expected DIMM details, got %+v", dimms)
}
if dimms[0].Details["correctable_ecc_error_count"] != int64(12) || dimms[0].Details["uncorrectable_ecc_error_count"] != int64(2) {
t.Fatalf("expected DIMM ECC counters, got %#v", dimms[0].Details)
}
if dimms[0].Details["temperature_c"] != 41.5 || dimms[0].Details["spare_blocks_remaining_pct"] != 88.0 {
t.Fatalf("expected DIMM telemetry details, got %#v", dimms[0].Details)
}
if dimms[0].Details["performance_degraded"] != true || dimms[0].Details["data_loss_detected"] != false {
t.Fatalf("expected DIMM boolean health details, got %#v", dimms[0].Details)
}
}
func TestReplayRedfishFromRawPayloads_UsesProcessorAndMemoryMetrics(t *testing.T) {
rawPayloads := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Id": "1",
"Processors": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Processors",
},
"Memory": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Memory",
},
},
"/redfish/v1/Systems/1/Processors": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Processors/CPU0"},
},
},
"/redfish/v1/Systems/1/Processors/CPU0": map[string]interface{}{
"Id": "CPU0",
"ProcessorType": "CPU",
"Model": "Intel Xeon",
"ProcessorMetrics": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Processors/CPU0/ProcessorMetrics",
},
},
"/redfish/v1/Systems/1/Processors/CPU0/ProcessorMetrics": map[string]interface{}{
"CorrectableErrors": 10,
"ThermalThrottled": true,
"MicrocodeVersion": "0x2b000643",
"TemperatureCelsius": 66,
},
"/redfish/v1/Systems/1/Memory": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Memory/DIMM0"},
},
},
"/redfish/v1/Systems/1/Memory/DIMM0": map[string]interface{}{
"Id": "DIMM0",
"DeviceLocator": "CPU0_C0D0",
"CapacityMiB": 32768,
"SerialNumber": "DIMM-001",
"MemoryMetrics": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Memory/DIMM0/MemoryMetrics",
},
},
"/redfish/v1/Systems/1/Memory/DIMM0/MemoryMetrics": map[string]interface{}{
"CorrectableECCErrorCount": 14,
"TemperatureCelsius": 42,
"PerformanceDegraded": true,
"SpareBlocksRemainingPercent": 91,
},
},
}
result, err := ReplayRedfishFromRawPayloads(rawPayloads, nil)
if err != nil {
t.Fatalf("ReplayRedfishFromRawPayloads() failed: %v", err)
}
if len(result.Hardware.CPUs) != 1 || result.Hardware.CPUs[0].Details == nil {
t.Fatalf("expected CPU details from replay metrics, got %+v", result.Hardware.CPUs)
}
if result.Hardware.CPUs[0].Details["correctable_error_count"] != int64(10) || result.Hardware.CPUs[0].Details["microcode"] != "0x2b000643" {
t.Fatalf("expected CPU replay metrics details, got %#v", result.Hardware.CPUs[0].Details)
}
if len(result.Hardware.Memory) != 1 || result.Hardware.Memory[0].Details == nil {
t.Fatalf("expected memory details from replay metrics, got %+v", result.Hardware.Memory)
}
if result.Hardware.Memory[0].Details["correctable_ecc_error_count"] != int64(14) || result.Hardware.Memory[0].Details["performance_degraded"] != true {
t.Fatalf("expected DIMM replay metrics details, got %#v", result.Hardware.Memory[0].Details)
}
}
func TestReplayRedfishFromRawPayloads_UsesDriveMetrics(t *testing.T) {
rawPayloads := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Id": "1",
"Storage": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage",
},
},
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/RAID1"},
},
},
"/redfish/v1/Systems/1/Storage/RAID1": map[string]interface{}{
"Id": "RAID1",
"Drives": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage/RAID1/Drives",
},
},
"/redfish/v1/Systems/1/Storage/RAID1/Drives": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/RAID1/Drives/Drive0"},
},
},
"/redfish/v1/Systems/1/Storage/RAID1/Drives/Drive0": map[string]interface{}{
"Id": "Drive0",
"Model": "NVMe SSD",
"SerialNumber": "SSD-001",
"DriveMetrics": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage/RAID1/Drives/Drive0/DriveMetrics",
},
},
"/redfish/v1/Systems/1/Storage/RAID1/Drives/Drive0/DriveMetrics": map[string]interface{}{
"PowerOnHours": 1001,
"MediaErrors": 3,
"AvailableSparePercent": 92,
"TemperatureCelsius": 37,
},
},
}
result, err := ReplayRedfishFromRawPayloads(rawPayloads, nil)
if err != nil {
t.Fatalf("ReplayRedfishFromRawPayloads() failed: %v", err)
}
if len(result.Hardware.Storage) != 1 || result.Hardware.Storage[0].Details == nil {
t.Fatalf("expected storage details from replay drive metrics, got %+v", result.Hardware.Storage)
}
if result.Hardware.Storage[0].Details["power_on_hours"] != int64(1001) || result.Hardware.Storage[0].Details["media_errors"] != int64(3) {
t.Fatalf("expected drive metrics counters, got %#v", result.Hardware.Storage[0].Details)
}
if result.Hardware.Storage[0].Details["available_spare_pct"] != 92.0 || result.Hardware.Storage[0].Details["temperature_c"] != 37.0 {
t.Fatalf("expected drive metrics telemetry, got %#v", result.Hardware.Storage[0].Details)
}
}
func TestRedfishCollectionMemberRefs_IncludesOemPublicMembers(t *testing.T) {
collection := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Drives/OB01"},
},
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Drives/FP00HDD00"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Drives/FP00HDD02"},
},
},
},
}
got := redfishCollectionMemberRefs(collection)
if len(got) != 3 {
t.Fatalf("expected 3 member refs, got %d: %v", len(got), got)
}
}
func TestParseDriveAndPSU_CollectComponentMetricsIntoDetails(t *testing.T) {
drive := parseDrive(map[string]interface{}{
"Id": "Drive0",
"Model": "NVMe SSD",
"SerialNumber": "SSD-001",
"TemperatureCelsius": 38.5,
"PowerOnHours": 12450,
"UnsafeShutdowns": 3,
"PredictedMediaLifeLeftPercent": 91,
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"AvailableSparePercent": 87,
},
},
})
if drive.Details == nil {
t.Fatalf("expected drive details to be populated")
}
if got := drive.Details["temperature_c"]; got != 38.5 {
t.Fatalf("expected drive temperature detail 38.5, got %#v", got)
}
if got := drive.Details["power_on_hours"]; got != int64(12450) {
t.Fatalf("expected drive power_on_hours detail, got %#v", got)
}
if got := drive.Details["life_remaining_pct"]; got != 91.0 {
t.Fatalf("expected drive life_remaining_pct detail, got %#v", got)
}
if got := drive.Details["available_spare_pct"]; got != 87.0 {
t.Fatalf("expected drive available_spare_pct detail from Oem/Public, got %#v", got)
}
driveOEM := parseDrive(map[string]interface{}{
"Id": "Drive1",
"Model": "NVMe SSD 2",
"SerialNumber": "SSD-002",
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"temperature": 19,
"PercentAvailableSpare": 93,
"PercentageUsed": 7,
},
},
})
if driveOEM.Details == nil {
t.Fatalf("expected oem drive details to be populated")
}
if got := driveOEM.Details["temperature_c"]; got != 19.0 {
t.Fatalf("expected lowercase OEM drive temperature 19, got %#v", got)
}
if got := driveOEM.Details["available_spare_pct"]; got != 93.0 {
t.Fatalf("expected OEM available_spare_pct 93, got %#v", got)
}
if got := driveOEM.Details["life_used_pct"]; got != 7.0 {
t.Fatalf("expected OEM life_used_pct 7, got %#v", got)
}
psu := parsePSU(map[string]interface{}{
"MemberId": "PSU0",
"SerialNumber": "PSU-001",
"TemperatureCelsius": 41,
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"LifeRemainingPercent": 96,
},
},
}, 1)
if psu.Details == nil {
t.Fatalf("expected psu details to be populated")
}
if got := psu.Details["temperature_c"]; got != 41.0 {
t.Fatalf("expected psu temperature detail 41, got %#v", got)
}
if got := psu.Details["life_remaining_pct"]; got != 96.0 {
t.Fatalf("expected psu life_remaining_pct detail, got %#v", got)
}
}
func TestParseGPUPCIeAndNIC_CollectComponentMetricsIntoDetails(t *testing.T) {
functionDocs := []map[string]interface{}{
{
"FunctionId": "0000:17:00.0",
"VendorId": "0x10de",
"DeviceId": "0x2331",
"TemperatureCelsius": 48.5,
"PowerConsumedWatts": 315.0,
"ECCCorrectedTotal": 12,
"BatteryHealthPercent": 87,
"SFPTemperatureCelsius": 36.2,
},
}
gpu := parseGPU(map[string]interface{}{
"Id": "GPU0",
"Model": "NVIDIA H100",
"Manufacturer": "NVIDIA",
}, functionDocs, 1)
if gpu.Details == nil || gpu.Details["temperature_c"] != 48.5 || gpu.Details["power_w"] != 315.0 {
t.Fatalf("expected gpu details from function docs, got %#v", gpu.Details)
}
pcie := parsePCIeDevice(map[string]interface{}{
"Id": "NIC1",
}, []map[string]interface{}{
{
"FunctionId": "0000:18:00.0",
"VendorId": "0x15b3",
"DeviceId": "0x1021",
"SFPTXPowerDBm": -1.8,
"SFPRXPowerDBm": -2.1,
"SFPBiasMA": 5.5,
"BatteryReplaceRequired": true,
},
})
if pcie.Details == nil || pcie.Details["sfp_tx_power_dbm"] != -1.8 || pcie.Details["battery_replace_required"] != true {
t.Fatalf("expected pcie details from function docs, got %#v", pcie.Details)
}
nic := parseNIC(map[string]interface{}{"Id": "1"})
enrichNICFromPCIe(&nic, map[string]interface{}{}, []map[string]interface{}{
{
"FunctionId": "0000:19:00.0",
"SFPTemperatureCelsius": 34.0,
},
}, nil)
if nic.Details == nil || nic.Details["sfp_temperature_c"] != 34.0 {
t.Fatalf("expected nic details from linked pcie function, got %#v", nic.Details)
}
}
func TestParseComponentDetails_UseLinkedSupplementalMetrics(t *testing.T) {
drive := parseDriveWithSupplementalDocs(
map[string]interface{}{
"Id": "Drive0",
"SerialNumber": "SSD-001",
},
map[string]interface{}{
"PowerOnHours": 5001,
"MediaErrors": 2,
"TemperatureC": 39.5,
"LifeUsedPercent": 9,
},
)
if drive.Details == nil || drive.Details["power_on_hours"] != int64(5001) || drive.Details["temperature_c"] != 39.5 {
t.Fatalf("expected drive details from supplemental metrics, got %#v", drive.Details)
}
psu := parsePSUWithSupplementalDocs(
map[string]interface{}{
"MemberId": "PSU0",
"SerialNumber": "PSU-001",
},
1,
map[string]interface{}{
"Temperature": 44,
"LifeRemainingPercent": 97,
},
)
if psu.Details == nil || psu.Details["temperature_c"] != 44.0 || psu.Details["life_remaining_pct"] != 97.0 {
t.Fatalf("expected psu details from supplemental metrics, got %#v", psu.Details)
}
gpu := parseGPUWithSupplementalDocs(
map[string]interface{}{
"Id": "GPU0",
"Model": "NVIDIA H100",
"Manufacturer": "NVIDIA",
},
nil,
[]map[string]interface{}{
{
"PowerConsumptionWatts": 305.0,
"HWSlowdown": true,
},
},
1,
)
if gpu.Details == nil || gpu.Details["power_w"] != 305.0 || gpu.Details["hw_slowdown"] != true {
t.Fatalf("expected gpu details from supplemental metrics, got %#v", gpu.Details)
}
}
func TestRecoverCriticalRedfishDocsPlanB_RetriesMembersFromExistingCollection(t *testing.T) {
t.Setenv("LOGPILE_REDFISH_CRITICAL_COOLDOWN", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_SLOW_GAP", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_PLANB_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_BACKOFF", "0s")
const memberPath = "/redfish/v1/Chassis/1/Drives/FP00HDD00"
mux := http.NewServeMux()
mux.HandleFunc(memberPath, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"Id": "FP00HDD00",
"Name": "FP00HDD00",
"Model": "HDD-TEST",
"MediaType": "HDD",
"Protocol": "SAS",
"CapacityBytes": int64(2000398934016),
"SerialNumber": "HDD-SN-001",
})
})
ts := httptest.NewServer(mux)
defer ts.Close()
rawTree := map[string]interface{}{
"/redfish/v1/Chassis/1/Drives": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Drives/OB01"},
},
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": memberPath},
},
},
},
},
}
fetchErrs := map[string]string{
memberPath: "Get \"https://example/redfish/v1/Chassis/1/Drives/FP00HDD00\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)",
}
c := NewRedfishConnector()
recovered := c.recoverCriticalRedfishDocsPlanB(
context.Background(),
ts.Client(),
Request{},
ts.URL,
[]string{"/redfish/v1/Chassis/1/Drives"},
rawTree,
fetchErrs,
redfishprofile.AcquisitionTuning{
RecoveryPolicy: redfishprofile.AcquisitionRecoveryPolicy{
EnableCriticalCollectionMemberRetry: true,
EnableCriticalSlowProbe: true,
},
},
nil,
)
if recovered == 0 {
t.Fatalf("expected plan-B to recover at least one document")
}
if _, ok := rawTree[memberPath]; !ok {
t.Fatalf("expected recovered member doc for %s", memberPath)
}
if _, ok := fetchErrs[memberPath]; ok {
t.Fatalf("expected fetch error for %s to be cleared after recovery", memberPath)
}
}
func TestRecoverCriticalRedfishDocsPlanB_RetriesMembersFromSystemMemoryCollection(t *testing.T) {
t.Setenv("LOGPILE_REDFISH_CRITICAL_COOLDOWN", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_SLOW_GAP", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_PLANB_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_BACKOFF", "0s")
const systemPath = "/redfish/v1/Systems/1"
const memoryPath = "/redfish/v1/Systems/1/Memory"
const dimmPath = "/redfish/v1/Systems/1/Memory/CPU1_C1D1"
mux := http.NewServeMux()
mux.HandleFunc(dimmPath, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"Id": "CPU1_C1D1",
"Name": "CPU1_C1D1",
"DeviceLocator": "CPU1_C1D1",
"CapacityMiB": 65536,
"MemoryDeviceType": "DDR5",
"Status": map[string]interface{}{"State": "Enabled", "Health": "OK"},
"SerialNumber": "DIMM-SN-001",
"PartNumber": "DIMM-PN-001",
})
})
ts := httptest.NewServer(mux)
defer ts.Close()
rawTree := map[string]interface{}{
memoryPath: map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": dimmPath},
},
},
}
fetchErrs := map[string]string{
dimmPath: `Get "https://example/redfish/v1/Systems/1/Memory/CPU1_C1D1": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`,
}
plan := redfishprofile.BuildAcquisitionPlan(redfishprofile.MatchSignals{})
match := redfishprofile.MatchProfiles(redfishprofile.MatchSignals{})
resolved := redfishprofile.ResolveAcquisitionPlan(match, plan, redfishprofile.DiscoveredResources{
SystemPaths: []string{systemPath},
}, redfishprofile.MatchSignals{})
criticalPaths := resolved.CriticalPaths
hasMemoryPath := false
for _, p := range criticalPaths {
if p == memoryPath {
hasMemoryPath = true
break
}
}
if !hasMemoryPath {
t.Fatalf("expected critical endpoints to include %s", memoryPath)
}
c := NewRedfishConnector()
recovered := c.recoverCriticalRedfishDocsPlanB(
context.Background(),
ts.Client(),
Request{},
ts.URL,
criticalPaths,
rawTree,
fetchErrs,
redfishprofile.AcquisitionTuning{
RecoveryPolicy: redfishprofile.AcquisitionRecoveryPolicy{
EnableCriticalCollectionMemberRetry: true,
EnableCriticalSlowProbe: true,
},
},
nil,
)
if recovered == 0 {
t.Fatalf("expected plan-B to recover at least one DIMM document")
}
if _, ok := rawTree[dimmPath]; !ok {
t.Fatalf("expected recovered DIMM doc for %s", dimmPath)
}
if _, ok := fetchErrs[dimmPath]; ok {
t.Fatalf("expected DIMM fetch error for %s to be cleared", dimmPath)
}
}
func TestRecoverCriticalRedfishDocsPlanB_SkipsMemberRetryWithoutRecoveryPolicy(t *testing.T) {
t.Setenv("LOGPILE_REDFISH_CRITICAL_COOLDOWN", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_SLOW_GAP", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_PLANB_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_BACKOFF", "0s")
const memoryPath = "/redfish/v1/Systems/1/Memory"
const dimmPath = "/redfish/v1/Systems/1/Memory/CPU1_C1D1"
rawTree := map[string]interface{}{
memoryPath: map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": dimmPath},
},
},
}
fetchErrs := map[string]string{
dimmPath: `Get "https://example/redfish/v1/Systems/1/Memory/CPU1_C1D1": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`,
}
c := NewRedfishConnector()
recovered := c.recoverCriticalRedfishDocsPlanB(
context.Background(),
http.DefaultClient,
Request{},
"https://example",
[]string{memoryPath},
rawTree,
fetchErrs,
redfishprofile.AcquisitionTuning{},
nil,
)
if recovered != 0 {
t.Fatalf("expected no recovery without recovery policy, got %d", recovered)
}
if _, ok := rawTree[dimmPath]; ok {
t.Fatalf("did not expect recovered DIMM doc for %s", dimmPath)
}
if _, ok := fetchErrs[dimmPath]; !ok {
t.Fatalf("expected DIMM fetch error for %s to remain", dimmPath)
}
}
func TestReplayCollectStorage_ProbesSupermicroNVMeDiskBayWhenCollectionEmpty(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/NVMeSSD"},
},
},
"/redfish/v1/Systems/1/Storage/NVMeSSD": map[string]interface{}{
"Drives": map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/NVMeSSD/Drives"},
},
"/redfish/v1/Systems/1/Storage/NVMeSSD/Drives": map[string]interface{}{
"Members": []interface{}{},
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane"},
},
},
"/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane": map[string]interface{}{
"Drives": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane/Drives"},
},
"/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane/Drives": map[string]interface{}{
"Members@odata.count": 0,
"Members": []interface{}{},
},
"/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane/Drives/Disk.Bay.0": map[string]interface{}{
"Id": "Disk.Bay.0",
"Name": "Disk.Bay.0",
"Manufacturer": "INTEL",
"SerialNumber": "BTLJ035203XT1P0FGN",
"Model": "INTEL SSDPE2KX010T8",
"CapacityBytes": int64(1000204886016),
"Protocol": "NVMe",
"MediaType": "SSD",
"Status": map[string]interface{}{"State": "Enabled", "Health": "OK"},
},
}}
got := r.collectStorage("/redfish/v1/Systems/1", testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableSupermicroNVMeBackplane: true}))
if len(got) != 1 {
t.Fatalf("expected one drive from direct Disk.Bay probe, got %d", len(got))
}
if got[0].SerialNumber != "BTLJ035203XT1P0FGN" {
t.Fatalf("unexpected serial: %q", got[0].SerialNumber)
}
if got[0].SizeGB == 0 {
t.Fatalf("expected size to be parsed from CapacityBytes")
}
}
func TestReplayCollectStorage_SkipsEnclosureRecoveryWhenDirectiveDisabled(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/1"},
},
},
"/redfish/v1/Systems/1/Storage/1": map[string]interface{}{
"Links": map[string]interface{}{
"Enclosures": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Enclosures/1"},
},
},
},
"/redfish/v1/Enclosures/1/Drives": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Enclosures/1/Drives/Drive1"},
},
},
"/redfish/v1/Enclosures/1/Drives/Drive1": map[string]interface{}{
"Id": "Drive1",
"Name": "Drive1",
"Model": "INTEL SSD",
"SerialNumber": "ENCLOSURE-DRIVE-001",
"Protocol": "SATA",
"MediaType": "SSD",
},
}}
got := r.collectStorage("/redfish/v1/Systems/1", testAnalysisPlan(redfishprofile.AnalysisDirectives{}))
if len(got) != 0 {
t.Fatalf("expected no enclosure recovery when directive is off, got %d", len(got))
}
}
func TestReplayCollectStorage_UsesKnownControllerRecoveryWhenEnabled(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/Storage/IntelVROC/Drives": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/IntelVROC/Drives/1"},
},
},
"/redfish/v1/Systems/1/Storage/IntelVROC/Drives/1": map[string]interface{}{
"Id": "1",
"Name": "Drive1",
"Model": "VROC SSD",
"SerialNumber": "VROC-001",
"Protocol": "NVMe",
"MediaType": "SSD",
},
}}
got := r.collectStorage("/redfish/v1/Systems/1", redfishprofile.ResolvedAnalysisPlan{
Directives: redfishprofile.AnalysisDirectives{EnableKnownStorageControllerRecovery: true},
KnownStorageDriveCollections: []string{"/Storage/IntelVROC/Drives"},
})
if len(got) != 1 {
t.Fatalf("expected one drive from known controller recovery, got %d", len(got))
}
if got[0].SerialNumber != "VROC-001" {
t.Fatalf("unexpected serial %q", got[0].SerialNumber)
}
}
func TestReplayCollectStorageVolumes_SkipsVolumeCapabilitiesFallbackMember(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/DE00A000"},
},
},
"/redfish/v1/Systems/1/Storage/DE00A000": map[string]interface{}{
"Id": "DE00A000",
"Volumes": map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/DE00A000/Volumes"},
},
"/redfish/v1/Systems/1/Storage/DE00A000/Volumes": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage/DE00A000/Volumes",
"@odata.type": "#VolumeCollection.VolumeCollection",
"Members": []interface{}{},
"Members@odata.count": 0,
"Name": "MR Volume Collection",
},
"/redfish/v1/Systems/1/Storage/DE00A000/Volumes/Capabilities": map[string]interface{}{
"@odata.id": "/redfish/v1/Systems/1/Storage/DE00A000/Volumes/Capabilities",
"@odata.type": "#Volume.v1_9_0.Volume",
"Id": "Capabilities",
"Name": "Capabilities for VolumeCollection",
},
}}
got := r.collectStorageVolumes("/redfish/v1/Systems/1", testAnalysisPlan(redfishprofile.AnalysisDirectives{}))
if len(got) != 0 {
t.Fatalf("expected capabilities-only volume collection to stay empty, got %+v", got)
}
}
func TestReplayCollectPCIeDevices_UsesChassisDeviceSupplementalDocs(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/2"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/2": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/2",
"Name": "BCM 5719 1Gb 4p BASE-T OCP Adptr",
"Model": "P51183-001",
"PartNumber": "P51183-001",
"Manufacturer": "Broadcom",
"SerialNumber": "1CH0150001",
"DeviceType": "SingleFunction",
},
"/redfish/v1/Chassis/1/Devices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Devices/2"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Devices/4"},
},
},
"/redfish/v1/Chassis/1/Devices/2": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/Devices/2",
"Name": "BCM 5719 1Gb 4p BASE-T OCP Adptr",
"DeviceType": "LOM/NIC",
"Manufacturer": "Broadcom",
"PartNumber": "BCM95719N1905HC",
"ProductPartNumber": "P51183-001",
"SerialNumber": "1CH0150001",
"Location": "OCP 3.0 Slot 15",
},
"/redfish/v1/Chassis/1/Devices/4": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/Devices/4",
"Name": "Empty slot 2",
"DeviceType": "Unknown",
"Location": "PCI-E Slot 2",
"SerialNumber": "",
},
}}
got := r.collectPCIeDevices(nil, []string{"/redfish/v1/Chassis/1"})
if len(got) != 1 {
t.Fatalf("expected one PCIe device, got %d", len(got))
}
if got[0].Slot != "OCP 3.0 Slot 15" {
t.Fatalf("expected chassis device location to override weak slot label, got %+v", got[0])
}
if got[0].DeviceClass != "LOM/NIC" {
t.Fatalf("expected chassis device type to enrich class, got %+v", got[0])
}
if got[0].DeviceClass == "P51183-001" {
t.Fatalf("device class should not degrade into part number: %+v", got[0])
}
}
func TestReplayCollectGPUs_DoesNotCollapseOnPlaceholderSerialAndSkipsNIC(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/3"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/9"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/7"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/3": map[string]interface{}{
"Id": "3",
"Name": "PCIeCard3",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"DeviceClass": "DisplayController",
},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/9": map[string]interface{}{
"Id": "9",
"Name": "PCIeCard9",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"DeviceClass": "DisplayController",
},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/7": map[string]interface{}{
"Id": "7",
"Name": "PCIeCard7",
"Model": "MCX631102AN-ADAT",
"Manufacturer": "NVIDIA",
"SerialNumber": "MT2538J00CZE",
"Oem": map[string]interface{}{
"Public": map[string]interface{}{
"DeviceClass": "NetworkController",
},
},
},
}}
got := r.collectGPUs(nil, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected 2 GPUs (two H200 cards), got %d", len(got))
}
for _, gpu := range got {
if gpu.Model == "MCX631102AN-ADAT" {
t.Fatalf("network adapter should not be classified as GPU")
}
}
}
func TestReplayCollectPCIeDevices_SkipsMSITopologyNoiseClasses(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/bridge"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/processor"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/signal"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/serial"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/display"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/network"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/storage"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/bridge": map[string]interface{}{
"Id": "bridge",
"Name": "Bridge",
"Description": "Bridge Device",
"Manufacturer": "Intel Corporation",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/bridge/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/bridge/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/bridge/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/bridge/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "Bridge",
"VendorId": "0x8086",
"DeviceId": "0x0db0",
},
"/redfish/v1/Chassis/1/PCIeDevices/processor": map[string]interface{}{
"Id": "processor",
"Name": "Processor",
"Description": "Processor Device",
"Manufacturer": "Intel Corporation",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/processor/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/processor/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/processor/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/processor/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "Processor",
"VendorId": "0x8086",
"DeviceId": "0x4944",
},
"/redfish/v1/Chassis/1/PCIeDevices/signal": map[string]interface{}{
"Id": "signal",
"Name": "Signal",
"Manufacturer": "Intel Corporation",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/signal/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/signal/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/signal/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/signal/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "SignalProcessingController",
"VendorId": "0x8086",
"DeviceId": "0x3254",
},
"/redfish/v1/Chassis/1/PCIeDevices/serial": map[string]interface{}{
"Id": "serial",
"Name": "Serial",
"Manufacturer": "Renesas",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/serial/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/serial/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/serial/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/serial/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "SerialBusController",
"VendorId": "0x1912",
"DeviceId": "0x0014",
},
"/redfish/v1/Chassis/1/PCIeDevices/display": map[string]interface{}{
"Id": "display",
"Name": "Display",
"Description": "Display Device",
"Manufacturer": "NVIDIA Corporation",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/display/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/display/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/display/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/display/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "DisplayController",
"VendorId": "0x10de",
"DeviceId": "0x233b",
},
"/redfish/v1/Chassis/1/PCIeDevices/network": map[string]interface{}{
"Id": "network",
"Name": "NIC",
"Description": "Network Device",
"Manufacturer": "Mellanox Technologies",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/network/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/network/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/network/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/network/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "NetworkController",
"VendorId": "0x15b3",
"DeviceId": "0x101f",
},
"/redfish/v1/Chassis/1/PCIeDevices/storage": map[string]interface{}{
"Id": "storage",
"Name": "Storage",
"Description": "Storage Device",
"Manufacturer": "Intel Corporation",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/storage/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/storage/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/storage/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/storage/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "MassStorageController",
"VendorId": "0x1234",
"DeviceId": "0x5678",
},
}}
got := r.collectPCIeDevices(nil, []string{"/redfish/v1/Chassis/1"})
if len(got) != 2 {
t.Fatalf("expected only endpoint PCIe devices to remain, got %d: %+v", len(got), got)
}
classes := map[string]bool{}
for _, dev := range got {
classes[dev.DeviceClass] = true
}
if !classes["NetworkController"] || !classes["MassStorageController"] {
t.Fatalf("expected network and storage PCIe devices to remain, got %+v", got)
}
if classes["Bridge"] || classes["Processor"] || classes["SignalProcessingController"] || classes["SerialBusController"] || classes["DisplayController"] {
t.Fatalf("expected MSI topology noise classes to be filtered, got %+v", got)
}
}
func TestReplayCollectPCIeDevices_SkipsNICsAlreadyRepresentedAsNetworkAdapters(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/nic"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/nic": map[string]interface{}{
"Id": "nic",
"Name": "PCIeDevice_00_39_00",
"Description": "Network Device",
"Manufacturer": "Mellanox Technologies",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/nic/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/nic/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/nic/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/nic/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "NetworkController",
"VendorId": "0x15b3",
"DeviceId": "0x101f",
"Links": map[string]interface{}{
"NetworkDeviceFunctions": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/NetworkAdapters/NIC1/NetworkDeviceFunctions/Function0"},
},
"NetworkDeviceFunctions@odata.count": 1,
},
},
}}
got := r.collectPCIeDevices(nil, []string{"/redfish/v1/Chassis/1"})
if len(got) != 0 {
t.Fatalf("expected network-backed PCIe duplicate to be skipped, got %+v", got)
}
}
func TestReplayCollectPCIeDevices_SkipsStorageServiceEndpoints(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/vmd"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/switch-mgmt"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/hba"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/vmd": map[string]interface{}{
"Id": "vmd",
"Description": "Storage Device",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/vmd/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/vmd/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/vmd/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/vmd/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "MassStorageController",
"VendorId": "0x8086",
"DeviceId": "0x28c0",
},
"/redfish/v1/Chassis/1/PCIeDevices/switch-mgmt": map[string]interface{}{
"Id": "switch-mgmt",
"Description": "Storage Device",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/switch-mgmt/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/switch-mgmt/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/switch-mgmt/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/switch-mgmt/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "MassStorageController",
"VendorId": "0x1000",
"DeviceId": "0x00b2",
},
"/redfish/v1/Chassis/1/PCIeDevices/hba": map[string]interface{}{
"Id": "hba",
"Description": "Storage Device",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/hba/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/hba/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/hba/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/hba/PCIeFunctions/1": map[string]interface{}{
"DeviceClass": "MassStorageController",
"VendorId": "0x1234",
"DeviceId": "0x5678",
},
}}
got := r.collectPCIeDevices(nil, []string{"/redfish/v1/Chassis/1"})
if len(got) != 1 {
t.Fatalf("expected only non-service storage controller to remain, got %+v", got)
}
if got[0].VendorID != 0x1234 || got[0].DeviceID != 0x5678 {
t.Fatalf("expected generic HBA to remain, got %+v", got[0])
}
}
func TestParseBoardInfo_NormalizesNullPlaceholders(t *testing.T) {
got := parseBoardInfo(map[string]interface{}{
"Manufacturer": "NULL",
"Model": "NULL",
"SerialNumber": "23E100051",
"PartNumber": "0 ",
"UUID": "fa403f6f-2ee9-11f0-bab9-346f1104085a",
})
if got.Manufacturer != "" {
t.Fatalf("expected empty manufacturer, got %q", got.Manufacturer)
}
if got.ProductName != "" {
t.Fatalf("expected empty product name, got %q", got.ProductName)
}
if got.PartNumber != "" {
t.Fatalf("expected empty part number, got %q", got.PartNumber)
}
if got.SerialNumber != "23E100051" {
t.Fatalf("unexpected serial number: %q", got.SerialNumber)
}
}
func TestParseBoardInfo_UsesSKUAsPartNumberFallback(t *testing.T) {
got := parseBoardInfo(map[string]interface{}{
"Manufacturer": "HPE",
"Model": "ProLiant DL380 Gen11",
"SerialNumber": "CZ2D1X0GS4",
"SKU": "P52560-421",
})
if got.PartNumber != "P52560-421" {
t.Fatalf("expected SKU to populate part number, got %q", got.PartNumber)
}
}
func TestShouldCrawlPath_SkipsJsonSchemas(t *testing.T) {
if shouldCrawlPath("/redfish/v1/JsonSchemas") {
t.Fatalf("expected /JsonSchemas to be skipped")
}
if shouldCrawlPath("/redfish/v1/JsonSchemas/ComputerSystem.v1_8_0") {
t.Fatalf("expected JsonSchemas members to be skipped")
}
if !shouldCrawlPath("/redfish/v1/Systems/1") {
t.Fatalf("expected normal hardware path to be crawled")
}
}
func TestReplayCollectGPUs_FromGraphicsControllers(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU1"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU0": map[string]interface{}{
"Id": "GPU0",
"Name": "GPU0",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654225094493",
"Status": map[string]interface{}{"State": "Enabled", "Health": "OK"},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU1": map[string]interface{}{
"Id": "GPU1",
"Name": "GPU1",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654425002635",
"Status": map[string]interface{}{"State": "Enabled", "Health": "OK"},
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected 2 GPUs from GraphicsControllers, got %d", len(got))
}
if got[0].SerialNumber == "" || got[1].SerialNumber == "" {
t.Fatalf("expected GPU serial numbers from GraphicsControllers")
}
}
func TestReplayCollectGPUs_DedupUsesRedfishPathBeforeHeuristics(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU1"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU0": map[string]interface{}{
"Id": "GPU0",
"Name": "H100-PCIE-80G",
"Model": "H100-PCIE-80G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU1": map[string]interface{}{
"Id": "GPU1",
"Name": "H100-PCIE-80G",
"Model": "H100-PCIE-80G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected both GPUs to be kept by unique redfish path, got %d", len(got))
}
}
func TestParseGPU_xFusionPCIeInterfaceMaxlanes(t *testing.T) {
// xFusion GPU PCIeDevices (PCIeCard1..N) carry link width in PCIeInterface
// with "Maxlanes" (lowercase 'l') rather than "MaxLanes".
doc := map[string]interface{}{
"Id": "PCIeCard1",
"Model": "RTX PRO 6000",
"PCIeInterface": map[string]interface{}{
"LanesInUse": 16,
"Maxlanes": 16,
"PCIeType": "Gen5",
"MaxPCIeType": "Gen5",
},
}
gpu := parseGPU(doc, nil, 1)
if gpu.CurrentLinkWidth != 16 || gpu.MaxLinkWidth != 16 {
t.Fatalf("expected link widths 16/16 from PCIeInterface, got current=%d max=%d", gpu.CurrentLinkWidth, gpu.MaxLinkWidth)
}
if gpu.CurrentLinkSpeed != "Gen5" || gpu.MaxLinkSpeed != "Gen5" {
t.Fatalf("expected link speeds Gen5/Gen5 from PCIeInterface, got current=%q max=%q", gpu.CurrentLinkSpeed, gpu.MaxLinkSpeed)
}
}
func TestParseGPU_UsesNestedOemSerialNumber(t *testing.T) {
doc := map[string]interface{}{
"Id": "GPU4",
"Name": "H100-PCIE-80G",
"Model": "H100-PCIE-80G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
"Oem": map[string]interface{}{
"SerialNumber": "1794024010533",
},
}
got := parseGPU(doc, nil, 1)
if got.SerialNumber != "1794024010533" {
t.Fatalf("expected nested OEM serial number, got %q", got.SerialNumber)
}
}
func TestParseBoardInfoWithFallback_UsesFRU(t *testing.T) {
system := map[string]interface{}{
"Manufacturer": "NULL",
"Model": "NULL",
"SerialNumber": "23E100051",
"PartNumber": "0",
}
chassis := map[string]interface{}{
"Manufacturer": "NULL",
"Model": "NULL",
}
fru := map[string]interface{}{
"FRUInfo": map[string]interface{}{
"Board": map[string]interface{}{
"Manufacturer": "Kaytus",
"ProductName": "KR4268X2",
},
},
}
got := parseBoardInfoWithFallback(system, chassis, fru)
if got.ProductName != "KR4268X2" {
t.Fatalf("expected product from FRU, got %q", got.ProductName)
}
if got.Manufacturer != "Kaytus" {
t.Fatalf("expected manufacturer from FRU, got %q", got.Manufacturer)
}
if got.SerialNumber != "23E100051" {
t.Fatalf("expected serial from system, got %q", got.SerialNumber)
}
}
func TestReplayRedfishFromRawPayloads_AddsMissingServerModelWarning(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "NULL",
"Model": "NULL",
"SerialNumber": "23E100051",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Id": "1",
"Manufacturer": "NULL",
"Model": "NULL",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
},
"redfish_fetch_errors": []map[string]interface{}{
{"path": "/redfish/v1/Systems/1/Oem/Public/FRU", "error": "status 500"},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
if got.Hardware == nil {
t.Fatalf("expected hardware")
}
if got.Hardware.BoardInfo.ProductName != "" {
t.Fatalf("expected empty model for warning test, got %q", got.Hardware.BoardInfo.ProductName)
}
found := false
for _, ev := range got.Events {
if ev.Source == "Redfish" && ev.EventType == "Collection Warning" {
found = true
break
}
}
if !found {
t.Fatalf("expected collection warning event about missing server model")
}
}
func TestReplayRedfishFromRawPayloads_StoresAnalysisProfilesMetadata(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Vendor": "AMI",
"Product": "AMI Redfish",
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Micro-Star International Co., Ltd.",
"Model": "CG290",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Manufacturer": "Micro-Star International Co., Ltd.",
"Model": "CG290",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
meta, ok := got.RawPayloads["redfish_analysis_profiles"].(map[string]any)
if !ok {
t.Fatalf("expected redfish_analysis_profiles metadata")
}
if meta["mode"] != redfishprofile.ModeMatched {
t.Fatalf("expected matched mode, got %#v", meta["mode"])
}
profiles, ok := meta["profiles"].([]string)
if !ok {
t.Fatalf("expected []string profiles, got %T", meta["profiles"])
}
foundMSI := false
for _, profile := range profiles {
if profile == "msi" {
foundMSI = true
break
}
}
if !foundMSI {
t.Fatalf("expected msi in applied profiles, got %v", profiles)
}
planMeta, ok := got.RawPayloads["redfish_analysis_plan"].(map[string]any)
if !ok {
t.Fatalf("expected redfish_analysis_plan metadata")
}
directives, ok := planMeta["directives"].(map[string]any)
if !ok {
t.Fatalf("expected directives map in redfish_analysis_plan")
}
if directives["generic_graphics_controller_dedup"] != true {
t.Fatalf("expected generic_graphics_controller_dedup directive, got %#v", directives["generic_graphics_controller_dedup"])
}
}
func TestReplayRedfishFromRawPayloads_AddsDriveFetchWarning(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Inspur",
"Model": "NF5688M7",
"SerialNumber": "23E100051",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Id": "1",
"Manufacturer": "Inspur",
"Model": "NF5688M7",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
},
"redfish_fetch_errors": []map[string]interface{}{
{
"path": "/redfish/v1/Chassis/1/Drives/FP00HDD00",
"error": `Get "...": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`,
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
found := false
for _, ev := range got.Events {
if ev.Source == "Redfish" &&
ev.EventType == "Collection Warning" &&
strings.Contains(strings.ToLower(ev.Description), "drive documents were unavailable") {
found = true
break
}
}
if !found {
t.Fatalf("expected collection warning event for drive fetch errors")
}
}
func TestReplayCollectGPUs_SkipsModelOnlyDuplicateFromGraphicsControllers(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/PCIeDevices/3"},
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/PCIeDevices/9"},
},
},
"/redfish/v1/Systems/1/PCIeDevices/3": map[string]interface{}{
"Id": "3",
"Name": "PCIeCard3",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654225094493",
},
"/redfish/v1/Systems/1/PCIeDevices/9": map[string]interface{}{
"Id": "9",
"Name": "PCIeCard9",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654425002635",
},
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU0"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU0": map[string]interface{}{
"Id": "GPU0",
"Name": "H200-SXM5-141G",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected 2 GPUs without generic duplicate, got %d", len(got))
}
for _, gpu := range got {
if gpu.Slot == "H200-SXM5-141G" {
t.Fatalf("unexpected model-only duplicate GPU row")
}
}
}
func TestReplayCollectGPUs_KeepsModelOnlyGraphicsDuplicateWhenDirectiveDisabled(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/4"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/9"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/4": map[string]interface{}{
"Id": "4",
"Name": "PCIeCard4",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654225094493",
},
"/redfish/v1/Chassis/1/PCIeDevices/9": map[string]interface{}{
"Id": "9",
"Name": "PCIeCard9",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654425002635",
},
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU0"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU0": map[string]interface{}{
"Id": "GPU0",
"Name": "H200-SXM5-141G",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{}))
if len(got) != 3 {
t.Fatalf("expected model-only graphics duplicate to remain when directive is off, got %d", len(got))
}
}
func TestApplyBoardInfoFallbackFromDocs_SkipsComponentProductNames(t *testing.T) {
board := models.BoardInfo{
SerialNumber: "23E100051",
}
docs := []map[string]interface{}{
{
"Model": "DDR5 DIMM",
"Manufacturer": "DELTA",
"SerialNumber": "802C1A2507D284B001",
},
{
"PlatformId": "NF5688M7",
"Manufacturer": "Inspur",
"PartNumber": "YZMB-00001",
},
}
applyBoardInfoFallbackFromDocs(&board, docs)
if board.ProductName != "NF5688M7" {
t.Fatalf("expected server model from fallback docs, got %q", board.ProductName)
}
if board.Manufacturer != "Inspur" {
t.Fatalf("expected manufacturer from server fallback doc, got %q", board.Manufacturer)
}
}
func TestDedupeStorage_IgnoresPlaceholderSerial(t *testing.T) {
in := []models.Storage{
{Slot: "OB01", Model: "N/A", SerialNumber: "N/A"},
{Slot: "OB02", Model: "N/A", SerialNumber: "N/A"},
{Slot: "OB03", Model: "N/A", SerialNumber: "N/A"},
{Slot: "OB04", Model: "N/A", SerialNumber: "N/A"},
}
out := dedupeStorage(in)
if len(out) != 4 {
t.Fatalf("expected all placeholder-serial NVMe drives to be kept by slot key, got %d", len(out))
}
}
func TestDedupeStorage_MergesPlaceholderSlotsWithRichDrivesByOrder(t *testing.T) {
in := []models.Storage{
{Slot: "PCIe8_RAID_Disk_1:0", Type: "SSD", Model: "SOLIDIGM SSDSC2K", SizeGB: 1787, SerialNumber: "S1", Present: true},
{Slot: "PCIe8_RAID_Disk_1:1", Type: "SSD", Model: "SOLIDIGM SSDSC2K", SizeGB: 1787, SerialNumber: "S2", Present: true},
{Slot: "PCIe8_RAID_Disk_1:2", Type: "SSD", Model: "SOLIDIGM SSDSC2K", SizeGB: 1787, SerialNumber: "S3", Present: true},
{Slot: "OB01", Type: "NVMe", Model: "N/A", SerialNumber: "N/A", Present: true},
{Slot: "OB02", Type: "NVMe", Model: "N/A", SerialNumber: "N/A", Present: true},
{Slot: "OB03", Type: "NVMe", Model: "N/A", SerialNumber: "N/A", Present: true},
{Slot: "OB04", Type: "NVMe", Model: "N/A", SerialNumber: "N/A", Present: true},
{Slot: "FP00HDD00", Type: "NVMe", Model: "INTEL SSDPE2KE032T8", SizeGB: 2980, SerialNumber: "N1", Present: true},
{Slot: "FP00HDD02", Type: "NVMe", Model: "INTEL SSDPE2KE032T8", SizeGB: 2980, SerialNumber: "N2", Present: true},
{Slot: "FP00HDD04", Type: "NVMe", Model: "INTEL SSDPE2KE032T8", SizeGB: 2980, SerialNumber: "N3", Present: true},
{Slot: "FP00HDD06", Type: "NVMe", Model: "INTEL SSDPE2KE032T8", SizeGB: 2980, SerialNumber: "N4", Present: true},
}
out := dedupeStorage(in)
if len(out) != 7 {
t.Fatalf("expected 7 rows after placeholder merge, got %d", len(out))
}
bySlot := make(map[string]models.Storage, len(out))
for _, d := range out {
bySlot[d.Slot] = d
if strings.HasPrefix(d.Slot, "FP00HDD") {
t.Fatalf("expected FP donor slot %q to be absorbed by placeholder slot", d.Slot)
}
}
if bySlot["OB01"].SerialNumber != "N1" || bySlot["OB02"].SerialNumber != "N2" || bySlot["OB03"].SerialNumber != "N3" || bySlot["OB04"].SerialNumber != "N4" {
t.Fatalf("expected OB slots to be enriched in order, got OB01=%q OB02=%q OB03=%q OB04=%q",
bySlot["OB01"].SerialNumber, bySlot["OB02"].SerialNumber, bySlot["OB03"].SerialNumber, bySlot["OB04"].SerialNumber)
}
if bySlot["OB01"].Model != "INTEL SSDPE2KE032T8" || bySlot["OB01"].SizeGB != 2980 {
t.Fatalf("expected OB01 to inherit rich model/size, got model=%q size=%d", bySlot["OB01"].Model, bySlot["OB01"].SizeGB)
}
}
func TestDedupeNetworkAdapters_MergesBySlotAndKeepsRicherData(t *testing.T) {
in := []models.NetworkAdapter{
{
Slot: "NIC-A",
Model: "N/A",
Vendor: "",
Present: true,
},
{
Slot: "NIC-A",
Model: "ConnectX-7",
Vendor: "NVIDIA",
SerialNumber: "NICSN001",
Firmware: "28.41.2020",
PortCount: 2,
MACAddresses: []string{"00:11:22:33:44:55"},
Present: true,
},
}
out := dedupeNetworkAdapters(in)
if len(out) != 1 {
t.Fatalf("expected merged single NIC row, got %d", len(out))
}
if out[0].SerialNumber != "NICSN001" || out[0].Model != "ConnectX-7" || out[0].Vendor != "NVIDIA" {
t.Fatalf("expected richer NIC fields preserved, got %+v", out[0])
}
}
func TestDedupePCIeDevices_MergesByLooseKeyAndKeepsBDF(t *testing.T) {
in := []models.PCIeDevice{
{
Slot: "PCIe Slot 3",
DeviceClass: "Network Controller",
PartNumber: "MCX75310AAS-NEAT",
},
{
Slot: "PCIe Slot 3",
DeviceClass: "Network Controller",
PartNumber: "MCX75310AAS-NEAT",
BDF: "0000:af:00.0",
VendorID: 0x15b3,
DeviceID: 0x1021,
SerialNumber: "MT000123",
},
}
out := dedupePCIeDevices(in)
if len(out) != 1 {
t.Fatalf("expected merged single PCIe row, got %d", len(out))
}
if out[0].BDF != "0000:af:00.0" || out[0].SerialNumber != "MT000123" || out[0].VendorID == 0 || out[0].DeviceID == 0 {
t.Fatalf("expected richer PCIe fields preserved, got %+v", out[0])
}
}
func TestAppendPSU_MergesRicherDuplicate(t *testing.T) {
var out []models.PSU
seen := make(map[string]int)
idx := 1
idx = appendPSU(&out, seen, models.PSU{
Slot: "PSU1",
Model: "N/A",
Present: true,
}, idx)
_ = appendPSU(&out, seen, models.PSU{
Slot: "PSU1",
Model: "DLG2700BW54C31",
SerialNumber: "DGPLV2515025L",
WattageW: 2700,
Firmware: "00.01.04",
Present: true,
}, idx)
if len(out) != 1 {
t.Fatalf("expected PSU duplicate merge, got %d rows", len(out))
}
if out[0].SerialNumber != "DGPLV2515025L" || out[0].WattageW != 2700 || out[0].Model != "DLG2700BW54C31" {
t.Fatalf("expected richer PSU fields preserved, got %+v", out[0])
}
}
func TestRedfishPSUNominalWattage_PrefersInputRangeOutputWattage(t *testing.T) {
doc := map[string]interface{}{
"PowerCapacityWatts": 22600,
"InputRanges": []interface{}{
map[string]interface{}{"OutputWattage": 2700},
map[string]interface{}{"OutputWattage": 3200},
},
}
if got := redfishPSUNominalWattage(doc); got != 3200 {
t.Fatalf("redfishPSUNominalWattage() = %d, want 3200", got)
}
}
func TestReplayCollectGPUs_DropsModelOnlyPlaceholderWhenConcreteDiscoveredLater(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU0"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU0": map[string]interface{}{
"Id": "GPU0",
"Name": "H200-SXM5-141G",
"Model": "H200-SXM5-141G",
},
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/4"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/4": map[string]interface{}{
"Id": "4",
"Name": "PCIeCard4",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"BDF": "0000:0f:00.0",
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 1 {
t.Fatalf("expected generic graphics placeholder to be dropped, got %d GPUs", len(got))
}
if got[0].Slot != "PCIeCard4" {
t.Fatalf("expected concrete PCIe GPU to remain, got slot=%q", got[0].Slot)
}
}
func TestReplayCollectGPUs_MergesGraphicsSerialIntoConcretePCIeGPU(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU4"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU4": map[string]interface{}{
"Id": "4",
"Name": "H100-PCIE-80G",
"Model": "H100-PCIE-80G",
"Manufacturer": "NVIDIA",
"Oem": map[string]interface{}{
"SerialNumber": "1794024010533",
},
},
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/8"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/8": map[string]interface{}{
"Id": "8",
"Name": "PCIeCard8",
"Model": "H100-PCIE-80G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
"BDF": "0000:b1:00.0",
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 1 {
t.Fatalf("expected merged single GPU row, got %d", len(got))
}
if got[0].Slot != "PCIeCard8" {
t.Fatalf("expected concrete PCIe slot, got %q", got[0].Slot)
}
if got[0].SerialNumber != "1794024010533" {
t.Fatalf("expected merged serial from graphics controller, got %q", got[0].SerialNumber)
}
}
func TestReplayCollectGPUs_MergesAmbiguousSameModelByOrder(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{},
},
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{},
},
}
pcieIDs := []int{4, 8, 12, 14, 20, 23, 26, 30}
serials := []string{
"1654425002361",
"1654425004310",
"1654425004204",
"1654225097289",
"1654225095717",
"1654425002114",
"1654425002714",
"1654425002991",
}
for i := 0; i < len(pcieIDs); i++ {
gpuPath := fmt.Sprintf("/redfish/v1/Systems/1/GraphicsControllers/GPU%d", i+1)
pciePath := fmt.Sprintf("/redfish/v1/Chassis/1/PCIeDevices/%d", pcieIDs[i])
tree["/redfish/v1/Systems/1/GraphicsControllers"].(map[string]interface{})["Members"] =
append(tree["/redfish/v1/Systems/1/GraphicsControllers"].(map[string]interface{})["Members"].([]interface{}), map[string]interface{}{"@odata.id": gpuPath})
tree["/redfish/v1/Chassis/1/PCIeDevices"].(map[string]interface{})["Members"] =
append(tree["/redfish/v1/Chassis/1/PCIeDevices"].(map[string]interface{})["Members"].([]interface{}), map[string]interface{}{"@odata.id": pciePath})
tree[gpuPath] = map[string]interface{}{
"Id": fmt.Sprintf("GPU%d", i+1),
"Name": "H200-SXM5-141G",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": serials[i],
}
tree[pciePath] = map[string]interface{}{
"Id": fmt.Sprintf("%d", pcieIDs[i]),
"Name": fmt.Sprintf("PCIeCard%d", pcieIDs[i]),
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"BDF": fmt.Sprintf("0000:%02x:00.0", i+1),
}
}
r := redfishSnapshotReader{tree: tree}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != len(pcieIDs) {
t.Fatalf("expected %d merged GPUs, got %d", len(pcieIDs), len(got))
}
bySlot := make(map[string]models.GPU, len(got))
for _, gpu := range got {
bySlot[gpu.Slot] = gpu
if strings.EqualFold(strings.TrimSpace(gpu.Slot), strings.TrimSpace(gpu.Model)) {
t.Fatalf("expected model-only placeholder to be dropped, got slot=%q", gpu.Slot)
}
}
for i, id := range pcieIDs {
slot := fmt.Sprintf("PCIeCard%d", id)
gpu, ok := bySlot[slot]
if !ok {
t.Fatalf("expected concrete slot %q in output", slot)
}
if gpu.SerialNumber != serials[i] {
t.Fatalf("expected slot %s serial %s, got %s", slot, serials[i], gpu.SerialNumber)
}
}
}
// TestCollectGPUsFromProcessors_SupermicroHGX verifies that GPU-type Processor
// entries (Supermicro HGX: HGX_Baseboard_0/Processors/GPU_SXM_N) are not added
// as duplicates when the same GPU is already present via Chassis PCIeDevices.
// The processor doc carries SerialNumber directly; the chassis ID ("HGX_GPU_SXM_1")
// does NOT match the processor Id ("GPU_SXM_1"), so chassis-based serial lookup
// fails and the dedup must fall back to the processor doc's own SerialNumber.
func TestCollectGPUsFromProcessors_SupermicroHGX(t *testing.T) {
tree := map[string]interface{}{
// Main chassis PCIeDevices — GPU1 and GPU2 with serials.
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU2"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1": map[string]interface{}{
"Id": "GPU1",
"Name": "GPU1",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN001",
"FirmwareVersion": "96.00.D9.00.02",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1": map[string]interface{}{
"FunctionId": "1",
"ClassCode": "0x030200",
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU2": map[string]interface{}{
"Id": "GPU2",
"Name": "GPU2",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN002",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU2/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU2/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU2/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU2/PCIeFunctions/1": map[string]interface{}{
"FunctionId": "2",
"ClassCode": "0x030200",
},
// HGX GPU chassis — named HGX_GPU_SXM_N (NOT GPU_SXM_N), so chassis-ID lookup
// by processor Id "GPU_SXM_1" will NOT find them.
"/redfish/v1/Chassis/HGX_GPU_SXM_1": map[string]interface{}{
"Id": "HGX_GPU_SXM_1",
},
"/redfish/v1/Chassis/HGX_GPU_SXM_2": map[string]interface{}{
"Id": "HGX_GPU_SXM_2",
},
// HGX Baseboard system with GPU-type Processors carrying the same serials.
"/redfish/v1/Systems/HGX_Baseboard_0/Processors": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1"},
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_2"},
},
},
"/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1": map[string]interface{}{
"Id": "GPU_SXM_1",
"Name": "Processor",
"ProcessorType": "GPU",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN001",
"UUID": "aaaaaaaa-0000-0000-0000-000000000001",
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"ServiceLabel": "SXM1",
},
},
},
"/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_2": map[string]interface{}{
"Id": "GPU_SXM_2",
"Name": "Processor",
"ProcessorType": "GPU",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN002",
"UUID": "aaaaaaaa-0000-0000-0000-000000000002",
"Location": map[string]interface{}{
"PartLocation": map[string]interface{}{
"ServiceLabel": "SXM2",
},
},
},
}
r := redfishSnapshotReader{tree: tree}
chassisPaths := []string{
"/redfish/v1/Chassis/1",
"/redfish/v1/Chassis/HGX_GPU_SXM_1",
"/redfish/v1/Chassis/HGX_GPU_SXM_2",
}
systemPaths := []string{"/redfish/v1/Systems/HGX_Baseboard_0"}
gpus := r.collectGPUs(systemPaths, chassisPaths, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
gpus = r.collectGPUsFromProcessors(systemPaths, chassisPaths, gpus, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableProcessorGPUFallback: true}))
if len(gpus) != 2 {
var slots []string
for _, g := range gpus {
slots = append(slots, fmt.Sprintf("%s(sn=%s)", g.Slot, g.SerialNumber))
}
t.Fatalf("expected 2 GPUs (no duplicates), got %d: %v", len(gpus), slots)
}
}
func TestCollectGPUsFromProcessors_SupermicroHGXUsesChassisAliasSerial(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1": map[string]interface{}{
"Id": "GPU1",
"Name": "GPU1",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN-ALIAS-001",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1": map[string]interface{}{
"FunctionId": "1",
"ClassCode": "0x030200",
},
"/redfish/v1/Chassis/HGX_GPU_SXM_1": map[string]interface{}{
"Id": "HGX_GPU_SXM_1",
"SerialNumber": "SN-ALIAS-001",
},
"/redfish/v1/Systems/HGX_Baseboard_0/Processors": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1"},
},
},
"/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1": map[string]interface{}{
"Id": "GPU_SXM_1",
"Name": "Processor",
"ProcessorType": "GPU",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
},
}
r := redfishSnapshotReader{tree: tree}
chassisPaths := []string{
"/redfish/v1/Chassis/1",
"/redfish/v1/Chassis/HGX_GPU_SXM_1",
}
systemPaths := []string{"/redfish/v1/Systems/HGX_Baseboard_0"}
gpus := r.collectGPUs(systemPaths, chassisPaths, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
gpus = r.collectGPUsFromProcessors(systemPaths, chassisPaths, gpus, redfishprofile.ResolvedAnalysisPlan{
Directives: redfishprofile.AnalysisDirectives{EnableProcessorGPUFallback: true, EnableProcessorGPUChassisAlias: true},
ProcessorGPUChassisLookupModes: []string{"hgx-alias"},
})
if len(gpus) != 1 {
t.Fatalf("expected alias serial dedupe to keep 1 gpu, got %d", len(gpus))
}
if gpus[0].SerialNumber != "SN-ALIAS-001" {
t.Fatalf("expected serial from aliased chassis, got %q", gpus[0].SerialNumber)
}
}
func TestCollectGPUsFromProcessors_MSIUsesIndexedChassisLookup(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/GPU1": map[string]interface{}{
"Id": "GPU1",
"SerialNumber": "MSI-SN-001",
},
"/redfish/v1/Systems/1/Processors": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Processors/GPU_SXM_1"},
},
},
"/redfish/v1/Systems/1/Processors/GPU_SXM_1": map[string]interface{}{
"Id": "GPU_SXM_1",
"Name": "Processor",
"ProcessorType": "GPU",
"Model": "NVIDIA RTX PRO 6000 Blackwell",
"Manufacturer": "NVIDIA",
},
}
r := redfishSnapshotReader{tree: tree}
gpus := r.collectGPUsFromProcessors(
[]string{"/redfish/v1/Systems/1"},
[]string{"/redfish/v1/Chassis/GPU1"},
nil,
redfishprofile.ResolvedAnalysisPlan{
Directives: redfishprofile.AnalysisDirectives{EnableProcessorGPUFallback: true, EnableMSIProcessorGPUChassisLookup: true},
ProcessorGPUChassisLookupModes: []string{"msi-index"},
},
)
if len(gpus) != 1 {
t.Fatalf("expected one gpu, got %d", len(gpus))
}
if gpus[0].SerialNumber != "MSI-SN-001" {
t.Fatalf("expected serial from MSI indexed chassis lookup, got %q", gpus[0].SerialNumber)
}
}
// TestReplayCollectGPUs_DedupCrossChassisSerial verifies that the same GPU
// appearing under two Chassis PCIeDevice trees (e.g. Chassis/1/PCIeDevices/GPU1
// and Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1) is deduplicated to one entry
// when both expose the same serial number.
func TestReplayCollectGPUs_DedupCrossChassisSerial(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1",
"Id": "GPU1",
"Name": "GPU1",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN-CROSSTEST-001",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1": map[string]interface{}{
"FunctionId": "1",
"ClassCode": "0x030200",
},
// Same GPU exposed via dedicated HGX chassis — same serial, different path.
"/redfish/v1/Chassis/HGX_GPU_SXM_1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1"},
},
},
"/redfish/v1/Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1",
"Id": "GPU_SXM_1",
"Name": "PCIe Device",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN-CROSSTEST-001",
"UUID": "deadbeef-0000-0000-0000-000000000001",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1/PCIeFunctions",
},
},
"/redfish/v1/Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{},
},
}
r := redfishSnapshotReader{tree: tree}
got := r.collectGPUs(nil, []string{
"/redfish/v1/Chassis/1",
"/redfish/v1/Chassis/HGX_GPU_SXM_1",
}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 1 {
var slots []string
for _, g := range got {
slots = append(slots, fmt.Sprintf("%s(sn=%s)", g.Slot, g.SerialNumber))
}
t.Fatalf("expected 1 GPU (cross-chassis serial dedup), got %d: %v", len(got), slots)
}
if got[0].SerialNumber != "SN-CROSSTEST-001" {
t.Fatalf("unexpected serial %q", got[0].SerialNumber)
}
}
// TestLooksLikeGPU_NVSwitchExcluded verifies that NVSwitch PCIe devices
// are not classified as GPUs even though their manufacturer is NVIDIA.
func TestLooksLikeGPU_NVSwitchExcluded(t *testing.T) {
doc := map[string]interface{}{
"Id": "NVSwitch_0",
"Name": "PCIe Device",
"Model": "NVSwitch",
"Manufacturer": "NVIDIA",
"DeviceType": "SingleFunction",
}
if looksLikeGPU(doc, nil) {
t.Fatal("NVSwitch should not be classified as a GPU")
}
}
func TestFirmwareInventoryDeviceName_PrefersIDForGenericSoftwareInventory(t *testing.T) {
doc := map[string]interface{}{
"Id": "HGX_FW_NVSwitch_0",
"Name": "Software Inventory",
"Version": "96.10.73.00.01",
}
got := firmwareInventoryDeviceName(doc)
if got != "HGX_FW_NVSwitch_0" {
t.Fatalf("expected firmware inventory id to be used, got %q", got)
}
}
func TestParsePCIeDeviceWithSupplementalDocs_NVSwitchThermalMetrics(t *testing.T) {
doc := map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/HGX_NVSwitch_0/PCIeDevices/NVSwitch_0",
"Id": "NVSwitch_0",
"Model": "NVSwitch",
"Manufacturer": "NVIDIA",
"DeviceType": "SingleFunction",
}
supplementalDocs := []map[string]interface{}{
{
"TemperatureReadingsCelsius": []interface{}{
map[string]interface{}{
"DeviceName": "NVSwitch_0",
"Reading": "31.593750",
},
},
},
}
got := parsePCIeDeviceWithSupplementalDocs(doc, nil, supplementalDocs)
if got.Details == nil {
t.Fatalf("expected NVSwitch details to be populated")
}
if temp := got.Details["temperature_c"]; temp != 31.59375 {
t.Fatalf("expected NVSwitch thermal metric, got %#v", got.Details)
}
}
func TestShouldCrawlPath_MemoryAndProcessorMetricsAreAllowed(t *testing.T) {
if !shouldCrawlPath("/redfish/v1/Systems/1/Memory/CPU0_C0D0") {
t.Fatalf("expected direct DIMM resource to be crawlable")
}
if shouldCrawlPath("/redfish/v1/Systems/1/Memory/CPU0_C0D0/Assembly") {
t.Fatalf("expected DIMM assembly subresource to be skipped")
}
if !shouldCrawlPath("/redfish/v1/Systems/1/Memory/CPU0_C0D0/MemoryMetrics") {
t.Fatalf("expected DIMM metrics subresource to be crawlable")
}
if !shouldCrawlPath("/redfish/v1/Systems/1/Processors/CPU0/ProcessorMetrics") {
t.Fatalf("expected CPU metrics subresource to be crawlable")
}
if shouldCrawlPath("/redfish/v1/Chassis/1/PCIeDevices/0/PCIeFunctions") {
t.Fatalf("expected broad chassis PCIeFunctions collection to be skipped")
}
if !shouldCrawlPath("/redfish/v1/Chassis/1/PCIeDevices/0/PCIeFunctions/1") {
t.Fatalf("expected direct chassis PCIeFunction member to remain crawlable")
}
if !shouldCrawlPath("/redfish/v1/Fabrics/HGX_NVLinkFabric_0/Switches/NVSwitch_0") {
t.Fatalf("expected NVSwitch fabric resource to be crawlable")
}
if !shouldCrawlPath("/redfish/v1/Fabrics/HGX_NVLinkFabric_0/Switches/NVSwitch_0/Ports/NVLink_0/Metrics") {
t.Fatalf("expected NVLink port metrics to be crawlable")
}
}
func TestIsRedfishMemoryMemberPath(t *testing.T) {
cases := []struct {
path string
want bool
}{
{path: "/redfish/v1/Systems/1/Memory", want: false},
{path: "/redfish/v1/Systems/1/Memory/CPU0_C0D0", want: true},
{path: "/redfish/v1/Systems/1/Memory/CPU0_C0D0/Assembly", want: false},
{path: "/redfish/v1/Systems/1/Memory/CPU0_C0D0/MemoryMetrics", want: false},
{path: "/redfish/v1/Chassis/1/Memory/CPU0_C0D0", want: false},
}
for _, tc := range cases {
got := isRedfishMemoryMemberPath(tc.path)
if got != tc.want {
t.Fatalf("isRedfishMemoryMemberPath(%q) = %v, want %v", tc.path, got, tc.want)
}
}
}
func TestRedfishSnapshotBranchKey(t *testing.T) {
cases := []struct {
path string
want string
}{
{path: "", want: ""},
{path: "/redfish/v1", want: ""},
{path: "/redfish/v1/Systems", want: "/redfish/v1/Systems"},
{path: "/redfish/v1/Systems/1", want: "/redfish/v1/Systems/1"},
{path: "/redfish/v1/Systems/1/Memory", want: "/redfish/v1/Systems/1/Memory"},
{path: "/redfish/v1/Systems/1/Memory/CPU0_C0D0", want: "/redfish/v1/Systems/1/Memory"},
{path: "/redfish/v1/Systems/1/PCIeDevices/GPU1", want: "/redfish/v1/Systems/1/PCIeDevices"},
{path: "/redfish/v1/Chassis/1/Sensors/1", want: "/redfish/v1/Chassis/1/Sensors"},
{path: "/redfish/v1/UpdateService/FirmwareInventory/BIOS", want: "/redfish/v1/UpdateService/FirmwareInventory"},
}
for _, tc := range cases {
got := redfishSnapshotBranchKey(tc.path)
if got != tc.want {
t.Fatalf("redfishSnapshotBranchKey(%q) = %q, want %q", tc.path, got, tc.want)
}
}
}
func TestShouldPostProbeCollectionPath(t *testing.T) {
var tuning redfishprofile.AcquisitionTuning
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Sensors", tuning) {
t.Fatalf("expected sensors collection to be skipped by default")
}
if shouldPostProbeCollectionPath("/redfish/v1/Systems/1/Storage/RAID/Drives", tuning) {
t.Fatalf("expected drives collection to be skipped without profile policy")
}
tuning.PostProbePolicy.EnableNumericCollectionProbe = true
t.Setenv("LOGPILE_REDFISH_SENSOR_POSTPROBE", "1")
if !shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Sensors", tuning) {
t.Fatalf("expected sensors collection to be post-probed when enabled")
}
if !shouldPostProbeCollectionPath("/redfish/v1/Systems/1/Storage/RAID/Drives", tuning) {
t.Fatalf("expected drives collection to be post-probed")
}
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Boards/BOARD1", tuning) {
t.Fatalf("expected board member resource to be skipped from post-probe")
}
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Assembly/Oem/COMMONb/COMMONbAssembly/1", tuning) {
t.Fatalf("expected assembly member resource to be skipped from post-probe")
}
}
func TestShouldAdaptivePostProbeCollectionPath(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PostProbePolicy: redfishprofile.AcquisitionPostProbePolicy{
EnableNumericCollectionProbe: true,
},
}
withExplicitNamedMembers := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/EthernetInterfaces/NIC-0-0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/EthernetInterfaces/NIC-0-1"},
},
}
if shouldAdaptivePostProbeCollectionPath("/redfish/v1/Systems/1/EthernetInterfaces", withExplicitNamedMembers, tuning) {
t.Fatalf("expected explicit non-numeric members to skip adaptive post-probe")
}
withNumericMembers := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/1"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/2"},
},
}
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/PCIeDevices", withNumericMembers, tuning) {
t.Fatalf("expected numeric members to allow adaptive post-probe")
}
withoutMembers := map[string]interface{}{"Name": "Drives"}
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/Drives", withoutMembers, tuning) {
t.Fatalf("expected missing members to allow adaptive post-probe")
}
if shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/Drives", withoutMembers, redfishprofile.AcquisitionTuning{}) {
t.Fatalf("expected post-probe to stay disabled without profile policy")
}
}
func TestShouldAdaptiveNVMeProbe(t *testing.T) {
withMembers := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Drives/OB01"},
},
}
if shouldAdaptiveNVMeProbe(withMembers) {
t.Fatalf("expected drives collection with explicit members to skip NVMe probe")
}
withoutMembers := map[string]interface{}{"Name": "Drives"}
if !shouldAdaptiveNVMeProbe(withoutMembers) {
t.Fatalf("expected drives collection without members to allow NVMe probe")
}
}
func TestRedfishAdaptivePrefetchTargets(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PrefetchPolicy: redfishprofile.AcquisitionPrefetchPolicy{
IncludeSuffixes: []string{
"/Memory",
"/Processors",
"/Storage",
},
},
}
candidates := []string{
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Processors",
"/redfish/v1/Systems/1/Storage",
}
rawTree := map[string]interface{}{
"/redfish/v1/Systems/1/Memory": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Memory/DIMM1"},
},
},
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/1"},
},
},
}
fetchErrs := map[string]string{
"/redfish/v1/Systems/1/Memory/DIMM1": "Get \"https://bmc/redfish/v1/Systems/1/Memory/DIMM1\": context deadline exceeded",
"/redfish/v1/Systems/1/Storage/1": "status 404 from /redfish/v1/Systems/1/Storage/1: not found",
"/redfish/v1/Systems/1/Processors": "Get \"https://bmc/redfish/v1/Systems/1/Processors\": context deadline exceeded",
"/redfish/v1/Systems/1/Storage/Volumes": "status 404 from /redfish/v1/Systems/1/Storage/Volumes: not found",
}
got := redfishAdaptivePrefetchTargets(redfishPrefetchTargets(candidates, tuning), rawTree, fetchErrs)
joined := strings.Join(got, "\n")
for _, wanted := range []string{
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Processors",
} {
if !strings.Contains(joined, wanted) {
t.Fatalf("expected adaptive prefetch target %q", wanted)
}
}
if strings.Contains(joined, "/redfish/v1/Systems/1/Storage") {
t.Fatalf("expected storage with only non-retryable missing members to be skipped")
}
}
func TestResolveAcquisitionPlan_DefaultSkipsNoisyBranches(t *testing.T) {
signals := redfishprofile.MatchSignals{}
match := redfishprofile.MatchProfiles(signals)
plan := redfishprofile.BuildAcquisitionPlan(signals)
resolved := redfishprofile.ResolveAcquisitionPlan(match, plan, redfishprofile.DiscoveredResources{
SystemPaths: []string{"/redfish/v1/Systems/1"},
ChassisPaths: []string{"/redfish/v1/Chassis/1"},
ManagerPaths: []string{"/redfish/v1/Managers/1"},
}, signals)
seeds := resolved.SeedPaths
joined := strings.Join(seeds, "\n")
for _, noisy := range []string{
"/redfish/v1/Fabrics",
"/redfish/v1/Chassis/1/Backplanes",
"/redfish/v1/Chassis/1/Boards",
"/redfish/v1/Chassis/1/Sensors",
"/redfish/v1/Managers/1/LogServices",
} {
if strings.Contains(joined, noisy) {
t.Fatalf("unexpected noisy seed %q", noisy)
}
}
for _, wanted := range []string{
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/PCIeDevices",
"/redfish/v1/Chassis/1/Drives",
"/redfish/v1/Chassis/1/NetworkAdapters",
"/redfish/v1/Managers/1/NetworkProtocol",
} {
if !strings.Contains(joined, wanted) {
t.Fatalf("expected seed %q", wanted)
}
}
}
func TestShouldPrefetchCriticalPath_UsesPrefetchPolicy(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PrefetchPolicy: redfishprofile.AcquisitionPrefetchPolicy{
IncludeSuffixes: []string{"/Storage", "/Oem/Public"},
ExcludeContains: []string{"/Assembly"},
},
}
if !shouldPrefetchCriticalPath("/redfish/v1/Systems/1/Storage", tuning) {
t.Fatal("expected storage path to be prefetched when included by policy")
}
if !shouldPrefetchCriticalPath("/redfish/v1/Systems/1/Oem/Public", tuning) {
t.Fatal("expected OEM public path to be prefetched when included by policy")
}
if shouldPrefetchCriticalPath("/redfish/v1/Chassis/1/Assembly", tuning) {
t.Fatal("expected excluded path to skip prefetch")
}
if shouldPrefetchCriticalPath("/redfish/v1/Chassis/1/Power", redfishprofile.AcquisitionTuning{}) {
t.Fatal("expected empty prefetch policy to disable suffix-based prefetch")
}
}
func TestRedfishPrefetchTargets_FilterNoisyBranches(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PrefetchPolicy: redfishprofile.AcquisitionPrefetchPolicy{
IncludeSuffixes: []string{
"/Memory",
"/Oem/Public/FRU",
"/Drives",
"/NetworkProtocol",
},
ExcludeContains: []string{
"/Backplanes",
"/Sensors",
"/LogServices",
},
},
}
critical := []string{
"/redfish/v1/Systems/1",
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Oem/Public/FRU",
"/redfish/v1/Chassis/1/Drives",
"/redfish/v1/Chassis/1/Backplanes",
"/redfish/v1/Chassis/1/Sensors",
"/redfish/v1/Managers/1/LogServices",
"/redfish/v1/Managers/1/NetworkProtocol",
}
got := redfishPrefetchTargets(critical, tuning)
joined := strings.Join(got, "\n")
for _, wanted := range []string{
"/redfish/v1/Systems/1",
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Oem/Public/FRU",
"/redfish/v1/Chassis/1/Drives",
"/redfish/v1/Managers/1/NetworkProtocol",
} {
if !strings.Contains(joined, wanted) {
t.Fatalf("expected prefetch target %q", wanted)
}
}
for _, noisy := range []string{
"/redfish/v1/Chassis/1/Backplanes",
"/redfish/v1/Chassis/1/Sensors",
"/redfish/v1/Managers/1/LogServices",
} {
if strings.Contains(joined, noisy) {
t.Fatalf("unexpected noisy prefetch target %q", noisy)
}
}
}
// TestChassisTypeCanHaveNVMe verifies that non-storage chassis types (GPU modules,
// RoT components, fabric zones) are excluded from NVMe bay probing, while storage
// and unclassified chassis types are kept.
//
// Regression guard: on Supermicro HGX (SYS-A21GE-NBRT) all 35 sub-chassis (GPUs,
// NVSwitches, PCIeRetimers, ERoT/IRoT, BMC, FPGA) have ChassisType=Module/Component/Zone
// and expose empty /Drives collections. Without this filter each chassis triggered
// 384 HTTP requests → ~22 minutes wasted per collection. (2026-03-12)
func TestChassisTypeCanHaveNVMe(t *testing.T) {
cases := []struct {
chassisType string
want bool
}{
// Non-storage sub-module types — must return false
{"Module", false}, // GPU SXM, PCIeRetimer, NVLinkManagementNIC
{"module", false}, // case-insensitive
{"Component", false}, // ERoT, IRoT, BMC, FPGA sub-chassis
{"component", false},
{"Zone", false}, // HGX_Chassis_0 fabric zone
{"zone", false},
// Storage-capable and generic types — must return true
{"Enclosure", true}, // NVMe StorageBackplane
{"RackMount", true}, // main server chassis
{"Blade", true}, // blade server chassis
{"StandAlone", true}, // standalone server
{"", true}, // unknown type — probe to be safe
}
for _, tc := range cases {
got := chassisTypeCanHaveNVMe(tc.chassisType)
if got != tc.want {
t.Errorf("chassisTypeCanHaveNVMe(%q) = %v, want %v", tc.chassisType, got, tc.want)
}
}
}
// TestNVMePostProbeSkipsNonStorageChassis verifies that the NVMe bay probe candidate
// selection skips chassis whose ChassisType indicates they cannot hold NVMe drives.
//
// Simulates an HGX topology: one GPU chassis (Module) and one NVMe backplane
// (Enclosure), both with empty /Drives collections. Only the backplane must be
// selected as a probe candidate.
func TestNVMePostProbeSkipsNonStorageChassis(t *testing.T) {
// Build the out map as collectRawRedfishTree would produce it
out := map[string]interface{}{
// GPU chassis — Module type, empty Drives: should be skipped
"/redfish/v1/Chassis/HGX_GPU_SXM_1": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/HGX_GPU_SXM_1",
"ChassisType": "Module",
"Name": "HGX_GPU_SXM_1",
},
"/redfish/v1/Chassis/HGX_GPU_SXM_1/Drives": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/HGX_GPU_SXM_1/Drives",
"Members": []interface{}{},
"Members@odata.count": 0,
},
// NVMe backplane — Enclosure type, empty Drives: must be selected
"/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane",
"ChassisType": "Enclosure",
"Name": "Backplane",
},
"/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane/Drives": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/NVMeSSD.0.Group.0.StorageBackplane/Drives",
"Members": []interface{}{},
"Members@odata.count": 0,
},
}
// Replicate the candidate selection logic from collectRawRedfishTree
var selected []string
for path, docAny := range out {
normalized := normalizeRedfishPath(path)
if !strings.HasSuffix(normalized, "/Drives") {
continue
}
doc, _ := docAny.(map[string]interface{})
if !shouldAdaptiveNVMeProbe(doc) {
continue
}
chassisPath := strings.TrimSuffix(normalized, "/Drives")
if chassisDocAny, ok := out[chassisPath]; ok {
if chassisDoc, ok := chassisDocAny.(map[string]interface{}); ok {
if !chassisTypeCanHaveNVMe(asString(chassisDoc["ChassisType"])) {
continue
}
}
}
selected = append(selected, normalized)
}
if len(selected) != 1 {
t.Fatalf("expected 1 NVMe probe candidate (backplane), got %d: %v", len(selected), selected)
}
if !strings.Contains(selected[0], "StorageBackplane") {
t.Fatalf("expected StorageBackplane to be selected, got %q", selected[0])
}
}
func TestIsVirtualStorageDrive_AMIVirtualMedia(t *testing.T) {
doc := map[string]interface{}{
"Id": "USB_Device1_Port4",
"Name": "Virtual Cdrom Device",
"Model": "Virtual Cdrom Device",
"Manufacturer": "American Megatrends Inc.",
"Protocol": "USB",
"CapacityBytes": 0,
"SerialNumber": "AAAABBBBCCCC1",
}
if !isVirtualStorageDrive(doc) {
t.Fatalf("expected AMI virtual media to be filtered")
}
}