ff49403fd5
- Add GET/PUT /api/artists/{id} for artist settings
- Update sync to create artists table entry (library settings)
- Support partial updates for monitored, path, quality/metadata profiles
- Add e2e tests for get, edit, partial update flows
223 lines
5.4 KiB
Go
223 lines
5.4 KiB
Go
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fujin/music-agregator/testing/e2e/testutil"
|
|
)
|
|
|
|
// TestEditArtist_Flow covers section 1.4 of FLOWS.md:
|
|
// 1. User changes quality profile, root folder, monitoring status
|
|
// 2. Persist to artists table
|
|
func TestEditArtist_Flow(t *testing.T) {
|
|
env := testutil.NewTestEnv(t)
|
|
defer env.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
|
defer cancel()
|
|
|
|
artistName := "Morcheeba"
|
|
|
|
if err := env.CleanupArtistByName(ctx, artistName); err != nil {
|
|
t.Fatalf("cleanup failed: %v", err)
|
|
}
|
|
|
|
syncResp, err := env.POST("/api/sync", map[string]any{
|
|
"artist": artistName,
|
|
"store": true,
|
|
"download": false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("sync failed: %v", err)
|
|
}
|
|
syncResp.AssertStatus(t, 200)
|
|
|
|
var syncResult struct {
|
|
ArtistID string `json:"artist_id"`
|
|
ArtistName string `json:"artist_name"`
|
|
}
|
|
if err := syncResp.DecodeJSON(&syncResult); err != nil {
|
|
t.Fatalf("failed to decode sync response: %v", err)
|
|
}
|
|
|
|
artistID := syncResult.ArtistID
|
|
|
|
t.Run("GetArtistSettings", func(t *testing.T) {
|
|
getResp, err := env.GET("/api/artists/" + artistID)
|
|
if err != nil {
|
|
t.Fatalf("get artist failed: %v", err)
|
|
}
|
|
getResp.AssertStatus(t, 200)
|
|
|
|
var artist struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Monitored bool `json:"monitored"`
|
|
}
|
|
if err := getResp.DecodeJSON(&artist); err != nil {
|
|
t.Fatalf("failed to decode artist: %v", err)
|
|
}
|
|
|
|
if artist.Name != syncResult.ArtistName {
|
|
t.Errorf("expected name=%q, got %q", syncResult.ArtistName, artist.Name)
|
|
}
|
|
})
|
|
|
|
t.Run("UpdateMonitoredStatus", func(t *testing.T) {
|
|
editResp, err := env.PUT("/api/artists/"+artistID, map[string]any{
|
|
"monitored": false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("edit request failed: %v", err)
|
|
}
|
|
editResp.AssertStatus(t, 200)
|
|
|
|
var result struct {
|
|
ID string `json:"id"`
|
|
Monitored bool `json:"monitored"`
|
|
}
|
|
if err := editResp.DecodeJSON(&result); err != nil {
|
|
t.Fatalf("failed to decode edit response: %v", err)
|
|
}
|
|
|
|
if result.Monitored != false {
|
|
t.Error("expected monitored=false after edit")
|
|
}
|
|
|
|
getResp, _ := env.GET("/api/artists/" + artistID)
|
|
var artist struct {
|
|
Monitored bool `json:"monitored"`
|
|
}
|
|
getResp.DecodeJSON(&artist)
|
|
if artist.Monitored != false {
|
|
t.Error("expected monitored=false to persist")
|
|
}
|
|
})
|
|
|
|
t.Run("UpdateQualityProfile", func(t *testing.T) {
|
|
editResp, err := env.PUT("/api/artists/"+artistID, map[string]any{
|
|
"quality_profile_id": "test-profile-id",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("edit request failed: %v", err)
|
|
}
|
|
editResp.AssertStatus(t, 200)
|
|
|
|
var result struct {
|
|
QualityProfileID *string `json:"quality_profile_id"`
|
|
}
|
|
if err := editResp.DecodeJSON(&result); err != nil {
|
|
t.Fatalf("failed to decode edit response: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("UpdateRootFolder", func(t *testing.T) {
|
|
editResp, err := env.PUT("/api/artists/"+artistID, map[string]any{
|
|
"root_folder_id": "test-folder-id",
|
|
"path": "/music/morcheeba",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("edit request failed: %v", err)
|
|
}
|
|
editResp.AssertStatus(t, 200)
|
|
|
|
var result struct {
|
|
RootFolderID *string `json:"root_folder_id"`
|
|
Path *string `json:"path"`
|
|
}
|
|
if err := editResp.DecodeJSON(&result); err != nil {
|
|
t.Fatalf("failed to decode edit response: %v", err)
|
|
}
|
|
|
|
if result.Path == nil || *result.Path != "/music/morcheeba" {
|
|
t.Errorf("expected path=/music/morcheeba, got %v", result.Path)
|
|
}
|
|
})
|
|
|
|
t.Cleanup(func() {
|
|
env.CleanupArtistByName(context.Background(), syncResult.ArtistName)
|
|
})
|
|
}
|
|
|
|
func TestEditArtist_NotFound(t *testing.T) {
|
|
env := testutil.NewTestEnv(t)
|
|
defer env.Close()
|
|
|
|
editResp, err := env.PUT("/api/artists/nonexistent-artist-id-99999", map[string]any{
|
|
"monitored": false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("edit request failed: %v", err)
|
|
}
|
|
|
|
editResp.AssertStatus(t, 404)
|
|
}
|
|
|
|
func TestEditArtist_PartialUpdate(t *testing.T) {
|
|
env := testutil.NewTestEnv(t)
|
|
defer env.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
|
defer cancel()
|
|
|
|
artistName := "Zero 7"
|
|
|
|
if err := env.CleanupArtistByName(ctx, artistName); err != nil {
|
|
t.Fatalf("cleanup failed: %v", err)
|
|
}
|
|
|
|
syncResp, err := env.POST("/api/sync", map[string]any{
|
|
"artist": artistName,
|
|
"store": true,
|
|
"download": false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("sync failed: %v", err)
|
|
}
|
|
syncResp.AssertStatus(t, 200)
|
|
|
|
var syncResult struct {
|
|
ArtistID string `json:"artist_id"`
|
|
ArtistName string `json:"artist_name"`
|
|
}
|
|
syncResp.DecodeJSON(&syncResult)
|
|
|
|
firstEdit, err := env.PUT("/api/artists/"+syncResult.ArtistID, map[string]any{
|
|
"monitored": false,
|
|
"path": "/music/zero7",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("first edit failed: %v", err)
|
|
}
|
|
firstEdit.AssertStatus(t, 200)
|
|
|
|
secondEdit, err := env.PUT("/api/artists/"+syncResult.ArtistID, map[string]any{
|
|
"monitored": true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("second edit failed: %v", err)
|
|
}
|
|
secondEdit.AssertStatus(t, 200)
|
|
|
|
getResp, _ := env.GET("/api/artists/" + syncResult.ArtistID)
|
|
var artist struct {
|
|
Monitored bool `json:"monitored"`
|
|
Path *string `json:"path"`
|
|
}
|
|
getResp.DecodeJSON(&artist)
|
|
|
|
if artist.Monitored != true {
|
|
t.Error("expected monitored=true after second edit")
|
|
}
|
|
|
|
if artist.Path == nil || *artist.Path != "/music/zero7" {
|
|
t.Errorf("expected path to be preserved, got %v", artist.Path)
|
|
}
|
|
|
|
t.Cleanup(func() {
|
|
env.CleanupArtistByName(context.Background(), syncResult.ArtistName)
|
|
})
|
|
}
|