Soulseek album poll: treat 'Aborted'/'Cancelled' transfers as failed
Live testing surfaced that slskd reports a peer-side abort as 'Completed, Aborted' at 0 bytes (peer accepts then drops every transfer). That string contains 'Completed', so the poll's completed-branch ran first and misread it as 'completed but file missing' — routing it into the #715 unresolved/download_path grace (gives up after 45s with a misleading 'download_path mismatch' log) instead of recognizing it as a failure. Add 'Aborted' and 'Cancelled' to the failure-token check (which runs before the completed branch), so these resolve immediately and correctly as failed. Test added for the all-aborted folder.
This commit is contained in:
parent
aa2806180e
commit
a60eae9315
2 changed files with 24 additions and 1 deletions
|
|
@ -1740,7 +1740,14 @@ class SoulseekClient(DownloadSourcePlugin):
|
||||||
os.path.basename((key[1] or '').replace('\\', '/')),
|
os.path.basename((key[1] or '').replace('\\', '/')),
|
||||||
))
|
))
|
||||||
state = (getattr(dl, 'state', '') or '') if dl else ''
|
state = (getattr(dl, 'state', '') or '') if dl else ''
|
||||||
if any(token in state for token in ('Errored', 'Failed', 'Rejected', 'TimedOut')):
|
# NOTE: check failure tokens BEFORE the 'Completed' branch — slskd
|
||||||
|
# reports terminal failures as "Completed, <reason>" (e.g.
|
||||||
|
# "Completed, Aborted" / "Completed, Cancelled" when a peer accepts
|
||||||
|
# then drops every transfer at 0 bytes). Those contain "Completed",
|
||||||
|
# so without catching the failure reason first they'd be misread as
|
||||||
|
# "completed but file missing" (the #715 download_path path).
|
||||||
|
if any(token in state for token in
|
||||||
|
('Errored', 'Failed', 'Rejected', 'TimedOut', 'Aborted', 'Cancelled')):
|
||||||
failed_states[key] = state or 'Failed'
|
failed_states[key] = state or 'Failed'
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[Soulseek album] Transfer failed from selected folder: %s (%s)",
|
"[Soulseek album] Transfer failed from selected folder: %s (%s)",
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,22 @@ def test_dropped_transfers_also_stall_out():
|
||||||
assert clock.now < 600.0
|
assert clock.now < 600.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_completed_aborted_classified_as_failed_not_unresolved():
|
||||||
|
"""slskd reports a peer-side abort as 'Completed, Aborted' at 0 bytes. Because
|
||||||
|
that string contains 'Completed', it was misread as 'completed but file
|
||||||
|
missing' (#715 path). It must be classified as FAILED — so an all-aborted
|
||||||
|
folder resolves immediately, not after the unresolved/stall grace."""
|
||||||
|
tk = _keys("01.flac", "02.flac")
|
||||||
|
aborted = [
|
||||||
|
_dl("peer", "01.flac", "Completed, Aborted", transferred=0, size=3_600_000),
|
||||||
|
_dl("peer", "02.flac", "Completed, Aborted", transferred=0, size=24_700_000),
|
||||||
|
]
|
||||||
|
stub = _StubClient([aborted], resolvable=set())
|
||||||
|
result, clock, _ = _run_poll(stub, tk, timeout=7200.0, interval=2.0)
|
||||||
|
assert result == [] # all failed → empty (caller falls back)
|
||||||
|
assert clock.now < 30.0 # resolved on the first poll, no 45s/180s wait
|
||||||
|
|
||||||
|
|
||||||
def test_clean_finish_unaffected():
|
def test_clean_finish_unaffected():
|
||||||
tk = _keys("01.flac", "02.flac")
|
tk = _keys("01.flac", "02.flac")
|
||||||
done = [_dl("peer", "01.flac", "Completed"), _dl("peer", "02.flac", "Succeeded")]
|
done = [_dl("peer", "01.flac", "Completed"), _dl("peer", "02.flac", "Succeeded")]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue