package worker_test import ( "os" "path/filepath" "slices" "testing" "github.com/jfraeys/fetch_ml/internal/worker" ) // TestScanExclusionsRecorded validates that scan exclusions are recorded in the manifest func TestScanExclusionsRecorded(t *testing.T) { runDir := t.TempDir() mustWrite := func(rel string, data []byte) { p := filepath.Join(runDir, rel) if err := os.MkdirAll(filepath.Dir(p), 0750); err != nil { t.Fatalf("mkdir: %v", err) } if err := os.WriteFile(p, data, 0600); err != nil { t.Fatalf("write file: %v", err) } } mustWrite("run_manifest.json", []byte("{}")) mustWrite("output.log", []byte("log")) mustWrite("code/ignored.txt", []byte("ignore")) mustWrite("snapshot/ignored.bin", []byte("ignore")) mustWrite("results/metrics.jsonl", []byte("m")) mustWrite("checkpoints/best.pt", []byte("checkpoint")) mustWrite("plots/loss.png", []byte("png")) art, err := worker.ScanArtifacts(runDir, false, nil) if err != nil { t.Fatalf("scanArtifacts: %v", err) } if art == nil { t.Fatalf("expected artifacts") } paths := make([]string, 0, len(art.Files)) var total int64 for _, f := range art.Files { paths = append(paths, f.Path) total += f.SizeBytes } want := []string{ "checkpoints/best.pt", "plots/loss.png", "results/metrics.jsonl", } if len(paths) != len(want) { t.Fatalf("expected %d files, got %d: %v", len(want), len(paths), paths) } for i := range want { if paths[i] != want[i] { t.Fatalf("expected paths[%d]=%q, got %q", i, want[i], paths[i]) } } if art.TotalSizeBytes != total { t.Fatalf("expected total_size_bytes=%d, got %d", total, art.TotalSizeBytes) } if art.DiscoveryTime.IsZero() { t.Fatalf("expected discovery_time") } // R.5: Verify exclusions are recorded if len(art.Exclusions) == 0 { t.Fatal("expected exclusions to be recorded, got none") } // Build map of excluded paths to reasons exclusionMap := make(map[string]string) for _, ex := range art.Exclusions { exclusionMap[ex.Path] = ex.Reason } // Verify specific exclusions are recorded with correct reasons // Note: When directories are excluded with fs.SkipDir, files inside are not walked // so only the directory itself is recorded as excluded wantExclusions := map[string]string{ "run_manifest.json": "manifest file excluded", "output.log": "log files excluded", "code": "source directory excluded", "snapshot": "snapshot directory excluded", } for path, wantReason := range wantExclusions { reason, found := exclusionMap[path] if !found { t.Errorf("expected exclusion for %q not found", path) continue } if reason != wantReason { t.Errorf("exclusion reason for %q: got %q, want %q", path, reason, wantReason) } } // Verify no unexpected exclusions allowedExclusions := []string{ "run_manifest.json", "output.log", "code", "snapshot", } for path := range exclusionMap { if !slices.Contains(allowedExclusions, path) { t.Errorf("unexpected exclusion: %q", path) } } }