package tracking_test import ( "os" "path/filepath" "testing" "time" "github.com/jfraeys/fetch_ml/internal/manifest" "github.com/jfraeys/fetch_ml/internal/worker" ) // TestManifestEnvironmentCapture verifies that RunManifest.Environment // is populated on every scan with ConfigHash and DetectionMethod. func TestManifestEnvironmentCapture(t *testing.T) { t.Run("EnvironmentPopulatedInManifest", func(t *testing.T) { // Create config cfg := &worker.Config{ ComplianceMode: "standard", MaxWorkers: 4, GPUVendor: "nvidia", Sandbox: worker.SandboxConfig{ NetworkMode: "none", SeccompProfile: "default-hardened", }, } // Compute expected config hash configHash, err := cfg.ComputeResolvedConfigHash() if err != nil { t.Fatalf("ComputeResolvedConfigHash failed: %v", err) } // Perform GPU detection to get detection method factory := &worker.GPUDetectorFactory{} result := factory.CreateDetectorWithInfo(cfg) detectionMethod := result.Info.DetectionMethod // Create manifest with environment info created := time.Now().UTC() m := manifest.NewRunManifest("run-env-test", "task-env", "job-env", created) m.Environment = &manifest.ExecutionEnvironment{ ConfigHash: configHash, GPUDetectionMethod: string(detectionMethod), GPUCount: 1, MaxWorkers: cfg.MaxWorkers, SandboxNetworkMode: cfg.Sandbox.NetworkMode, SandboxNoNewPrivs: cfg.Sandbox.NoNewPrivileges, ComplianceMode: cfg.ComplianceMode, } // R.1: Environment must be populated if m.Environment == nil { t.Fatal("Environment is nil") } // R.1: Environment.ConfigHash must be non-empty if m.Environment.ConfigHash == "" { t.Error("Environment.ConfigHash is empty") } // R.1: Environment.DetectionMethod must be non-empty if m.Environment.GPUDetectionMethod == "" { t.Error("Environment.DetectionMethod is empty") } // Verify ConfigHash matches expected value if m.Environment.ConfigHash != configHash { t.Errorf("ConfigHash mismatch: got %q, want %q", m.Environment.ConfigHash, configHash) } // Verify DetectionMethod matches if m.Environment.GPUDetectionMethod != string(detectionMethod) { t.Errorf("DetectionMethod mismatch: got %q, want %q", m.Environment.GPUDetectionMethod, detectionMethod) } // Scan artifacts 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("results/metrics.jsonl", []byte("metrics")) mustWrite("checkpoints/best.pt", []byte("checkpoint")) caps := &worker.SandboxConfig{ MaxArtifactFiles: 100, MaxArtifactTotalBytes: 1024 * 1024 * 1024, } arts, err := worker.ScanArtifacts(runDir, false, caps) if err != nil { t.Fatalf("ScanArtifacts failed: %v", err) } // Attach artifacts to manifest m.Artifacts = arts // Write and reload manifest dir := t.TempDir() if err := m.WriteToDir(dir); err != nil { t.Fatalf("WriteToDir failed: %v", err) } loaded, err := manifest.LoadFromDir(dir) if err != nil { t.Fatalf("LoadFromDir failed: %v", err) } // Verify environment persisted if loaded.Environment == nil { t.Fatal("Environment not persisted in manifest") } if loaded.Environment.ConfigHash != configHash { t.Errorf("loaded ConfigHash = %q, want %q", loaded.Environment.ConfigHash, configHash) } if loaded.Environment.GPUDetectionMethod != string(detectionMethod) { t.Errorf("loaded DetectionMethod = %q, want %q", loaded.Environment.GPUDetectionMethod, detectionMethod) } }) t.Run("EnvironmentRequiredFields", func(t *testing.T) { env := &manifest.ExecutionEnvironment{ ConfigHash: "required-hash", GPUDetectionMethod: "config", MaxWorkers: 4, SandboxNetworkMode: "none", SandboxNoNewPrivs: true, } // Verify required fields _ = env.MaxWorkers _ = env.SandboxNoNewPrivs if env.ConfigHash == "" { t.Error("ConfigHash is required") } if env.GPUDetectionMethod == "" { t.Error("DetectionMethod is required") } if env.SandboxNetworkMode == "" { t.Error("SandboxNetworkMode is required") } }) }