package webui import ( "encoding/json" "net/http/httptest" "strings" "testing" "bee/audit/internal/app" "bee/audit/internal/platform" ) func TestHandleAPISATRunDecodesBodyWithoutContentLength(t *testing.T) { globalQueue.mu.Lock() originalTasks := globalQueue.tasks globalQueue.tasks = nil globalQueue.mu.Unlock() t.Cleanup(func() { globalQueue.mu.Lock() globalQueue.tasks = originalTasks globalQueue.mu.Unlock() }) h := &handler{opts: HandlerOptions{App: &app.App{}}} req := httptest.NewRequest("POST", "/api/sat/cpu/run", strings.NewReader(`{"profile":"smoke"}`)) req.ContentLength = -1 rec := httptest.NewRecorder() h.handleAPISATRun("cpu").ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String()) } globalQueue.mu.Lock() defer globalQueue.mu.Unlock() if len(globalQueue.tasks) != 1 { t.Fatalf("tasks=%d want 1", len(globalQueue.tasks)) } if got := globalQueue.tasks[0].params.BurnProfile; got != "smoke" { t.Fatalf("burn profile=%q want smoke", got) } if got := globalQueue.tasks[0].Priority; got != taskPriorityValidate { t.Fatalf("priority=%d want %d", got, taskPriorityValidate) } } func TestHandleAPIBenchmarkNvidiaRunQueuesSelectedGPUs(t *testing.T) { globalQueue.mu.Lock() originalTasks := globalQueue.tasks globalQueue.tasks = nil globalQueue.mu.Unlock() t.Cleanup(func() { globalQueue.mu.Lock() globalQueue.tasks = originalTasks globalQueue.mu.Unlock() }) prevList := apiListNvidiaGPUs apiListNvidiaGPUs = func(_ *app.App) ([]platform.NvidiaGPU, error) { return []platform.NvidiaGPU{ {Index: 1, Name: "NVIDIA H100 PCIe"}, {Index: 3, Name: "NVIDIA H100 PCIe"}, }, nil } t.Cleanup(func() { apiListNvidiaGPUs = prevList }) h := &handler{opts: HandlerOptions{App: &app.App{}}} req := httptest.NewRequest("POST", "/api/bee-bench/nvidia/perf/run", strings.NewReader(`{"profile":"standard","gpu_indices":[1,3],"run_nccl":false}`)) rec := httptest.NewRecorder() h.handleAPIBenchmarkNvidiaRun(rec, req) if rec.Code != 200 { t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String()) } globalQueue.mu.Lock() defer globalQueue.mu.Unlock() if len(globalQueue.tasks) != 1 { t.Fatalf("tasks=%d want 1", len(globalQueue.tasks)) } task := globalQueue.tasks[0] if task.Target != "nvidia-bench-perf" { t.Fatalf("target=%q want nvidia-bench-perf", task.Target) } if got := task.params.GPUIndices; len(got) != 2 || got[0] != 1 || got[1] != 3 { t.Fatalf("gpu indices=%v want [1 3]", got) } if task.params.RunNCCL { t.Fatal("RunNCCL should reflect explicit false from request") } if task.Priority != taskPriorityBenchmark { t.Fatalf("priority=%d want %d", task.Priority, taskPriorityBenchmark) } } func TestHandleAPIBenchmarkNvidiaRunSplitsMixedGPUModels(t *testing.T) { globalQueue.mu.Lock() originalTasks := globalQueue.tasks globalQueue.tasks = nil globalQueue.mu.Unlock() t.Cleanup(func() { globalQueue.mu.Lock() globalQueue.tasks = originalTasks globalQueue.mu.Unlock() }) prevList := apiListNvidiaGPUs apiListNvidiaGPUs = func(_ *app.App) ([]platform.NvidiaGPU, error) { return []platform.NvidiaGPU{ {Index: 0, Name: "NVIDIA H100 PCIe"}, {Index: 1, Name: "NVIDIA H100 PCIe"}, {Index: 2, Name: "NVIDIA H200 NVL"}, }, nil } t.Cleanup(func() { apiListNvidiaGPUs = prevList }) h := &handler{opts: HandlerOptions{App: &app.App{}}} req := httptest.NewRequest("POST", "/api/bee-bench/nvidia/perf/run", strings.NewReader(`{"profile":"standard","gpu_indices":[0,1,2],"run_nccl":false}`)) rec := httptest.NewRecorder() h.handleAPIBenchmarkNvidiaRun(rec, req) if rec.Code != 200 { t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String()) } var resp taskRunResponse if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil { t.Fatalf("decode response: %v", err) } if len(resp.TaskIDs) != 2 { t.Fatalf("task_ids=%v want 2 items", resp.TaskIDs) } globalQueue.mu.Lock() defer globalQueue.mu.Unlock() if len(globalQueue.tasks) != 2 { t.Fatalf("tasks=%d want 2", len(globalQueue.tasks)) } if got := globalQueue.tasks[0].params.GPUIndices; len(got) != 2 || got[0] != 0 || got[1] != 1 { t.Fatalf("task[0] gpu indices=%v want [0 1]", got) } if got := globalQueue.tasks[1].params.GPUIndices; len(got) != 1 || got[0] != 2 { t.Fatalf("task[1] gpu indices=%v want [2]", got) } if got := globalQueue.tasks[0].Priority; got != taskPriorityBenchmark { t.Fatalf("task[0] priority=%d want %d", got, taskPriorityBenchmark) } if got := globalQueue.tasks[1].Priority; got != taskPriorityBenchmark { t.Fatalf("task[1] priority=%d want %d", got, taskPriorityBenchmark) } } func TestHandleAPIBenchmarkPowerFitRampQueuesBenchmarkPowerFitTasks(t *testing.T) { globalQueue.mu.Lock() originalTasks := globalQueue.tasks globalQueue.tasks = nil globalQueue.mu.Unlock() t.Cleanup(func() { globalQueue.mu.Lock() globalQueue.tasks = originalTasks globalQueue.mu.Unlock() }) prevList := apiListNvidiaGPUs apiListNvidiaGPUs = func(_ *app.App) ([]platform.NvidiaGPU, error) { return []platform.NvidiaGPU{ {Index: 0, Name: "NVIDIA H100 PCIe"}, {Index: 1, Name: "NVIDIA H100 PCIe"}, {Index: 2, Name: "NVIDIA H100 PCIe"}, }, nil } t.Cleanup(func() { apiListNvidiaGPUs = prevList }) h := &handler{opts: HandlerOptions{App: &app.App{}}} req := httptest.NewRequest("POST", "/api/bee-bench/nvidia/power/run", strings.NewReader(`{"profile":"standard","gpu_indices":[0,1,2],"ramp_up":true}`)) rec := httptest.NewRecorder() h.handleAPIBenchmarkNvidiaRunKind("nvidia-bench-power").ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String()) } globalQueue.mu.Lock() defer globalQueue.mu.Unlock() if len(globalQueue.tasks) != 3 { t.Fatalf("tasks=%d want 3", len(globalQueue.tasks)) } for i, task := range globalQueue.tasks { if task.Target != "nvidia-bench-power" { t.Fatalf("task[%d] target=%q", i, task.Target) } if task.Priority != taskPriorityBenchmark { t.Fatalf("task[%d] priority=%d want %d", i, task.Priority, taskPriorityBenchmark) } } } func TestHandleAPISATRunSplitsMixedNvidiaTaskSet(t *testing.T) { globalQueue.mu.Lock() originalTasks := globalQueue.tasks globalQueue.tasks = nil globalQueue.mu.Unlock() t.Cleanup(func() { globalQueue.mu.Lock() globalQueue.tasks = originalTasks globalQueue.mu.Unlock() }) prevList := apiListNvidiaGPUs apiListNvidiaGPUs = func(_ *app.App) ([]platform.NvidiaGPU, error) { return []platform.NvidiaGPU{ {Index: 0, Name: "NVIDIA H100 PCIe"}, {Index: 1, Name: "NVIDIA H100 PCIe"}, {Index: 2, Name: "NVIDIA H200 NVL"}, }, nil } t.Cleanup(func() { apiListNvidiaGPUs = prevList }) h := &handler{opts: HandlerOptions{App: &app.App{}}} req := httptest.NewRequest("POST", "/api/sat/nvidia-targeted-power/run", strings.NewReader(`{"profile":"acceptance","gpu_indices":[0,1,2]}`)) rec := httptest.NewRecorder() h.handleAPISATRun("nvidia-targeted-power").ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String()) } globalQueue.mu.Lock() defer globalQueue.mu.Unlock() if len(globalQueue.tasks) != 2 { t.Fatalf("tasks=%d want 2", len(globalQueue.tasks)) } if got := globalQueue.tasks[0].params.GPUIndices; len(got) != 2 || got[0] != 0 || got[1] != 1 { t.Fatalf("task[0] gpu indices=%v want [0 1]", got) } if got := globalQueue.tasks[1].params.GPUIndices; len(got) != 1 || got[0] != 2 { t.Fatalf("task[1] gpu indices=%v want [2]", got) } if got := globalQueue.tasks[0].Priority; got != taskPriorityValidate { t.Fatalf("task[0] priority=%d want %d", got, taskPriorityValidate) } if got := globalQueue.tasks[1].Priority; got != taskPriorityValidate { t.Fatalf("task[1] priority=%d want %d", got, taskPriorityValidate) } } func TestDefaultTaskPriorityOrder(t *testing.T) { got := []int{ defaultTaskPriority("install-to-ram", taskParams{}), defaultTaskPriority("audit", taskParams{}), defaultTaskPriority("cpu", taskParams{}), defaultTaskPriority("cpu", taskParams{StressMode: true}), defaultTaskPriority("nvidia-stress", taskParams{}), defaultTaskPriority("nvidia-bench-perf", taskParams{}), defaultTaskPriority("nvidia-bench-power", taskParams{}), } want := []int{ taskPriorityInstallToRAM, taskPriorityAudit, taskPriorityValidate, taskPriorityValidateStress, taskPriorityBurn, taskPriorityBenchmark, taskPriorityBenchmark, } for i := range want { if got[i] != want[i] { t.Fatalf("priority[%d]=%d want %d", i, got[i], want[i]) } } if !(got[0] > got[1] && got[1] > got[2] && got[2] > got[3] && got[3] > got[4] && got[4] > got[5] && got[5] == got[6]) { t.Fatalf("priority order=%v", got) } } func TestPushFanRingsTracksByNameAndCarriesForwardMissingSamples(t *testing.T) { h := &handler{} h.pushFanRings([]platform.FanReading{ {Name: "FAN_A", RPM: 4200}, {Name: "FAN_B", RPM: 5100}, }) h.pushFanRings([]platform.FanReading{ {Name: "FAN_B", RPM: 5200}, }) if len(h.fanNames) != 2 || h.fanNames[0] != "FAN_A" || h.fanNames[1] != "FAN_B" { t.Fatalf("fanNames=%v", h.fanNames) } aVals, _ := h.ringFans[0].snapshot() bVals, _ := h.ringFans[1].snapshot() if len(aVals) != 2 || len(bVals) != 2 { t.Fatalf("fan ring lengths: A=%d B=%d", len(aVals), len(bVals)) } if aVals[1] != 4200 { t.Fatalf("FAN_A should carry forward last value, got %v", aVals) } if bVals[1] != 5200 { t.Fatalf("FAN_B should use latest sampled value, got %v", bVals) } }