fix: address fourth code review findings
- Fix FK constraint violation in SyncArtistDiscography: delete notifications_sent rows before external_releases to prevent constraint failure when re-syncing artists with prior notifications. - Implement per-artist type filtering: FilterReleaseGroups now accepts FilterOptions with IgnoreSingles/IgnoreCompilations flags, read from artist_settings table via getArtistFilterOptions. - Fix inconsistent error wrapping: GetExternalRelease now wraps errors with fmt.Errorf like all other functions in the package; updated test to use errors.Is for sql.ErrNoRows check. - Add tests: FilterReleaseGroups ignore singles/compilations, SyncArtistDiscography per-artist type filtering, and FK-safe resync.
This commit is contained in:
@@ -740,3 +740,152 @@ func TestSyncArtistDiscography_CleansStaleReleases(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: per-artist ignore_singles filters out Single type
|
||||
// -----------------------------------------------------------------------
|
||||
func TestSyncArtistDiscography_IgnoreSingles(t *testing.T) {
|
||||
artistMBID := "artist-singles-test"
|
||||
artistName := "Singles Artist"
|
||||
|
||||
server := newTestMBServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := mbReleaseGroupListResponse(
|
||||
mbReleaseGroupXML("rg-1", "Album", "Album", "Official", artistMBID, artistName, "2024-01-01")+
|
||||
mbReleaseGroupXML("rg-2", "Single", "Single", "Official", artistMBID, artistName, "2024-02-01"),
|
||||
2,
|
||||
)
|
||||
w.Write([]byte(resp))
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
db := newTestDB(t)
|
||||
defer db.Close()
|
||||
// Seed artist with ignore_singles = true.
|
||||
if _, err := db.Conn().Exec(
|
||||
"INSERT INTO artist_settings (id, name, ignore_singles, monitored) VALUES (?, ?, 1, 1)",
|
||||
artistMBID, artistName,
|
||||
); err != nil {
|
||||
t.Fatalf("seed artist: %v", err)
|
||||
}
|
||||
|
||||
client := newTestClient(server.URL)
|
||||
ctx := context.Background()
|
||||
|
||||
releases, err := SyncArtistDiscography(ctx, client, db, artistMBID, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("SyncArtistDiscography() error: %v", err)
|
||||
}
|
||||
if len(releases) != 1 {
|
||||
t.Fatalf("expected 1 release (singles filtered), got %d", len(releases))
|
||||
}
|
||||
if releases[0].Type != "Album" {
|
||||
t.Errorf("expected type Album, got %s", releases[0].Type)
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: per-artist ignore_compilations filters out Compilation type
|
||||
// -----------------------------------------------------------------------
|
||||
func TestSyncArtistDiscography_IgnoreCompilations(t *testing.T) {
|
||||
artistMBID := "artist-comp-test"
|
||||
artistName := "Comp Artist"
|
||||
|
||||
server := newTestMBServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := mbReleaseGroupListResponse(
|
||||
mbReleaseGroupXML("rg-1", "Album", "Album", "Official", artistMBID, artistName, "2024-01-01")+
|
||||
mbReleaseGroupXML("rg-2", "Best Of", "Compilation", "Official", artistMBID, artistName, "2024-02-01"),
|
||||
2,
|
||||
)
|
||||
w.Write([]byte(resp))
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
db := newTestDB(t)
|
||||
defer db.Close()
|
||||
// Seed artist with ignore_compilations = true.
|
||||
if _, err := db.Conn().Exec(
|
||||
"INSERT INTO artist_settings (id, name, ignore_compilations, monitored) VALUES (?, ?, 1, 1)",
|
||||
artistMBID, artistName,
|
||||
); err != nil {
|
||||
t.Fatalf("seed artist: %v", err)
|
||||
}
|
||||
|
||||
client := newTestClient(server.URL)
|
||||
ctx := context.Background()
|
||||
|
||||
releases, err := SyncArtistDiscography(ctx, client, db, artistMBID, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("SyncArtistDiscography() error: %v", err)
|
||||
}
|
||||
if len(releases) != 1 {
|
||||
t.Fatalf("expected 1 release (compilations filtered), got %d", len(releases))
|
||||
}
|
||||
if releases[0].Type != "Album" {
|
||||
t.Errorf("expected type Album, got %s", releases[0].Type)
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: resync with notifications_sent does not violate FK constraint
|
||||
// -----------------------------------------------------------------------
|
||||
func TestSyncArtistDiscography_ResyncWithNotifications(t *testing.T) {
|
||||
artistMBID := "artist-fk-test"
|
||||
artistName := "FK Artist"
|
||||
|
||||
server := newTestMBServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := mbReleaseGroupListResponse(
|
||||
mbReleaseGroupXML("rg-1", "Album", "Album", "Official", artistMBID, artistName, "2024-01-01"),
|
||||
1,
|
||||
)
|
||||
w.Write([]byte(resp))
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
db := newTestDB(t)
|
||||
defer db.Close()
|
||||
seedArtist(t, db, artistMBID, artistName)
|
||||
|
||||
client := newTestClient(server.URL)
|
||||
ctx := context.Background()
|
||||
|
||||
// First sync.
|
||||
_, err := SyncArtistDiscography(ctx, client, db, artistMBID, 24*time.Hour)
|
||||
if err != nil {
|
||||
t.Fatalf("first SyncArtistDiscography() error: %v", err)
|
||||
}
|
||||
|
||||
// Insert a notifications_sent row referencing the release.
|
||||
_, err = db.Conn().Exec(
|
||||
"INSERT INTO notifications_sent (rgid) VALUES (?)", "rg-1",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("insert notification: %v", err)
|
||||
}
|
||||
|
||||
// Force cache expiry.
|
||||
_, err = db.Conn().Exec("UPDATE external_releases SET cached_at = ? WHERE artist_id = ?",
|
||||
time.Now().Add(-48*time.Hour).Format("2006-01-02 15:04:05"), artistMBID)
|
||||
if err != nil {
|
||||
t.Fatalf("expire cache: %v", err)
|
||||
}
|
||||
|
||||
// Second sync should succeed without FK violation.
|
||||
releases, err := SyncArtistDiscography(ctx, client, db, artistMBID, 24*time.Hour)
|
||||
if err != nil {
|
||||
t.Fatalf("second SyncArtistDiscography() error (FK violation?): %v", err)
|
||||
}
|
||||
if len(releases) != 1 {
|
||||
t.Fatalf("expected 1 release after resync, got %d", len(releases))
|
||||
}
|
||||
|
||||
// Notification should have been cleaned up.
|
||||
var count int
|
||||
err = db.Conn().QueryRow("SELECT COUNT(*) FROM notifications_sent WHERE rgid = ?", "rg-1").Scan(&count)
|
||||
if err != nil {
|
||||
t.Fatalf("count notifications: %v", err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Errorf("expected 0 notifications after resync, got %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user