fix(network): add offline cooldown guard for remote metadata requests

This commit is contained in:
pixelpaws
2026-04-20 15:04:04 +08:00
parent 0ced53c059
commit 5a7f4dc88b
8 changed files with 364 additions and 14 deletions

View File

@@ -0,0 +1,74 @@
import asyncio
import errno
from datetime import datetime, timedelta
import pytest
from py.services.connectivity_guard import (
OFFLINE_COOLDOWN_ERROR,
ConnectivityGuard,
)
from py.services.downloader import Downloader
@pytest.fixture(autouse=True)
def reset_connectivity_guard_singleton():
ConnectivityGuard._instance = None
yield
ConnectivityGuard._instance = None
async def test_connectivity_guard_enters_cooldown_after_threshold():
guard = await ConnectivityGuard.get_instance()
assert guard.online is True
assert guard.should_block_request() is False
guard.register_network_failure(OSError(errno.ENETUNREACH, "unreachable"))
guard.register_network_failure(asyncio.TimeoutError("timeout"))
assert guard.should_block_request() is False
assert guard.failure_count == 2
guard.register_network_failure(ConnectionRefusedError("refused"))
assert guard.online is False
assert guard.failure_count == 3
assert guard.should_block_request() is True
assert guard.cooldown_remaining_seconds() > 0
async def test_connectivity_guard_recovers_after_success():
guard = await ConnectivityGuard.get_instance()
guard.online = False
guard.failure_count = 5
guard.cooldown_until = datetime.now() + timedelta(seconds=90)
guard.register_success()
assert guard.online is True
assert guard.failure_count == 0
assert guard.cooldown_until is None
assert guard.should_block_request() is False
async def test_downloader_short_circuits_all_request_helpers_during_cooldown():
guard = await ConnectivityGuard.get_instance()
guard.cooldown_until = datetime.now() + timedelta(seconds=30)
guard.online = False
guard.failure_count = 3
downloader = Downloader()
ok, payload = await downloader.make_request("GET", "https://example.invalid")
assert ok is False
assert payload == OFFLINE_COOLDOWN_ERROR
ok, payload, headers = await downloader.download_to_memory("https://example.invalid")
assert ok is False
assert payload == OFFLINE_COOLDOWN_ERROR
assert headers is None
ok, payload = await downloader.get_response_headers("https://example.invalid")
assert ok is False
assert payload == OFFLINE_COOLDOWN_ERROR