"""Tests for `worker_utils.set_album_api_track_count` — the shared helper enrichment workers call to cache authoritative track counts.""" import sqlite3 from core.worker_utils import set_album_api_track_count class _RecordingCursor: """Minimal cursor stand-in that captures execute() calls.""" def __init__(self): self.calls = [] def execute(self, query, params=None): self.calls.append((query, params)) # --------------------------------------------------------------------------- # Happy-path writes # --------------------------------------------------------------------------- def test_writes_positive_int_count(): cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-1", 12) assert len(cursor.calls) == 1 query, params = cursor.calls[0] assert "UPDATE albums SET api_track_count = ?" in query assert "WHERE id = ?" in query assert params == (12, "album-1") def test_coerces_numeric_string_to_int(): """Deezer / raw API dicts often have track counts as strings.""" cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-2", "14") assert cursor.calls[0][1] == (14, "album-2") def test_writes_one_for_single_track_album(): cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-single", 1) assert cursor.calls[0][1] == (1, "album-single") # --------------------------------------------------------------------------- # Skip-write cases (don't overwrite good values with bad ones) # --------------------------------------------------------------------------- def test_skips_write_when_count_is_zero(): """A source that doesn't report track counts must not clobber a value written by another source.""" cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-x", 0) assert cursor.calls == [] def test_skips_write_when_count_is_none(): cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-x", None) assert cursor.calls == [] def test_skips_write_when_count_is_negative(): cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-x", -1) assert cursor.calls == [] def test_skips_write_on_non_numeric_string(): cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-x", "not a number") assert cursor.calls == [] def test_skips_write_on_non_numeric_object(): cursor = _RecordingCursor() set_album_api_track_count(cursor, "album-x", object()) assert cursor.calls == [] # --------------------------------------------------------------------------- # Does not commit — caller owns the transaction # --------------------------------------------------------------------------- def test_helper_does_not_commit(): """Workers batch multiple UPDATEs into one transaction. The helper must not call commit() or it would break that batching.""" class _StrictCursor(_RecordingCursor): commits = 0 def commit(self): # pragma: no cover — asserts it's never called _StrictCursor.commits += 1 cursor = _StrictCursor() set_album_api_track_count(cursor, "album-y", 5) assert _StrictCursor.commits == 0 # --------------------------------------------------------------------------- # Error isolation — a cursor.execute failure must not poison the worker's # other UPDATEs in the same transaction # --------------------------------------------------------------------------- def test_swallows_cursor_execute_errors(): """If the column doesn't exist yet (e.g., migration hasn't run) or the DB is otherwise unhappy, the helper must not propagate the error. Otherwise the worker's other UPDATEs (spotify_album_id, thumb_url, etc.) batched in the same transaction would roll back.""" class _BrokenCursor: def execute(self, query, params=None): raise RuntimeError("no such column: api_track_count") cursor = _BrokenCursor() # Should not raise. set_album_api_track_count(cursor, "album-z", 10) def test_repairs_missing_api_track_count_column(): conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE albums (id TEXT PRIMARY KEY, title TEXT)") cursor.execute("INSERT INTO albums (id, title) VALUES ('album-z', 'Album')") set_album_api_track_count(cursor, "album-z", 10) cursor.execute("PRAGMA table_info(albums)") cols = {row[1] for row in cursor.fetchall()} cursor.execute("SELECT api_track_count FROM albums WHERE id = 'album-z'") row = cursor.fetchone() conn.close() assert 'api_track_count' in cols assert row[0] == 10