Files
easy_tdx_max/tests/unit/test_sync_transport.py
Justin Gu 095c88f735 fix(transport): ping 容错 TdxConnectionError,避免单台服务器拖垮测速
ping_host 仅 except OSError,但握手期 _recv_exact_sock 抛的 TdxConnectionError
继承自 TdxError(Exception) 而非 OSError,逃出捕获后经 ping_all 的 fut.result()
重新抛出,导致非交易时间服务器 accept 后立即 FIN 时整个 easy-tdx ping 崩溃。
- ping_host: except (OSError, TdxConnectionError),对齐 docstring 返回 None
- ping_all: fut.result() 加 try/except 防御层,单 host 失败只跳过不崩
- 新增 2 例回归测试
2026-06-13 21:09:55 +08:00

89 lines
2.9 KiB
Python

"""同步 transport 回归测试。"""
from unittest.mock import patch
from easy_tdx.exceptions import TdxConnectionError
from easy_tdx.transport.sync import TdxConnection, ping_all, ping_host
class _FakeSocket:
def __init__(self) -> None:
self.timeout: float | None = None
self.connected_to: tuple[str, int] | None = None
self.closed = False
def settimeout(self, timeout: float) -> None:
self.timeout = timeout
def connect(self, address: tuple[str, int]) -> None:
self.connected_to = address
def sendall(self, data: bytes) -> None:
pass
def close(self) -> None:
self.closed = True
def test_sync_connection_closes_socket_when_setup_fails() -> None:
sock = _FakeSocket()
conn = TdxConnection("127.0.0.1", port=7709, timeout=0.2)
with (
patch("easy_tdx.transport.sync.socket.socket", return_value=sock),
patch.object(
TdxConnection,
"_send_setup",
side_effect=TdxConnectionError("setup failed"),
),
):
try:
conn.connect()
except TdxConnectionError as exc:
assert "setup failed" in str(exc)
else: # pragma: no cover - 防御性断言
raise AssertionError("expected setup failure")
assert sock.timeout == 0.2
assert sock.connected_to == ("127.0.0.1", 7709)
assert sock.closed is True
assert conn._sock is None
def test_ping_host_returns_none_when_server_closes_during_handshake() -> None:
"""握手期服务器关闭连接(_recv_exact_sock 抛 TdxConnectionError)应返回 None。
回归:ping_host 旧版仅 except OSError,未捕获 TdxConnectionError(继承自
TdxError(Exception) 而非 OSError),导致单个服务器握手失败就让整个
ping_all / `easy-tdx ping` 命令崩溃。非交易时间服务器 accept 后立即 FIN
时必现。
"""
sock = _FakeSocket()
with (
patch("easy_tdx.transport.sync.socket.socket", return_value=sock),
patch(
"easy_tdx.transport.sync._recv_exact_sock",
side_effect=TdxConnectionError("连接被服务器关闭"),
),
):
result = ping_host("192.0.2.1", port=7709, timeout=0.2)
assert result is None
assert sock.closed is True
def test_ping_all_skips_handshake_failure_without_crash() -> None:
"""ping_all 中任一服务器握手失败(TdxConnectionError)应被跳过,不崩溃。"""
def fake_ping(host: str, port: int, timeout: float) -> float | None:
if host == "bad":
raise TdxConnectionError("连接被服务器关闭")
return 0.05
with patch("easy_tdx.transport.sync.ping_host", side_effect=fake_ping):
results = ping_all(hosts=["good", "bad"], port=7709, timeout=0.2)
hosts_ok = [h for h, _ in results]
assert "good" in hosts_ok
assert "bad" not in hosts_ok