A transient HTTP 500 during the range probe aborted bundle staging. Retry PM-owned requests and body transfers with one bounded policy, instead of retrying complete installs or stacking caller retry loops. Keep partial ranges across attempts and interrupt backoff on pause. Keep the CDN serial fallback active until its source finishes. Do not retry permanent HTTP errors, certificate failures, bad hashes or disk errors. Use the same policy for metadata reads and artifact hashing. Verified: 217 focused tests passed, 1 skipped, and Ruff passed on the changed Python files. The pinned Windows ARM64 uv archive also survived an injected HTTP 500 through the PM CLI and its installed binary ran. The full suite and desktop release build were not run.
38 lines
1.4 KiB
Python
38 lines
1.4 KiB
Python
"""A CDN refusal downgrades this transfer once, including later network retries."""
|
|
|
|
import hashlib
|
|
|
|
import pytest
|
|
|
|
from pm.downloader import Download, Source
|
|
from tests.pm._range_server import RangeHandler, dl_server, url # noqa: F401
|
|
|
|
|
|
@pytest.mark.parametrize("refused_status", [403, 404])
|
|
def test_serial_fallback_survives_a_transient_retry(tmp_path, dl_server, monkeypatch, refused_status):
|
|
payload = b"verified bytes"
|
|
RangeHandler.payloads["/tool"] = payload
|
|
original_get = RangeHandler.do_GET
|
|
dest = tmp_path / "tool"
|
|
dl = Download([Source(url(dl_server, "/tool"), dest, hashlib.sha256(payload).hexdigest())],
|
|
partials_dir=tmp_path / "partials")
|
|
modes = []
|
|
waits = []
|
|
|
|
def respond(handler):
|
|
if handler.headers.get("Range") != "bytes=0-0":
|
|
modes.append(dl.connections)
|
|
if len(modes) < 3:
|
|
handler.send_error(refused_status if len(modes) == 1 else 503)
|
|
return
|
|
original_get(handler)
|
|
|
|
monkeypatch.setattr(RangeHandler, "do_GET", respond)
|
|
monkeypatch.setattr(dl, "_wait_retry", waits.append)
|
|
dl.run()
|
|
assert dest.read_bytes() == payload
|
|
assert modes[0] > 1
|
|
assert modes[1:] == [1, 1], "a network retry must not undo the CDN downgrade"
|
|
assert len(waits) == 1
|
|
assert dl.connections == modes[0], "the downgrade belongs to this source, not later downloads"
|