From 7db71e943666bda897d41a606ceae59368207687 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:05:13 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AA=20Add=20unit=20tests=20for=20=5Fre?= =?UTF-8?q?solvers=5Funix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added four comprehensive test scenarios using `unittest.mock.patch` to verify `_resolvers_unix` in `src/netsleuth/netinfo.py`. These cover parsing `/etc/resolv.conf`, parsing `scutil --dns` output on macOS, correctly combining the results of both, and gracefully handling missing files and failing subprocess commands. This increases `netinfo.py` test coverage and ensures robust parsing logic for system DNS resolvers. Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> --- tests/test_netinfo.py | 77 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/tests/test_netinfo.py b/tests/test_netinfo.py index 7134cd9..5685718 100644 --- a/tests/test_netinfo.py +++ b/tests/test_netinfo.py @@ -2,6 +2,7 @@ from __future__ import annotations from netsleuth.models import Capabilities from netsleuth.netinfo import ( + _resolvers_unix, choose_latency_backend, choose_trace_backend, degradation_note, @@ -28,7 +29,7 @@ def test_unix_falls_back_to_raw_icmp_when_datagram_is_unavailable(): from netsleuth.netinfo import detect_capabilities -from unittest.mock import patch +from unittest.mock import mock_open, patch def test_detect_capabilities_linux_happy_path(): with patch("netsleuth.netinfo.platform.system", return_value="Linux"), \ @@ -334,3 +335,77 @@ def test_collect_local_net_no_network(mock_resolvers, mock_gw, mock_stats, mock_ assert result.default_gateway_v6 is None assert result.is_dual_stack is False assert result.cgnat is False + + +@patch("netsleuth.netinfo.subprocess.run") +@patch("builtins.open", new_callable=mock_open, read_data="nameserver 1.1.1.1\nnameserver 8.8.8.8\n") +def test_resolvers_unix_parses_resolv_conf(mock_file, mock_run): + mock_run.side_effect = OSError("No such file or directory") + + result = _resolvers_unix() + + assert result == {"system": ["1.1.1.1", "8.8.8.8"]} + mock_file.assert_called_once_with("/etc/resolv.conf", encoding="utf-8", errors="replace") + mock_run.assert_called_once() + + +@patch("netsleuth.netinfo.subprocess.run") +@patch("builtins.open") +def test_resolvers_unix_parses_scutil(mock_file, mock_run): + mock_file.side_effect = OSError("No such file or directory") + + import subprocess + mock_run.return_value = subprocess.CompletedProcess( + args=["scutil", "--dns"], + returncode=0, + stdout=""" +DNS configuration +resolver #1 + if_index : 4 (en0) + nameserver[0] : 192.168.1.1 + nameserver[1] : 1.0.0.1 + flags : Request A records +""" + ) + + result = _resolvers_unix() + + assert result == {"en0": ["192.168.1.1", "1.0.0.1"]} + mock_file.assert_called_once_with("/etc/resolv.conf", encoding="utf-8", errors="replace") + mock_run.assert_called_once_with(["scutil", "--dns"], capture_output=True, text=True, errors="replace", timeout=15) + + +@patch("netsleuth.netinfo.subprocess.run") +@patch("builtins.open", new_callable=mock_open, read_data="nameserver 8.8.4.4\n") +def test_resolvers_unix_handles_both(mock_file, mock_run): + import subprocess + mock_run.return_value = subprocess.CompletedProcess( + args=["scutil", "--dns"], + returncode=0, + stdout=""" +DNS configuration +resolver #1 + if_index : 5 (en1) + nameserver[0] : 10.0.0.1 +""" + ) + + result = _resolvers_unix() + + assert result == { + "system": ["8.8.4.4"], + "en1": ["10.0.0.1"] + } + mock_file.assert_called_once_with("/etc/resolv.conf", encoding="utf-8", errors="replace") + mock_run.assert_called_once() + + +@patch("netsleuth.netinfo.subprocess.run") +@patch("builtins.open") +def test_resolvers_unix_handles_all_failures(mock_file, mock_run): + mock_file.side_effect = OSError("No resolv.conf") + mock_run.side_effect = OSError("No scutil") + + result = _resolvers_unix() + + assert result == {}