package hpe_ilo_ahs import ( "bytes" "compress/gzip" "encoding/binary" "testing" "git.mchus.pro/mchus/logpile/internal/parser" ) func TestDetectAHS(t *testing.T) { p := &Parser{} score := p.Detect([]parser.ExtractedFile{{ Path: "HPE_CZ2D1X0GS3_20260330.ahs", Content: makeAHSArchive(t, []ahsTestEntry{{Name: "CUST_INFO.DAT", Payload: []byte("x")}}), }}) if score < 80 { t.Fatalf("expected high confidence detect, got %d", score) } } func TestParseAHSInventory(t *testing.T) { p := &Parser{} content := makeAHSArchive(t, []ahsTestEntry{ {Name: "CUST_INFO.DAT", Payload: make([]byte, 16)}, {Name: "0000088-2026-03-30.zbb", Payload: gzipBytes(t, []byte(sampleInventoryBlob()))}, }) result, err := p.Parse([]parser.ExtractedFile{{ Path: "HPE_CZ2D1X0GS3_20260330.ahs", Content: content, }}) if err != nil { t.Fatalf("parse failed: %v", err) } if result.Hardware == nil { t.Fatalf("expected hardware section") } board := result.Hardware.BoardInfo if board.Manufacturer != "HPE" { t.Fatalf("unexpected board manufacturer: %q", board.Manufacturer) } if board.ProductName != "ProLiant DL380 Gen11" { t.Fatalf("unexpected board product: %q", board.ProductName) } if board.SerialNumber != "CZ2D1X0GS3" { t.Fatalf("unexpected board serial: %q", board.SerialNumber) } if board.PartNumber != "P52560-421" { t.Fatalf("unexpected board part number: %q", board.PartNumber) } if len(result.Hardware.CPUs) != 1 || result.Hardware.CPUs[0].Model != "Intel(R) Xeon(R) Gold 6444Y" { t.Fatalf("unexpected CPUs: %+v", result.Hardware.CPUs) } if len(result.Hardware.Memory) != 1 { t.Fatalf("expected one DIMM, got %d", len(result.Hardware.Memory)) } if result.Hardware.Memory[0].PartNumber != "HMCG88AEBRA115N" { t.Fatalf("unexpected DIMM part number: %q", result.Hardware.Memory[0].PartNumber) } if len(result.Hardware.NetworkAdapters) != 2 { t.Fatalf("expected two network adapters, got %d", len(result.Hardware.NetworkAdapters)) } if len(result.Hardware.PowerSupply) != 1 { t.Fatalf("expected one PSU, got %d", len(result.Hardware.PowerSupply)) } if result.Hardware.PowerSupply[0].SerialNumber != "5XUWB0C4DJG4BV" { t.Fatalf("unexpected PSU serial: %q", result.Hardware.PowerSupply[0].SerialNumber) } if len(result.Hardware.Storage) != 1 { t.Fatalf("expected one physical drive, got %d", len(result.Hardware.Storage)) } drive := result.Hardware.Storage[0] if drive.Model != "SAMSUNGMZ7L3480HCHQ-00A07" { t.Fatalf("unexpected drive model: %q", drive.Model) } if drive.SerialNumber != "S664NC0Y502720" { t.Fatalf("unexpected drive serial: %q", drive.SerialNumber) } if drive.SizeGB != 480 { t.Fatalf("unexpected drive size: %d", drive.SizeGB) } if len(result.Hardware.Firmware) == 0 { t.Fatalf("expected firmware inventory") } foundILO := false foundControllerFW := false for _, item := range result.Hardware.Firmware { if item.DeviceName == "iLO 6" && item.Version == "v1.63p20" { foundILO = true } if item.DeviceName == "HPE MR408i-o Gen11" && item.Version == "52.26.3-5379" { foundControllerFW = true } } if !foundILO { t.Fatalf("expected iLO firmware entry") } if !foundControllerFW { t.Fatalf("expected controller firmware entry") } if len(result.Hardware.Devices) < 6 { t.Fatalf("expected canonical devices, got %d", len(result.Hardware.Devices)) } if len(result.Events) == 0 { t.Fatalf("expected parsed events") } } type ahsTestEntry struct { Name string Payload []byte Flag uint32 } func makeAHSArchive(t *testing.T, entries []ahsTestEntry) []byte { t.Helper() var buf bytes.Buffer for _, entry := range entries { header := make([]byte, ahsHeaderSize) copy(header[:4], []byte("ABJR")) binary.LittleEndian.PutUint16(header[4:6], 0x0300) binary.LittleEndian.PutUint16(header[6:8], 0x0002) binary.LittleEndian.PutUint32(header[8:12], uint32(len(entry.Payload))) flag := entry.Flag if flag == 0 { flag = 0x80000002 if len(entry.Payload) >= 2 && entry.Payload[0] == 0x1f && entry.Payload[1] == 0x8b { flag = 0x80000001 } } binary.LittleEndian.PutUint32(header[16:20], flag) copy(header[20:52], []byte(entry.Name)) buf.Write(header) buf.Write(entry.Payload) } return buf.Bytes() } func gzipBytes(t *testing.T, payload []byte) []byte { t.Helper() var buf bytes.Buffer zw := gzip.NewWriter(&buf) if _, err := zw.Write(payload); err != nil { t.Fatalf("gzip payload: %v", err) } if err := zw.Close(); err != nil { t.Fatalf("close gzip writer: %v", err) } return buf.Bytes() } func sampleInventoryBlob() string { return stringsJoin( "iLO 6 v1.63p20 built on Sep 13 2024", "HPE", "ProLiant DL380 Gen11", "CZ2D1X0GS3", "P52560-421", "Proc 1", "Intel(R) Corporation", "Intel(R) Xeon(R) Gold 6444Y", "PROC 1 DIMM 3", "Hynix", "HMCG88AEBRA115N", "2B5F92C6", "Power Supply 1", "5XUWB0C4DJG4BV", "P03178-B21", "PciRoot(0x1)/Pci(0x5,0x0)/Pci(0x0,0x0)", "NIC.Slot.1.1", "Network Controller", "Slot 1", "MCX512A-ACAT", "MT2230478382", "PciRoot(0x3)/Pci(0x1,0x0)/Pci(0x0,0x0)", "OCP.Slot.15.1", "Broadcom NetXtreme Gigabit Ethernet - NIC", "OCP Slot 15", "P51183-001", "1CH0150001", "20.28.41", "System ROM", "v2.22 (06/19/2024)", "03/30/2026 09:47:33", "iLO network link down.", `{"@odata.id":"/redfish/v1/Systems/1/Storage/DE00A000/Controllers/0","@odata.type":"#StorageController.v1_7_0.StorageController","Id":"0","Name":"HPE MR408i-o Gen11","FirmwareVersion":"52.26.3-5379","Manufacturer":"HPE","Model":"HPE MR408i-o Gen11","PartNumber":"P58543-001","SKU":"P58335-B21","SerialNumber":"PXSFQ0BBIJY3B3","Status":{"State":"Enabled","Health":"OK"},"Location":{"PartLocation":{"ServiceLabel":"Slot=14","LocationType":"Slot","LocationOrdinalValue":14}},"PCIeInterface":{"PCIeType":"Gen4","LanesInUse":8}}`, `{"@odata.id":"/redfish/v1/Chassis/DE00A000/Drives/0","@odata.type":"#Drive.v1_17_0.Drive","Id":"0","Name":"480GB 6G SATA SSD","Status":{"State":"StandbyOffline","Health":"OK"},"PhysicalLocation":{"PartLocation":{"ServiceLabel":"Slot=14:Port=1:Box=3:Bay=1","LocationType":"Bay","LocationOrdinalValue":1}},"CapacityBytes":480103981056,"MediaType":"SSD","Model":"SAMSUNGMZ7L3480HCHQ-00A07","Protocol":"SATA","Revision":"JXTC604Q","SerialNumber":"S664NC0Y502720","PredictedMediaLifeLeftPercent":100}`, `{"@odata.id":"/redfish/v1/Chassis/DE00A000/Drives/64515","@odata.type":"#Drive.v1_17_0.Drive","Id":"64515","Name":"Empty Bay","Status":{"State":"Absent","Health":"OK"}}`, ) } func stringsJoin(parts ...string) string { return string(bytes.Join(func() [][]byte { out := make([][]byte, 0, len(parts)) for _, part := range parts { out = append(out, []byte(part)) } return out }(), []byte{0})) }