128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package subsonic
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"os/exec"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
|
|
)
|
|
|
|
func requireMPVForTest(t *testing.T) {
|
|
t.Helper()
|
|
if _, err := exec.LookPath("mpv"); err != nil {
|
|
t.Skip("mpv not installed")
|
|
}
|
|
}
|
|
|
|
func TestJukeboxControlLifecycle(t *testing.T) {
|
|
requireMPVForTest(t)
|
|
s, srv := newTestRecorderServer(t)
|
|
createTestUser(t, s, "alice", "password123", true)
|
|
seedLibrary(t, s)
|
|
|
|
songs := []string{}
|
|
q0 := baseParams("alice", "password123")
|
|
q0.Set("f", "json")
|
|
resp := getPath(t, srv.URL, "/rest/getRandomSongs.view", q0)
|
|
j := decodeJSON(t, resp)
|
|
for _, s := range j["randomSongs"].(map[string]any)["song"].([]any) {
|
|
songs = append(songs, s.(map[string]any)["id"].(string))
|
|
}
|
|
if len(songs) == 0 {
|
|
t.Fatal("no songs available to jukebox")
|
|
}
|
|
|
|
q := baseParams("alice", "password123")
|
|
q.Set("action", "set")
|
|
for _, id := range songs {
|
|
q.Add("id", id)
|
|
}
|
|
q.Set("f", "json")
|
|
resp = getPath(t, srv.URL, "/rest/jukeboxControl.view", q)
|
|
j = decodeJSON(t, resp)
|
|
status, ok := j["jukeboxStatus"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected jukeboxStatus in response: %v", j)
|
|
}
|
|
_ = status
|
|
|
|
time.Sleep(200 * time.Millisecond)
|
|
|
|
q2 := baseParams("alice", "password123")
|
|
q2.Set("action", "get")
|
|
q2.Set("f", "json")
|
|
resp = getPath(t, srv.URL, "/rest/jukeboxControl.view", q2)
|
|
j = decodeJSON(t, resp)
|
|
playlist, ok := j["jukeboxPlaylist"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected jukeboxPlaylist for action=get: %v", j)
|
|
}
|
|
entries, ok := playlist["entry"].([]any)
|
|
if !ok || len(entries) != len(songs) {
|
|
t.Fatalf("jukeboxPlaylist entries = %v, want %d", playlist["entry"], len(songs))
|
|
}
|
|
|
|
q3 := baseParams("alice", "password123")
|
|
q3.Set("action", "stop")
|
|
resp = getPath(t, srv.URL, "/rest/jukeboxControl.view", q3)
|
|
x := decodeXML(t, resp)
|
|
if x.Status != "ok" {
|
|
t.Fatalf("stop failed: %+v", x)
|
|
}
|
|
|
|
q4 := baseParams("alice", "password123")
|
|
q4.Set("action", "setGain")
|
|
q4.Set("gain", "0.3")
|
|
q4.Set("f", "json")
|
|
resp = getPath(t, srv.URL, "/rest/jukeboxControl.view", q4)
|
|
j = decodeJSON(t, resp)
|
|
status = j["jukeboxStatus"].(map[string]any)
|
|
if gain, _ := status["gain"].(float64); gain < 0.29 || gain > 0.31 {
|
|
t.Fatalf("gain = %v, want ~0.3", status["gain"])
|
|
}
|
|
|
|
q5 := baseParams("alice", "password123")
|
|
q5.Set("action", "clear")
|
|
resp = getPath(t, srv.URL, "/rest/jukeboxControl.view", q5)
|
|
x = decodeXML(t, resp)
|
|
if x.Status != "ok" {
|
|
t.Fatalf("clear failed: %+v", x)
|
|
}
|
|
}
|
|
|
|
func TestJukeboxControlRequiresPermission(t *testing.T) {
|
|
requireMPVForTest(t)
|
|
s, db := newTestServer(t)
|
|
u := createTestUser(t, s, "alice", "password123", false)
|
|
srv := httptest.NewServer(s.Router())
|
|
defer srv.Close()
|
|
|
|
perms := u.Permissions
|
|
perms.Jukebox = false
|
|
if err := database.SetUserPermissions(db, u.ID, perms); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
q := baseParams("alice", "password123")
|
|
q.Set("action", "status")
|
|
resp := getPath(t, srv.URL, "/rest/jukeboxControl.view", q)
|
|
x := decodeXML(t, resp)
|
|
if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized {
|
|
t.Fatalf("expected error 50 without jukebox permission, got %+v", x)
|
|
}
|
|
}
|
|
|
|
func TestJukeboxControlMissingAction(t *testing.T) {
|
|
requireMPVForTest(t)
|
|
s, srv := newTestRecorderServer(t)
|
|
createTestUser(t, s, "alice", "password123", true)
|
|
|
|
resp := getPath(t, srv.URL, "/rest/jukeboxControl.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)
|
|
}
|
|
}
|