update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
This commit is contained in:
282
server/nativeapi/queue_test.go
Normal file
282
server/nativeapi/queue_test.go
Normal file
@@ -0,0 +1,282 @@
|
||||
package nativeapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
"github.com/navidrome/navidrome/tests"
|
||||
"github.com/navidrome/navidrome/utils/gg"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Queue Endpoints", func() {
|
||||
var (
|
||||
ds *tests.MockDataStore
|
||||
repo *tests.MockPlayQueueRepo
|
||||
user model.User
|
||||
userRepo *tests.MockedUserRepo
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
repo = &tests.MockPlayQueueRepo{}
|
||||
user = model.User{ID: "u1", UserName: "user"}
|
||||
userRepo = tests.CreateMockUserRepo()
|
||||
_ = userRepo.Put(&user)
|
||||
ds = &tests.MockDataStore{MockedPlayQueue: repo, MockedUser: userRepo, MockedProperty: &tests.MockedPropertyRepo{}}
|
||||
})
|
||||
|
||||
Describe("POST /queue", func() {
|
||||
It("saves the queue", func() {
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1", "s2"}), Current: gg.P(1), Position: gg.P(int64(10))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/queue", bytes.NewReader(body))
|
||||
ctx := request.WithUser(req.Context(), user)
|
||||
ctx = request.WithClient(ctx, "TestClient")
|
||||
req = req.WithContext(ctx)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
saveQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusNoContent))
|
||||
Expect(repo.Queue).ToNot(BeNil())
|
||||
Expect(repo.Queue.Current).To(Equal(1))
|
||||
Expect(repo.Queue.Items).To(HaveLen(2))
|
||||
Expect(repo.Queue.Items[1].ID).To(Equal("s2"))
|
||||
Expect(repo.Queue.ChangedBy).To(Equal("TestClient"))
|
||||
})
|
||||
|
||||
It("saves an empty queue", func() {
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{}), Current: gg.P(0), Position: gg.P(int64(0))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
saveQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusNoContent))
|
||||
Expect(repo.Queue).ToNot(BeNil())
|
||||
Expect(repo.Queue.Items).To(HaveLen(0))
|
||||
})
|
||||
|
||||
It("returns bad request for invalid current index (negative)", func() {
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1", "s2"}), Current: gg.P(-1), Position: gg.P(int64(10))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
saveQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusBadRequest))
|
||||
Expect(w.Body.String()).To(ContainSubstring("current index out of bounds"))
|
||||
})
|
||||
|
||||
It("returns bad request for invalid current index (too large)", func() {
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1", "s2"}), Current: gg.P(2), Position: gg.P(int64(10))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
saveQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusBadRequest))
|
||||
Expect(w.Body.String()).To(ContainSubstring("current index out of bounds"))
|
||||
})
|
||||
|
||||
It("returns bad request for malformed JSON", func() {
|
||||
req := httptest.NewRequest("POST", "/queue", bytes.NewReader([]byte("invalid json")))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
saveQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusBadRequest))
|
||||
})
|
||||
|
||||
It("returns internal server error when store fails", func() {
|
||||
repo.Err = true
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1"}), Current: gg.P(0), Position: gg.P(int64(10))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
saveQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusInternalServerError))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("GET /queue", func() {
|
||||
It("returns the queue", func() {
|
||||
queue := &model.PlayQueue{
|
||||
UserID: user.ID,
|
||||
Current: 1,
|
||||
Position: 55,
|
||||
Items: model.MediaFiles{
|
||||
{ID: "track1", Title: "Song 1"},
|
||||
{ID: "track2", Title: "Song 2"},
|
||||
{ID: "track3", Title: "Song 3"},
|
||||
},
|
||||
}
|
||||
repo.Queue = queue
|
||||
req := httptest.NewRequest("GET", "/queue", nil)
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusOK))
|
||||
Expect(w.Header().Get("Content-Type")).To(Equal("application/json"))
|
||||
var resp model.PlayQueue
|
||||
Expect(json.Unmarshal(w.Body.Bytes(), &resp)).To(Succeed())
|
||||
Expect(resp.Current).To(Equal(1))
|
||||
Expect(resp.Position).To(Equal(int64(55)))
|
||||
Expect(resp.Items).To(HaveLen(3))
|
||||
Expect(resp.Items[0].ID).To(Equal("track1"))
|
||||
Expect(resp.Items[1].ID).To(Equal("track2"))
|
||||
Expect(resp.Items[2].ID).To(Equal("track3"))
|
||||
})
|
||||
|
||||
It("returns empty queue when user has no queue", func() {
|
||||
req := httptest.NewRequest("GET", "/queue", nil)
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusOK))
|
||||
var resp model.PlayQueue
|
||||
Expect(json.Unmarshal(w.Body.Bytes(), &resp)).To(Succeed())
|
||||
Expect(resp.Items).To(BeEmpty())
|
||||
Expect(resp.Current).To(Equal(0))
|
||||
Expect(resp.Position).To(Equal(int64(0)))
|
||||
})
|
||||
|
||||
It("returns internal server error when retrieve fails", func() {
|
||||
repo.Err = true
|
||||
req := httptest.NewRequest("GET", "/queue", nil)
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusInternalServerError))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("PUT /queue", func() {
|
||||
It("updates the queue fields", func() {
|
||||
repo.Queue = &model.PlayQueue{UserID: user.ID, Items: model.MediaFiles{{ID: "s1"}, {ID: "s2"}, {ID: "s3"}}}
|
||||
payload := updateQueuePayload{Current: gg.P(2), Position: gg.P(int64(20))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader(body))
|
||||
ctx := request.WithUser(req.Context(), user)
|
||||
ctx = request.WithClient(ctx, "TestClient")
|
||||
req = req.WithContext(ctx)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusNoContent))
|
||||
Expect(repo.Queue).ToNot(BeNil())
|
||||
Expect(repo.Queue.Current).To(Equal(2))
|
||||
Expect(repo.Queue.Position).To(Equal(int64(20)))
|
||||
Expect(repo.Queue.ChangedBy).To(Equal("TestClient"))
|
||||
})
|
||||
|
||||
It("updates only ids", func() {
|
||||
repo.Queue = &model.PlayQueue{UserID: user.ID, Current: 1}
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1", "s2"})}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusNoContent))
|
||||
Expect(repo.Queue.Items).To(HaveLen(2))
|
||||
Expect(repo.LastCols).To(ConsistOf("items"))
|
||||
})
|
||||
|
||||
It("updates ids and current", func() {
|
||||
repo.Queue = &model.PlayQueue{UserID: user.ID}
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1", "s2"}), Current: gg.P(1)}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusNoContent))
|
||||
Expect(repo.Queue.Items).To(HaveLen(2))
|
||||
Expect(repo.Queue.Current).To(Equal(1))
|
||||
Expect(repo.LastCols).To(ConsistOf("items", "current"))
|
||||
})
|
||||
|
||||
It("returns bad request when new ids invalidate current", func() {
|
||||
repo.Queue = &model.PlayQueue{UserID: user.ID, Current: 2}
|
||||
payload := updateQueuePayload{Ids: gg.P([]string{"s1", "s2"})}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusBadRequest))
|
||||
})
|
||||
|
||||
It("returns bad request when current out of bounds", func() {
|
||||
repo.Queue = &model.PlayQueue{UserID: user.ID, Items: model.MediaFiles{{ID: "s1"}}}
|
||||
payload := updateQueuePayload{Current: gg.P(3)}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusBadRequest))
|
||||
})
|
||||
|
||||
It("returns bad request for malformed JSON", func() {
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader([]byte("{")))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusBadRequest))
|
||||
})
|
||||
|
||||
It("returns internal server error when store fails", func() {
|
||||
repo.Err = true
|
||||
payload := updateQueuePayload{Position: gg.P(int64(10))}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("PUT", "/queue", bytes.NewReader(body))
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
updateQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusInternalServerError))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("DELETE /queue", func() {
|
||||
It("clears the queue", func() {
|
||||
repo.Queue = &model.PlayQueue{UserID: user.ID, Items: model.MediaFiles{{ID: "s1"}}}
|
||||
req := httptest.NewRequest("DELETE", "/queue", nil)
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
clearQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusNoContent))
|
||||
Expect(repo.Queue).To(BeNil())
|
||||
})
|
||||
|
||||
It("returns internal server error when clear fails", func() {
|
||||
repo.Err = true
|
||||
req := httptest.NewRequest("DELETE", "/queue", nil)
|
||||
req = req.WithContext(request.WithUser(req.Context(), user))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
clearQueue(ds)(w, req)
|
||||
Expect(w.Code).To(Equal(http.StatusInternalServerError))
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user