Subsonic: album/song lists (getAlbumList/2, getRandomSongs, getSongsByGenre, getNowPlaying, getStarred/2) and search (search, search2, search3)

This commit is contained in:
2026-08-23 00:08:06 -05:00
parent f40a011c46
commit a297454065
6 changed files with 742 additions and 0 deletions
+146
View File
@@ -0,0 +1,146 @@
package subsonic
import (
"net/http/httptest"
"testing"
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
)
func TestGetAlbumListTypes(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
for _, listType := range []string{"random", "newest", "highest", "frequent", "alphabeticalByName", "alphabeticalByArtist"} {
q := baseParams("alice", "password123")
q.Set("type", listType)
q.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getAlbumList.view", q)
j := decodeJSON(t, resp)
if j["status"] != "ok" {
t.Errorf("type=%s: status = %v, want ok (%v)", listType, j["status"], j)
}
}
}
func TestGetAlbumListByYear(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
q := baseParams("alice", "password123")
q.Set("type", "byYear")
q.Set("fromYear", "2000")
q.Set("toYear", "2030")
q.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getAlbumList2.view", q)
j := decodeJSON(t, resp)
list := j["albumList2"].(map[string]any)
albums, ok := list["album"].([]any)
if !ok || len(albums) == 0 {
t.Fatalf("expected at least one album in byYear 2000-2030 range, got %v", list)
}
}
func TestGetAlbumListByYearMissingParam(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
q := baseParams("alice", "password123")
q.Set("type", "byYear")
q.Set("fromYear", "2000")
resp := getPath(t, srv.URL, "/rest/getAlbumList.view", q)
x := decodeXML(t, resp)
if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrMissingParameter {
t.Fatalf("expected error 10 for missing toYear, got %+v", x)
}
}
func TestGetAlbumListMissingType(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
resp := getPath(t, srv.URL, "/rest/getAlbumList.view", baseParams("alice", "password123"))
x := decodeXML(t, resp)
if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrMissingParameter {
t.Fatalf("expected error 10, got %+v", x)
}
}
func TestGetRandomSongs(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
q := baseParams("alice", "password123")
q.Set("size", "1")
q.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getRandomSongs.view", q)
j := decodeJSON(t, resp)
songs := j["randomSongs"].(map[string]any)["song"].([]any)
if len(songs) != 1 {
t.Fatalf("randomSongs = %v, want 1", songs)
}
}
func TestGetSongsByGenre(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
q := baseParams("alice", "password123")
q.Set("genre", "Rock")
q.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getSongsByGenre.view", q)
j := decodeJSON(t, resp)
songs := j["songsByGenre"].(map[string]any)["song"].([]any)
if len(songs) != 2 {
t.Fatalf("songsByGenre = %v, want 2", songs)
}
}
func TestGetNowPlayingEmpty(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
q := baseParams("alice", "password123")
q.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getNowPlaying.view", q)
j := decodeJSON(t, resp)
if j["status"] != "ok" {
t.Fatalf("status = %v", j["status"])
}
}
func TestGetStarredAndStarred2(t *testing.T) {
s, db := newTestServer(t)
u := createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
srv := httptest.NewServer(s.Router())
defer srv.Close()
songs, err := database.ListSongs(db, 1, 0)
if err != nil || len(songs) == 0 {
t.Fatalf("ListSongs: %v %v", songs, err)
}
if err := database.Star(db, u.ID, "song", songs[0].ID); err != nil {
t.Fatal(err)
}
q := baseParams("alice", "password123")
q.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getStarred.view", q)
j := decodeJSON(t, resp)
starred := j["starred"].(map[string]any)
if s, ok := starred["song"].([]any); !ok || len(s) != 1 {
t.Fatalf("starred.song = %v, want 1", starred["song"])
}
resp2 := getPath(t, srv.URL, "/rest/getStarred2.view", q)
j2 := decodeJSON(t, resp2)
starred2 := j2["starred2"].(map[string]any)
if s, ok := starred2["song"].([]any); !ok || len(s) != 1 {
t.Fatalf("starred2.song = %v, want 1", starred2["song"])
}
}