package xfusion import ( "testing" "git.mchus.pro/mchus/logpile/internal/parser" ) // loadTestArchive extracts the given archive path for use in tests. // Skips the test if the file is not found (CI environments without testdata). func loadTestArchive(t *testing.T, path string) []parser.ExtractedFile { t.Helper() files, err := parser.ExtractArchive(path) if err != nil { t.Skipf("cannot load test archive %s: %v", path, err) } return files } func TestDetect_G5500V7(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} score := p.Detect(files) if score < 80 { t.Fatalf("expected Detect score >= 80, got %d", score) } } func TestParse_G5500V7_BoardInfo(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if result.Hardware == nil { t.Fatal("Hardware is nil") } board := result.Hardware.BoardInfo if board.SerialNumber != "210619KUGGXGS2000015" { t.Errorf("BoardInfo.SerialNumber = %q, want 210619KUGGXGS2000015", board.SerialNumber) } if board.ProductName != "G5500 V7" { t.Errorf("BoardInfo.ProductName = %q, want G5500 V7", board.ProductName) } } func TestParse_G5500V7_CPUs(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Hardware.CPUs) != 2 { t.Fatalf("expected 2 CPUs, got %d", len(result.Hardware.CPUs)) } cpu1 := result.Hardware.CPUs[0] if cpu1.Cores != 32 { t.Errorf("CPU1 cores = %d, want 32", cpu1.Cores) } if cpu1.Threads != 64 { t.Errorf("CPU1 threads = %d, want 64", cpu1.Threads) } if cpu1.SerialNumber == "" { t.Error("CPU1 SerialNumber is empty") } } func TestParse_G5500V7_Memory(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } // Only 2 DIMMs are populated (rest are "NO DIMM") if len(result.Hardware.Memory) != 2 { t.Fatalf("expected 2 populated DIMMs, got %d", len(result.Hardware.Memory)) } dimm := result.Hardware.Memory[0] if dimm.SizeMB != 65536 { t.Errorf("DIMM0 SizeMB = %d, want 65536", dimm.SizeMB) } if dimm.Type != "DDR5" { t.Errorf("DIMM0 Type = %q, want DDR5", dimm.Type) } } func TestParse_G5500V7_GPUs(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Hardware.GPUs) != 8 { t.Fatalf("expected 8 GPUs, got %d", len(result.Hardware.GPUs)) } for _, gpu := range result.Hardware.GPUs { if gpu.SerialNumber == "" { t.Errorf("GPU slot %s has empty SerialNumber", gpu.Slot) } if gpu.Model == "" { t.Errorf("GPU slot %s has empty Model", gpu.Slot) } if gpu.Firmware == "" { t.Errorf("GPU slot %s has empty Firmware", gpu.Slot) } } } func TestParse_G5500V7_NICs(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Hardware.NetworkCards) < 1 { t.Fatal("expected at least 1 NIC (OCP CX6), got 0") } nic := result.Hardware.NetworkCards[0] if nic.SerialNumber == "" { t.Errorf("NIC SerialNumber is empty") } } func TestParse_G5500V7_PSUs(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Hardware.PowerSupply) != 4 { t.Fatalf("expected 4 PSUs, got %d", len(result.Hardware.PowerSupply)) } for _, psu := range result.Hardware.PowerSupply { if psu.WattageW != 3000 { t.Errorf("PSU slot %s wattage = %d, want 3000", psu.Slot, psu.WattageW) } if psu.SerialNumber == "" { t.Errorf("PSU slot %s has empty SerialNumber", psu.Slot) } } } func TestParse_G5500V7_Storage(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Hardware.Storage) != 2 { t.Fatalf("expected 2 storage devices, got %d", len(result.Hardware.Storage)) } for _, disk := range result.Hardware.Storage { if disk.SerialNumber == "" { t.Errorf("disk slot %s has empty SerialNumber", disk.Slot) } if disk.Model == "" { t.Errorf("disk slot %s has empty Model", disk.Slot) } } } func TestParse_G5500V7_Sensors(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Sensors) < 20 { t.Fatalf("expected at least 20 sensors, got %d", len(result.Sensors)) } } func TestParse_G5500V7_Events(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.Events) < 5 { t.Fatalf("expected at least 5 events, got %d", len(result.Events)) } // All events should have real timestamps (not epoch 0) for _, ev := range result.Events { if ev.Timestamp.Year() <= 1970 { t.Errorf("event has epoch timestamp: %v %s", ev.Timestamp, ev.Description) } } } func TestParse_G5500V7_FRU(t *testing.T) { files := loadTestArchive(t, "../../../../example/G5500V7_210619KUGGXGS2000015_20260318-1128.tar.gz") p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse: %v", err) } if len(result.FRU) < 3 { t.Fatalf("expected at least 3 FRU entries, got %d", len(result.FRU)) } // Check mainboard FRU serial found := false for _, f := range result.FRU { if f.SerialNumber == "210619KUGGXGS2000015" { found = true } } if !found { t.Error("mainboard serial 210619KUGGXGS2000015 not found in FRU") } }