package inspur import ( "strings" "testing" "git.mchus.pro/mchus/logpile/internal/models" ) func TestParsePCIeDevices_UsesDeviceNameAsModelWhenPartNumberMissing(t *testing.T) { content := []byte(`RESTful PCIE Device info: [{"id":1,"present":1,"vendor_id":32902,"vendor_name":"Intel","device_id":5409,"device_name":"I350T4V2","bus_num":69,"dev_num":0,"func_num":0,"max_link_width":4,"max_link_speed":2,"current_link_width":4,"current_link_speed":2,"location":"#CPU0_PCIE4","dev_type":2,"dev_subtype":0,"part_num":"","serial_num":"","fw_ver":""}] BMC sdr Info:`) devices := ParsePCIeDevices(content) if len(devices) != 1 { t.Fatalf("expected 1 device, got %d", len(devices)) } if devices[0].PartNumber != "I350T4V2" { t.Fatalf("expected part/model I350T4V2, got %q", devices[0].PartNumber) } if devices[0].BDF != "0000:45:00.0" || devices[0].Slot != devices[0].BDF { t.Fatalf("expected canonical BDF slot 0000:45:00.0, got slot=%q bdf=%q", devices[0].Slot, devices[0].BDF) } if devices[0].NUMANode == nil || *devices[0].NUMANode != 0 { t.Fatalf("expected CPU affinity 0, got %v", devices[0].NUMANode) } } func TestParsePCIeDevices_ReadsAffinityFromCombinedComponentLog(t *testing.T) { content := []byte(`RESTful PCIE Device info: [{"id":3,"present":1,"vendor_id":5555,"vendor_name":"NVIDIA","device_id":4125,"device_name":"MCX623106AN-CDAT","bus_num":177,"dev_num":0,"func_num":0,"max_link_width":16,"max_link_speed":4,"current_link_width":16,"current_link_speed":4,"location":"Riser 3 Slot 1","DeviceLocator":"CPU1_PE1_PCIE1","dev_type":2,"dev_subtype":0}] RESTful Network Adapter info: {"sys_adapters":[]}`) devices := ParsePCIeDevices(content) if len(devices) != 1 { t.Fatalf("expected 1 device, got %d", len(devices)) } if devices[0].NUMANode == nil || *devices[0].NUMANode != 1 { t.Fatalf("expected CPU affinity 1 from DeviceLocator, got %v", devices[0].NUMANode) } } func TestParseInspurCPUAffinity_UnknownRemainsNil(t *testing.T) { for _, location := range []string{"", "N/A", "Riser 2 Slot 1", "SCPU1_SLOT"} { if got := parseInspurCPUAffinity(location); got != nil { t.Fatalf("parseInspurCPUAffinity(%q) = %v, want nil", location, got) } } } func TestMergePCIeDevices_EnrichesGenericAssetEntry(t *testing.T) { base := []models.PCIeDevice{ { Slot: "#CPU1_PCIE9", BDF: "98:00.0", VendorID: 0x9005, DeviceID: 0x028f, DeviceClass: "SAS", Manufacturer: "Adaptec / Microsemi", }, } rest := []models.PCIeDevice{ { Slot: "#CPU1_PCIE9", BDF: "98:00.0", VendorID: 0x9005, DeviceID: 0x028f, DeviceClass: "Storage Controller", Manufacturer: "Microchip", PartNumber: "PM8222-SHBA", }, } got := MergePCIeDevices(base, rest) if len(got) != 1 { t.Fatalf("expected 1 merged device, got %d", len(got)) } if got[0].PartNumber != "PM8222-SHBA" { t.Fatalf("expected merged part number PM8222-SHBA, got %q", got[0].PartNumber) } } func TestMergePCIeDevices_EnrichesNUMAAffinity(t *testing.T) { node := 1 got := MergePCIeDevices( []models.PCIeDevice{{BDF: "98:00.0"}}, []models.PCIeDevice{{BDF: "98:00.0", NUMANode: &node}}, ) if len(got) != 1 || got[0].NUMANode == nil || *got[0].NUMANode != 1 { t.Fatalf("expected merged NUMA affinity 1, got %#v", got) } } func TestParsePCIeDevices_ResolvesModelFromPCIIDsWhenDeviceNameIsRawHex(t *testing.T) { content := []byte(`RESTful PCIE Device info: [{"id":5,"present":1,"vendor_id":36869,"vendor_name":"","device_id":655,"device_name":"0x028F","bus_num":152,"dev_num":0,"func_num":0,"max_link_width":8,"max_link_speed":3,"current_link_width":8,"current_link_speed":3,"location":"#CPU1_PCIE9","dev_type":1,"dev_subtype":7,"part_num":"","serial_num":"","fw_ver":""}] BMC sdr Info:`) devices := ParsePCIeDevices(content) if len(devices) != 1 { t.Fatalf("expected 1 device, got %d", len(devices)) } if devices[0].PartNumber == "" { t.Fatalf("expected part number resolved from pci.ids, got empty") } if strings.HasPrefix(strings.ToLower(strings.TrimSpace(devices[0].PartNumber)), "0x") { t.Fatalf("expected resolved name instead of raw hex, got %q", devices[0].PartNumber) } if devices[0].Manufacturer == "" { t.Fatalf("expected manufacturer resolved from pci.ids") } }