136 lines
4.5 KiB
Python
136 lines
4.5 KiB
Python
import asyncio
|
|
import logging
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from services.audiodb_browse_queue import AudioDBBrowseQueue, BrowseQueueItem
|
|
|
|
|
|
@pytest.fixture
|
|
def queue():
|
|
return AudioDBBrowseQueue()
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_audiodb_svc():
|
|
svc = AsyncMock()
|
|
svc.fetch_and_cache_artist_images = AsyncMock(return_value=None)
|
|
svc.fetch_and_cache_album_images = AsyncMock(return_value=None)
|
|
return svc
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_prefs():
|
|
prefs = MagicMock()
|
|
settings = MagicMock()
|
|
settings.audiodb_enabled = True
|
|
prefs.get_advanced_settings.return_value = settings
|
|
return prefs
|
|
|
|
|
|
class TestEnqueue:
|
|
@pytest.mark.asyncio
|
|
async def test_enqueue_adds_item(self, queue: AudioDBBrowseQueue):
|
|
await queue.enqueue("artist", "abc-123", name="Coldplay")
|
|
assert queue._queue.qsize() == 1
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_enqueue_dedup_same_mbid(self, queue: AudioDBBrowseQueue):
|
|
await queue.enqueue("artist", "abc-123")
|
|
await queue.enqueue("artist", "abc-123")
|
|
assert queue._queue.qsize() == 1
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_enqueue_different_mbids(self, queue: AudioDBBrowseQueue):
|
|
await queue.enqueue("artist", "abc-123")
|
|
await queue.enqueue("album", "def-456")
|
|
assert queue._queue.qsize() == 2
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_enqueue_full_queue_drops(self, queue: AudioDBBrowseQueue):
|
|
queue._queue = asyncio.Queue(maxsize=2)
|
|
await queue.enqueue("artist", "a")
|
|
await queue.enqueue("artist", "b")
|
|
await queue.enqueue("artist", "c")
|
|
assert queue._queue.qsize() == 2
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dedup_expires(self, queue: AudioDBBrowseQueue):
|
|
await queue.enqueue("artist", "abc-123")
|
|
queue._recent["abc-123"] -= 4000
|
|
await queue.enqueue("artist", "abc-123")
|
|
assert queue._queue.qsize() == 2
|
|
|
|
|
|
class TestConsumer:
|
|
@pytest.mark.asyncio
|
|
async def test_consumer_processes_artist(self, queue, mock_audiodb_svc, mock_prefs):
|
|
await queue.enqueue("artist", "abc-123", name="Coldplay")
|
|
|
|
task = queue.start_consumer(mock_audiodb_svc, mock_prefs)
|
|
await asyncio.sleep(0.05)
|
|
task.cancel()
|
|
try:
|
|
await task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
|
|
mock_audiodb_svc.fetch_and_cache_artist_images.assert_called_once_with(
|
|
"abc-123", "Coldplay", is_monitored=False,
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_consumer_processes_album(self, queue, mock_audiodb_svc, mock_prefs):
|
|
await queue.enqueue("album", "def-456", name="Parachutes", artist_name="Coldplay")
|
|
|
|
task = queue.start_consumer(mock_audiodb_svc, mock_prefs)
|
|
await asyncio.sleep(0.05)
|
|
task.cancel()
|
|
try:
|
|
await task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
|
|
mock_audiodb_svc.fetch_and_cache_album_images.assert_called_once_with(
|
|
"def-456", artist_name="Coldplay", album_name="Parachutes", is_monitored=False,
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_consumer_skips_when_disabled(self, queue, mock_audiodb_svc, mock_prefs):
|
|
mock_prefs.get_advanced_settings.return_value.audiodb_enabled = False
|
|
await queue.enqueue("artist", "abc-123", name="Coldplay")
|
|
|
|
task = queue.start_consumer(mock_audiodb_svc, mock_prefs)
|
|
await asyncio.sleep(0.05)
|
|
task.cancel()
|
|
try:
|
|
await task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
|
|
mock_audiodb_svc.fetch_and_cache_artist_images.assert_not_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_consumer_handles_item_error(self, queue, mock_audiodb_svc, mock_prefs, caplog):
|
|
mock_audiodb_svc.fetch_and_cache_artist_images.side_effect = RuntimeError("boom")
|
|
await queue.enqueue("artist", "abc-123", name="Coldplay")
|
|
|
|
caplog.set_level(logging.ERROR, logger="services.audiodb_browse_queue")
|
|
task = queue.start_consumer(mock_audiodb_svc, mock_prefs)
|
|
await asyncio.sleep(0.05)
|
|
task.cancel()
|
|
try:
|
|
await task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
|
|
assert queue._queue.qsize() == 0
|
|
assert any(
|
|
record.levelno == logging.ERROR
|
|
and "audiodb.browse_queue action=item_error" in record.message
|
|
and "entity_type=artist" in record.message
|
|
and "mbid=abc-123" in record.message
|
|
for record in caplog.records
|
|
)
|