70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""A transient RPC failure must not take the whole process down with it."""
|
|||
|
|
|
||
|
|
import time
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from dsc.client import SeafileClient
|
||
|
|
from dsc.errors import GracefulShutdown
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def client(monkeypatch):
|
||
|
|
monkeypatch.setattr(time, "sleep", lambda seconds: None)
|
||
|
|
return SeafileClient("seafile.example", "user", "pw", "/dsc", token="tok-en")
|
||
|
|
|
||
|
|
|
||
|
|
def test_watch_status_survives_a_transient_rpc_failure(client, monkeypatch):
|
||
|
|
"""The loop keeps going instead of crashing the container."""
|
||
|
|
calls = []
|
||
|
|
|
||
|
|
def flaky_get_status():
|
||
|
|
calls.append(1)
|
||
|
|
if len(calls) == 1:
|
||
|
|
raise ConnectionError("daemon restarting")
|
||
|
|
raise GracefulShutdown("SIGTERM") # ends the otherwise-infinite loop
|
||
|
|
|
||
|
|
monkeypatch.setattr(client, "get_status", flaky_get_status)
|
||
|
|
|
||
|
|
with pytest.raises(GracefulShutdown):
|
||
|
|
client.watch_status()
|
||
|
|
|
||
|
|
assert len(calls) == 2, "the loop must retry after the first failure"
|
||
|
|
|
||
|
|
|
||
|
|
def test_watch_status_still_propagates_a_stop_signal(client, monkeypatch):
|
||
|
|
"""A DscError, such as a stop signal, must still end the loop."""
|
||
|
|
monkeypatch.setattr(client, "get_status",
|
||
|
|
lambda: (_ for _ in ()).throw(GracefulShutdown("SIGINT")))
|
||
|
|
|
||
|
|
with pytest.raises(GracefulShutdown):
|
||
|
|
client.watch_status()
|
||
|
|
|
||
|
|
|
||
|
|
def test_watch_status_keeps_prior_state_across_a_failed_read(client, monkeypatch, caplog):
|
||
|
|
"""
|
||
|
|
A failed read is logged and skipped; it must not corrupt prior state,
|
||
|
|
so a real change right after the failure is still detected and logged.
|
||
|
|
"""
|
||
|
|
calls = []
|
||
|
|
|
||
|
|
def flaky_get_status():
|
||
|
|
calls.append(1)
|
||
|
|
if len(calls) == 1:
|
||
|
|
return {"Docs": "syncing"}
|
||
|
|
if len(calls) == 2:
|
||
|
|
raise ConnectionError("daemon restarting")
|
||
|
|
if len(calls) == 3:
|
||
|
|
return {"Docs": "done"}
|
||
|
|
raise GracefulShutdown("SIGTERM")
|
||
|
|
|
||
|
|
monkeypatch.setattr(client, "get_status", flaky_get_status)
|
||
|
|
|
||
|
|
with caplog.at_level("INFO"):
|
||
|
|
with pytest.raises(GracefulShutdown):
|
||
|
|
client.watch_status()
|
||
|
|
|
||
|
|
assert "Could not read sync status" in caplog.text
|
||
|
|
assert "syncing" in caplog.text
|
||
|
|
assert "done" in caplog.text
|
||
|
|
assert len(calls) == 4
|