package main import ( "os" "path/filepath" "testing" "git.mchus.pro/mchus/logpile/internal/exporter" "git.mchus.pro/mchus/logpile/internal/models" ) func TestIsAuditCandidate(t *testing.T) { tests := []struct { name string path string includePlain bool want bool }{ {name: "tar gzip", path: "dump.tar.gz", want: true}, {name: "zip", path: "dump.zip", want: true}, {name: "plain log excluded", path: "component.log", want: false}, {name: "plain log requested", path: "nvidia-bug-report.log", includePlain: true, want: true}, {name: "JSON report excluded", path: "report.json", want: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := isAuditCandidate(tt.path, tt.includePlain); got != tt.want { t.Fatalf("isAuditCandidate(%q, %v) = %v, want %v", tt.path, tt.includePlain, got, tt.want) } }) } } func TestCPUOnlyReanimatorPayloadPreservesRequiredFields(t *testing.T) { payload := &exporter.ReanimatorExport{ Filename: "dump.tar.gz", CollectedAt: "2026-07-27T10:34:40Z", Hardware: exporter.ReanimatorHardware{ Board: exporter.ReanimatorBoard{SerialNumber: "23E102624"}, CPUs: []exporter.ReanimatorCPU{{Socket: 0, SerialNumber: "D46E5D6B1D3E40E1"}}, Firmware: []exporter.ReanimatorFirmware{{DeviceName: "BIOS", Version: "1.0"}}, }, } got := cpuOnlyReanimatorPayload(payload) if got.CollectedAt == "" || got.Hardware.Board.SerialNumber == "" || len(got.Hardware.CPUs) != 1 { t.Fatalf("required ingest fields were lost: %+v", got) } if len(got.Hardware.Firmware) != 0 { t.Fatalf("expected non-CPU hardware to be removed: %+v", got.Hardware.Firmware) } } func TestFlatReanimatorName(t *testing.T) { got := flatReanimatorName("v1", "NL/example/dump.tar.gz") if got != "v1__dump.tar.gz.reanimator.json" { t.Fatalf("unexpected flat name %q", got) } } func TestBuildCPUAudit(t *testing.T) { tests := []struct { name string cpu models.CPU finding string promoted bool expectedSer string }{ { name: "PPIN promoted", cpu: models.CPU{Socket: 0, PPIN: "D46E5D6B1D3E40E1", SerialNumber: "D46E5D6B1D3E40E1"}, finding: "ppin_used_as_serial", promoted: true, expectedSer: "D46E5D6B1D3E40E1", }, { name: "regression detected", cpu: models.CPU{Socket: 1, PPIN: "D44F8D6B9155EE0E"}, finding: "missing_serial_with_ppin", expectedSer: "D44F8D6B9155EE0E", }, { name: "placeholder serial with PPIN", cpu: models.CPU{Socket: 1, PPIN: "D44F8D6B9155EE0E", SerialNumber: "Unknown"}, finding: "missing_serial_with_ppin", expectedSer: "D44F8D6B9155EE0E", }, { name: "native serial", cpu: models.CPU{Socket: 0, SerialNumber: "CPU-SERIAL"}, finding: "source_serial_present", expectedSer: "CPU-SERIAL", }, { name: "placeholder PPIN", cpu: models.CPU{Socket: 0, PPIN: "N/A"}, finding: "cpu_identity_missing", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := buildCPUAudit(tt.cpu) if got.Finding != tt.finding || got.PPINPromoted != tt.promoted || got.ExpectedSerialNumber != tt.expectedSer { t.Fatalf("unexpected audit: %+v", got) } }) } } func TestRunAuditWritesFailureReportAndSummary(t *testing.T) { input := t.TempDir() output := t.TempDir() badArchive := filepath.Join(input, "bad.zip") if err := os.WriteFile(badArchive, []byte("not a zip"), 0o644); err != nil { t.Fatalf("write fixture: %v", err) } summary, err := runAudit(input, output, 1, false) if err != nil { t.Fatalf("runAudit failed: %v", err) } if summary.FilesFound != 1 || summary.FilesFailed != 1 || summary.FilesParsed != 0 { t.Fatalf("unexpected summary: %+v", summary) } for _, name := range []string{"bad.zip.cpu-audit.json", "_summary.json"} { if _, err := os.Stat(filepath.Join(output, name)); err != nil { t.Fatalf("expected %s: %v", name, err) } } }