f03ca44a8e
* feat(plugins): add lyrics provider plugin capability Refactor the lyrics system from a static function to an interface-based service that supports WASM plugin providers. Plugins listed in the LyricsPriority config (alongside "embedded" and file extensions) are now resolved through the plugin system. Includes capability definition, Go/Rust PDK, adapter, Wire integration, and tests for plugin fallback behavior. * test(plugins): add lyrics capability integration test with test plugin * fix(plugins): default lyrics language to 'xxx' when plugin omits it Per the OpenSubsonic spec, the server must return 'und' or 'xxx' when the lyrics language is unknown. The lyrics plugin adapter was passing an empty string through when a plugin didn't provide a language value. This defaults the language to 'xxx', consistent with all other callers of model.ToLyrics() in the codebase. * refactor(plugins): rename lyrics import to improve clarity Signed-off-by: Deluan <deluan@navidrome.org> * refactor(lyrics): update TrackInfo description for clarity Signed-off-by: Deluan <deluan@navidrome.org> * fix(lyrics): enhance lyrics plugin handling and case sensitivity Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): update payload type to string with byte format for task data Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
543 lines
16 KiB
Go
543 lines
16 KiB
Go
package subsonic
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http/httptest"
|
|
|
|
"github.com/navidrome/navidrome/core/auth"
|
|
"github.com/navidrome/navidrome/log"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/model/request"
|
|
"github.com/navidrome/navidrome/server/subsonic/responses"
|
|
"github.com/navidrome/navidrome/tests"
|
|
"github.com/navidrome/navidrome/utils/req"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Album Lists", func() {
|
|
var router *Router
|
|
var ds model.DataStore
|
|
var mockRepo *tests.MockAlbumRepo
|
|
var w *httptest.ResponseRecorder
|
|
ctx := log.NewContext(context.TODO())
|
|
|
|
BeforeEach(func() {
|
|
ds = &tests.MockDataStore{}
|
|
auth.Init(ds)
|
|
mockRepo = ds.Album(ctx).(*tests.MockAlbumRepo)
|
|
router = New(ds, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
|
|
w = httptest.NewRecorder()
|
|
})
|
|
|
|
Describe("GetAlbumList", func() {
|
|
It("should return list of the type specified", func() {
|
|
r := newGetRequest("type=newest", "offset=10", "size=20")
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
resp, err := router.GetAlbumList(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList.Album[0].Id).To(Equal("1"))
|
|
Expect(resp.AlbumList.Album[1].Id).To(Equal("2"))
|
|
Expect(w.Header().Get("x-total-count")).To(Equal("2"))
|
|
Expect(mockRepo.Options.Offset).To(Equal(10))
|
|
Expect(mockRepo.Options.Max).To(Equal(20))
|
|
})
|
|
|
|
It("should fail if missing type parameter", func() {
|
|
r := newGetRequest()
|
|
_, err := router.GetAlbumList(w, r)
|
|
|
|
Expect(err).To(MatchError(req.ErrMissingParam))
|
|
})
|
|
|
|
It("should return error if call fails", func() {
|
|
mockRepo.SetError(true)
|
|
r := newGetRequest("type=newest")
|
|
|
|
_, err := router.GetAlbumList(w, r)
|
|
|
|
Expect(err).To(MatchError(errSubsonic))
|
|
var subErr subError
|
|
errors.As(err, &subErr)
|
|
Expect(subErr.code).To(Equal(responses.ErrorGeneric))
|
|
})
|
|
|
|
Context("with musicFolderId parameter", func() {
|
|
var user model.User
|
|
var ctx context.Context
|
|
|
|
BeforeEach(func() {
|
|
user = model.User{
|
|
ID: "test-user",
|
|
Libraries: []model.Library{
|
|
{ID: 1, Name: "Library 1"},
|
|
{ID: 2, Name: "Library 2"},
|
|
{ID: 3, Name: "Library 3"},
|
|
},
|
|
}
|
|
ctx = request.WithUser(context.Background(), user)
|
|
})
|
|
|
|
It("should filter albums by specific library when musicFolderId is provided", func() {
|
|
r := newGetRequest("type=newest", "musicFolderId=1")
|
|
r = r.WithContext(ctx)
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
|
|
resp, err := router.GetAlbumList(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList.Album).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?)"))
|
|
Expect(args).To(ContainElement(1))
|
|
})
|
|
|
|
It("should filter albums by multiple libraries when multiple musicFolderId are provided", func() {
|
|
r := newGetRequest("type=newest", "musicFolderId=1", "musicFolderId=2")
|
|
r = r.WithContext(ctx)
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
|
|
resp, err := router.GetAlbumList(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList.Album).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?,?)"))
|
|
Expect(args).To(ContainElements(1, 2))
|
|
})
|
|
|
|
It("should return all accessible albums when no musicFolderId is provided", func() {
|
|
r := newGetRequest("type=newest")
|
|
r = r.WithContext(ctx)
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
|
|
resp, err := router.GetAlbumList(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList.Album).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?,?,?)"))
|
|
Expect(args).To(ContainElements(1, 2, 3))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("GetAlbumList2", func() {
|
|
It("should return list of the type specified", func() {
|
|
r := newGetRequest("type=newest", "offset=10", "size=20")
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
resp, err := router.GetAlbumList2(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList2.Album[0].Id).To(Equal("1"))
|
|
Expect(resp.AlbumList2.Album[1].Id).To(Equal("2"))
|
|
Expect(w.Header().Get("x-total-count")).To(Equal("2"))
|
|
Expect(mockRepo.Options.Offset).To(Equal(10))
|
|
Expect(mockRepo.Options.Max).To(Equal(20))
|
|
})
|
|
|
|
It("should fail if missing type parameter", func() {
|
|
r := newGetRequest()
|
|
|
|
_, err := router.GetAlbumList2(w, r)
|
|
|
|
Expect(err).To(MatchError(req.ErrMissingParam))
|
|
})
|
|
|
|
It("should return error if call fails", func() {
|
|
mockRepo.SetError(true)
|
|
r := newGetRequest("type=newest")
|
|
|
|
_, err := router.GetAlbumList2(w, r)
|
|
|
|
Expect(err).To(MatchError(errSubsonic))
|
|
var subErr subError
|
|
errors.As(err, &subErr)
|
|
Expect(subErr.code).To(Equal(responses.ErrorGeneric))
|
|
})
|
|
|
|
Context("with musicFolderId parameter", func() {
|
|
var user model.User
|
|
var ctx context.Context
|
|
|
|
BeforeEach(func() {
|
|
user = model.User{
|
|
ID: "test-user",
|
|
Libraries: []model.Library{
|
|
{ID: 1, Name: "Library 1"},
|
|
{ID: 2, Name: "Library 2"},
|
|
{ID: 3, Name: "Library 3"},
|
|
},
|
|
}
|
|
ctx = request.WithUser(context.Background(), user)
|
|
})
|
|
|
|
It("should filter albums by specific library when musicFolderId is provided", func() {
|
|
r := newGetRequest("type=newest", "musicFolderId=1")
|
|
r = r.WithContext(ctx)
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
|
|
resp, err := router.GetAlbumList2(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList2.Album).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
Expect(mockRepo.Options.Filters).ToNot(BeNil())
|
|
})
|
|
|
|
It("should filter albums by multiple libraries when multiple musicFolderId are provided", func() {
|
|
r := newGetRequest("type=newest", "musicFolderId=1", "musicFolderId=2")
|
|
r = r.WithContext(ctx)
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
|
|
resp, err := router.GetAlbumList2(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList2.Album).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
Expect(mockRepo.Options.Filters).ToNot(BeNil())
|
|
})
|
|
|
|
It("should return all accessible albums when no musicFolderId is provided", func() {
|
|
r := newGetRequest("type=newest")
|
|
r = r.WithContext(ctx)
|
|
mockRepo.SetData(model.Albums{
|
|
{ID: "1"}, {ID: "2"},
|
|
})
|
|
|
|
resp, err := router.GetAlbumList2(w, r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.AlbumList2.Album).To(HaveLen(2))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("GetRandomSongs", func() {
|
|
var mockMediaFileRepo *tests.MockMediaFileRepo
|
|
|
|
BeforeEach(func() {
|
|
mockMediaFileRepo = ds.MediaFile(ctx).(*tests.MockMediaFileRepo)
|
|
})
|
|
|
|
It("should return random songs", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("size=2")
|
|
|
|
resp, err := router.GetRandomSongs(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.RandomSongs.Songs).To(HaveLen(2))
|
|
})
|
|
|
|
Context("with musicFolderId parameter", func() {
|
|
var user model.User
|
|
var ctx context.Context
|
|
|
|
BeforeEach(func() {
|
|
user = model.User{
|
|
ID: "test-user",
|
|
Libraries: []model.Library{
|
|
{ID: 1, Name: "Library 1"},
|
|
{ID: 2, Name: "Library 2"},
|
|
{ID: 3, Name: "Library 3"},
|
|
},
|
|
}
|
|
ctx = request.WithUser(context.Background(), user)
|
|
})
|
|
|
|
It("should filter songs by specific library when musicFolderId is provided", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("size=2", "musicFolderId=1")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetRandomSongs(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.RandomSongs.Songs).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockMediaFileRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?)"))
|
|
Expect(args).To(ContainElement(1))
|
|
})
|
|
|
|
It("should filter songs by multiple libraries when multiple musicFolderId are provided", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("size=2", "musicFolderId=1", "musicFolderId=2")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetRandomSongs(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.RandomSongs.Songs).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockMediaFileRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?,?)"))
|
|
Expect(args).To(ContainElements(1, 2))
|
|
})
|
|
|
|
It("should return all accessible songs when no musicFolderId is provided", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("size=2")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetRandomSongs(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.RandomSongs.Songs).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockMediaFileRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?,?,?)"))
|
|
Expect(args).To(ContainElements(1, 2, 3))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("GetSongsByGenre", func() {
|
|
var mockMediaFileRepo *tests.MockMediaFileRepo
|
|
|
|
BeforeEach(func() {
|
|
mockMediaFileRepo = ds.MediaFile(ctx).(*tests.MockMediaFileRepo)
|
|
})
|
|
|
|
It("should return songs by genre", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("count=2", "genre=rock")
|
|
|
|
resp, err := router.GetSongsByGenre(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.SongsByGenre.Songs).To(HaveLen(2))
|
|
})
|
|
|
|
Context("with musicFolderId parameter", func() {
|
|
var user model.User
|
|
var ctx context.Context
|
|
|
|
BeforeEach(func() {
|
|
user = model.User{
|
|
ID: "test-user",
|
|
Libraries: []model.Library{
|
|
{ID: 1, Name: "Library 1"},
|
|
{ID: 2, Name: "Library 2"},
|
|
{ID: 3, Name: "Library 3"},
|
|
},
|
|
}
|
|
ctx = request.WithUser(context.Background(), user)
|
|
})
|
|
|
|
It("should filter songs by specific library when musicFolderId is provided", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("count=2", "genre=rock", "musicFolderId=1")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetSongsByGenre(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.SongsByGenre.Songs).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockMediaFileRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?)"))
|
|
Expect(args).To(ContainElement(1))
|
|
})
|
|
|
|
It("should filter songs by multiple libraries when multiple musicFolderId are provided", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("count=2", "genre=rock", "musicFolderId=1", "musicFolderId=2")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetSongsByGenre(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.SongsByGenre.Songs).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockMediaFileRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?,?)"))
|
|
Expect(args).To(ContainElements(1, 2))
|
|
})
|
|
|
|
It("should return all accessible songs when no musicFolderId is provided", func() {
|
|
mockMediaFileRepo.SetData(model.MediaFiles{
|
|
{ID: "1", Title: "Song 1"},
|
|
{ID: "2", Title: "Song 2"},
|
|
})
|
|
r := newGetRequest("count=2", "genre=rock")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetSongsByGenre(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.SongsByGenre.Songs).To(HaveLen(2))
|
|
// Verify that library filter was applied
|
|
query, args, _ := mockMediaFileRepo.Options.Filters.ToSql()
|
|
Expect(query).To(ContainSubstring("library_id IN (?,?,?)"))
|
|
Expect(args).To(ContainElements(1, 2, 3))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("GetStarred", func() {
|
|
var mockArtistRepo *tests.MockArtistRepo
|
|
var mockAlbumRepo *tests.MockAlbumRepo
|
|
var mockMediaFileRepo *tests.MockMediaFileRepo
|
|
|
|
BeforeEach(func() {
|
|
mockArtistRepo = ds.Artist(ctx).(*tests.MockArtistRepo)
|
|
mockAlbumRepo = ds.Album(ctx).(*tests.MockAlbumRepo)
|
|
mockMediaFileRepo = ds.MediaFile(ctx).(*tests.MockMediaFileRepo)
|
|
})
|
|
|
|
It("should return starred items", func() {
|
|
mockArtistRepo.SetData(model.Artists{{ID: "1", Name: "Artist 1"}})
|
|
mockAlbumRepo.SetData(model.Albums{{ID: "1", Name: "Album 1"}})
|
|
mockMediaFileRepo.SetData(model.MediaFiles{{ID: "1", Title: "Song 1"}})
|
|
r := newGetRequest()
|
|
|
|
resp, err := router.GetStarred(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.Starred.Artist).To(HaveLen(1))
|
|
Expect(resp.Starred.Album).To(HaveLen(1))
|
|
Expect(resp.Starred.Song).To(HaveLen(1))
|
|
})
|
|
|
|
Context("with musicFolderId parameter", func() {
|
|
var user model.User
|
|
var ctx context.Context
|
|
|
|
BeforeEach(func() {
|
|
user = model.User{
|
|
ID: "test-user",
|
|
Libraries: []model.Library{
|
|
{ID: 1, Name: "Library 1"},
|
|
{ID: 2, Name: "Library 2"},
|
|
{ID: 3, Name: "Library 3"},
|
|
},
|
|
}
|
|
ctx = request.WithUser(context.Background(), user)
|
|
})
|
|
|
|
It("should filter starred items by specific library when musicFolderId is provided", func() {
|
|
mockArtistRepo.SetData(model.Artists{{ID: "1", Name: "Artist 1"}})
|
|
mockAlbumRepo.SetData(model.Albums{{ID: "1", Name: "Album 1"}})
|
|
mockMediaFileRepo.SetData(model.MediaFiles{{ID: "1", Title: "Song 1"}})
|
|
r := newGetRequest("musicFolderId=1")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetStarred(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.Starred.Artist).To(HaveLen(1))
|
|
Expect(resp.Starred.Album).To(HaveLen(1))
|
|
Expect(resp.Starred.Song).To(HaveLen(1))
|
|
// Verify that library filter was applied to all types
|
|
artistQuery, artistArgs, _ := mockArtistRepo.Options.Filters.ToSql()
|
|
Expect(artistQuery).To(ContainSubstring("library_id IN (?)"))
|
|
Expect(artistArgs).To(ContainElement(1))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("GetStarred2", func() {
|
|
var mockArtistRepo *tests.MockArtistRepo
|
|
var mockAlbumRepo *tests.MockAlbumRepo
|
|
var mockMediaFileRepo *tests.MockMediaFileRepo
|
|
|
|
BeforeEach(func() {
|
|
mockArtistRepo = ds.Artist(ctx).(*tests.MockArtistRepo)
|
|
mockAlbumRepo = ds.Album(ctx).(*tests.MockAlbumRepo)
|
|
mockMediaFileRepo = ds.MediaFile(ctx).(*tests.MockMediaFileRepo)
|
|
})
|
|
|
|
It("should return starred items in ID3 format", func() {
|
|
mockArtistRepo.SetData(model.Artists{{ID: "1", Name: "Artist 1"}})
|
|
mockAlbumRepo.SetData(model.Albums{{ID: "1", Name: "Album 1"}})
|
|
mockMediaFileRepo.SetData(model.MediaFiles{{ID: "1", Title: "Song 1"}})
|
|
r := newGetRequest()
|
|
|
|
resp, err := router.GetStarred2(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.Starred2.Artist).To(HaveLen(1))
|
|
Expect(resp.Starred2.Album).To(HaveLen(1))
|
|
Expect(resp.Starred2.Song).To(HaveLen(1))
|
|
})
|
|
|
|
Context("with musicFolderId parameter", func() {
|
|
var user model.User
|
|
var ctx context.Context
|
|
|
|
BeforeEach(func() {
|
|
user = model.User{
|
|
ID: "test-user",
|
|
Libraries: []model.Library{
|
|
{ID: 1, Name: "Library 1"},
|
|
{ID: 2, Name: "Library 2"},
|
|
{ID: 3, Name: "Library 3"},
|
|
},
|
|
}
|
|
ctx = request.WithUser(context.Background(), user)
|
|
})
|
|
|
|
It("should filter starred items by specific library when musicFolderId is provided", func() {
|
|
mockArtistRepo.SetData(model.Artists{{ID: "1", Name: "Artist 1"}})
|
|
mockAlbumRepo.SetData(model.Albums{{ID: "1", Name: "Album 1"}})
|
|
mockMediaFileRepo.SetData(model.MediaFiles{{ID: "1", Title: "Song 1"}})
|
|
r := newGetRequest("musicFolderId=1")
|
|
r = r.WithContext(ctx)
|
|
|
|
resp, err := router.GetStarred2(r)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(resp.Starred2.Artist).To(HaveLen(1))
|
|
Expect(resp.Starred2.Album).To(HaveLen(1))
|
|
Expect(resp.Starred2.Song).To(HaveLen(1))
|
|
// Verify that library filter was applied to all types
|
|
artistQuery, artistArgs, _ := mockArtistRepo.Options.Filters.ToSql()
|
|
Expect(artistQuery).To(ContainSubstring("library_id IN (?)"))
|
|
Expect(artistArgs).To(ContainElement(1))
|
|
})
|
|
})
|
|
})
|
|
})
|