Files
vibesonic/internal/subsonic/playback_report_test.go
T

172 lines
4.9 KiB
Go

package subsonic
import (
"testing"
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
)
func TestReportPlaybackPlaying(t *testing.T) {
s, db := newTestServer(t)
createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
song := firstSong(t, s)
srv := newSubsonicTestServer(t, s)
q := baseParams("alice", "password123")
q.Set("mediaId", song.ID)
q.Set("mediaType", "song")
q.Set("positionMs", "5000")
q.Set("state", "playing")
resp := getPath(t, srv, "/rest/reportPlayback.view", q)
x := decodeXML(t, resp)
if x.Status != "ok" {
t.Fatalf("reportPlayback failed: %+v", x)
}
nowPlaying, err := database.ListNowPlaying(db)
if err != nil {
t.Fatal(err)
}
if len(nowPlaying) != 1 || nowPlaying[0].SongID != song.ID {
t.Fatalf("now playing = %v, want 1 entry for %s", nowPlaying, song.ID)
}
}
func TestReportPlaybackStoppedClearsNowPlayingAndRecordsHistory(t *testing.T) {
s, db := newTestServer(t)
u := createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
song := firstSong(t, s)
srv := newSubsonicTestServer(t, s)
q := baseParams("alice", "password123")
q.Set("mediaId", song.ID)
q.Set("mediaType", "song")
q.Set("positionMs", "1000")
q.Set("state", "playing")
getPath(t, srv, "/rest/reportPlayback.view", q)
q2 := baseParams("alice", "password123")
q2.Set("mediaId", song.ID)
q2.Set("mediaType", "song")
q2.Set("positionMs", "45000")
q2.Set("state", "stopped")
resp := getPath(t, srv, "/rest/reportPlayback.view", q2)
x := decodeXML(t, resp)
if x.Status != "ok" {
t.Fatalf("reportPlayback stopped failed: %+v", x)
}
nowPlaying, err := database.ListNowPlaying(db)
if err != nil {
t.Fatal(err)
}
if len(nowPlaying) != 0 {
t.Fatalf("now playing should be cleared after stopped, got %v", nowPlaying)
}
history, err := database.ListRecentlyPlayed(db, u.ID, 10)
if err != nil {
t.Fatal(err)
}
if len(history) != 1 {
t.Fatalf("expected a playback_history entry after stopped, got %v", history)
}
}
func TestReportPlaybackIgnoreScrobble(t *testing.T) {
s, db := newTestServer(t)
u := createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
song := firstSong(t, s)
srv := newSubsonicTestServer(t, s)
q := baseParams("alice", "password123")
q.Set("mediaId", song.ID)
q.Set("mediaType", "song")
q.Set("positionMs", "45000")
q.Set("state", "stopped")
q.Set("ignoreScrobble", "true")
getPath(t, srv, "/rest/reportPlayback.view", q)
history, err := database.ListRecentlyPlayed(db, u.ID, 10)
if err != nil {
t.Fatal(err)
}
if len(history) != 0 {
t.Fatalf("ignoreScrobble=true should not record history, got %v", history)
}
}
func TestReportPlaybackInvalidState(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
seedLibrary(t, s)
song := firstSong(t, s)
q := baseParams("alice", "password123")
q.Set("mediaId", song.ID)
q.Set("mediaType", "song")
q.Set("positionMs", "1000")
q.Set("state", "bogus")
resp := getPath(t, srv.URL, "/rest/reportPlayback.view", q)
x := decodeXML(t, resp)
if x.Status != "failed" {
t.Fatalf("expected failure for invalid state, got %+v", x)
}
}
func TestReportPlaybackMissingParams(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
resp := getPath(t, srv.URL, "/rest/reportPlayback.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 TestReportPlaybackUnknownMedia(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
q := baseParams("alice", "password123")
q.Set("mediaId", "sg_doesnotexist")
q.Set("mediaType", "song")
q.Set("positionMs", "0")
q.Set("state", "playing")
resp := getPath(t, srv.URL, "/rest/reportPlayback.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)
}
}
// TestReportPlaybackDoesNotLeakOtherUsersBookmarksOrQueue guards the
// "never expose one user's private state to another" requirement: each
// user's saved play queue is scoped by user, so alice's report never
// becomes visible in bob's queue.
func TestReportPlaybackDoesNotLeakAcrossUsers(t *testing.T) {
s, srv := newTestRecorderServer(t)
createTestUser(t, s, "alice", "password123", false)
createTestUser(t, s, "bob", "password123", false)
seedLibrary(t, s)
song := firstSong(t, s)
q := baseParams("alice", "password123")
q.Set("mediaId", song.ID)
q.Set("mediaType", "song")
q.Set("positionMs", "1000")
q.Set("state", "playing")
getPath(t, srv.URL, "/rest/reportPlayback.view", q)
q2 := baseParams("bob", "password123")
q2.Set("f", "json")
resp := getPath(t, srv.URL, "/rest/getPlayQueue.view", q2)
j := decodeJSON(t, resp)
if _, ok := j["playQueue"]; ok {
t.Fatalf("bob should not see alice's queue/report state: %v", j)
}
}