df779c9e6d
* fix: Sync issues - AudioDB warmig + automatic sync skips * progress ui/ux + discovery and album fixes * artist fixes * several request level fixes and improvements * handle request fails + artist refresh + resilience fixes * fix format * fix stop sync fail + last.fn mbid issues + failures/validation reworks
220 lines
9.2 KiB
Python
220 lines
9.2 KiB
Python
"""Round-trip tests for AdvancedSettings ↔ AdvancedSettingsFrontend conversion."""
|
|
|
|
import msgspec
|
|
import pytest
|
|
|
|
from api.v1.schemas.advanced_settings import AdvancedSettings, AdvancedSettingsFrontend
|
|
|
|
|
|
class TestDirectRemoteImagesRoundTrip:
|
|
def test_default_value_is_true(self) -> None:
|
|
settings = AdvancedSettings()
|
|
assert settings.direct_remote_images_enabled is True
|
|
|
|
def test_frontend_default_is_true(self) -> None:
|
|
frontend = AdvancedSettingsFrontend()
|
|
assert frontend.direct_remote_images_enabled is True
|
|
|
|
def test_roundtrip_preserves_true(self) -> None:
|
|
backend = AdvancedSettings(direct_remote_images_enabled=True)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.direct_remote_images_enabled is True
|
|
restored = frontend.to_backend()
|
|
assert restored.direct_remote_images_enabled is True
|
|
|
|
def test_roundtrip_preserves_false(self) -> None:
|
|
backend = AdvancedSettings(direct_remote_images_enabled=False)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.direct_remote_images_enabled is False
|
|
restored = frontend.to_backend()
|
|
assert restored.direct_remote_images_enabled is False
|
|
|
|
|
|
class TestAudioDBNameSearchFallbackRoundTrip:
|
|
def test_default_value_is_false(self) -> None:
|
|
settings = AdvancedSettings()
|
|
assert settings.audiodb_name_search_fallback is False
|
|
|
|
def test_frontend_default_is_false(self) -> None:
|
|
frontend = AdvancedSettingsFrontend()
|
|
assert frontend.audiodb_name_search_fallback is False
|
|
|
|
def test_roundtrip_preserves_true(self) -> None:
|
|
backend = AdvancedSettings(audiodb_name_search_fallback=True)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.audiodb_name_search_fallback is True
|
|
restored = frontend.to_backend()
|
|
assert restored.audiodb_name_search_fallback is True
|
|
|
|
def test_roundtrip_preserves_false(self) -> None:
|
|
backend = AdvancedSettings(audiodb_name_search_fallback=False)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.audiodb_name_search_fallback is False
|
|
restored = frontend.to_backend()
|
|
assert restored.audiodb_name_search_fallback is False
|
|
|
|
|
|
class TestCacheTtlAudiodbFoundRoundTrip:
|
|
def test_default_value(self) -> None:
|
|
settings = AdvancedSettings()
|
|
frontend = AdvancedSettingsFrontend.from_backend(settings)
|
|
assert frontend.cache_ttl_audiodb_found == 168
|
|
|
|
def test_roundtrip_preserves(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_audiodb_found=604800)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_audiodb_found == 168
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_audiodb_found == 604800
|
|
|
|
def test_custom_value_roundtrip(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_audiodb_found=36000)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_audiodb_found == 10
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_audiodb_found == 36000
|
|
|
|
|
|
class TestCacheTtlAudiodbNotFoundRoundTrip:
|
|
def test_default_value(self) -> None:
|
|
settings = AdvancedSettings()
|
|
frontend = AdvancedSettingsFrontend.from_backend(settings)
|
|
assert frontend.cache_ttl_audiodb_not_found == 24
|
|
|
|
def test_roundtrip_preserves(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_audiodb_not_found=86400)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_audiodb_not_found == 24
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_audiodb_not_found == 86400
|
|
|
|
def test_custom_value_roundtrip(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_audiodb_not_found=7200)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_audiodb_not_found == 2
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_audiodb_not_found == 7200
|
|
|
|
|
|
class TestCacheTtlAudiodbLibraryRoundTrip:
|
|
def test_default_value(self) -> None:
|
|
settings = AdvancedSettings()
|
|
frontend = AdvancedSettingsFrontend.from_backend(settings)
|
|
assert frontend.cache_ttl_audiodb_library == 336
|
|
|
|
def test_roundtrip_preserves(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_audiodb_library=1209600)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_audiodb_library == 336
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_audiodb_library == 1209600
|
|
|
|
|
|
class TestCacheTtlRecentlyViewedBytesRoundTrip:
|
|
def test_default_value(self) -> None:
|
|
settings = AdvancedSettings()
|
|
frontend = AdvancedSettingsFrontend.from_backend(settings)
|
|
assert frontend.cache_ttl_recently_viewed_bytes == 48
|
|
|
|
def test_roundtrip_preserves(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_recently_viewed_bytes=172800)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_recently_viewed_bytes == 48
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_recently_viewed_bytes == 172800
|
|
|
|
|
|
class TestAudiodbValidationClamping:
|
|
def test_cache_ttl_found_below_min(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_audiodb_found=100)
|
|
|
|
def test_cache_ttl_found_above_max(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_audiodb_found=99999999)
|
|
|
|
def test_cache_ttl_not_found_below_min(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_audiodb_not_found=100)
|
|
|
|
def test_cache_ttl_not_found_above_max(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_audiodb_not_found=999999)
|
|
|
|
def test_cache_ttl_library_below_min(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_audiodb_library=100)
|
|
|
|
def test_cache_ttl_library_above_max(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_audiodb_library=99999999)
|
|
|
|
def test_cache_ttl_recently_viewed_bytes_below_min(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_recently_viewed_bytes=100)
|
|
|
|
def test_cache_ttl_recently_viewed_bytes_above_max(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_recently_viewed_bytes=999999)
|
|
|
|
def test_api_key_empty_coerced(self) -> None:
|
|
settings = AdvancedSettings(audiodb_api_key="")
|
|
assert settings.audiodb_api_key == "123"
|
|
|
|
def test_api_key_whitespace_coerced(self) -> None:
|
|
settings = AdvancedSettings(audiodb_api_key=" ")
|
|
assert settings.audiodb_api_key == "123"
|
|
|
|
|
|
class TestAudiodbEnabledRoundTrip:
|
|
def test_default_is_true(self) -> None:
|
|
settings = AdvancedSettings()
|
|
frontend = AdvancedSettingsFrontend.from_backend(settings)
|
|
assert frontend.audiodb_enabled is True
|
|
|
|
def test_roundtrip_false(self) -> None:
|
|
backend = AdvancedSettings(audiodb_enabled=False)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.audiodb_enabled is False
|
|
restored = frontend.to_backend()
|
|
assert restored.audiodb_enabled is False
|
|
|
|
def test_roundtrip_true(self) -> None:
|
|
backend = AdvancedSettings(audiodb_enabled=True)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.audiodb_enabled is True
|
|
restored = frontend.to_backend()
|
|
assert restored.audiodb_enabled is True
|
|
|
|
|
|
class TestSyncSettingsRoundTrip:
|
|
"""Round-trip tests for the sync robustness settings."""
|
|
|
|
@pytest.mark.parametrize("field,backend_val,frontend_val", [
|
|
("sync_stall_timeout_minutes", 15, 15),
|
|
("sync_max_timeout_hours", 6, 6),
|
|
("audiodb_prewarm_concurrency", 6, 6),
|
|
("audiodb_prewarm_delay", 1.5, 1.5),
|
|
("artist_discovery_precache_concurrency", 5, 5),
|
|
])
|
|
def test_roundtrip_preserves_value(self, field: str, backend_val, frontend_val) -> None:
|
|
backend = AdvancedSettings(**{field: backend_val})
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert getattr(frontend, field) == frontend_val
|
|
restored = frontend.to_backend()
|
|
assert getattr(restored, field) == backend_val
|
|
|
|
@pytest.mark.parametrize("field,default_val", [
|
|
("sync_stall_timeout_minutes", 10),
|
|
("sync_max_timeout_hours", 8),
|
|
("audiodb_prewarm_concurrency", 4),
|
|
("audiodb_prewarm_delay", 0.3),
|
|
("artist_discovery_precache_concurrency", 5),
|
|
("artist_discovery_precache_delay", 0.2),
|
|
])
|
|
def test_defaults_match(self, field: str, default_val) -> None:
|
|
backend = AdvancedSettings()
|
|
frontend = AdvancedSettingsFrontend()
|
|
assert getattr(backend, field) == default_val
|
|
assert getattr(frontend, field) == default_val
|