package inspurlegacy import ( "testing" "git.mchus.pro/mchus/logpile/internal/models" ) // buildFRU assembles a minimal but spec-shaped IPMI FRU image with a chassis, // board and product area. Single-char fields are encoded as 0xC1 (type 3, // length 1) exactly as the real Inspur image does. func buildFRU() []byte { tl3 := func(s string) []byte { return append([]byte{byte(0xC0 | len(s))}, []byte(s)...) } chassis := []byte{0x01, 0x00, 0x17} // version, len placeholder, Rack Mount chassis = append(chassis, tl3("0")...) chassis = append(chassis, tl3("0")...) chassis = pad8(chassis) chassis[1] = byte(len(chassis) / 8) board := []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00} // v, len, lang, 3-byte date board = append(board, tl3("Inspur")...) board = append(board, tl3("NF5280M5")...) board = append(board, tl3("MBL911S22243C30")...) board = append(board, tl3("YZMB-00882-104")...) board = pad8(board) board[1] = byte(len(board) / 8) product := []byte{0x01, 0x00, 0x00} // v, len, lang product = append(product, tl3("Inspur")...) product = append(product, tl3("NF5466M5")...) product = append(product, tl3("0")...) // part placeholder product = append(product, tl3("0")...) // version placeholder product = append(product, tl3("221353113")...) product = append(product, tl3("0")...) // asset tag placeholder product = pad8(product) product[1] = byte(len(product) / 8) header := make([]byte, 8) header[0] = 0x01 header[2] = 1 // chassis at 8 header[3] = byte((8 + len(chassis)) / 8) // board header[4] = byte((8 + len(chassis) + len(board)) / 8) out := append(header, chassis...) out = append(out, board...) out = append(out, product...) return out } func pad8(b []byte) []byte { for len(b)%8 != 0 { b = append(b, 0x00) } return b } func TestDecodeBinaryFRU_Identity(t *testing.T) { fru, ok := DecodeBinaryFRU(buildFRU()) if !ok { t.Fatal("decode failed") } if fru.ProductName != "NF5466M5" { t.Errorf("product name = %q", fru.ProductName) } if fru.ProductSerial != "221353113" { t.Errorf("product serial = %q", fru.ProductSerial) } if fru.BoardPart != "YZMB-00882-104" { t.Errorf("board part = %q", fru.BoardPart) } if fru.ChassisType != "Rack Mount Chassis" { t.Errorf("chassis type = %q", fru.ChassisType) } } func TestBinaryFRU_ApplyToBoardInfo_PrefersProductSerialAndBoardPart(t *testing.T) { fru, _ := DecodeBinaryFRU(buildFRU()) var b models.BoardInfo fru.applyToBoardInfo(&b) if b.SerialNumber != "221353113" { t.Errorf("board serial = %q, want operator-facing product serial", b.SerialNumber) } if b.PartNumber != "YZMB-00882-104" { t.Errorf("board part = %q, want board part (product part is placeholder)", b.PartNumber) } if b.Manufacturer != "Inspur" { t.Errorf("board manufacturer = %q", b.Manufacturer) } // An already-populated field is never overwritten. pre := models.BoardInfo{SerialNumber: "EXISTING"} fru.applyToBoardInfo(&pre) if pre.SerialNumber != "EXISTING" { t.Errorf("existing serial overwritten: %q", pre.SerialNumber) } } func TestDecodeBinaryFRU_RejectsGarbage(t *testing.T) { if _, ok := DecodeBinaryFRU([]byte{0x00, 0x00}); ok { t.Error("expected decode to fail on short/garbage input") } }