From 38fd663d9936aef1a8777a43bc1345d9bd6d58e5 Mon Sep 17 00:00:00 2001 From: lainx86 Date: Tue, 28 Jul 2026 00:45:49 +0700 Subject: [PATCH] fix: handle disappearing interfaces in Ping discovery --- core/services/ping/ping360_ethernet_prober.py | 2 +- core/services/ping/setup.py | 1 + .../ping/test_ping360_ethernet_prober.py | 47 +++++++++++++++++++ pyproject.toml | 1 + 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 core/services/ping/test_ping360_ethernet_prober.py diff --git a/core/services/ping/ping360_ethernet_prober.py b/core/services/ping/ping360_ethernet_prober.py index dabf5498c6..36168f559a 100644 --- a/core/services/ping/ping360_ethernet_prober.py +++ b/core/services/ping/ping360_ethernet_prober.py @@ -24,7 +24,7 @@ def list_ips() -> Set[str]: for interface in available_networks: ips.extend( phys.address - for phys in network_interface_addresses[interface] + for phys in network_interface_addresses.get(interface, []) if phys.family == socket.AF_INET and phys.address != "127.0.0.1" ) return set(ips) # make sure there are not duplicated entries diff --git a/core/services/ping/setup.py b/core/services/ping/setup.py index 579faaa206..d818e40a29 100644 --- a/core/services/ping/setup.py +++ b/core/services/ping/setup.py @@ -24,6 +24,7 @@ "anyio == 3.7.1", "fastapi-versioning == 0.9.1", "loguru == 0.5.3", + "psutil == 5.7.2", "pyserial == 3.5", "starlette == 0.27.0", "uvicorn == 0.13.4", diff --git a/core/services/ping/test_ping360_ethernet_prober.py b/core/services/ping/test_ping360_ethernet_prober.py new file mode 100644 index 0000000000..22a9600817 --- /dev/null +++ b/core/services/ping/test_ping360_ethernet_prober.py @@ -0,0 +1,47 @@ +import socket +import sys +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import patch + +_PING_DIR = str(Path(__file__).resolve().parent) +sys.path.insert(0, _PING_DIR) +# Root pytest also finds other services' top-level modules (e.g. ardupilot_manager/exceptions.py). +for _name in ("exceptions", "pingutils", "ping360_ethernet_prober", "portwatcher"): + _mod = sys.modules.get(_name) + if _mod is not None and not str(getattr(_mod, "__file__", "")).startswith(_PING_DIR): + del sys.modules[_name] + +import psutil + +import ping360_ethernet_prober + + +def test_list_ips_ignores_interfaces_missing_from_address_snapshot() -> None: + stats = { + "eth0": SimpleNamespace(isup=True), + "lo": SimpleNamespace(isup=True), + "wlan0": SimpleNamespace(isup=False), + "noipv4": SimpleNamespace(isup=True), + "uap0": SimpleNamespace(isup=True), + } + addresses = { + "eth0": [SimpleNamespace(family=socket.AF_INET, address="192.168.2.2")], + "lo": [SimpleNamespace(family=socket.AF_INET, address="127.0.0.1")], + "wlan0": [SimpleNamespace(family=socket.AF_INET, address="192.168.10.2")], + "noipv4": [SimpleNamespace(family=socket.AF_INET6, address="::1")], + } + + with ( + patch.object(psutil, "net_if_stats", return_value=stats), + patch.object(psutil, "net_if_addrs", return_value=addresses), + ): + assert ping360_ethernet_prober.list_ips() == {"192.168.2.2"} + + +def test_list_ips_returns_empty_set_for_empty_snapshots() -> None: + with ( + patch.object(psutil, "net_if_stats", return_value={}), + patch.object(psutil, "net_if_addrs", return_value={}), + ): + assert ping360_ethernet_prober.list_ips() == set() diff --git a/pyproject.toml b/pyproject.toml index 2776ccd625..2a712274e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ pytest = "7.4.2" coverage = "7.5.1" pytest-cov = "4.1.0" pydantic = "1.10.12" +psutil = "5.7.2" docker = "6.1.3" aiodocker = "0.21.0" aiohttp = "3.9.5"