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