mirror of
https://github.com/navidrome/navidrome.git
synced 2025-06-06 02:13:29 +03:00
Started the implementation of getMusicDirectory. Probably will need to introduce a new 'service' layer...
This commit is contained in:
parent
68786d4b39
commit
9577d9ae87
@ -3,7 +3,6 @@ package api_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"encoding/xml"
|
|
||||||
"github.com/deluan/gosonic/api/responses"
|
"github.com/deluan/gosonic/api/responses"
|
||||||
"github.com/deluan/gosonic/consts"
|
"github.com/deluan/gosonic/consts"
|
||||||
"github.com/deluan/gosonic/domain"
|
"github.com/deluan/gosonic/domain"
|
||||||
@ -39,17 +38,13 @@ func TestGetIndexes(t *testing.T) {
|
|||||||
mockRepo.SetError(true)
|
mockRepo.SetError(true)
|
||||||
_, w := Get(AddParams("/rest/getIndexes.view", "ifModifiedSince=0"), "TestGetIndexes")
|
_, w := Get(AddParams("/rest/getIndexes.view", "ifModifiedSince=0"), "TestGetIndexes")
|
||||||
|
|
||||||
v := responses.Subsonic{}
|
So(w.Body, ShouldReceiveError, responses.ERROR_GENERIC)
|
||||||
xml.Unmarshal(w.Body.Bytes(), &v)
|
|
||||||
So(v.Status, ShouldEqual, "fail")
|
|
||||||
})
|
})
|
||||||
Convey("Return fail on Property Table error", func() {
|
Convey("Return fail on Property Table error", func() {
|
||||||
propRepo.SetError(true)
|
propRepo.SetError(true)
|
||||||
_, w := Get(AddParams("/rest/getIndexes.view"), "TestGetIndexes")
|
_, w := Get(AddParams("/rest/getIndexes.view"), "TestGetIndexes")
|
||||||
|
|
||||||
v := responses.Subsonic{}
|
So(w.Body, ShouldReceiveError, responses.ERROR_GENERIC)
|
||||||
xml.Unmarshal(w.Body.Bytes(), &v)
|
|
||||||
So(v.Status, ShouldEqual, "fail")
|
|
||||||
})
|
})
|
||||||
Convey("When the index is empty", func() {
|
Convey("When the index is empty", func() {
|
||||||
_, w := Get(AddParams("/rest/getIndexes.view"), "TestGetIndexes")
|
_, w := Get(AddParams("/rest/getIndexes.view"), "TestGetIndexes")
|
||||||
|
44
api/get_music_directory.go
Normal file
44
api/get_music_directory.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/deluan/gosonic/api/responses"
|
||||||
|
"github.com/deluan/gosonic/domain"
|
||||||
|
"github.com/deluan/gosonic/utils"
|
||||||
|
"github.com/karlkfi/inject"
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetMusicDirectoryController struct {
|
||||||
|
BaseAPIController
|
||||||
|
artistRepo domain.ArtistRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GetMusicDirectoryController) Prepare() {
|
||||||
|
inject.ExtractAssignable(utils.Graph, &c.artistRepo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GetMusicDirectoryController) Get() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
c.SendError(responses.ERROR_MISSING_PARAMETER, "id parameter required")
|
||||||
|
}
|
||||||
|
|
||||||
|
found, err := c.artistRepo.Exists(id)
|
||||||
|
if err != nil {
|
||||||
|
beego.Error("Error searching for Artist:", err)
|
||||||
|
c.SendError(responses.ERROR_GENERIC, "Internal Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
_, err := c.artistRepo.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
beego.Error("Error reading Artist from DB", err)
|
||||||
|
c.SendError(responses.ERROR_GENERIC, "Internal Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response := c.NewEmpty()
|
||||||
|
response.Directory = &responses.Directory{}
|
||||||
|
c.SendResponse(response)
|
||||||
|
}
|
40
api/get_music_directory_test.go
Normal file
40
api/get_music_directory_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package api_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/deluan/gosonic/domain"
|
||||||
|
"github.com/deluan/gosonic/tests/mocks"
|
||||||
|
"github.com/deluan/gosonic/utils"
|
||||||
|
. "github.com/deluan/gosonic/tests"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"github.com/deluan/gosonic/api/responses"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetMusicDirectory(t *testing.T) {
|
||||||
|
Init(t, false)
|
||||||
|
|
||||||
|
mockRepo := mocks.CreateMockArtistRepo()
|
||||||
|
utils.DefineSingleton(new(domain.ArtistRepository), func() domain.ArtistRepository {
|
||||||
|
return mockRepo
|
||||||
|
})
|
||||||
|
|
||||||
|
mockRepo.SetData("[]")
|
||||||
|
mockRepo.SetError(false)
|
||||||
|
|
||||||
|
Convey("Subject: GetMusicDirectory Endpoint", t, func() {
|
||||||
|
Convey("Should fail if missing Id parameter", func() {
|
||||||
|
_, w := Get(AddParams("/rest/getMusicDirectory.view"), "TestGetMusicDirectory")
|
||||||
|
|
||||||
|
So(w.Body, ShouldReceiveError, responses.ERROR_MISSING_PARAMETER)
|
||||||
|
})
|
||||||
|
Convey("Id is for an artist", func() {
|
||||||
|
Convey("Return fail on Artist Table error", func() {
|
||||||
|
mockRepo.SetError(true)
|
||||||
|
_, w := Get(AddParams("/rest/getMusicDirectory.view", "id=1"), "TestGetMusicDirectory")
|
||||||
|
|
||||||
|
So(w.Body, ShouldReceiveError, responses.ERROR_GENERIC)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -6,7 +6,7 @@ type Subsonic struct {
|
|||||||
XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
|
XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
|
||||||
Status string `xml:"status,attr" json:"status"`
|
Status string `xml:"status,attr" json:"status"`
|
||||||
Version string `xml:"version,attr" json:"version"`
|
Version string `xml:"version,attr" json:"version"`
|
||||||
Error *Error `xml:",omitempty" json:"error,omitempty"`
|
Error *Error `xml:"error,omitempty" json:"error,omitempty"`
|
||||||
License *License `xml:"license,omitempty" json:"license,omitempty"`
|
License *License `xml:"license,omitempty" json:"license,omitempty"`
|
||||||
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
|
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
|
||||||
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
|
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
|
||||||
@ -18,8 +18,8 @@ type JsonWrapper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Code int `xml:"code,attr"`
|
Code int `xml:"code,attr" json:"code"`
|
||||||
Message string `xml:"message,attr"`
|
Message string `xml:"message,attr" json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type License struct {
|
type License struct {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package responses
|
package responses_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
. "github.com/deluan/gosonic/tests"
|
. "github.com/deluan/gosonic/tests"
|
||||||
|
. "github.com/deluan/gosonic/api/responses"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSubsonicResponses(t *testing.T) {
|
func TestSubsonicResponses(t *testing.T) {
|
||||||
|
@ -10,4 +10,5 @@ func init() {
|
|||||||
utils.DefineSingleton(new(domain.ArtistIndexRepository), persistence.NewArtistIndexRepository)
|
utils.DefineSingleton(new(domain.ArtistIndexRepository), persistence.NewArtistIndexRepository)
|
||||||
utils.DefineSingleton(new(domain.PropertyRepository), persistence.NewPropertyRepository)
|
utils.DefineSingleton(new(domain.PropertyRepository), persistence.NewPropertyRepository)
|
||||||
utils.DefineSingleton(new(domain.MediaFolderRepository), persistence.NewMediaFolderRepository)
|
utils.DefineSingleton(new(domain.MediaFolderRepository), persistence.NewMediaFolderRepository)
|
||||||
|
utils.DefineSingleton(new(domain.ArtistRepository), persistence.NewArtistRepository)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ func mapEndpoints() {
|
|||||||
beego.NSRouter("/getLicense.view", &api.GetLicenseController{}, "*:Get"),
|
beego.NSRouter("/getLicense.view", &api.GetLicenseController{}, "*:Get"),
|
||||||
beego.NSRouter("/getMusicFolders.view", &api.GetMusicFoldersController{}, "*:Get"),
|
beego.NSRouter("/getMusicFolders.view", &api.GetMusicFoldersController{}, "*:Get"),
|
||||||
beego.NSRouter("/getIndexes.view", &api.GetIndexesController{}, "*:Get"),
|
beego.NSRouter("/getIndexes.view", &api.GetIndexesController{}, "*:Get"),
|
||||||
|
beego.NSRouter("/getMusicDirectory.view", &api.GetMusicDirectoryController{}, "*:Get"),
|
||||||
)
|
)
|
||||||
beego.AddNamespace(ns)
|
beego.AddNamespace(ns)
|
||||||
|
|
||||||
|
@ -3,4 +3,5 @@ package domain
|
|||||||
type BaseRepository interface {
|
type BaseRepository interface {
|
||||||
NewId(fields ...string) string
|
NewId(fields ...string) string
|
||||||
CountAll() (int, error)
|
CountAll() (int, error)
|
||||||
|
Exists(id string) (bool, error)
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,11 @@ func (r *baseRepository) CountAll() (int, error) {
|
|||||||
return len(ids), err
|
return len(ids), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *baseRepository) Exists(id string) (bool, error) {
|
||||||
|
res, err := db().SIsMember([]byte(r.table + "s:all"), []byte(id))
|
||||||
|
return res != 0, err
|
||||||
|
}
|
||||||
|
|
||||||
func (r *baseRepository) saveOrUpdate(id string, entity interface{}) error {
|
func (r *baseRepository) saveOrUpdate(id string, entity interface{}) error {
|
||||||
recordPrefix := fmt.Sprintf("%s:%s:", r.table, id)
|
recordPrefix := fmt.Sprintf("%s:%s:", r.table, id)
|
||||||
allKey := r.table + "s:all"
|
allKey := r.table + "s:all"
|
||||||
|
@ -7,17 +7,17 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type artistIndex struct {
|
type artistIndexRepository struct {
|
||||||
baseRepository
|
baseRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistIndexRepository() domain.ArtistIndexRepository {
|
func NewArtistIndexRepository() domain.ArtistIndexRepository {
|
||||||
r := &artistIndex{}
|
r := &artistIndexRepository{}
|
||||||
r.init("index", &domain.ArtistIndex{})
|
r.init("index", &domain.ArtistIndex{})
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *artistIndex) Put(m *domain.ArtistIndex) error {
|
func (r *artistIndexRepository) Put(m *domain.ArtistIndex) error {
|
||||||
if m.Id == "" {
|
if m.Id == "" {
|
||||||
return errors.New("Id is not set")
|
return errors.New("Id is not set")
|
||||||
}
|
}
|
||||||
@ -25,13 +25,13 @@ func (r *artistIndex) Put(m *domain.ArtistIndex) error {
|
|||||||
return r.saveOrUpdate(m.Id, m)
|
return r.saveOrUpdate(m.Id, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *artistIndex) Get(id string) (*domain.ArtistIndex, error) {
|
func (r *artistIndexRepository) Get(id string) (*domain.ArtistIndex, error) {
|
||||||
var rec interface{}
|
var rec interface{}
|
||||||
rec, err := r.readEntity(id)
|
rec, err := r.readEntity(id)
|
||||||
return rec.(*domain.ArtistIndex), err
|
return rec.(*domain.ArtistIndex), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *artistIndex) GetAll() ([]domain.ArtistIndex, error) {
|
func (r *artistIndexRepository) GetAll() ([]domain.ArtistIndex, error) {
|
||||||
var indices = make([]domain.ArtistIndex, 0)
|
var indices = make([]domain.ArtistIndex, 0)
|
||||||
err := r.loadAll(&indices, "")
|
err := r.loadAll(&indices, "")
|
||||||
return indices, err
|
return indices, err
|
||||||
|
@ -23,6 +23,17 @@ func TestIndexRepository(t *testing.T) {
|
|||||||
|
|
||||||
So(s, shouldBeEqual, i)
|
So(s, shouldBeEqual, i)
|
||||||
})
|
})
|
||||||
|
Convey("It should be able to check for existance of an Id", func() {
|
||||||
|
i := &domain.ArtistIndex{Id: "123"}
|
||||||
|
|
||||||
|
repo.Put(i)
|
||||||
|
|
||||||
|
s, _ := repo.Exists("123")
|
||||||
|
So(s, ShouldBeTrue)
|
||||||
|
|
||||||
|
s, _ = repo.Exists("NOT_FOUND")
|
||||||
|
So(s, ShouldBeFalse)
|
||||||
|
})
|
||||||
Convey("Method Put() should return error if Id is not set", func() {
|
Convey("Method Put() should return error if Id is not set", func() {
|
||||||
i := &domain.ArtistIndex{}
|
i := &domain.ArtistIndex{}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/deluan/gosonic/api/responses"
|
||||||
|
"bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ShouldMatchXML(actual interface{}, expected ...interface{}) string {
|
func ShouldMatchXML(actual interface{}, expected ...interface{}) string {
|
||||||
@ -25,6 +27,17 @@ func ShouldMatchJSON(actual interface{}, expected ...interface{}) string {
|
|||||||
return ShouldEqual(s, expected[0].(string))
|
return ShouldEqual(s, expected[0].(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ShouldReceiveError(actual interface{}, expected ...interface{}) string {
|
||||||
|
v := responses.Subsonic{}
|
||||||
|
err := xml.Unmarshal(actual.(*bytes.Buffer).Bytes(), &v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Malformed XML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ShouldEqual(v.Error.Code, expected[0].(int))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func UnindentJSON(j []byte) string {
|
func UnindentJSON(j []byte) string {
|
||||||
var m = make(map[string]interface{})
|
var m = make(map[string]interface{})
|
||||||
json.Unmarshal(j, &m)
|
json.Unmarshal(j, &m)
|
38
tests/mocks/mock_artist_repo.go
Normal file
38
tests/mocks/mock_artist_repo.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/deluan/gosonic/domain"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateMockArtistRepo() *MockArtist {
|
||||||
|
return &MockArtist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockArtist struct {
|
||||||
|
domain.ArtistRepository
|
||||||
|
data map[string]domain.Artist
|
||||||
|
err bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockArtist) SetError(err bool) {
|
||||||
|
m.err = err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockArtist) SetData(j string) {
|
||||||
|
m.data = make(map[string]domain.Artist)
|
||||||
|
err := json.Unmarshal([]byte(j), &m.data)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("ERROR: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockArtist) Exists(id string) (bool, error) {
|
||||||
|
if m.err {
|
||||||
|
return false, errors.New("Error!")
|
||||||
|
}
|
||||||
|
_, found := m.data[id];
|
||||||
|
return found, nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user