Support bundle is now built on-the-fly when the user clicks the button,
regardless of whether other tasks are running:
- GET /export/support.tar.gz builds the bundle synchronously and streams it
directly to the client; the temp archive is removed after serving
- Remove POST /api/export/bundle and handleAPIExportBundle — the task-queue
approach meant the bundle could only be downloaded after navigating away
and back, and was blocked entirely while a long SAT test was running
- UI: single "Download Support Bundle" button; fetch+blob gives a loading
state ("Building...") while the server collects logs, then triggers the
browser download with the correct filename from Content-Disposition
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
93 lines
2.2 KiB
Go
93 lines
2.2 KiB
Go
package webui
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"bee/audit/internal/app"
|
|
"bee/audit/internal/platform"
|
|
)
|
|
|
|
func TestXrandrCommandAddsDefaultX11Env(t *testing.T) {
|
|
t.Setenv("DISPLAY", "")
|
|
t.Setenv("XAUTHORITY", "")
|
|
|
|
cmd := xrandrCommand("--query")
|
|
|
|
var hasDisplay bool
|
|
var hasXAuthority bool
|
|
for _, kv := range cmd.Env {
|
|
if kv == "DISPLAY=:0" {
|
|
hasDisplay = true
|
|
}
|
|
if kv == "XAUTHORITY=/home/bee/.Xauthority" {
|
|
hasXAuthority = true
|
|
}
|
|
}
|
|
if !hasDisplay {
|
|
t.Fatalf("DISPLAY not injected: %v", cmd.Env)
|
|
}
|
|
if !hasXAuthority {
|
|
t.Fatalf("XAUTHORITY not injected: %v", cmd.Env)
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
|
|
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)
|
|
}
|
|
}
|