Started the implementation of getMusicDirectory. Probably will need to introduce a new 'service' layer...

This commit is contained in:
Deluan 2016-03-02 20:00:55 -05:00
parent 68786d4b39
commit 9577d9ae87
15 changed files with 166 additions and 16 deletions

View File

@ -3,7 +3,6 @@ package api_test
import (
"testing"
"encoding/xml"
"github.com/deluan/gosonic/api/responses"
"github.com/deluan/gosonic/consts"
"github.com/deluan/gosonic/domain"
@ -39,17 +38,13 @@ func TestGetIndexes(t *testing.T) {
mockRepo.SetError(true)
_, w := Get(AddParams("/rest/getIndexes.view", "ifModifiedSince=0"), "TestGetIndexes")
v := responses.Subsonic{}
xml.Unmarshal(w.Body.Bytes(), &v)
So(v.Status, ShouldEqual, "fail")
So(w.Body, ShouldReceiveError, responses.ERROR_GENERIC)
})
Convey("Return fail on Property Table error", func() {
propRepo.SetError(true)
_, w := Get(AddParams("/rest/getIndexes.view"), "TestGetIndexes")
v := responses.Subsonic{}
xml.Unmarshal(w.Body.Bytes(), &v)
So(v.Status, ShouldEqual, "fail")
So(w.Body, ShouldReceiveError, responses.ERROR_GENERIC)
})
Convey("When the index is empty", func() {
_, w := Get(AddParams("/rest/getIndexes.view"), "TestGetIndexes")

View 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)
}

View 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)
})
})
})
}

View File

@ -6,7 +6,7 @@ type Subsonic struct {
XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
Status string `xml:"status,attr" json:"status"`
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"`
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
@ -18,8 +18,8 @@ type JsonWrapper struct {
}
type Error struct {
Code int `xml:"code,attr"`
Message string `xml:"message,attr"`
Code int `xml:"code,attr" json:"code"`
Message string `xml:"message,attr" json:"message"`
}
type License struct {

View File

@ -1,9 +1,10 @@
package responses
package responses_test
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
. "github.com/deluan/gosonic/tests"
. "github.com/deluan/gosonic/api/responses"
)
func TestSubsonicResponses(t *testing.T) {

View File

@ -10,4 +10,5 @@ func init() {
utils.DefineSingleton(new(domain.ArtistIndexRepository), persistence.NewArtistIndexRepository)
utils.DefineSingleton(new(domain.PropertyRepository), persistence.NewPropertyRepository)
utils.DefineSingleton(new(domain.MediaFolderRepository), persistence.NewMediaFolderRepository)
utils.DefineSingleton(new(domain.ArtistRepository), persistence.NewArtistRepository)
}

View File

@ -20,6 +20,7 @@ func mapEndpoints() {
beego.NSRouter("/getLicense.view", &api.GetLicenseController{}, "*:Get"),
beego.NSRouter("/getMusicFolders.view", &api.GetMusicFoldersController{}, "*:Get"),
beego.NSRouter("/getIndexes.view", &api.GetIndexesController{}, "*:Get"),
beego.NSRouter("/getMusicDirectory.view", &api.GetMusicDirectoryController{}, "*:Get"),
)
beego.AddNamespace(ns)

View File

@ -3,4 +3,5 @@ package domain
type BaseRepository interface {
NewId(fields ...string) string
CountAll() (int, error)
Exists(id string) (bool, error)
}

View File

@ -39,6 +39,11 @@ func (r *baseRepository) CountAll() (int, error) {
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 {
recordPrefix := fmt.Sprintf("%s:%s:", r.table, id)
allKey := r.table + "s:all"

View File

@ -7,17 +7,17 @@ import (
"sort"
)
type artistIndex struct {
type artistIndexRepository struct {
baseRepository
}
func NewArtistIndexRepository() domain.ArtistIndexRepository {
r := &artistIndex{}
r := &artistIndexRepository{}
r.init("index", &domain.ArtistIndex{})
return r
}
func (r *artistIndex) Put(m *domain.ArtistIndex) error {
func (r *artistIndexRepository) Put(m *domain.ArtistIndex) error {
if m.Id == "" {
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)
}
func (r *artistIndex) Get(id string) (*domain.ArtistIndex, error) {
func (r *artistIndexRepository) Get(id string) (*domain.ArtistIndex, error) {
var rec interface{}
rec, err := r.readEntity(id)
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)
err := r.loadAll(&indices, "")
return indices, err

View File

@ -23,6 +23,17 @@ func TestIndexRepository(t *testing.T) {
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() {
i := &domain.ArtistIndex{}

View File

@ -5,6 +5,8 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
"github.com/deluan/gosonic/api/responses"
"bytes"
)
func ShouldMatchXML(actual interface{}, expected ...interface{}) string {
@ -25,6 +27,17 @@ func ShouldMatchJSON(actual interface{}, expected ...interface{}) 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 {
var m = make(map[string]interface{})
json.Unmarshal(j, &m)

View 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
}