package unraid import ( "testing" "git.mchus.pro/mchus/logpile/internal/parser" ) func TestDetect(t *testing.T) { tests := []struct { name string files []parser.ExtractedFile wantMin int wantMax int shouldFind bool }{ { name: "typical unraid diagnostics", files: []parser.ExtractedFile{ { Path: "box3-diagnostics-20260205-2333/unraid-7.2.0.txt", Content: []byte("7.2.0\n"), }, { Path: "box3-diagnostics-20260205-2333/system/vars.txt", Content: []byte("[parity] => Array\n[disk1] => Array\n"), }, }, wantMin: 50, wantMax: 100, shouldFind: true, }, { name: "unraid with kernel marker", files: []parser.ExtractedFile{ { Path: "diagnostics/system/lscpu.txt", Content: []byte("Unraid kernel build 6.12.54"), }, }, wantMin: 50, wantMax: 100, shouldFind: true, }, { name: "not unraid", files: []parser.ExtractedFile{ { Path: "some/random/file.txt", Content: []byte("just some random content"), }, }, wantMin: 0, wantMax: 0, shouldFind: false, }, } p := &Parser{} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := p.Detect(tt.files) if tt.shouldFind && got < tt.wantMin { t.Errorf("Detect() = %v, want at least %v", got, tt.wantMin) } if got > tt.wantMax { t.Errorf("Detect() = %v, want at most %v", got, tt.wantMax) } if !tt.shouldFind && got > 0 { t.Errorf("Detect() = %v, want 0 (should not detect)", got) } }) } } func TestParse_Version(t *testing.T) { files := []parser.ExtractedFile{ { Path: "unraid-7.2.0.txt", Content: []byte("7.2.0\n"), }, } p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse() error = %v", err) } if len(result.Hardware.Firmware) == 0 { t.Fatal("expected firmware info") } fw := result.Hardware.Firmware[0] if fw.DeviceName != "Unraid OS" { t.Errorf("DeviceName = %v, want 'Unraid OS'", fw.DeviceName) } if fw.Version != "7.2.0" { t.Errorf("Version = %v, want '7.2.0'", fw.Version) } } func TestParse_CPU(t *testing.T) { lscpuContent := `Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit CPU(s): 16 Model name: Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz Core(s) per socket: 8 Socket(s): 1 CPU max MHz: 3400.0000 ` files := []parser.ExtractedFile{ { Path: "diagnostics/system/lscpu.txt", Content: []byte(lscpuContent), }, } p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse() error = %v", err) } if len(result.Hardware.CPUs) == 0 { t.Fatal("expected CPU info") } cpu := result.Hardware.CPUs[0] if cpu.Model != "Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz" { t.Errorf("Model = %v", cpu.Model) } if cpu.Cores != 8 { t.Errorf("Cores = %v, want 8", cpu.Cores) } if cpu.Threads != 16 { t.Errorf("Threads = %v, want 16", cpu.Threads) } if cpu.FrequencyMHz != 3400 { t.Errorf("FrequencyMHz = %v, want 3400", cpu.FrequencyMHz) } } func TestParse_Memory(t *testing.T) { memContent := ` total used free shared buff/cache available Mem: 50Gi 11Gi 1.4Gi 565Mi 39Gi 39Gi Swap: 0B 0B 0B Total: 50Gi 11Gi 1.4Gi ` files := []parser.ExtractedFile{ { Path: "diagnostics/system/memory.txt", Content: []byte(memContent), }, } p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse() error = %v", err) } if len(result.Hardware.Memory) == 0 { t.Fatal("expected memory info") } mem := result.Hardware.Memory[0] expectedSizeMB := 50 * 1024 // 50 GiB in MB if mem.SizeMB != expectedSizeMB { t.Errorf("SizeMB = %v, want %v", mem.SizeMB, expectedSizeMB) } if mem.Type != "DRAM" { t.Errorf("Type = %v, want 'DRAM'", mem.Type) } } func TestParse_SMART(t *testing.T) { smartContent := `smartctl 7.5 2025-04-30 r5714 [x86_64-linux-6.12.54-Unraid] (local build) Copyright (C) 2002-25, Bruce Allen, Christian Franke, www.smartmontools.org === START OF INFORMATION SECTION === Device Model: ST4000NM000B-2TF100 Serial Number: WX103EC9 LU WWN Device Id: 5 000c50 0ed59db60 Firmware Version: TNA1 User Capacity: 4,000,787,030,016 bytes [4.00 TB] Sector Size: 512 bytes logical/physical Rotation Rate: 7200 rpm Form Factor: 3.5 inches SATA Version is: SATA 3.3, 6.0 Gb/s (current: 6.0 Gb/s) === START OF READ SMART DATA SECTION === SMART overall-health self-assessment test result: PASSED ` files := []parser.ExtractedFile{ { Path: "diagnostics/smart/ST4000NM000B-2TF100_WX103EC9-20260205-2333 disk1 (sdi).txt", Content: []byte(smartContent), }, } p := &Parser{} result, err := p.Parse(files) if err != nil { t.Fatalf("Parse() error = %v", err) } if len(result.Hardware.Storage) == 0 { t.Fatal("expected storage info") } disk := result.Hardware.Storage[0] if disk.Model != "ST4000NM000B-2TF100" { t.Errorf("Model = %v, want 'ST4000NM000B-2TF100'", disk.Model) } if disk.SerialNumber != "WX103EC9" { t.Errorf("SerialNumber = %v, want 'WX103EC9'", disk.SerialNumber) } if disk.Firmware != "TNA1" { t.Errorf("Firmware = %v, want 'TNA1'", disk.Firmware) } if disk.SizeGB != 4000 { t.Errorf("SizeGB = %v, want 4000", disk.SizeGB) } if disk.Type != "hdd" { t.Errorf("Type = %v, want 'hdd'", disk.Type) } // Check that no health warnings were generated (PASSED health) healthWarnings := 0 for _, event := range result.Events { if event.EventType == "Disk Health" && event.Severity == "warning" { healthWarnings++ } } if healthWarnings != 0 { t.Errorf("Expected no health warnings for PASSED disk, got %v", healthWarnings) } } func TestParser_Metadata(t *testing.T) { p := &Parser{} if p.Name() != "Unraid Parser" { t.Errorf("Name() = %v, want 'Unraid Parser'", p.Name()) } if p.Vendor() != "unraid" { t.Errorf("Vendor() = %v, want 'unraid'", p.Vendor()) } if p.Version() == "" { t.Error("Version() should not be empty") } }