From ec8f1c87f115cb098eb382eaf6394b84f535c6cb Mon Sep 17 00:00:00 2001 From: Pouzor Date: Sun, 10 May 2026 19:45:36 +0200 Subject: [PATCH] fix(status): use ms timeout for ping on macOS ping(8) -W flag is milliseconds on macOS, seconds on Linux. Code used -W 1 for both, giving macOS a 1ms timeout that fails any host with RTT >1ms (typical wifi/mesh is 2-10ms). Use -W 1000 on darwin to match the intended 1s timeout. Add regression test asserting the platform-specific value. --- backend/app/services/status_checker.py | 6 ++++++ backend/tests/test_status_checker.py | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/backend/app/services/status_checker.py b/backend/app/services/status_checker.py index 7f150e8..4f6ba75 100644 --- a/backend/app/services/status_checker.py +++ b/backend/app/services/status_checker.py @@ -60,8 +60,14 @@ async def check_node(check_method: str, target: str | None, ip: str | None) -> d async def _ping(host: str) -> bool: + # ping(8) -W flag units differ by OS: + # Linux: seconds (-W 1 = 1s) + # macOS: milliseconds (-W 1 = 1ms — fails for any RTT >1ms) + # Windows: -w in ms (-w 1000 = 1s) if sys.platform == "win32": args = ["ping", "-n", "1", "-w", "1000", host] + elif sys.platform == "darwin": + args = ["ping", "-c", "1", "-W", "1000", host] else: args = ["ping", "-c", "1", "-W", "1", host] proc = await asyncio.create_subprocess_exec( diff --git a/backend/tests/test_status_checker.py b/backend/tests/test_status_checker.py index 3033127..3d23cd8 100644 --- a/backend/tests/test_status_checker.py +++ b/backend/tests/test_status_checker.py @@ -169,6 +169,31 @@ async def test_ping_uses_unix_args_on_non_windows(): assert "-c" in captured["args"] assert "-W" in captured["args"] assert "-n" not in captured["args"] + # Linux: -W is in seconds; 1s is the intended timeout + w_idx = captured["args"].index("-W") + assert captured["args"][w_idx + 1] == "1" + + +@pytest.mark.asyncio +async def test_ping_uses_macos_millisecond_timeout(): + """macOS ping(8) -W is milliseconds, not seconds. 1ms would fail any RTT >1ms.""" + captured = {} + + async def fake_exec(*args, **kwargs): + captured["args"] = args + proc = MagicMock() + proc.returncode = 0 + proc.wait = AsyncMock() + return proc + + with patch("app.services.status_checker.sys.platform", "darwin"), \ + patch("asyncio.create_subprocess_exec", side_effect=fake_exec): + await _ping("192.168.1.1") + + assert "-c" in captured["args"] + assert "-W" in captured["args"] + w_idx = captured["args"].index("-W") + assert captured["args"][w_idx + 1] == "1000" @pytest.mark.asyncio