259 lines
6.8 KiB
Go
259 lines
6.8 KiB
Go
package lenovo_xcc
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
"git.mchus.pro/mchus/logpile/internal/parser"
|
|
)
|
|
|
|
const exampleArchive = "/Users/mchusavitin/Documents/git/logpile/example/7D76CTO1WW_JF0002KT_xcc_mini-log_20260413-122150.zip"
|
|
|
|
func TestDetect_LenovoXCCMiniLog(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
score := p.Detect(files)
|
|
if score < 80 {
|
|
t.Errorf("expected Detect score >= 80 for XCC mini-log archive, got %d", score)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_BasicSysInfo(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, err := p.Parse(files)
|
|
if err != nil {
|
|
t.Fatalf("Parse returned error: %v", err)
|
|
}
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil result or hardware")
|
|
}
|
|
|
|
hw := result.Hardware
|
|
if hw.BoardInfo.SerialNumber == "" {
|
|
t.Error("BoardInfo.SerialNumber is empty")
|
|
}
|
|
if hw.BoardInfo.ProductName == "" {
|
|
t.Error("BoardInfo.ProductName is empty")
|
|
}
|
|
t.Logf("BoardInfo: serial=%s model=%s uuid=%s", hw.BoardInfo.SerialNumber, hw.BoardInfo.ProductName, hw.BoardInfo.UUID)
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_CPUs(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
if len(result.Hardware.CPUs) == 0 {
|
|
t.Error("expected at least one CPU, got none")
|
|
}
|
|
for i, cpu := range result.Hardware.CPUs {
|
|
t.Logf("CPU[%d]: socket=%d model=%q cores=%d threads=%d freq=%dMHz", i, cpu.Socket, cpu.Model, cpu.Cores, cpu.Threads, cpu.FrequencyMHz)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_Memory(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
if len(result.Hardware.Memory) == 0 {
|
|
t.Error("expected memory DIMMs, got none")
|
|
}
|
|
t.Logf("Memory: %d DIMMs", len(result.Hardware.Memory))
|
|
for i, m := range result.Hardware.Memory {
|
|
t.Logf("DIMM[%d]: slot=%s present=%v size=%dMB sn=%s", i, m.Slot, m.Present, m.SizeMB, m.SerialNumber)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_Storage(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
t.Logf("Storage: %d disks", len(result.Hardware.Storage))
|
|
for i, s := range result.Hardware.Storage {
|
|
t.Logf("Disk[%d]: slot=%s model=%q size=%dGB sn=%s", i, s.Slot, s.Model, s.SizeGB, s.SerialNumber)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_PCIeCards(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
t.Logf("PCIe cards: %d", len(result.Hardware.PCIeDevices))
|
|
for i, c := range result.Hardware.PCIeDevices {
|
|
t.Logf("Card[%d]: slot=%s desc=%q bdf=%s", i, c.Slot, c.Description, c.BDF)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_PSUs(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
if len(result.Hardware.PowerSupply) == 0 {
|
|
t.Error("expected PSUs, got none")
|
|
}
|
|
for i, p := range result.Hardware.PowerSupply {
|
|
t.Logf("PSU[%d]: slot=%s wattage=%dW status=%s sn=%s", i, p.Slot, p.WattageW, p.Status, p.SerialNumber)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_Sensors(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
if len(result.Sensors) == 0 {
|
|
t.Error("expected sensors, got none")
|
|
}
|
|
t.Logf("Sensors: %d", len(result.Sensors))
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_Events(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
if len(result.Events) == 0 {
|
|
t.Error("expected events, got none")
|
|
}
|
|
t.Logf("Events: %d", len(result.Events))
|
|
for i, e := range result.Events {
|
|
if i >= 5 {
|
|
break
|
|
}
|
|
t.Logf("Event[%d]: severity=%s ts=%s desc=%q", i, e.Severity, e.Timestamp.Format("2006-01-02T15:04:05"), e.Description)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_FRU(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
t.Logf("FRU: %d entries", len(result.FRU))
|
|
for i, f := range result.FRU {
|
|
t.Logf("FRU[%d]: desc=%q product=%q serial=%q", i, f.Description, f.ProductName, f.SerialNumber)
|
|
}
|
|
}
|
|
|
|
func TestParse_LenovoXCCMiniLog_Firmware(t *testing.T) {
|
|
files, err := parser.ExtractArchive(exampleArchive)
|
|
if err != nil {
|
|
t.Skipf("example archive not available: %v", err)
|
|
}
|
|
|
|
p := &Parser{}
|
|
result, _ := p.Parse(files)
|
|
if result == nil || result.Hardware == nil {
|
|
t.Fatal("Parse returned nil")
|
|
}
|
|
|
|
if len(result.Hardware.Firmware) == 0 {
|
|
t.Error("expected firmware entries, got none")
|
|
}
|
|
for i, f := range result.Hardware.Firmware {
|
|
t.Logf("FW[%d]: name=%q version=%q buildtime=%q", i, f.DeviceName, f.Version, f.BuildTime)
|
|
}
|
|
}
|
|
|
|
func TestParseDIMMs_UnqualifiedDIMMAddsWarningEvent(t *testing.T) {
|
|
content := []byte(`{
|
|
"items": [{
|
|
"memory": [{
|
|
"memory_name": "DIMM A1",
|
|
"memory_status": "Unqualified DIMM",
|
|
"memory_type": "DDR5",
|
|
"memory_capacity": 32
|
|
}]
|
|
}]
|
|
}`)
|
|
|
|
memory, events := parseDIMMs(content)
|
|
if len(memory) != 1 {
|
|
t.Fatalf("expected 1 DIMM, got %d", len(memory))
|
|
}
|
|
if len(events) != 1 {
|
|
t.Fatalf("expected 1 warning event, got %d", len(events))
|
|
}
|
|
if events[0].Severity != models.SeverityWarning {
|
|
t.Fatalf("expected warning severity, got %q", events[0].Severity)
|
|
}
|
|
if events[0].SensorName != "DIMM A1" {
|
|
t.Fatalf("unexpected sensor name: %q", events[0].SensorName)
|
|
}
|
|
}
|
|
|
|
func TestSeverity_UnqualifiedDIMMMessageBecomesWarning(t *testing.T) {
|
|
if got := xccSeverity("I", "System found Unqualified DIMM in slot DIMM A1"); got != models.SeverityWarning {
|
|
t.Fatalf("expected warning severity, got %q", got)
|
|
}
|
|
}
|