mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
Removed the now-empty userValidation.js and its test file since the validation function was reduced to a no-op. Cleaned up the callers in UserCreate and UserEdit that referenced it. Simplified the mock GetUserLibraries fallback to delegate to GetAll instead of duplicating its logic, and removed redundant comments.
321 lines
6.9 KiB
Go
321 lines
6.9 KiB
Go
package tests
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"strconv"
|
|
|
|
"github.com/Masterminds/squirrel"
|
|
"github.com/deluan/rest"
|
|
"github.com/navidrome/navidrome/model"
|
|
)
|
|
|
|
type MockLibraryRepo struct {
|
|
model.LibraryRepository
|
|
Data map[int]model.Library
|
|
UserLibraries map[string][]int // per-user library ID assignments
|
|
Err error
|
|
PutFn func(*model.Library) error // Allow custom Put behavior for testing
|
|
}
|
|
|
|
func (m *MockLibraryRepo) SetData(data model.Libraries) {
|
|
m.Data = make(map[int]model.Library)
|
|
for _, d := range data {
|
|
m.Data[d.ID] = d
|
|
}
|
|
}
|
|
|
|
func (m *MockLibraryRepo) GetAll(...model.QueryOptions) (model.Libraries, error) {
|
|
if m.Err != nil {
|
|
return nil, m.Err
|
|
}
|
|
var libraries model.Libraries
|
|
for _, lib := range m.Data {
|
|
libraries = append(libraries, lib)
|
|
}
|
|
// Sort by ID for predictable order
|
|
slices.SortFunc(libraries, func(a, b model.Library) int {
|
|
return a.ID - b.ID
|
|
})
|
|
return libraries, nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) CountAll(qo ...model.QueryOptions) (int64, error) {
|
|
if m.Err != nil {
|
|
return 0, m.Err
|
|
}
|
|
|
|
// If no query options, return total count
|
|
if len(qo) == 0 || qo[0].Filters == nil {
|
|
return int64(len(m.Data)), nil
|
|
}
|
|
|
|
// Handle squirrel.Eq filter for ID validation
|
|
if eq, ok := qo[0].Filters.(squirrel.Eq); ok {
|
|
if idFilter, exists := eq["id"]; exists {
|
|
if ids, isSlice := idFilter.([]int); isSlice {
|
|
count := 0
|
|
for _, id := range ids {
|
|
if _, exists := m.Data[id]; exists {
|
|
count++
|
|
}
|
|
}
|
|
return int64(count), nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// Default to total count for other filters
|
|
return int64(len(m.Data)), nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) Get(id int) (*model.Library, error) {
|
|
if m.Err != nil {
|
|
return nil, m.Err
|
|
}
|
|
if lib, ok := m.Data[id]; ok {
|
|
return &lib, nil
|
|
}
|
|
return nil, model.ErrNotFound
|
|
}
|
|
|
|
func (m *MockLibraryRepo) GetPath(id int) (string, error) {
|
|
if m.Err != nil {
|
|
return "", m.Err
|
|
}
|
|
if lib, ok := m.Data[id]; ok {
|
|
return lib.Path, nil
|
|
}
|
|
return "", model.ErrNotFound
|
|
}
|
|
|
|
func (m *MockLibraryRepo) Put(library *model.Library) error {
|
|
if m.PutFn != nil {
|
|
return m.PutFn(library)
|
|
}
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
if m.Data == nil {
|
|
m.Data = make(map[int]model.Library)
|
|
}
|
|
m.Data[library.ID] = *library
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) Delete(id int) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
if _, ok := m.Data[id]; !ok {
|
|
return model.ErrNotFound
|
|
}
|
|
delete(m.Data, id)
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) StoreMusicFolder() error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) AddArtist(id int, artistID string) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) ScanBegin(id int, fullScan bool) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) ScanEnd(id int) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) ScanInProgress() (bool, error) {
|
|
if m.Err != nil {
|
|
return false, m.Err
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) RefreshStats(id int) error {
|
|
return nil
|
|
}
|
|
|
|
// User-library association methods - mock implementations
|
|
|
|
func (m *MockLibraryRepo) GetUsersWithLibraryAccess(libraryID int) (model.Users, error) {
|
|
if m.Err != nil {
|
|
return nil, m.Err
|
|
}
|
|
// Mock: return empty users for now
|
|
return model.Users{}, nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) Count(options ...rest.QueryOptions) (int64, error) {
|
|
return m.CountAll()
|
|
}
|
|
|
|
func (m *MockLibraryRepo) Read(id string) (any, error) {
|
|
idInt, _ := strconv.Atoi(id)
|
|
mf, err := m.Get(idInt)
|
|
if errors.Is(err, model.ErrNotFound) {
|
|
return nil, rest.ErrNotFound
|
|
}
|
|
return mf, err
|
|
}
|
|
|
|
func (m *MockLibraryRepo) ReadAll(options ...rest.QueryOptions) (any, error) {
|
|
return m.GetAll()
|
|
}
|
|
|
|
func (m *MockLibraryRepo) EntityName() string {
|
|
return "library"
|
|
}
|
|
|
|
func (m *MockLibraryRepo) NewInstance() any {
|
|
return &model.Library{}
|
|
}
|
|
|
|
// REST Repository methods (string-based IDs)
|
|
|
|
func (m *MockLibraryRepo) Save(entity any) (string, error) {
|
|
lib := entity.(*model.Library)
|
|
if m.Err != nil {
|
|
return "", m.Err
|
|
}
|
|
|
|
// Validate required fields
|
|
if lib.Name == "" {
|
|
return "", &rest.ValidationError{Errors: map[string]string{"name": "library name is required"}}
|
|
}
|
|
if lib.Path == "" {
|
|
return "", &rest.ValidationError{Errors: map[string]string{"path": "library path is required"}}
|
|
}
|
|
|
|
// Generate ID if not set
|
|
if lib.ID == 0 {
|
|
lib.ID = len(m.Data) + 1
|
|
}
|
|
if m.Data == nil {
|
|
m.Data = make(map[int]model.Library)
|
|
}
|
|
m.Data[lib.ID] = *lib
|
|
return strconv.Itoa(lib.ID), nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) Update(id string, entity any, cols ...string) error {
|
|
lib := entity.(*model.Library)
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
|
|
// Validate required fields
|
|
if lib.Name == "" {
|
|
return &rest.ValidationError{Errors: map[string]string{"name": "library name is required"}}
|
|
}
|
|
if lib.Path == "" {
|
|
return &rest.ValidationError{Errors: map[string]string{"path": "library path is required"}}
|
|
}
|
|
|
|
idInt, err := strconv.Atoi(id)
|
|
if err != nil {
|
|
return errors.New("invalid ID format")
|
|
}
|
|
if _, exists := m.Data[idInt]; !exists {
|
|
return rest.ErrNotFound
|
|
}
|
|
lib.ID = idInt
|
|
m.Data[idInt] = *lib
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) DeleteByStringID(id string) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
idInt, err := strconv.Atoi(id)
|
|
if err != nil {
|
|
return errors.New("invalid ID format")
|
|
}
|
|
if _, exists := m.Data[idInt]; !exists {
|
|
return rest.ErrNotFound
|
|
}
|
|
delete(m.Data, idInt)
|
|
return nil
|
|
}
|
|
|
|
// Service-level methods for core.Library interface
|
|
|
|
func (m *MockLibraryRepo) GetUserLibraries(ctx context.Context, userID string) (model.Libraries, error) {
|
|
if m.Err != nil {
|
|
return nil, m.Err
|
|
}
|
|
if userID == "non-existent" {
|
|
return nil, model.ErrNotFound
|
|
}
|
|
if m.UserLibraries != nil {
|
|
ids, ok := m.UserLibraries[userID]
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
var libraries model.Libraries
|
|
for _, id := range ids {
|
|
if lib, exists := m.Data[id]; exists {
|
|
libraries = append(libraries, lib)
|
|
}
|
|
}
|
|
slices.SortFunc(libraries, func(a, b model.Library) int {
|
|
return a.ID - b.ID
|
|
})
|
|
return libraries, nil
|
|
}
|
|
return m.GetAll()
|
|
}
|
|
|
|
func (m *MockLibraryRepo) SetUserLibraries(ctx context.Context, userID string, libraryIDs []int) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
if userID == "non-existent" {
|
|
return model.ErrNotFound
|
|
}
|
|
if userID == "admin-1" {
|
|
return fmt.Errorf("%w: cannot manually assign libraries to admin users", model.ErrValidation)
|
|
}
|
|
for _, id := range libraryIDs {
|
|
if _, exists := m.Data[id]; !exists {
|
|
return fmt.Errorf("%w: library ID %d does not exist", model.ErrValidation, id)
|
|
}
|
|
}
|
|
if m.UserLibraries == nil {
|
|
m.UserLibraries = make(map[string][]int)
|
|
}
|
|
m.UserLibraries[userID] = libraryIDs
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLibraryRepo) ValidateLibraryAccess(ctx context.Context, userID string, libraryID int) error {
|
|
if m.Err != nil {
|
|
return m.Err
|
|
}
|
|
// For testing purposes, allow access to all libraries
|
|
return nil
|
|
}
|
|
|
|
var _ model.LibraryRepository = (*MockLibraryRepo)(nil)
|
|
var _ model.ResourceRepository = (*MockLibraryRepo)(nil)
|