package h3c import ( "strings" "testing" "git.mchus.pro/mchus/logpile/internal/models" "git.mchus.pro/mchus/logpile/internal/parser" ) func TestDetectH3C_GenerationRouting(t *testing.T) { g5 := &G5Parser{} g6 := &G6Parser{} g5Files := []parser.ExtractedFile{ {Path: "bmc/pack.info", Content: []byte("STARTTIME:0")}, {Path: "static/FRUInfo.ini", Content: []byte("[Baseboard]\nBoard Manufacturer=H3C\n")}, {Path: "static/hardware_info.ini", Content: []byte("[Processors: Processor 1]\nModel: Intel Xeon\n")}, {Path: "static/hardware.info", Content: []byte("[Disk_0_Front_NA]\nSerialNumber=DISK-0\n")}, {Path: "static/firmware_version.ini", Content: []byte("[System board]\nBIOS Version: 5.59\n")}, {Path: "user/test1.csv", Content: []byte("Record Time Stamp,DescInfo\n2025-01-01 00:00:00,foo\n")}, } if gotG5, gotG6 := g5.Detect(g5Files), g6.Detect(g5Files); gotG5 <= gotG6 { t.Fatalf("expected G5 confidence > G6 for G5 sample, got g5=%d g6=%d", gotG5, gotG6) } g6Files := []parser.ExtractedFile{ {Path: "bmc/pack.info", Content: []byte("STARTTIME:0")}, {Path: "static/FRUInfo.ini", Content: []byte("[Baseboard]\nBoard Manufacturer=H3C\n")}, {Path: "static/board_info.ini", Content: []byte("[System board]\nBoardMfr=H3C\n")}, {Path: "static/firmware_version.json", Content: []byte(`{"BIOS":{"Firmware Name":"BIOS","Firmware Version":"6.10"}}`)}, {Path: "static/CPUDetailInfo.xml", Content: []byte("X")}, {Path: "static/MemoryDetailInfo.xml", Content: []byte("A0")}, {Path: "user/Sel.json", Content: []byte(`{"Id":1}`)}, } if gotG5, gotG6 := g5.Detect(g6Files), g6.Detect(g6Files); gotG6 <= gotG5 { t.Fatalf("expected G6 confidence > G5 for G6 sample, got g5=%d g6=%d", gotG5, gotG6) } } func TestParseH3CG6_RaidAndNVMeEnrichment(t *testing.T) { p := &G6Parser{} files := []parser.ExtractedFile{ { Path: "static/storage_disk.ini", Content: []byte(`[Disk_000] DiskSlotDesc=Front0 Present=YES SerialNumber=SER-0 `), }, { Path: "static/raid.json", Content: []byte(`{ "RaidConfig": { "CtrlInfo": [ { "CtrlSlot": 1, "CtrlName": "RAID-LSI-9560", "LDInfo": [ { "LDID": "0", "LDName": "VD0", "RAIDLevel": "1", "CapacityBytes": 1000000000, "Status": "Optimal" } ] } ] } }`), }, { Path: "static/Storage_RAID-LSI-9560-LP-8i-4GB[1].txt", Content: []byte(`Controller Information ------------------------------------------------------------------------ AssetTag : RAID-LSI-9560 Logical Device Information ------------------------------------------------------------------------ LDID : 0 Name : VD0 RAID Level : 1 CapacityBytes : 1000000000 Status : Optimal Physical Device Information ------------------------------------------------------------------------ ConnectionID : 0 Position : Front0 StatusIndicator : OK Protocol : SATA MediaType : SSD Manufacturer : Samsung Model : PM893 Revision : GDC1 SerialNumber : SER-0 CapacityBytes : 480000000000 ConnectionID : 1 Position : Front1 StatusIndicator : OK Protocol : SATA MediaType : SSD Manufacturer : Samsung Model : PM893 Revision : GDC1 SerialNumber : SER-1 CapacityBytes : 480000000000 `), }, { Path: "static/NVMe_info.txt", Content: []byte(`[NVMe_0] Present=YES DiskSlotDesc=Front2 Model=INTEL SSDPE2KX010T8 SerialNumber=NVME-1 Firmware=V100 CapacityBytes=1000204886016 Interface=NVMe Status=OK `), }, } result, err := p.Parse(files) if err != nil { t.Fatalf("parse failed: %v", err) } if result.Hardware == nil { t.Fatalf("expected hardware section") } if len(result.Hardware.Volumes) != 1 { t.Fatalf("expected 1 volume, got %d", len(result.Hardware.Volumes)) } vol := result.Hardware.Volumes[0] if vol.RAIDLevel != "RAID1" { t.Fatalf("expected RAID1 level, got %q", vol.RAIDLevel) } if vol.SizeGB != 1 { t.Fatalf("expected 1GB logical volume, got %d", vol.SizeGB) } if len(result.Hardware.Storage) != 3 { t.Fatalf("expected 3 unique storage devices, got %d", len(result.Hardware.Storage)) } var front0 *models.Storage var nvme *models.Storage for i := range result.Hardware.Storage { s := &result.Hardware.Storage[i] if strings.EqualFold(s.SerialNumber, "SER-0") { front0 = s } if strings.EqualFold(s.SerialNumber, "NVME-1") { nvme = s } } if front0 == nil { t.Fatalf("expected merged Front0 disk by serial SER-0") } if front0.Model != "PM893" { t.Fatalf("expected Front0 model PM893, got %q", front0.Model) } if front0.SizeGB != 480 { t.Fatalf("expected Front0 size 480GB, got %d", front0.SizeGB) } if nvme == nil { t.Fatalf("expected NVMe disk by serial NVME-1") } if nvme.Type != "nvme" { t.Fatalf("expected nvme type, got %q", nvme.Type) } } func TestParseH3CG6(t *testing.T) { p := &G6Parser{} files := []parser.ExtractedFile{ { Path: "static/FRUInfo.ini", Content: []byte(`[Baseboard] Board Manufacturer=H3C Board Product Name=RS36M2C6SB Product Product Name=H3C UniServer R4700 G6 Product Serial Number=210235A4FYH257000010 Product Part Number=0235A4FY `), }, { Path: "static/firmware_version.json", Content: []byte(`{ "BMCP": {"Firmware Name":"HDM","Firmware Version":"1.83","Location":"bmc card","Part Model":"-"}, "BIOS": {"Firmware Name":"BIOS","Firmware Version":"6.10.53","Location":"system board","Part Model":"-"} }`), }, { Path: "static/CPUDetailInfo.xml", Content: []byte(` Presence INTEL(R) XEON(R) GOLD 6542Y 0xb54 0x1004 0x18 0x30 68-5C-81-C1-0E-A3-4E-40 68-5C-81-C1-0E-A3-4E-40 `), }, { Path: "static/MemoryDetailInfo.xml", Content: []byte(` Presence CPU1_CH1_D0 (A0) M321R8GA0PB0-CWMXJ RDIMM 80CE032519135C82ED 0x2 0x10000 0x1130 0x15e0 A0 `), }, { Path: "static/storage_disk.ini", Content: []byte(`[Disk_000] SerialNumber=S6KLNN0Y516813 DiskSlotDesc=Front0 Present=YES `), }, { Path: "static/net_cfg.ini", Content: []byte(`[Network Configuration] eth0 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 eth0.2 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6 inet6 addr: fe80::32c6:d7ff:fe94:54f6/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1496 Metric:1 eth1 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F5 inet addr:10.201.129.0 Bcast:10.201.143.255 Mask:255.255.240.0 inet6 addr: fe80::32c6:d7ff:fe94:54f5/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 `), }, { Path: "static/psu_cfg.ini", Content: []byte(`[Psu0] SN=210231AGUNH257001569 Max_Power(W)=1600 Manufacturer=Great Wall Power Status=Input Normal, Output Normal Present_Status=Present Power_ID=1 Model=GW-CRPS1600D2 Version=03.02.00 [Psu1] Manufacturer=Great Wall Power_ID=2 Version=03.02.00 Power Status=Input Normal, Output Normal SN=210231AGUNH257001570 Model=GW-CRPS1600D2 Present_Status=Present Max_Power(W)=1600 `), }, { Path: "static/hardware_info.ini", Content: []byte(`[Ethernet adapters: Port 1] Device Type : NIC Network Port : Port 1 Location : PCIE-[1] MAC Address : E4:3D:1A:6F:B0:30 Speed : 8.0GT/s Product Name : NIC-BCM957414-F-B-25Gb-2P [Ethernet adapters: Port 2] Device Type : NIC Network Port : Port 2 Location : PCIE-[1] MAC Address : E4:3D:1A:6F:B0:31 Speed : 8.0GT/s Product Name : NIC-BCM957414-F-B-25Gb-2P [PCIe Card: PCIe 1] Location : 1 Product Name : NIC-BCM957414-F-B-25Gb-2P Status : Normal Vendor ID : 0x14E4 Device ID : 0x16D7 Serial Number : NICSN-G6-001 Part Number : NICPN-G6-001 Firmware Version : 22.35.1010 `), }, { Path: "static/sensor_info.ini", Content: []byte(`Sensor Name | Reading | Unit | Status| Crit low Inlet_Temp | 20.000 | degrees C | ok | na CPU1_Status | 0x0 | discrete | 0x8080| na `), }, { Path: "user/Sel.json", Content: []byte(` { "Created": "2025-07-14 03:34:18 UTC+08:00", "Severity": "Info", "EntryCode": "Asserted", "EntryType": "Event", "Id": 1, "Level": "Info", "Message": "Processor Presence detected", "SensorName": "CPU1_Status", "SensorType": "Processor" }, { "Created": "2025-07-14 20:56:45 UTC+08:00", "Severity": "Critical", "EntryCode": "Asserted", "EntryType": "Event", "Id": 2, "Level": "Critical", "Message": "Power Supply AC lost", "SensorName": "PSU1_Status", "SensorType": "Power Supply" } `), }, } result, err := p.Parse(files) if err != nil { t.Fatalf("parse failed: %v", err) } if result.Hardware == nil { t.Fatalf("expected hardware section") } if result.Hardware.BoardInfo.Manufacturer != "H3C" { t.Fatalf("unexpected board manufacturer: %q", result.Hardware.BoardInfo.Manufacturer) } if result.Hardware.BoardInfo.ProductName != "H3C UniServer R4700 G6" { t.Fatalf("unexpected board product: %q", result.Hardware.BoardInfo.ProductName) } if result.Hardware.BoardInfo.SerialNumber != "210235A4FYH257000010" { t.Fatalf("unexpected board serial: %q", result.Hardware.BoardInfo.SerialNumber) } if len(result.Hardware.Firmware) < 2 { t.Fatalf("expected firmware entries, got %d", len(result.Hardware.Firmware)) } if len(result.Hardware.CPUs) != 1 { t.Fatalf("expected 1 cpu, got %d", len(result.Hardware.CPUs)) } if result.Hardware.CPUs[0].Cores != 24 { t.Fatalf("expected 24 cores, got %d", result.Hardware.CPUs[0].Cores) } if len(result.Hardware.Memory) != 1 { t.Fatalf("expected 1 dimm, got %d", len(result.Hardware.Memory)) } if result.Hardware.Memory[0].SizeMB != 65536 { t.Fatalf("expected 65536MB, got %d", result.Hardware.Memory[0].SizeMB) } if len(result.Hardware.Storage) != 1 { t.Fatalf("expected 1 disk, got %d", len(result.Hardware.Storage)) } if result.Hardware.Storage[0].SerialNumber != "S6KLNN0Y516813" { t.Fatalf("unexpected disk serial: %q", result.Hardware.Storage[0].SerialNumber) } if len(result.Hardware.PowerSupply) != 2 { t.Fatalf("expected 2 PSUs from psu_cfg.ini, got %d", len(result.Hardware.PowerSupply)) } if result.Hardware.PowerSupply[0].WattageW == 0 { t.Fatalf("expected PSU wattage parsed, got 0") } if len(result.Hardware.NetworkAdapters) != 1 { t.Fatalf("expected 1 host network adapter from hardware_info.ini, got %d", len(result.Hardware.NetworkAdapters)) } macs := make(map[string]struct{}) var hostNIC models.NetworkAdapter var hostNICFound bool for _, nic := range result.Hardware.NetworkAdapters { if len(nic.MACAddresses) == 0 { t.Fatalf("expected MAC on network adapter %+v", nic) } for _, mac := range nic.MACAddresses { macs[strings.ToLower(mac)] = struct{}{} } if strings.EqualFold(nic.Slot, "PCIe 1") && strings.Contains(strings.ToLower(nic.Model), "bcm957414") { hostNIC = nic hostNICFound = true } } if !hostNICFound { t.Fatalf("expected host NIC from hardware_info.ini, got %+v", result.Hardware.NetworkAdapters) } if _, ok := macs["e4:3d:1a:6f:b0:30"]; !ok { t.Fatalf("expected host NIC MAC e4:3d:1a:6f:b0:30 in adapters, got %+v", result.Hardware.NetworkAdapters) } if _, ok := macs["e4:3d:1a:6f:b0:31"]; !ok { t.Fatalf("expected host NIC MAC e4:3d:1a:6f:b0:31 in adapters, got %+v", result.Hardware.NetworkAdapters) } if !strings.Contains(strings.ToLower(hostNIC.Vendor), "broadcom") { t.Fatalf("expected host NIC vendor enrichment from Vendor ID, got %q", hostNIC.Vendor) } if hostNIC.SerialNumber != "NICSN-G6-001" { t.Fatalf("expected host NIC serial from PCIe card section, got %q", hostNIC.SerialNumber) } if hostNIC.PartNumber != "NICPN-G6-001" { t.Fatalf("expected host NIC part number from PCIe card section, got %q", hostNIC.PartNumber) } if hostNIC.Firmware != "22.35.1010" { t.Fatalf("expected host NIC firmware from PCIe card section, got %q", hostNIC.Firmware) } if len(result.Sensors) != 2 { t.Fatalf("expected 2 sensors, got %d", len(result.Sensors)) } if result.Sensors[0].Name != "Inlet_Temp" { t.Fatalf("unexpected first sensor: %q", result.Sensors[0].Name) } if len(result.Events) != 2 { t.Fatalf("expected 2 events, got %d", len(result.Events)) } if result.Events[0].Timestamp.Year() != 2025 || result.Events[0].Timestamp.Month() != 7 { t.Fatalf("expected SEL timestamp from payload, got %s", result.Events[0].Timestamp) } if result.Events[1].Severity != models.SeverityCritical { t.Fatalf("expected critical severity for AC lost event, got %q", result.Events[1].Severity) } } func TestParseH3CG5_PCIeArgumentsEnrichesNonNVMeStorage(t *testing.T) { p := &G5Parser{} files := []parser.ExtractedFile{ { Path: "static/storage_disk.ini", Content: []byte(`[Disk_000] DiskSlotDesc=Front slot 3 Present=YES SerialNumber=SAT-03 `), }, { Path: "static/NVMe_info.txt", Content: []byte(`[NVMe_0] Present=YES DiskSlotDesc=Front slot 108 SerialNumber=NVME-108 `), }, { Path: "static/PCIe_arguments_table.xml", Content: []byte(` SSD SSD-SATA-960G 0x144D SSD SSD-3.84T-NVMe-SFF 0x144D `), }, } result, err := p.Parse(files) if err != nil { t.Fatalf("parse failed: %v", err) } if result.Hardware == nil { t.Fatalf("expected hardware section") } if len(result.Hardware.Storage) != 2 { t.Fatalf("expected 2 storage devices, got %d", len(result.Hardware.Storage)) } var sata *models.Storage var nvme *models.Storage for i := range result.Hardware.Storage { s := &result.Hardware.Storage[i] switch s.SerialNumber { case "SAT-03": sata = s case "NVME-108": nvme = s } } if sata == nil { t.Fatalf("expected SATA storage SAT-03") } if sata.Model != "SSD-SATA-960G" { t.Fatalf("expected SATA model enrichment from PCIe table, got %q", sata.Model) } if !strings.Contains(strings.ToLower(sata.Manufacturer), "samsung") { t.Fatalf("expected SATA vendor enrichment to Samsung, got %q", sata.Manufacturer) } if nvme == nil { t.Fatalf("expected NVMe storage NVME-108") } if nvme.Model != "SSD-3.84T-NVMe-SFF" { t.Fatalf("expected NVMe model enrichment from PCIe table, got %q", nvme.Model) } if !strings.Contains(strings.ToLower(nvme.Manufacturer), "samsung") { t.Fatalf("expected NVMe vendor enrichment to Samsung, got %q", nvme.Manufacturer) } } func TestParseH3CG5_VariantLayout(t *testing.T) { p := &G5Parser{} files := []parser.ExtractedFile{ { Path: "static/FRUInfo.ini", Content: []byte(`[Baseboard] Board Manufacturer=H3C Product Product Name=H3C UniServer R4900 G5 Product Serial Number=02A6AX5231C003VM `), }, { Path: "static/firmware_version.ini", Content: []byte(`[System board] BIOS Version : 5.59 V100R001B05D078 ME Version : 4.4.4.202 HDM Version : 3.34.01 HDM V100R001B05D078SP01 CPLD Version : V00C `), }, { Path: "static/board_cfg.ini", Content: []byte(`[Board Type] Board Type : R4900 G5 [Board Version] Board Version : VER.D [Customer ID] CustomerID : 255 [OEM ID] OEM Flag : 1 `), }, { Path: "static/hardware_info.ini", Content: []byte(`[Processors: Processor 1] Model : Intel(R) Xeon(R) Gold 6342 CPU @ 2.80GHz Status : Normal Frequency : 2800 MHz Cores : 24 Threads : 48 L1 Cache : 1920 KB L2 Cache : 30720 KB L3 Cache : 36864 KB CPU PPIN : 49-A9-50-C0-15-9F-2D-DC [Processors: Processor 2] Model : Intel(R) Xeon(R) Gold 6342 CPU @ 2.80GHz Status : Normal Frequency : 2800 MHz Cores : 24 Threads : 48 CPU PPIN : 49-AC-3D-BF-85-7F-17-58 [Memory Details: Dimm Index 0] Location : Processor 1 Channel : 1 Socket ID : A0 Status : Normal Size : 65536 MB Maximum Frequency : 3200 MHz Type : DDR4 Ranks : 2R DIMM Technology : RDIMM Part Number : M393A8G40AB2-CWE Manufacture : Samsung Serial Number : S02K0D0243351D7079 [Memory Details: Dimm Index 16] Location : Processor 2 Channel : 1 Socket ID : A0 Status : Normal Size : 65536 MB Maximum Frequency : 3200 MHz Type : DDR4 Ranks : 2R DIMM Technology : RDIMM Part Number : M393A8G40AB2-CWE Manufacture : Samsung Serial Number : S02K0D0243351D73F0 [Ethernet adapters: Port 1] Device Type : NIC Network Port : Port 1 Location : PCIE-[1] MAC Address : E4:3D:1A:6F:B0:30 Speed : 8.0GT/s Product Name : NIC-BCM957414-F-B-25Gb-2P [Ethernet adapters: Port 2] Device Type : NIC Network Port : Port 2 Location : PCIE-[1] MAC Address : E4:3D:1A:6F:B0:31 Speed : 8.0GT/s Product Name : NIC-BCM957414-F-B-25Gb-2P [Ethernet adapters: Port 1] Device Type : NIC Network Port : Port 1 Location : PCIE-[4] MAC Address : E8:EB:D3:4F:2E:90 Speed : 8.0GT/s Product Name : NIC-MCX512A-ACAT-2*25Gb-F [Ethernet adapters: Port 2] Device Type : NIC Network Port : Port 2 Location : PCIE-[4] MAC Address : E8:EB:D3:4F:2E:91 Speed : 8.0GT/s Product Name : NIC-MCX512A-ACAT-2*25Gb-F [PCIe Card: PCIe 1] Location : 1 Product Name : NIC-BCM957414-F-B-25Gb-2P Status : Normal Vendor ID : 0x14E4 Device ID : 0x16D7 Serial Number : NICSN-G5-001 Part Number : NICPN-G5-001 Firmware Version : 21.80.1 [PCIe Card: PCIe 4] Location : 4 Product Name : NIC-MCX512A-ACAT-2*25Gb-F Status : Normal Vendor ID : 0x15B3 Device ID : 0x1017 Serial Number : NICSN-G5-004 Part Number : NICPN-G5-004 Firmware Version : 28.33.15 `), }, { Path: "static/hardware.info", Content: []byte(`[Disk_0_Front_NA] Present=YES SlotNum=0 FrontOrRear=Front SerialNumber=22443C4EE184 [Nvme_Front slot 21] Present=YES NvmePhySlot=Front slot 21 SlotNum=121 SerialNumber=NVME-21 [Nvme_255_121] Present=YES SlotNum=121 SerialNumber=NVME-21 `), }, { Path: "static/raid.json", Content: []byte(`{ "RAIDCONFIG": { "Ctrl info": [ { "CtrlDevice Slot": 3, "CtrlDevice Name": "AVAGO MegaRAID SAS 9460-8i", "LDInfo": [ { "LD ID": 0, "LD_name": "SystemRAID", "RAID_level(RAID 0,RAID 1,RAID 5,RAID 6,RAID 00,RAID 10,RAID 50,RAID 60)": "RAID1", "Logical_capicity(per 512byte)": 936640512 } ] }, { "CtrlDevice Slot": 6, "CtrlDevice Name": "MegaRAID 9560-16i 8GB", "LDInfo": [ { "LD ID": 0, "LD_name": "DataRAID", "RAID_level(RAID 0,RAID 1,RAID 5,RAID 6,RAID 00,RAID 10,RAID 50,RAID 60)": "RAID50", "Logical_capicity(per 512byte)": 90004783104 } ] } ] } }`), }, { Path: "static/Raid_BP_Conf_Info.ini", Content: []byte(`[BP Information] Description | BP TYPE | I2cPort | BpConnectorNum | FrontOrRear | Node Num | DiskSlotRange | 8SFF SAS/SATA | BP_G5_8SFF | AUX_1 | ~ | ~ | ~ | ~ | 8SFF SAS/SATA | BP_G5_8SFF | AUX_2 | ~ | ~ | ~ | ~ | 8SFF SAS/SATA | BP_G5_8SFF | AUX_3 | ~ | ~ | ~ | ~ | [RAID Information] PCIE SLOT | RAID SAS_NUM | 3 | 2 | 6 | 4 | `), }, { Path: "static/PCIe_arguments_table.xml", Content: []byte(` SSD SSD-1.92T/3.84T-NVMe-EV-SFF-sa 0x144D `), }, { Path: "static/psu_cfg.ini", Content: []byte(`[Active / Standby configuration] Power ID : 1 Present Status : Present Cold Status : Active Power Model : DPS-1300AB-6 R SN : 210231ACT9H232000080 Max Power(W) : 1300 Power ID : 2 Present Status : Present Cold Status : Active Power Model : DPS-1300AB-6 R SN : 210231ACT9H232000079 Max Power(W) : 1300 `), }, { Path: "static/net_cfg.ini", Content: []byte(`[Network Configuration] eth0 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 eth0.2 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6 inet6 addr: fe80::32c6:d7ff:fe94:54f6/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1496 Metric:1 eth1 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F5 inet addr:10.201.129.0 Bcast:10.201.143.255 Mask:255.255.240.0 inet6 addr: fe80::32c6:d7ff:fe94:54f5/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 `), }, { Path: "static/smartdata/Front0/first_date_analysis.txt", Content: []byte(`The Current System Time Is 2023_09_22_14_19_39 Model Info: ATA Micron_5300_MTFD Serial Number: 22443C4EE184 `), }, { Path: "user/test1.csv", Content: []byte(`Record Time Stamp,Severity Level,Severity Level ID,SensorTypeStr,SensorName,Event Dir,Event Occurred Time,DescInfo,Explanation,Suggestion 2025-04-01 08:50:13,Minor,0x1,NA,NA,NA,2025-04-01 08:50:13,"SSH login failed from IP: 10.200.10.121 user: admin"," "," " Pre-Init,Info,0x0,Management Subsystem Health,Health,Assertion event,Pre-Init,"Management controller off-line"," "," " 2025-04-01 08:51:10,Major,0x2,Power Supply,PSU1_Status,Assertion event,2025-04-01 08:51:10,"Power Supply AC lost"," "," " `), }, } result, err := p.Parse(files) if err != nil { t.Fatalf("parse failed: %v", err) } if result.Hardware == nil { t.Fatalf("expected hardware section") } if len(result.Hardware.CPUs) != 2 { t.Fatalf("expected 2 CPUs from hardware_info.ini, got %d", len(result.Hardware.CPUs)) } if result.Hardware.CPUs[0].FrequencyMHz != 2800 { t.Fatalf("expected CPU frequency 2800MHz, got %d", result.Hardware.CPUs[0].FrequencyMHz) } if len(result.Hardware.Memory) != 2 { t.Fatalf("expected 2 DIMMs from hardware_info.ini, got %d", len(result.Hardware.Memory)) } if result.Hardware.Memory[0].SizeMB != 65536 { t.Fatalf("expected DIMM size 65536MB, got %d", result.Hardware.Memory[0].SizeMB) } if len(result.Hardware.Firmware) < 4 { t.Fatalf("expected firmware entries from firmware_version.ini, got %d", len(result.Hardware.Firmware)) } if result.Hardware.BoardInfo.Version == "" { t.Fatalf("expected board version from board_cfg.ini") } if !strings.Contains(result.Hardware.BoardInfo.Description, "CustomerID: 255") { t.Fatalf("expected board description enrichment from board_cfg.ini, got %q", result.Hardware.BoardInfo.Description) } if len(result.Hardware.Storage) != 2 { t.Fatalf("expected 2 unique storage devices from hardware.info, got %d", len(result.Hardware.Storage)) } var nvmeFound bool var diskModelEnriched bool for _, s := range result.Hardware.Storage { if s.SerialNumber == "NVME-21" { nvmeFound = true if s.Type != "nvme" { t.Fatalf("expected NVME-21 type nvme, got %q", s.Type) } if !strings.Contains(strings.ToLower(s.Manufacturer), "samsung") { t.Fatalf("expected NVME vendor enrichment to Samsung, got %q", s.Manufacturer) } if s.Model != "SSD-1.92T/3.84T-NVMe-EV-SFF-sa" { t.Fatalf("expected NVME model enrichment from PCIe table, got %q", s.Model) } } if s.SerialNumber == "22443C4EE184" && strings.Contains(s.Model, "Micron") { diskModelEnriched = true } } if !nvmeFound { t.Fatalf("expected deduped NVME storage by serial NVME-21") } if !diskModelEnriched { t.Fatalf("expected disk model enrichment from smartdata by serial") } if len(result.Hardware.PowerSupply) != 2 { t.Fatalf("expected 2 PSUs from psu_cfg.ini, got %d", len(result.Hardware.PowerSupply)) } if result.Hardware.PowerSupply[0].WattageW == 0 { t.Fatalf("expected PSU wattage parsed, got 0") } if len(result.Hardware.NetworkAdapters) != 2 { t.Fatalf("expected 2 host network adapters from hardware_info.ini, got %d", len(result.Hardware.NetworkAdapters)) } if len(result.Hardware.NetworkCards) != 2 { t.Fatalf("expected 2 network cards synthesized from adapters, got %d", len(result.Hardware.NetworkCards)) } var g5NIC models.NetworkAdapter var g5NICFound bool for _, nic := range result.Hardware.NetworkAdapters { if strings.EqualFold(nic.Slot, "PCIe 1") && strings.Contains(strings.ToLower(nic.Model), "bcm957414") { g5NIC = nic g5NICFound = true break } } if !g5NICFound { t.Fatalf("expected host NIC PCIe 1 from hardware_info.ini, got %+v", result.Hardware.NetworkAdapters) } if !strings.Contains(strings.ToLower(g5NIC.Vendor), "broadcom") { t.Fatalf("expected G5 NIC vendor from Vendor ID, got %q", g5NIC.Vendor) } if g5NIC.SerialNumber != "NICSN-G5-001" { t.Fatalf("expected G5 NIC serial from PCIe card section, got %q", g5NIC.SerialNumber) } if g5NIC.PartNumber != "NICPN-G5-001" { t.Fatalf("expected G5 NIC part number from PCIe card section, got %q", g5NIC.PartNumber) } if g5NIC.Firmware != "21.80.1" { t.Fatalf("expected G5 NIC firmware from PCIe card section, got %q", g5NIC.Firmware) } if len(result.Hardware.Devices) != 5 { t.Fatalf("expected 5 topology devices from Raid_BP_Conf_Info.ini (3 BP + 2 RAID), got %d", len(result.Hardware.Devices)) } var bpFound bool var raidFound bool for _, d := range result.Hardware.Devices { if strings.Contains(d.ID, "h3c-bp-") && strings.Contains(d.Model, "BP_G5_8SFF") { bpFound = true } desc, _ := d.Details["description"].(string) if strings.Contains(d.ID, "h3c-raid-slot-3") && strings.Contains(desc, "SAS ports: 2") { raidFound = true } } if !bpFound || !raidFound { t.Fatalf("expected parsed backplane and RAID topology devices, got %+v", result.Hardware.Devices) } if len(result.Hardware.Volumes) != 2 { t.Fatalf("expected 2 RAID volumes (same LD ID on different controllers), got %d", len(result.Hardware.Volumes)) } var raid1Found bool var raid50Found bool for _, v := range result.Hardware.Volumes { if strings.Contains(v.Controller, "slot 3") { raid1Found = v.RAIDLevel == "RAID1" && v.CapacityBytes > 0 } if strings.Contains(v.Controller, "slot 6") { raid50Found = v.RAIDLevel == "RAID50" && v.CapacityBytes > 0 } } if !raid1Found || !raid50Found { t.Fatalf("expected RAID1 and RAID50 volumes with parsed capacities, got %+v", result.Hardware.Volumes) } if len(result.Events) != 2 { t.Fatalf("expected 2 CSV events (Pre-Init skipped), got %d", len(result.Events)) } if result.Events[0].Severity != models.SeverityWarning { t.Fatalf("expected Minor CSV severity mapped to warning, got %q", result.Events[0].Severity) } if result.Events[1].Severity != models.SeverityCritical { t.Fatalf("expected Major CSV severity mapped to critical, got %q", result.Events[1].Severity) } }