package lidarr import ( "context" "encoding/json" "errors" "io" "net/http" "testing" ) func TestListUnmappedTrackFiles(t *testing.T) { c, srv := newTestClient(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/v1/trackfile" || r.URL.Query().Get("unmapped") != "true" { t.Errorf("request = %s?%s, want /api/v1/trackfile?unmapped=true", r.URL.Path, r.URL.RawQuery) } _, _ = w.Write([]byte(`[{"id":7,"path":"/music/A/B (2017)/A - B - 02 - X.mp3","albumId":0}]`)) }) defer srv.Close() got, err := c.ListUnmappedTrackFiles(context.Background()) if err != nil { t.Fatalf("ListUnmappedTrackFiles: %v", err) } if len(got) != 1 || got[0].ID != 7 || got[0].Path != "/music/A/B (2017)/A - B - 02 - X.mp3" { t.Errorf("got %+v", got) } } func TestReleaseReads(t *testing.T) { c, srv := newTestClient(func(w http.ResponseWriter, r *http.Request) { switch { case r.URL.Path == "/api/v1/album/4723": _, _ = w.Write([]byte(`{"id":4723,"releases":[ {"id":10148,"title":"Humanz","format":"14x12\" Vinyl, Digital Media","trackCount":68,"mediumCount":15,"monitored":true}, {"id":10149,"title":"Humanz","format":"Digital Media","trackCount":40,"mediumCount":1,"monitored":false}]}`)) case r.URL.Path == "/api/v1/track" && r.URL.Query().Get("albumId") == "4723": _, _ = w.Write([]byte(`[{"id":1,"title":"Ascension","mediumNumber":1,"trackFileId":9}]`)) case r.URL.Path == "/api/v1/track" && r.URL.Query().Get("albumReleaseId") == "10149": _, _ = w.Write([]byte(`[{"id":2,"title":"Ascension","mediumNumber":1,"trackFileId":0}]`)) default: t.Errorf("unexpected request %s?%s", r.URL.Path, r.URL.RawQuery) w.WriteHeader(http.StatusNotFound) } }) defer srv.Close() ctx := context.Background() rels, err := c.GetAlbumReleases(ctx, 4723) if err != nil { t.Fatalf("GetAlbumReleases: %v", err) } if len(rels) != 2 || !rels[0].Monitored || rels[0].MediumCount != 15 || rels[1].TrackCount != 40 { t.Errorf("releases = %+v", rels) } tr, err := c.ListAlbumTracks(ctx, 4723) if err != nil || len(tr) != 1 || tr[0].TrackFileID != 9 { t.Errorf("ListAlbumTracks = %+v, %v", tr, err) } tr, err = c.ListReleaseTracks(ctx, 10149) if err != nil || len(tr) != 1 || tr[0].Title != "Ascension" { t.Errorf("ListReleaseTracks = %+v, %v", tr, err) } } // The PUT carries the whole resource back, with only the releases' monitored // flags changed: exactly the chosen release is monitored, and a field Minstrel // does not model survives the round trip. func TestSetMonitoredRelease_RoundTripsTheResource(t *testing.T) { var put map[string]any c, srv := newTestClient(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/v1/album/4723" { t.Errorf("path = %q", r.URL.Path) } switch r.Method { case http.MethodGet: _, _ = w.Write([]byte(`{"id":4723,"anyReleaseOk":false,"secondaryTypes":["Studio"],"releases":[ {"id":10148,"monitored":true},{"id":10149,"monitored":false}]}`)) case http.MethodPut: b, _ := io.ReadAll(r.Body) if err := json.Unmarshal(b, &put); err != nil { t.Errorf("PUT body: %v", err) } w.WriteHeader(http.StatusAccepted) } }) defer srv.Close() if err := c.SetMonitoredRelease(context.Background(), 4723, 10149); err != nil { t.Fatalf("SetMonitoredRelease: %v", err) } rels := put["releases"].([]any) if m := rels[0].(map[string]any)["monitored"]; m != false { t.Errorf("old release monitored = %v, want false", m) } if m := rels[1].(map[string]any)["monitored"]; m != true { t.Errorf("new release monitored = %v, want true", m) } if st, _ := put["secondaryTypes"].([]any); len(st) != 1 || st[0] != "Studio" { t.Errorf("secondaryTypes = %v, want it carried through unchanged", put["secondaryTypes"]) } } func TestSetMonitoredRelease_UnknownReleaseSendsNothing(t *testing.T) { c, srv := newTestClient(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPut { t.Error("PUT sent for a release the album does not have") } _, _ = w.Write([]byte(`{"id":4723,"releases":[{"id":10148,"monitored":true}]}`)) }) defer srv.Close() if err := c.SetMonitoredRelease(context.Background(), 4723, 999); !errors.Is(err, ErrNotFound) { t.Errorf("err = %v, want ErrNotFound", err) } } func TestSearchAlbums_PostsTheCommand(t *testing.T) { var got map[string]any c, srv := newTestClient(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost || r.URL.Path != "/api/v1/command" { t.Errorf("request = %s %s, want POST /api/v1/command", r.Method, r.URL.Path) } b, _ := io.ReadAll(r.Body) _ = json.Unmarshal(b, &got) w.WriteHeader(http.StatusCreated) _, _ = w.Write([]byte(`{"id":1,"name":"AlbumSearch"}`)) }) defer srv.Close() if err := c.SearchAlbums(context.Background(), []int{4723, 12}); err != nil { t.Fatalf("SearchAlbums: %v", err) } ids, _ := got["albumIds"].([]any) if got["name"] != "AlbumSearch" || len(ids) != 2 || ids[0] != float64(4723) || ids[1] != float64(12) { t.Errorf("command = %v", got) } }