Files
minstrel/internal/api/admin_summary_test.go
T
bvandeusenandClaude Opus 5.5 ace7e22e6a
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m37s
release / integration (push) Successful in 5m10s
release / android (push) Successful in 5m16s
release / Build signed APK (releases and dev) (push) Successful in 5m27s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 24s
release / Verify release artifacts (tag releases only) (push) Skipped
feat: Admin is a left rail with how many wait on you in each queue, and the Overview opens with a verdict, the queues that need you and since when, then the clear ones on one line (M503 #5605)
- GET /api/admin/summary: every admin queue (requests, reported tracks,
  playback errors, duplicates, suspect sources, missing files) with its
  count and the age of its oldest item, in one query.
- The admin layout drops the 11-tab strip for SectionRail, as Settings and
  the Collection have, with each queue's count as its badge; the counts
  refresh on each admin navigation and every 30s.
- The Overview leads with "Nothing needs you." or "N things need you.",
  lists each waiting queue with "oldest 3d ago" and a link to it, counts a
  failed library scan as a problem, and names the empty queues on one line.
  The request and quarantine previews and the stat tiles are gone; those
  queues are worked on their own pages. A failed summary says so with Try
  again instead of reading as all-clear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:58:13 -04:00

65 lines
1.9 KiB
Go

package api
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/go-chi/chi/v5"
"git.fabledsword.com/bvandeusen/minstrel/internal/auth"
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
)
func getAdminSummary(t *testing.T, h *handlers, user dbq.User) (int, adminSummaryView) {
t.Helper()
r := chi.NewRouter()
r.Route("/api/admin", func(admin chi.Router) {
admin.Use(auth.RequireAdmin())
admin.Get("/summary", h.handleGetAdminSummary)
})
w := httptest.NewRecorder()
r.ServeHTTP(w, withUser(httptest.NewRequest(http.MethodGet, "/api/admin/summary", nil), user))
var out adminSummaryView
if w.Code == http.StatusOK {
if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil {
t.Fatal(err)
}
}
return w.Code, out
}
// The summary counts each queue an admin acts on and says since when the
// oldest item has waited; an empty queue has no since (#5605).
func TestAdminSummary_CountsTheQueuesAndSinceWhen(t *testing.T) {
h, _ := testHandlersWithClientFn(t)
admin := seedUser(t, h.pool, "admin", "pw", true)
listener := seedUser(t, h.pool, "listener", "pw", false)
ctx := context.Background()
code, empty := getAdminSummary(t, h, admin)
if code != http.StatusOK {
t.Fatalf("status = %d", code)
}
if empty.Requests.Count != 0 || empty.Requests.Since != nil || empty.Missing.Count != 0 {
t.Errorf("empty summary = %+v", empty)
}
if _, err := dbq.New(h.pool).CreateRequest(ctx, dbq.CreateRequestParams{
UserID: listener.ID, Kind: dbq.RequestKindArtist, ArtistMbid: "a0000000-0000-4000-8000-000000000001",
ArtistName: "Annadale",
}); err != nil {
t.Fatal(err)
}
_, got := getAdminSummary(t, h, admin)
if got.Requests.Count != 1 || got.Requests.Since == nil {
t.Errorf("requests = %+v, want 1 with a since", got.Requests)
}
if code, _ := getAdminSummary(t, h, listener); code != http.StatusForbidden {
t.Errorf("a listener got %d, want 403", code)
}
}