soulsync/tests/test_enrichment_artist_id_guard.py
BoulderBadgeDad 85549197e6 Apply artist-id name-guard to audiodb/qobuz/tidal workers too
The blind 'correct the parent artist's source id from an album/track match'
logic was copy-pasted into four enrichment workers; the Deezer fix only covered
one. AudioDB, Qobuz, and Tidal had the identical bug and would corrupt their own
id columns (and re-corrupt after any cleanup).

All three now gate the correction on a name match between the result's artist
and the parent artist (audiodb reads result['strArtist']; qobuz/tidal thread the
result artist name in from their callers, as Deezer does). Regression tests
cover mismatch-skips and match-corrects for each.
2026-06-05 07:47:59 -07:00

100 lines
4.2 KiB
Python

"""Regression: the album/track-driven 'artist id correction' in every
enrichment worker that has it must NOT overwrite an artist's source id unless
the result's artist name actually matches.
This is the same Kendrick/Jorja bug fixed in the Deezer worker (see
tests/test_deezer_worker_artist_id_guard.py), proven here to be closed in the
three other workers that copy-pasted the pattern: AudioDB, Qobuz, Tidal.
A track our library credits to Jorja Smith that lives on Kendrick's curated
'Black Panther' album resolves to that album, whose primary artist is Kendrick.
Without a name check, each worker would 'correct' Jorja's source id to
Kendrick's — corrupting it (and sharing one id across unrelated artists).
"""
from __future__ import annotations
from core.audiodb_worker import AudioDBWorker
from core.qobuz_worker import QobuzWorker
from core.tidal_worker import TidalWorker
def _stub(cls, correct_attr):
"""Build a bare worker instance (no __init__/clients) wired to record
corrections instead of writing to a db."""
w = cls.__new__(cls)
w.name_similarity_threshold = 0.80
w._corrections = []
setattr(w, correct_attr, lambda item, cid: w._corrections.append((item['id'], cid)))
return w
def _item(artist_name, parent_id, id_key):
return {'type': 'track', 'id': 1, 'name': 'Some Track',
'artist': artist_name, id_key: parent_id}
# --------------------------------------------------------------------------
# AudioDB — _verify_artist_id(item, result_dict); name is result['strArtist'].
# --------------------------------------------------------------------------
def test_audiodb_skips_correction_on_name_mismatch():
w = _stub(AudioDBWorker, '_correct_artist_audiodb_id')
item = _item('Jorja Smith', '111', 'artist_audiodb_id')
w._verify_artist_id(item, {'idArtist': '999', 'strArtist': 'Kendrick Lamar'})
assert w._corrections == []
def test_audiodb_corrects_on_name_match():
w = _stub(AudioDBWorker, '_correct_artist_audiodb_id')
item = _item('Kendrick Lamar', '111', 'artist_audiodb_id')
w._verify_artist_id(item, {'idArtist': '999', 'strArtist': 'Kendrick Lamar'})
assert w._corrections == [(1, '999')]
# --------------------------------------------------------------------------
# Qobuz — _verify_artist_id(item, result_artist_id, result_artist_name).
# --------------------------------------------------------------------------
def test_qobuz_skips_correction_on_name_mismatch():
w = _stub(QobuzWorker, '_correct_artist_qobuz_id')
item = _item('Jorja Smith', '111', 'artist_qobuz_id')
w._verify_artist_id(item, '999', 'Kendrick Lamar')
assert w._corrections == []
def test_qobuz_corrects_on_name_match():
w = _stub(QobuzWorker, '_correct_artist_qobuz_id')
item = _item('Kendrick Lamar', '111', 'artist_qobuz_id')
w._verify_artist_id(item, '999', 'Kendrick Lamar')
assert w._corrections == [(1, '999')]
# --------------------------------------------------------------------------
# Tidal — _verify_artist_id(item, result_artist_id, result_artist_name).
# --------------------------------------------------------------------------
def test_tidal_skips_correction_on_name_mismatch():
w = _stub(TidalWorker, '_correct_artist_tidal_id')
item = _item('Jorja Smith', '111', 'artist_tidal_id')
w._verify_artist_id(item, '999', 'Kendrick Lamar')
assert w._corrections == []
def test_tidal_corrects_on_name_match():
w = _stub(TidalWorker, '_correct_artist_tidal_id')
item = _item('Kendrick Lamar', '111', 'artist_tidal_id')
w._verify_artist_id(item, '999', 'Kendrick Lamar')
assert w._corrections == [(1, '999')]
# --------------------------------------------------------------------------
# Shared: a missing result name preserves the old "trust the search" behavior
# (only the workers that pass an id+name — qobuz/tidal — exercise this path).
# --------------------------------------------------------------------------
def test_qobuz_missing_result_name_preserves_old_behavior():
w = _stub(QobuzWorker, '_correct_artist_qobuz_id')
item = _item('Kendrick Lamar', '111', 'artist_qobuz_id')
w._verify_artist_id(item, '999', None)
assert w._corrections == [(1, '999')]