feat(hpe): improve inventory extraction and export fidelity

This commit is contained in:
Mikhail Chusavitin
2026-03-30 15:04:17 +03:00
parent d8c3256e41
commit c47c34fd11
12 changed files with 989 additions and 59 deletions
+117
View File
@@ -1316,6 +1316,23 @@ func TestParsePCIeDevice_PrefersFunctionClassOverDeviceType(t *testing.T) {
}
}
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",
@@ -2160,6 +2177,94 @@ func TestReplayCollectStorage_UsesKnownControllerRecoveryWhenEnabled(t *testing.
}
}
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{}{
@@ -2240,6 +2345,18 @@ func TestParseBoardInfo_NormalizesNullPlaceholders(t *testing.T) {
}
}
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")