0f25ebc26d
* plex integration * The big one - Full Music Source page rework + Playlist importing + Full Plex Integration + Discovery Options + More Like This/Surprise Me/Instant Mix + More... * Music source track page - Play all / shuffle fixes * lint * format * fix type checks * format
136 lines
5.0 KiB
Python
136 lines
5.0 KiB
Python
"""Tests for AudioDB settings, API key masking, round-trips, and validation."""
|
|
|
|
import pytest
|
|
import msgspec
|
|
|
|
from api.v1.schemas.advanced_settings import (
|
|
AdvancedSettings,
|
|
AdvancedSettingsFrontend,
|
|
_mask_api_key,
|
|
_is_masked_api_key,
|
|
)
|
|
|
|
|
|
class TestMaskApiKey:
|
|
def test_long_key_shows_last_three(self) -> None:
|
|
assert _mask_api_key("myapikey123") == "***...123"
|
|
|
|
def test_four_char_key(self) -> None:
|
|
assert _mask_api_key("1234") == "***...234"
|
|
|
|
def test_three_char_key_fully_masked(self) -> None:
|
|
assert _mask_api_key("123") == "***"
|
|
|
|
def test_two_char_key_fully_masked(self) -> None:
|
|
assert _mask_api_key("ab") == "***"
|
|
|
|
def test_one_char_key_fully_masked(self) -> None:
|
|
assert _mask_api_key("x") == "***"
|
|
|
|
def test_empty_key_fully_masked(self) -> None:
|
|
assert _mask_api_key("") == "***"
|
|
|
|
|
|
class TestIsMaskedApiKey:
|
|
def test_masked_with_suffix(self) -> None:
|
|
assert _is_masked_api_key("***...123") is True
|
|
|
|
def test_masked_short(self) -> None:
|
|
assert _is_masked_api_key("***") is True
|
|
|
|
def test_plaintext_key(self) -> None:
|
|
assert _is_masked_api_key("mynewkey") is False
|
|
|
|
def test_empty_string(self) -> None:
|
|
assert _is_masked_api_key("") is False
|
|
|
|
def test_partial_asterisks(self) -> None:
|
|
assert _is_masked_api_key("** not masked") is False
|
|
|
|
def test_triple_asterisks_with_extra(self) -> None:
|
|
assert _is_masked_api_key("***extra") is True
|
|
|
|
|
|
class TestApiKeyRoundTrip:
|
|
def test_from_backend_masks_long_key(self) -> None:
|
|
backend = AdvancedSettings(audiodb_api_key="secretkey")
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.audiodb_api_key == "***...key"
|
|
|
|
def test_from_backend_masks_default_key(self) -> None:
|
|
backend = AdvancedSettings(audiodb_api_key="123")
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.audiodb_api_key == "***"
|
|
|
|
def test_to_backend_passes_masked_key_through(self) -> None:
|
|
frontend = AdvancedSettingsFrontend(audiodb_api_key="***...key")
|
|
backend = frontend.to_backend()
|
|
assert backend.audiodb_api_key == "***...key"
|
|
|
|
def test_to_backend_passes_new_plaintext_key(self) -> None:
|
|
frontend = AdvancedSettingsFrontend(audiodb_api_key="newkey456")
|
|
backend = frontend.to_backend()
|
|
assert backend.audiodb_api_key == "newkey456"
|
|
|
|
def test_default_api_key_is_123(self) -> None:
|
|
settings = AdvancedSettings()
|
|
assert settings.audiodb_api_key == "123"
|
|
|
|
def test_frontend_default_api_key_is_123(self) -> None:
|
|
frontend = AdvancedSettingsFrontend()
|
|
assert frontend.audiodb_api_key == "123"
|
|
|
|
|
|
class TestApiKeyEmptyGuard:
|
|
def test_empty_key_coerced_to_default(self) -> None:
|
|
settings = AdvancedSettings(audiodb_api_key="")
|
|
assert settings.audiodb_api_key == "123"
|
|
|
|
def test_whitespace_key_coerced_to_default(self) -> None:
|
|
settings = AdvancedSettings(audiodb_api_key=" ")
|
|
assert settings.audiodb_api_key == "123"
|
|
|
|
def test_valid_key_preserved(self) -> None:
|
|
settings = AdvancedSettings(audiodb_api_key="premium_key")
|
|
assert settings.audiodb_api_key == "premium_key"
|
|
|
|
|
|
class TestRecentlyViewedBytesTTLRoundTrip:
|
|
def test_default_backend_value(self) -> None:
|
|
settings = AdvancedSettings()
|
|
assert settings.cache_ttl_recently_viewed_bytes == 172800
|
|
|
|
def test_default_frontend_value(self) -> None:
|
|
frontend = AdvancedSettingsFrontend()
|
|
assert frontend.cache_ttl_recently_viewed_bytes == 48
|
|
|
|
def test_roundtrip_preserves_value(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
|
|
|
|
def test_roundtrip_custom_value(self) -> None:
|
|
backend = AdvancedSettings(cache_ttl_recently_viewed_bytes=36000)
|
|
frontend = AdvancedSettingsFrontend.from_backend(backend)
|
|
assert frontend.cache_ttl_recently_viewed_bytes == 10
|
|
restored = frontend.to_backend()
|
|
assert restored.cache_ttl_recently_viewed_bytes == 36000
|
|
|
|
def test_backend_validation_rejects_too_low(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_recently_viewed_bytes=3599)
|
|
|
|
def test_backend_validation_rejects_too_high(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettings(cache_ttl_recently_viewed_bytes=604801)
|
|
|
|
def test_frontend_validation_rejects_too_high(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettingsFrontend(cache_ttl_recently_viewed_bytes=169)
|
|
|
|
def test_frontend_validation_rejects_too_low(self) -> None:
|
|
with pytest.raises(msgspec.ValidationError):
|
|
AdvancedSettingsFrontend(cache_ttl_recently_viewed_bytes=0)
|