Files
minstrel/internal/api/admin_library_missing_wants_test.go
T
bvandeusenandClaude Opus 5.5 08a2c06b85 docs: api comments say what the endpoints do, not how they came to be (#6277)
Rewrites the internal/api comment blocks to rule 32: task, milestone and
rule ids gone, the stories behind them restated as the constraint they
left, stale references corrected (the stream secret is wired from config,
the timezone handler already refreshes the scheduler, the Android app is
the native client, the design docs cited are not in the repo). Also
rewraps comment lines over 80 columns left by the earlier batches.

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

85 lines
3.1 KiB
Go

package api
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/jackc/pgx/v5/pgtype"
)
// seedMissingWant marks a track's file missing for two days and puts its
// album on the wanted list, held at heldDaysAgo (0 for an open want) and
// last searched with nothing found.
func seedMissingWant(t *testing.T, h *handlers, trackID, albumID pgtype.UUID, group string, heldDaysAgo int) string {
t.Helper()
ctx := context.Background()
if _, err := h.pool.Exec(ctx,
`UPDATE tracks SET missing_since = now() - interval '2 days' WHERE id = $1`, trackID); err != nil {
t.Fatalf("mark missing: %v", err)
}
if _, err := h.pool.Exec(ctx, `DELETE FROM wants WHERE release_group_mbid = $1`, group); err != nil {
t.Fatalf("clear want: %v", err)
}
var id pgtype.UUID
if err := h.pool.QueryRow(ctx,
`INSERT INTO wants (release_group_mbid, artist_mbid, artist_name, title, reason, album_id,
wanted_at, fulfilled_at, searched_at, search_outcome)
VALUES ($1, 'artist-'||$1, 'Artist', 'Album '||$1, 'library', $2,
now() - interval '30 days',
CASE WHEN $3::int > 0 THEN now() - make_interval(days => $3::int) END,
now() - interval '1 hour', 'nothing')
RETURNING id`, group, albumID, heldDaysAgo).Scan(&id); err != nil {
t.Fatalf("insert want: %v", err)
}
return uuidToString(id)
}
// A folder's album that was held before its files went is not wanted back
// yet (every library album is on the list, held); an open want comes with
// its search, so the Missing page can show it and act on it.
func TestListMissingTracks_WantState(t *testing.T) {
h, pool := testHandlers(t)
truncateLibrary(t, pool)
admin := seedUser(t, pool, "admin", "pw", true)
heldTrack, _ := seedTrackOnDisk(t, h, "missheld")
openTrack, _ := seedTrackOnDisk(t, h, "missopen")
seedMissingWant(t, h, heldTrack.ID, heldTrack.AlbumID, "rg-missing-held", 10)
openID := seedMissingWant(t, h, openTrack.ID, openTrack.AlbumID, "rg-missing-open", 0)
req := withUser(httptest.NewRequest(http.MethodGet, "/api/admin/library/missing", nil), admin)
w := httptest.NewRecorder()
h.handleListMissingTracks(w, req)
if w.Code != http.StatusOK {
t.Fatalf("status %d: %s", w.Code, w.Body.String())
}
var resp adminMissingResponse
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatalf("decode: %v", err)
}
if len(resp.Groups) != 2 {
t.Fatalf("groups = %d, want 2", len(resp.Groups))
}
byTitle := map[string]missingGroupView{}
for _, g := range resp.Groups {
byTitle[g.Tracks[0].Title] = g
}
if r := byTitle["AdmQ Track missheld"].Reacquisition; r != nil {
t.Errorf("held before the loss: reacquisition = %+v, want none", r)
}
r := byTitle["AdmQ Track missopen"].Reacquisition
if r == nil || r.WantedAt == nil || r.HeldAt != nil {
t.Fatalf("open want: reacquisition = %+v, want wanted and not held", r)
}
if r.Want == nil || r.Want.ID != openID {
t.Fatalf("open want: want = %+v, want id %s", r.Want, openID)
}
if r.Want.Search == nil || r.Want.Search.Outcome != "nothing" {
t.Errorf("open want: search = %+v, want outcome nothing", r.Want.Search)
}
}