A transient ping failure (network blip, Navidrome busy mid-scan) makes _setup_client null out the configured creds, and _connection_attempted then latches the client "disconnected" — so is_connected() returned False forever until the user hit the manual Test button to re-read config. That's the reported "disconnects every 5-10 min, reconnects instantly on Test." Fix: ensure_connection no longer latches on a failed attempt — once a short throttle (_RECONNECT_THROTTLE_S = 20s) elapses it re-attempts, and is_connected() triggers that retry whenever it's currently disconnected. So a blip recovers on its own within the next status check, no manual reconnect. The throttle prevents ping storms when Navidrome is genuinely down. Tests: transient failure self-heals after the throttle (and doesn't re-ping within it); a connected client never re-pings; first connect attempts once. 115 navidrome/ media-server tests green.
54 lines
2.1 KiB
Python
54 lines
2.1 KiB
Python
"""Navidrome connection self-heals after a transient ping failure (jimmydotcom).
|
|
|
|
A failed ping nukes the creds in _setup_client; previously _connection_attempted
|
|
latched the client 'disconnected' until a manual Test. Now is_connected re-attempts
|
|
(throttled) so a blip recovers on its own."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from core.navidrome_client import NavidromeClient
|
|
|
|
|
|
def test_self_heals_after_transient_failure(monkeypatch):
|
|
c = NavidromeClient()
|
|
calls = {'n': 0}
|
|
|
|
def fake_setup():
|
|
calls['n'] += 1
|
|
if calls['n'] == 1: # transient failure nukes creds
|
|
c.base_url = c.username = c.password = None
|
|
else: # blip passed → connects
|
|
c.base_url, c.username, c.password = 'http://nd:4533', 'u', 'p'
|
|
monkeypatch.setattr(c, '_setup_client', fake_setup)
|
|
|
|
assert c.is_connected() is False # first attempt fails
|
|
assert calls['n'] == 1
|
|
|
|
assert c.is_connected() is False # immediate recheck: throttled
|
|
assert calls['n'] == 1 # did NOT re-ping (no storm)
|
|
|
|
c._last_connect_attempt -= (c._RECONNECT_THROTTLE_S + 1) # throttle window elapses
|
|
assert c.is_connected() is True # re-attempts → recovers itself
|
|
assert calls['n'] == 2 # no manual reconnect was needed
|
|
|
|
|
|
def test_connected_client_does_not_reattempt(monkeypatch):
|
|
c = NavidromeClient()
|
|
c.base_url, c.username, c.password = 'http://nd', 'u', 'p'
|
|
c._connection_attempted = True
|
|
calls = {'n': 0}
|
|
monkeypatch.setattr(c, '_setup_client', lambda: calls.__setitem__('n', calls['n'] + 1))
|
|
assert c.is_connected() is True
|
|
assert calls['n'] == 0 # already connected → never re-pings
|
|
|
|
|
|
def test_first_connect_attempts_once(monkeypatch):
|
|
c = NavidromeClient()
|
|
calls = {'n': 0}
|
|
|
|
def fake_setup():
|
|
calls['n'] += 1
|
|
c.base_url, c.username, c.password = 'http://nd', 'u', 'p'
|
|
monkeypatch.setattr(c, '_setup_client', fake_setup)
|
|
assert c.is_connected() is True
|
|
assert calls['n'] == 1
|