Bug: the admin 'Scanning Libraries' widget fed the server's 0-1 progress straight into percent strings and bar widths, so the overall and per-library percentages capped at '1%' and the bars never filled. Both now scale by 100 (matching the setup page, which was already correct). Bug: scan state only reached clients via websocket events, so a page opened (or refreshed) mid-scan showed nothing until the next tick — and the admin widget never re-attached at all. The worker now exposes active jobs (with their library_id so rows keep their names), served as GET /api/scanner/active (admin, re-attaches the widget + polling) and GET /api/scanner/active-summary (any user, restores the sidebar indicator on load). Idle hides both, exactly as before. Annoyance: the sidebar's 'Scanning… N%' was a block element between the logo and the nav, shoving every menu entry down while a scan ran. The percent now lives inside the fixed-height logo row next to the spinner (spinner last, so growing digits extend leftward); nothing below it moves.
61 lines
1.8 KiB
Go
61 lines
1.8 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// GetActiveScanJobs backs the refresh-survival contract: a client that
|
|
// loads the page mid-scan must be able to discover pending/running jobs
|
|
// (with their library) rather than only learning about scans from
|
|
// websocket events emitted after the page opened.
|
|
func TestGetActiveScanJobs(t *testing.T) {
|
|
w := NewWorker(1, nil)
|
|
|
|
seed := map[string]*JobResult{
|
|
"running-scan": {JobID: "running-scan", Status: JobStatusRunning, LibraryID: "lib-1", Progress: 0.42},
|
|
"pending-scan": {JobID: "pending-scan", Status: JobStatusPending, LibraryID: "lib-2"},
|
|
"done-scan": {JobID: "done-scan", Status: JobStatusCompleted, LibraryID: "lib-3"},
|
|
"failed-scan": {JobID: "failed-scan", Status: JobStatusFailed},
|
|
"cancelled": {JobID: "cancelled", Status: JobStatusCancelled},
|
|
}
|
|
w.mu.Lock()
|
|
w.results = seed
|
|
w.mu.Unlock()
|
|
|
|
active := w.GetActiveScanJobs()
|
|
if len(active) != 2 {
|
|
t.Fatalf("expected 2 active jobs, got %d (%+v)", len(active), active)
|
|
}
|
|
|
|
seen := map[string]JobResult{}
|
|
for _, job := range active {
|
|
seen[job.JobID] = job
|
|
}
|
|
|
|
running, ok := seen["running-scan"]
|
|
if !ok {
|
|
t.Fatal("running scan missing from active jobs")
|
|
}
|
|
if running.LibraryID != "lib-1" {
|
|
t.Errorf("expected library_id lib-1, got %q", running.LibraryID)
|
|
}
|
|
if running.Progress != 0.42 {
|
|
t.Errorf("expected progress 0.42, got %v", running.Progress)
|
|
}
|
|
if _, ok := seen["pending-scan"]; !ok {
|
|
t.Error("pending scan missing from active jobs")
|
|
}
|
|
for _, id := range []string{"done-scan", "failed-scan", "cancelled"} {
|
|
if _, ok := seen[id]; ok {
|
|
t.Errorf("terminal job %q must not appear as active", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetActiveScanJobsEmpty(t *testing.T) {
|
|
w := NewWorker(1, nil)
|
|
if jobs := w.GetActiveScanJobs(); len(jobs) != 0 {
|
|
t.Fatalf("expected no active jobs, got %d", len(jobs))
|
|
}
|
|
}
|