package subsonic import ( "net/http/httptest" "testing" "git.noroutes.net/NoRoutes/vibetunes/internal/database" ) func TestPlaylistLifecycle(t *testing.T) { s, db := newTestServer(t) createTestUser(t, s, "alice", "password123", false) seedLibrary(t, s) srv := httptest.NewServer(s.Router()) defer srv.Close() songs, err := database.ListSongs(db, 2, 0) if err != nil || len(songs) != 2 { t.Fatalf("ListSongs: %v %v", songs, err) } // Create q := baseParams("alice", "password123") q.Set("name", "My Playlist") q.Add("songId", songs[0].ID) q.Set("f", "json") resp := getPath(t, srv.URL, "/rest/createPlaylist.view", q) j := decodeJSON(t, resp) playlist := j["playlist"].(map[string]any) if playlist["name"] != "My Playlist" { t.Fatalf("created playlist name = %v", playlist["name"]) } playlistID := playlist["id"].(string) if entrySongs, ok := playlist["entry"].([]any); !ok || len(entrySongs) != 1 { t.Fatalf("created playlist entries = %v, want 1", playlist["entry"]) } // getPlaylists lists it resp = getPath(t, srv.URL, "/rest/getPlaylists.view", q) j = decodeJSON(t, resp) playlists := j["playlists"].(map[string]any)["playlist"].([]any) if len(playlists) != 1 { t.Fatalf("getPlaylists = %v, want 1", playlists) } // getPlaylist shows the one song q2 := baseParams("alice", "password123") q2.Set("id", playlistID) q2.Set("f", "json") resp = getPath(t, srv.URL, "/rest/getPlaylist.view", q2) j = decodeJSON(t, resp) got := j["playlist"].(map[string]any) if entries, ok := got["entry"].([]any); !ok || len(entries) != 1 { t.Fatalf("getPlaylist entries = %v, want 1", got["entry"]) } // updatePlaylist: rename, add second song q3 := baseParams("alice", "password123") q3.Set("playlistId", playlistID) q3.Set("name", "Renamed") q3.Add("songIdToAdd", songs[1].ID) resp = getPath(t, srv.URL, "/rest/updatePlaylist.view", q3) x := decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("updatePlaylist failed: %+v", x) } resp = getPath(t, srv.URL, "/rest/getPlaylist.view", q2) j = decodeJSON(t, resp) got = j["playlist"].(map[string]any) if got["name"] != "Renamed" { t.Fatalf("playlist name after update = %v, want Renamed", got["name"]) } if entries, ok := got["entry"].([]any); !ok || len(entries) != 2 { t.Fatalf("entries after add = %v, want 2", got["entry"]) } // updatePlaylist: remove index 0 q4 := baseParams("alice", "password123") q4.Set("playlistId", playlistID) q4.Add("songIndexToRemove", "0") getPath(t, srv.URL, "/rest/updatePlaylist.view", q4) resp = getPath(t, srv.URL, "/rest/getPlaylist.view", q2) j = decodeJSON(t, resp) got = j["playlist"].(map[string]any) if entries, ok := got["entry"].([]any); !ok || len(entries) != 1 { t.Fatalf("entries after remove = %v, want 1", got["entry"]) } // deletePlaylist q5 := baseParams("alice", "password123") q5.Set("id", playlistID) resp = getPath(t, srv.URL, "/rest/deletePlaylist.view", q5) x = decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("deletePlaylist failed: %+v", x) } resp = getPath(t, srv.URL, "/rest/getPlaylists.view", q) j = decodeJSON(t, resp) pls := j["playlists"].(map[string]any) if _, ok := pls["playlist"]; ok { t.Fatalf("expected no playlists after delete, got %v", pls) } } func TestPlaylistPermissions(t *testing.T) { s, db := newTestServer(t) owner := createTestUser(t, s, "owner", "password123", false) createTestUser(t, s, "other", "password123", false) srv := httptest.NewServer(s.Router()) defer srv.Close() p, err := database.CreatePlaylist(db, owner.ID, "Private", "", false) if err != nil { t.Fatal(err) } q := baseParams("other", "password123") q.Set("id", p.ID) resp := getPath(t, srv.URL, "/rest/getPlaylist.view", q) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50 accessing another user's private playlist, got %+v", x) } resp = getPath(t, srv.URL, "/rest/deletePlaylist.view", q) x = decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50 deleting another user's playlist, got %+v", x) } } func TestGetPlaylistNotFound(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "alice", "password123", false) q := baseParams("alice", "password123") q.Set("id", "pl_doesnotexist") resp := getPath(t, srv.URL, "/rest/getPlaylist.view", q) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrNotFound { t.Fatalf("expected error 70, got %+v", x) } }