package experiment import ( "os" "path/filepath" "testing" "time" "github.com/jfraeys/fetch_ml/internal/experiment" ) func findArchivedExperiment(t *testing.T, basePath, commitID string) string { t.Helper() archiveRoot := filepath.Join(basePath, "archive") var found string _ = filepath.WalkDir(archiveRoot, func(path string, d os.DirEntry, err error) error { if err != nil { return nil } if d.IsDir() && filepath.Base(path) == commitID { found = path return filepath.SkipDir } return nil }) return found } const ( experimentsPath = "/experiments" testCommitID = "abc123" ) func TestNewManager(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) // Test that manager was created successfully by checking it can generate paths path := manager.GetExperimentPath("test") if path == "" { t.Error("Manager should be able to generate paths") } } func TestGetExperimentPath(t *testing.T) { t.Parallel() // Enable parallel execution const experimentsPath = "/experiments" const testCommitID = "abc123" basePath := experimentsPath manager := experiment.NewManager(basePath) commitID := testCommitID expectedPath := filepath.Join(basePath, commitID) actualPath := manager.GetExperimentPath(commitID) if actualPath != expectedPath { t.Errorf("Expected path %s, got %s", expectedPath, actualPath) } } func TestGetFilesPath(t *testing.T) { t.Parallel() // Enable parallel execution basePath := experimentsPath manager := experiment.NewManager(basePath) commitID := testCommitID expectedPath := filepath.Join(basePath, commitID, "files") actualPath := manager.GetFilesPath(commitID) if actualPath != expectedPath { t.Errorf("Expected path %s, got %s", expectedPath, actualPath) } } func TestGetMetadataPath(t *testing.T) { t.Parallel() // Enable parallel execution basePath := experimentsPath manager := experiment.NewManager(basePath) commitID := testCommitID expectedPath := filepath.Join(basePath, commitID, "meta.bin") actualPath := manager.GetMetadataPath(commitID) if actualPath != expectedPath { t.Errorf("Expected path %s, got %s", expectedPath, actualPath) } } func TestExperimentExists(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) // Test non-existent experiment if manager.ExperimentExists("nonexistent") { t.Error("Experiment should not exist") } // Create experiment directory commitID := testCommitID experimentPath := manager.GetExperimentPath(commitID) err := os.MkdirAll(experimentPath, 0750) if err != nil { t.Fatalf("Failed to create experiment directory: %v", err) } // Test existing experiment if !manager.ExperimentExists(commitID) { t.Error("Experiment should exist") } } func TestCreateExperiment(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) commitID := testCommitID err := manager.CreateExperiment(commitID) if err != nil { t.Fatalf("Failed to create experiment: %v", err) } // Verify experiment directory exists if !manager.ExperimentExists(commitID) { t.Error("Experiment should exist after creation") } // Verify files directory exists filesPath := manager.GetFilesPath(commitID) info, err := os.Stat(filesPath) if err != nil { t.Fatalf("Files directory should exist: %v", err) } if !info.IsDir() { t.Error("Files path should be a directory") } } func TestWriteAndReadMetadata(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) commitID := testCommitID originalMetadata := &experiment.Metadata{ CommitID: commitID, Timestamp: time.Now().Unix(), JobName: "test_experiment", User: "testuser", } // Create experiment first err := manager.CreateExperiment(commitID) if err != nil { t.Fatalf("Failed to create experiment: %v", err) } // Write metadata err = manager.WriteMetadata(originalMetadata) if err != nil { t.Fatalf("Failed to write metadata: %v", err) } // Read metadata loadedMetadata, err := manager.ReadMetadata(commitID) if err != nil { t.Fatalf("Failed to read metadata: %v", err) } // Verify metadata if loadedMetadata.CommitID != originalMetadata.CommitID { t.Errorf("Expected commit ID %s, got %s", originalMetadata.CommitID, loadedMetadata.CommitID) } if loadedMetadata.Timestamp != originalMetadata.Timestamp { t.Errorf("Expected timestamp %d, got %d", originalMetadata.Timestamp, loadedMetadata.Timestamp) } if loadedMetadata.JobName != originalMetadata.JobName { t.Errorf("Expected job name %s, got %s", originalMetadata.JobName, loadedMetadata.JobName) } if loadedMetadata.User != originalMetadata.User { t.Errorf("Expected user %s, got %s", originalMetadata.User, loadedMetadata.User) } } func TestReadMetadataNonExistent(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) // Try to read metadata from non-existent experiment _, err := manager.ReadMetadata("nonexistent") if err == nil { t.Error("Expected error when reading metadata from non-existent experiment") } } func TestWriteMetadataNonExistentDir(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) commitID := testCommitID metadata := &experiment.Metadata{ CommitID: commitID, Timestamp: time.Now().Unix(), JobName: "test_experiment", User: "testuser", } // Try to write metadata without creating experiment directory first err := manager.WriteMetadata(metadata) if err == nil { t.Error("Expected error when writing metadata to non-existent experiment") } } func TestListExperiments(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) // Create multiple experiments experiments := []string{"abc123", "def456", "ghi789"} for _, commitID := range experiments { err := manager.CreateExperiment(commitID) if err != nil { t.Fatalf("Failed to create experiment %s: %v", commitID, err) } } // List experiments experimentList, err := manager.ListExperiments() if err != nil { t.Fatalf("Failed to list experiments: %v", err) } if len(experimentList) != 3 { t.Errorf("Expected 3 experiments, got %d", len(experimentList)) } // Verify all experiments are listed for _, commitID := range experiments { found := false for _, exp := range experimentList { if exp == commitID { found = true break } } if !found { t.Errorf("Experiment %s not found in list", commitID) } } } func TestPruneExperiments(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) // Create experiments with different timestamps now := time.Now() experiments := []struct { commitID string timestamp int64 }{ {"old1", now.AddDate(0, 0, -10).Unix()}, {"old2", now.AddDate(0, 0, -5).Unix()}, {"recent", now.AddDate(0, 0, -1).Unix()}, } for _, exp := range experiments { // Create experiment directory err := manager.CreateExperiment(exp.commitID) if err != nil { t.Fatalf("Failed to create experiment %s: %v", exp.commitID, err) } // Write metadata metadata := &experiment.Metadata{ CommitID: exp.commitID, Timestamp: exp.timestamp, JobName: "experiment_" + exp.commitID, User: "testuser", } err = manager.WriteMetadata(metadata) if err != nil { t.Fatalf("Failed to write metadata for %s: %v", exp.commitID, err) } } // Prune experiments (keep 1, prune older than 3 days) pruned, err := manager.PruneExperiments(1, 3) if err != nil { t.Fatalf("Failed to prune experiments: %v", err) } // Should prune old1 and old2 (older than 3 days) if len(pruned) != 2 { t.Errorf("Expected 2 pruned experiments, got %d", len(pruned)) } // Verify recent experiment still exists if !manager.ExperimentExists("recent") { t.Error("Recent experiment should still exist") } // Verify old experiments are gone if manager.ExperimentExists("old1") { t.Error("Old experiment 1 should be pruned") } if manager.ExperimentExists("old2") { t.Error("Old experiment 2 should be pruned") } if archived := findArchivedExperiment(t, basePath, "old1"); archived == "" { t.Error("Old experiment 1 should be archived") } if archived := findArchivedExperiment(t, basePath, "old2"); archived == "" { t.Error("Old experiment 2 should be archived") } } func TestPruneExperimentsKeepCount(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) // Create experiments with different timestamps now := time.Now() experiments := []string{"exp1", "exp2", "exp3", "exp4"} for i, commitID := range experiments { // Create experiment directory err := manager.CreateExperiment(commitID) if err != nil { t.Fatalf("Failed to create experiment %s: %v", commitID, err) } // Write metadata with different timestamps (newer first) metadata := &experiment.Metadata{ CommitID: commitID, Timestamp: now.Add(-time.Duration(i) * time.Hour).Unix(), JobName: "experiment_" + commitID, User: "testuser", } err = manager.WriteMetadata(metadata) if err != nil { t.Fatalf("Failed to write metadata for %s: %v", commitID, err) } } // Prune experiments (keep 2 newest, no age limit) pruned, err := manager.PruneExperiments(2, 0) if err != nil { t.Fatalf("Failed to prune experiments: %v", err) } // Should prune 2 oldest experiments if len(pruned) != 2 { t.Errorf("Expected 2 pruned experiments, got %d", len(pruned)) } // Verify newest experiments still exist if !manager.ExperimentExists("exp1") { t.Error("Newest experiment should still exist") } if !manager.ExperimentExists("exp2") { t.Error("Second newest experiment should still exist") } // Verify oldest experiments are gone if manager.ExperimentExists("exp3") { t.Error("Old experiment 3 should be pruned") } if manager.ExperimentExists("exp4") { t.Error("Old experiment 4 should be pruned") } if archived := findArchivedExperiment(t, basePath, "exp3"); archived == "" { t.Error("Old experiment 3 should be archived") } if archived := findArchivedExperiment(t, basePath, "exp4"); archived == "" { t.Error("Old experiment 4 should be archived") } } func TestMetadataPartialFields(t *testing.T) { t.Parallel() // Enable parallel execution basePath := t.TempDir() manager := experiment.NewManager(basePath) commitID := "abc123" // Create experiment err := manager.CreateExperiment(commitID) if err != nil { t.Fatalf("Failed to create experiment: %v", err) } // Test metadata with only required fields metadata := &experiment.Metadata{ CommitID: commitID, Timestamp: time.Now().Unix(), // JobName and User are optional } err = manager.WriteMetadata(metadata) if err != nil { t.Fatalf("Failed to write metadata: %v", err) } // Read it back loadedMetadata, err := manager.ReadMetadata(commitID) if err != nil { t.Fatalf("Failed to read metadata: %v", err) } if loadedMetadata.CommitID != commitID { t.Errorf("Expected commit ID %s, got %s", commitID, loadedMetadata.CommitID) } if loadedMetadata.JobName != "" { t.Errorf("Expected empty job name, got %s", loadedMetadata.JobName) } if loadedMetadata.User != "" { t.Errorf("Expected empty user, got %s", loadedMetadata.User) } }