favicon + ci workflow + makefile changes (#33)
* favicon + ci workflow + makefile changes * fix lint * run workflows on any branch/pr * fix workflow
This commit is contained in:
@@ -166,7 +166,7 @@ async def get_artist_monitoring_status(
|
||||
)
|
||||
try:
|
||||
return await artist_service.get_artist_monitoring_status(artist_id)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001
|
||||
logger.debug("Failed to fetch monitoring status for %s", artist_id, exc_info=True)
|
||||
return ArtistMonitoringStatus(in_lidarr=False, monitored=False, auto_download=False)
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ async def get_profile(
|
||||
try:
|
||||
s = await jellyfin_service.get_stats()
|
||||
return LibraryStats(source="Jellyfin", total_tracks=s.total_tracks, total_albums=s.total_albums, total_artists=s.total_artists)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("Failed to fetch Jellyfin stats for profile: %s", e)
|
||||
return None
|
||||
|
||||
@@ -97,7 +97,7 @@ async def get_profile(
|
||||
try:
|
||||
s = await local_service.get_storage_stats()
|
||||
return LibraryStats(source="Local Files", total_tracks=s.total_tracks, total_albums=s.total_albums, total_artists=s.total_artists, total_size_bytes=s.total_size_bytes, total_size_human=s.total_size_human)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("Failed to fetch Local Files stats for profile: %s", e)
|
||||
return None
|
||||
|
||||
@@ -107,7 +107,7 @@ async def get_profile(
|
||||
try:
|
||||
s = await navidrome_service.get_stats()
|
||||
return LibraryStats(source="Navidrome", total_tracks=s.total_tracks, total_albums=s.total_albums, total_artists=s.total_artists)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("Failed to fetch Navidrome stats for profile: %s", e)
|
||||
return None
|
||||
|
||||
|
||||
@@ -463,7 +463,7 @@ class LibraryService:
|
||||
if future is not None and future.done() and not future.cancelled():
|
||||
try:
|
||||
future.exception()
|
||||
except BaseException:
|
||||
except BaseException: # noqa: BLE001
|
||||
pass
|
||||
except (ExternalServiceError, CircuitOpenError):
|
||||
raise
|
||||
|
||||
@@ -103,7 +103,7 @@ class LibraryPrecacheService:
|
||||
if asyncio.current_task().cancelling() > 0:
|
||||
raise # outer task cancelled; propagate
|
||||
# inner task exited cleanly after cancel
|
||||
except (asyncio.TimeoutError, Exception):
|
||||
except (asyncio.TimeoutError, Exception): # noqa: BLE001
|
||||
logger.warning("Precache task did not exit within 15s of cancel")
|
||||
await status_service.complete_sync(str(exc))
|
||||
raise ExternalServiceError(str(exc))
|
||||
|
||||
@@ -50,6 +50,36 @@ def mount_frontend(app: FastAPI):
|
||||
return FileResponse(logo)
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
|
||||
@app.get("/favicon.ico")
|
||||
async def serve_favicon_ico():
|
||||
if icon := resolve_asset("favicon.ico"):
|
||||
return FileResponse(icon, media_type="image/x-icon", headers={"Cache-Control": "public, max-age=604800"})
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
|
||||
@app.get("/favicon-{size}.png")
|
||||
async def serve_favicon_png(size: str):
|
||||
if icon := resolve_asset(f"favicon-{size}.png"):
|
||||
return FileResponse(icon, media_type="image/png", headers={"Cache-Control": "public, max-age=604800"})
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
|
||||
@app.get("/apple-touch-icon.png")
|
||||
async def serve_apple_touch_icon():
|
||||
if icon := resolve_asset("apple-touch-icon.png"):
|
||||
return FileResponse(icon, media_type="image/png", headers={"Cache-Control": "public, max-age=604800"})
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
|
||||
@app.get("/android-chrome-{size}.png")
|
||||
async def serve_android_chrome(size: str):
|
||||
if icon := resolve_asset(f"android-chrome-{size}.png"):
|
||||
return FileResponse(icon, media_type="image/png", headers={"Cache-Control": "public, max-age=604800"})
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
|
||||
@app.get("/site.webmanifest")
|
||||
async def serve_webmanifest():
|
||||
if manifest := resolve_asset("site.webmanifest"):
|
||||
return FileResponse(manifest, media_type="application/manifest+json", headers={"Cache-Control": "public, max-age=604800"})
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
|
||||
@app.get("/")
|
||||
async def serve_root():
|
||||
if index_html.exists():
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
os.environ.setdefault("ROOT_APP_DIR", tempfile.mkdtemp())
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Tests for LibraryDB paginated query methods."""
|
||||
|
||||
import asyncio
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
@@ -55,83 +54,74 @@ async def _seed(db: LibraryDB, n_albums: int = 100, n_artists: int = 20) -> None
|
||||
# --- Album pagination ---
|
||||
|
||||
|
||||
def test_albums_basic_pagination(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=10, offset=0)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_basic_pagination(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=10, offset=0)
|
||||
assert total == 100
|
||||
assert len(items) == 10
|
||||
|
||||
|
||||
def test_albums_offset_beyond_total(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=10, offset=200)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_offset_beyond_total(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=10, offset=200)
|
||||
assert total == 100
|
||||
assert len(items) == 0
|
||||
|
||||
|
||||
def test_albums_last_partial_page(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=30, offset=90)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_last_partial_page(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=30, offset=90)
|
||||
assert total == 100
|
||||
assert len(items) == 10
|
||||
|
||||
|
||||
def test_albums_sort_by_title_asc(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, _ = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, sort_by="title", sort_order="asc")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_sort_by_title_asc(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, _ = await db.get_albums_paginated(limit=100, offset=0, sort_by="title", sort_order="asc")
|
||||
titles = [i.get("title", "") for i in items]
|
||||
assert titles == sorted(titles, key=str.casefold)
|
||||
|
||||
|
||||
def test_albums_sort_by_title_desc(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, _ = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, sort_by="title", sort_order="desc")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_sort_by_title_desc(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, _ = await db.get_albums_paginated(limit=100, offset=0, sort_by="title", sort_order="desc")
|
||||
titles = [i.get("title", "") for i in items]
|
||||
assert titles == sorted(titles, key=str.casefold, reverse=True)
|
||||
|
||||
|
||||
def test_albums_sort_by_year(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, _ = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, sort_by="year", sort_order="desc")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_sort_by_year(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, _ = await db.get_albums_paginated(limit=100, offset=0, sort_by="year", sort_order="desc")
|
||||
years = [i.get("year", 0) or 0 for i in items]
|
||||
assert years == sorted(years, reverse=True)
|
||||
|
||||
|
||||
def test_albums_sort_by_date_added(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, _ = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, sort_by="date_added", sort_order="desc")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_sort_by_date_added(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, _ = await db.get_albums_paginated(limit=100, offset=0, sort_by="date_added", sort_order="desc")
|
||||
dates = [i.get("date_added", 0) or 0 for i in items]
|
||||
assert dates == sorted(dates, reverse=True)
|
||||
|
||||
|
||||
def test_albums_search_by_title(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, search="Album A")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_search_by_title(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=100, offset=0, search="Album A")
|
||||
assert total > 0
|
||||
assert all("Album A" in i.get("title", "") for i in items)
|
||||
|
||||
|
||||
def test_albums_search_by_artist(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, search="Artist A")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_search_by_artist(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=100, offset=0, search="Artist A")
|
||||
assert total > 0
|
||||
assert all(
|
||||
"Artist A" in i.get("artist_name", "") or "Artist A" in i.get("title", "")
|
||||
@@ -139,61 +129,51 @@ def test_albums_search_by_artist(db: LibraryDB):
|
||||
)
|
||||
|
||||
|
||||
def test_albums_search_no_results(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=10, offset=0, search="zzz_no_match_zzz")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_search_no_results(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=10, offset=0, search="zzz_no_match_zzz")
|
||||
assert total == 0
|
||||
assert len(items) == 0
|
||||
|
||||
|
||||
def test_albums_search_case_insensitive(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items_upper, total_upper = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, search="ALBUM A")
|
||||
)
|
||||
items_lower, total_lower = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, search="album a")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_search_case_insensitive(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items_upper, total_upper = await db.get_albums_paginated(limit=100, offset=0, search="ALBUM A")
|
||||
items_lower, total_lower = await db.get_albums_paginated(limit=100, offset=0, search="album a")
|
||||
assert total_upper == total_lower
|
||||
assert len(items_upper) == len(items_lower)
|
||||
|
||||
|
||||
def test_albums_search_escapes_like_metacharacters(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items_pct, total_pct = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, search="100%")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_search_escapes_like_metacharacters(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items_pct, total_pct = await db.get_albums_paginated(limit=100, offset=0, search="100%")
|
||||
assert total_pct == 0
|
||||
assert len(items_pct) == 0
|
||||
items_under, total_under = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=100, offset=0, search="Album_A")
|
||||
)
|
||||
items_under, total_under = await db.get_albums_paginated(limit=100, offset=0, search="Album_A")
|
||||
assert total_under == 0
|
||||
|
||||
|
||||
def test_artists_search_escapes_like_metacharacters(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=100, offset=0, search="Artist%B")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_search_escapes_like_metacharacters(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_artists_paginated(limit=100, offset=0, search="Artist%B")
|
||||
assert total == 0
|
||||
|
||||
|
||||
def test_albums_invalid_sort_falls_back(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=10, offset=0, sort_by="nonexistent")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_invalid_sort_falls_back(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_albums_paginated(limit=10, offset=0, sort_by="nonexistent")
|
||||
assert total == 100
|
||||
assert len(items) == 10
|
||||
|
||||
|
||||
def test_albums_empty_library(db: LibraryDB):
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(limit=10, offset=0)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_empty_library(db: LibraryDB):
|
||||
items, total = await db.get_albums_paginated(limit=10, offset=0)
|
||||
assert total == 0
|
||||
assert len(items) == 0
|
||||
|
||||
@@ -201,64 +181,57 @@ def test_albums_empty_library(db: LibraryDB):
|
||||
# --- Artist pagination ---
|
||||
|
||||
|
||||
def test_artists_basic_pagination(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=5, offset=0)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_basic_pagination(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_artists_paginated(limit=5, offset=0)
|
||||
assert total == 20
|
||||
assert len(items) == 5
|
||||
|
||||
|
||||
def test_artists_offset_beyond_total(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=10, offset=50)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_offset_beyond_total(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_artists_paginated(limit=10, offset=50)
|
||||
assert total == 20
|
||||
assert len(items) == 0
|
||||
|
||||
|
||||
def test_artists_sort_by_name_asc(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, _ = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=20, offset=0, sort_by="name", sort_order="asc")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_sort_by_name_asc(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, _ = await db.get_artists_paginated(limit=20, offset=0, sort_by="name", sort_order="asc")
|
||||
names = [i.get("name", "") for i in items]
|
||||
assert names == sorted(names, key=str.casefold)
|
||||
|
||||
|
||||
def test_artists_sort_by_album_count_desc(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, _ = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=20, offset=0, sort_by="album_count", sort_order="desc")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_sort_by_album_count_desc(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, _ = await db.get_artists_paginated(limit=20, offset=0, sort_by="album_count", sort_order="desc")
|
||||
counts = [i.get("album_count", 0) for i in items]
|
||||
assert counts == sorted(counts, reverse=True)
|
||||
|
||||
|
||||
def test_artists_search(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=20, offset=0, search="Artist B")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_search(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_artists_paginated(limit=20, offset=0, search="Artist B")
|
||||
assert total > 0
|
||||
assert all("Artist B" in i.get("name", "") for i in items)
|
||||
|
||||
|
||||
def test_artists_search_no_results(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db))
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=10, offset=0, search="zzz_no_match_zzz")
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_search_no_results(db: LibraryDB):
|
||||
await _seed(db)
|
||||
items, total = await db.get_artists_paginated(limit=10, offset=0, search="zzz_no_match_zzz")
|
||||
assert total == 0
|
||||
assert len(items) == 0
|
||||
|
||||
|
||||
def test_artists_empty_library(db: LibraryDB):
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(limit=10, offset=0)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_empty_library(db: LibraryDB):
|
||||
items, total = await db.get_artists_paginated(limit=10, offset=0)
|
||||
assert total == 0
|
||||
assert len(items) == 0
|
||||
|
||||
@@ -266,16 +239,15 @@ def test_artists_empty_library(db: LibraryDB):
|
||||
# --- Pagination consistency (no duplicates/missing across pages) ---
|
||||
|
||||
|
||||
def test_albums_pagination_no_duplicates(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db, n_albums=50))
|
||||
@pytest.mark.asyncio
|
||||
async def test_albums_pagination_no_duplicates(db: LibraryDB):
|
||||
await _seed(db, n_albums=50)
|
||||
all_mbids: list[str] = []
|
||||
offset = 0
|
||||
page_size = 10
|
||||
while True:
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_albums_paginated(
|
||||
limit=page_size, offset=offset, sort_by="title", sort_order="asc"
|
||||
)
|
||||
items, total = await db.get_albums_paginated(
|
||||
limit=page_size, offset=offset, sort_by="title", sort_order="asc"
|
||||
)
|
||||
if not items:
|
||||
break
|
||||
@@ -285,16 +257,15 @@ def test_albums_pagination_no_duplicates(db: LibraryDB):
|
||||
assert len(set(all_mbids)) == 50
|
||||
|
||||
|
||||
def test_artists_pagination_no_duplicates(db: LibraryDB):
|
||||
asyncio.get_event_loop().run_until_complete(_seed(db, n_albums=10, n_artists=30))
|
||||
@pytest.mark.asyncio
|
||||
async def test_artists_pagination_no_duplicates(db: LibraryDB):
|
||||
await _seed(db, n_albums=10, n_artists=30)
|
||||
all_mbids: list[str] = []
|
||||
offset = 0
|
||||
page_size = 7
|
||||
while True:
|
||||
items, total = asyncio.get_event_loop().run_until_complete(
|
||||
db.get_artists_paginated(
|
||||
limit=page_size, offset=offset, sort_by="name", sort_order="asc"
|
||||
)
|
||||
items, total = await db.get_artists_paginated(
|
||||
limit=page_size, offset=offset, sort_by="name", sort_order="asc"
|
||||
)
|
||||
if not items:
|
||||
break
|
||||
|
||||
@@ -356,7 +356,7 @@ async def test_request_429(caplog):
|
||||
with caplog.at_level("WARNING"), pytest.raises(RateLimitedError):
|
||||
await repo.get_artist_by_mbid("cc197bad-dc9c-440d-a5b5-d52ba2e14234")
|
||||
assert repo._client.get.call_count == 3
|
||||
assert _audiodb_circuit_breaker.failure_count == 3
|
||||
assert _audiodb_circuit_breaker.failure_count == 1
|
||||
ratelimit_logs = [r.message for r in caplog.records if "audiodb.ratelimit" in r.message]
|
||||
assert len(ratelimit_logs) == 3
|
||||
assert all("retry_after_s=60" in msg for msg in ratelimit_logs)
|
||||
@@ -625,7 +625,7 @@ async def test_rate_limit_failures_open_circuit_and_short_circuit_next_lookup():
|
||||
response = _mock_response(429)
|
||||
repo._client.get = AsyncMock(return_value=response)
|
||||
|
||||
for _ in range(2):
|
||||
for _ in range(5):
|
||||
with pytest.raises(RateLimitedError):
|
||||
await repo.get_artist_by_mbid("cc197bad-dc9c-440d-a5b5-d52ba2e14234")
|
||||
|
||||
@@ -646,7 +646,7 @@ async def test_audiodb_specific_circuit_state_change_logs(caplog):
|
||||
repo._client.get = AsyncMock(return_value=fail_resp)
|
||||
|
||||
with caplog.at_level("INFO"):
|
||||
for _ in range(2):
|
||||
for _ in range(5):
|
||||
with pytest.raises(ExternalServiceError):
|
||||
await repo.get_artist_by_mbid("cc197bad-dc9c-440d-a5b5-d52ba2e14234")
|
||||
|
||||
|
||||
@@ -50,11 +50,13 @@ class TestCacheStatsNonblocking:
|
||||
return fake_du
|
||||
return fake_find
|
||||
|
||||
with patch("services.cache_service.CACHE_DIR") as mock_dir, \
|
||||
with patch("services.cache_service.get_covers_cache_dir") as mock_get_dir, \
|
||||
patch("services.cache_service.shutil.which", return_value="/usr/bin/du"), \
|
||||
patch("services.cache_service.asyncio.to_thread", side_effect=mock_to_thread) as mock_tt:
|
||||
mock_dir = MagicMock()
|
||||
mock_dir.exists.return_value = True
|
||||
mock_dir.__str__ = lambda s: "/app/cache/covers"
|
||||
mock_get_dir.return_value = mock_dir
|
||||
|
||||
stats = await svc.get_stats()
|
||||
|
||||
@@ -67,8 +69,10 @@ class TestCacheStatsNonblocking:
|
||||
"""Second call within TTL returns cached stats without subprocess."""
|
||||
svc = _make_service()
|
||||
|
||||
with patch("services.cache_service.CACHE_DIR") as mock_dir:
|
||||
with patch("services.cache_service.get_covers_cache_dir") as mock_get_dir:
|
||||
mock_dir = MagicMock()
|
||||
mock_dir.exists.return_value = False
|
||||
mock_get_dir.return_value = mock_dir
|
||||
|
||||
stats1 = await svc.get_stats()
|
||||
stats2 = await svc.get_stats()
|
||||
|
||||
@@ -146,7 +146,7 @@ class TestRequestServiceSkipsLidarr:
|
||||
|
||||
svc = RequestService(lidarr, MagicMock(), MagicMock())
|
||||
|
||||
with pytest.raises(ExternalServiceError, match="not configured"):
|
||||
with pytest.raises(ExternalServiceError, match="isn.t configured"):
|
||||
await svc.request_album("test-mbid")
|
||||
|
||||
|
||||
|
||||
@@ -372,8 +372,10 @@ class TestCacheStatsAudioDBWiring:
|
||||
)
|
||||
svc._stats_cache_ttl = 0
|
||||
|
||||
with patch("services.cache_service.CACHE_DIR") as mock_dir:
|
||||
with patch("services.cache_service.get_covers_cache_dir") as mock_get_dir:
|
||||
mock_dir = MagicMock()
|
||||
mock_dir.exists.return_value = False
|
||||
mock_get_dir.return_value = mock_dir
|
||||
stats = await svc.get_stats()
|
||||
|
||||
assert stats.disk_audiodb_artist_count == 15
|
||||
|
||||
Reference in New Issue
Block a user