User report: "Not authenticated with Spotify" daily + workers paused. The
log was misleading — is_spotify_authenticated() returns False for five
distinct reasons (no creds / rate-limit ban / post-ban cooldown / no
cached token / probe failure), and all five API call sites logged the
same bare "Not authenticated with Spotify". So a routine rate-limit ban
read as a logout, and the real cause (logged only at DEBUG) was invisible.
New pure describe_spotify_unavailable() maps the real state to a clear
message (priority matches is_spotify_authenticated): not-configured →
rate-limited ("ban ~Nm left (not a logout)") → post-ban cooldown →
no-token ("not connected — re-authenticate") → "auth check failed (token
refresh may have failed)". A side-effect-free client method
(_auth_unavailable_reason) gathers the live state (reads the cached token,
no API probe) and the 5 sites log it.
Now a daily ban is identifiable as a ban, and a genuine logout is
identifiable as one — so reports like this are diagnosable from the log
alone. 7 tests pin the priority/messaging. Full suite clean.
54 lines
2.3 KiB
Python
54 lines
2.3 KiB
Python
"""The 'Not authenticated with Spotify' log line was a catch-all — it fired for
|
|
a rate-limit ban, a post-ban cooldown, a missing token, AND a genuine probe
|
|
failure, so a daily ban looked like a logout. describe_spotify_unavailable maps
|
|
the real state to a clear reason; these pin the priority + messaging.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from core.spotify_client import describe_spotify_unavailable
|
|
|
|
|
|
def test_not_configured_wins_first():
|
|
msg = describe_spotify_unavailable(configured=False, rate_limited=True)
|
|
assert 'not configured' in msg.lower()
|
|
|
|
|
|
def test_rate_limited_says_ban_not_logout():
|
|
msg = describe_spotify_unavailable(configured=True, rate_limited=True, ban_seconds_left=1680)
|
|
assert 'rate-limited' in msg.lower()
|
|
assert '28m' in msg # 1680s -> ~28 min
|
|
assert 'not a logout' in msg.lower()
|
|
|
|
|
|
def test_rate_limited_without_known_duration():
|
|
msg = describe_spotify_unavailable(configured=True, rate_limited=True, ban_seconds_left=0)
|
|
assert 'rate-limited' in msg.lower() and 'not a logout' in msg.lower()
|
|
|
|
|
|
def test_cooldown_when_not_rate_limited():
|
|
msg = describe_spotify_unavailable(configured=True, rate_limited=False,
|
|
in_cooldown=True, cooldown_seconds_left=45)
|
|
assert 'cooldown' in msg.lower() and '45s' in msg
|
|
|
|
|
|
def test_no_token_is_a_real_logout():
|
|
msg = describe_spotify_unavailable(configured=True, rate_limited=False,
|
|
in_cooldown=False, has_token=False)
|
|
assert 'not connected' in msg.lower() and 're-authenticate' in msg.lower()
|
|
|
|
|
|
def test_probe_failure_fallback():
|
|
# configured, not rate-limited, not cooldown, has a token, but auth still
|
|
# failed → token refresh likely failed.
|
|
msg = describe_spotify_unavailable(configured=True, rate_limited=False,
|
|
in_cooldown=False, has_token=True)
|
|
assert 'auth check failed' in msg.lower()
|
|
|
|
|
|
def test_rate_limit_takes_priority_over_missing_token():
|
|
# A ban must never be reported as "not connected".
|
|
msg = describe_spotify_unavailable(configured=True, rate_limited=True,
|
|
ban_seconds_left=600, has_token=False)
|
|
assert 'rate-limited' in msg.lower()
|
|
assert 'not connected' not in msg.lower()
|