"""Tests for network probes — TDD: tests before implementation.""" import socket from unittest.mock import MagicMock, patch import pytest from i2p_apps.setup.network_probe import ( BandwidthEstimate, DnsProbeResult, LatencyProbeResult, NetworkProbeResult, check_dns, estimate_bandwidth, measure_tcp_rtt, probe_dns, probe_latency, run_network_probes, ) class TestCheckDns: def test_successful_resolution(self): with patch("i2p_apps.setup.network_probe.socket.getaddrinfo") as mock: mock.return_value = [(2, 1, 6, "", ("93.184.216.34", 0))] success, latency = check_dns("example.com") assert success is True assert latency >= 0 def test_failed_resolution(self): with patch("i2p_apps.setup.network_probe.socket.getaddrinfo") as mock: mock.side_effect = socket.gaierror("Name resolution failed") success, latency = check_dns("nonexistent.invalid") assert success is False assert latency == 0.0 class TestProbeDns: def test_all_domains_resolve(self): with patch("i2p_apps.setup.network_probe.check_dns") as mock: mock.return_value = (True, 10.0) result = probe_dns() assert isinstance(result, DnsProbeResult) assert result.can_resolve_neutral is True assert result.can_resolve_cdn is True assert result.resolver_latency_ms > 0 def test_partial_resolution(self): results = { "example.com": (True, 10.0), "cloudflare.com": (False, 0.0), } with patch("i2p_apps.setup.network_probe.check_dns") as mock: mock.side_effect = lambda d: results.get(d, (False, 0.0)) result = probe_dns() assert result.can_resolve_neutral is True assert result.can_resolve_cdn is False class TestMeasureTcpRtt: def test_successful_connection(self): mock_sock = MagicMock() mock_sock.connect_ex.return_value = 0 with patch("i2p_apps.setup.network_probe.socket.socket", return_value=mock_sock): rtt = measure_tcp_rtt("example.com", 443) assert rtt is not None assert rtt >= 0 def test_connection_timeout(self): mock_sock = MagicMock() mock_sock.connect_ex.side_effect = OSError("timeout") with patch("i2p_apps.setup.network_probe.socket.socket", return_value=mock_sock): rtt = measure_tcp_rtt("unreachable.invalid", 443) assert rtt is None class TestProbeLatency: def test_returns_latency_result(self): with patch("i2p_apps.setup.network_probe.measure_tcp_rtt") as mock: mock.return_value = 0.045 # 45ms result = probe_latency(endpoints=["example.com:443", "cloudflare.com:443"]) assert isinstance(result, LatencyProbeResult) assert result.rtt_ms > 0 assert result.endpoints_reached > 0 def test_no_endpoints_reachable(self): with patch("i2p_apps.setup.network_probe.measure_tcp_rtt", return_value=None): result = probe_latency(endpoints=["unreachable.invalid:443"]) assert result.endpoints_reached == 0 assert result.rtt_ms == 0.0 class TestEstimateBandwidth: def test_successful_download(self): mock_resp = MagicMock() mock_resp.read.return_value = b"x" * 102400 mock_resp.status = 200 mock_resp.__enter__ = lambda s: s mock_resp.__exit__ = MagicMock(return_value=False) with patch("i2p_apps.setup.network_probe.urllib.request.urlopen", return_value=mock_resp): result = estimate_bandwidth(url="https://example.com/test") assert result is not None assert isinstance(result, BandwidthEstimate) assert result.download_mbps > 0 assert result.method == "cdn_download" def test_download_failure(self): with patch("i2p_apps.setup.network_probe.urllib.request.urlopen", side_effect=OSError("Connection refused")): result = estimate_bandwidth(url="https://unreachable.invalid/test") assert result is None class TestRunNetworkProbes: def test_full_probe(self): with patch("i2p_apps.setup.network_probe.probe_dns") as mock_dns, \ patch("i2p_apps.setup.network_probe.probe_latency") as mock_lat, \ patch("i2p_apps.setup.network_probe.estimate_bandwidth") as mock_bw, \ patch("i2p_apps.setup.network_probe.check_dns") as mock_check: mock_dns.return_value = DnsProbeResult( can_resolve_neutral=True, can_resolve_cdn=True, can_resolve_reseed=True, resolver_latency_ms=10.0, ) mock_lat.return_value = LatencyProbeResult( rtt_ms=45.0, jitter_ms=8.0, endpoints_reached=3, endpoints_tested=3, ) mock_bw.return_value = BandwidthEstimate( download_mbps=12.0, method="cdn_download", ) mock_check.return_value = (True, 10.0) result = run_network_probes() assert isinstance(result, NetworkProbeResult) assert result.dns.can_resolve_neutral is True assert result.latency.rtt_ms == 45.0 assert result.bandwidth is not None def test_no_bandwidth_probe(self): with patch("i2p_apps.setup.network_probe.probe_dns") as mock_dns, \ patch("i2p_apps.setup.network_probe.probe_latency") as mock_lat, \ patch("i2p_apps.setup.network_probe.check_dns") as mock_check: mock_dns.return_value = DnsProbeResult( can_resolve_neutral=True, can_resolve_cdn=True, can_resolve_reseed=False, resolver_latency_ms=10.0, ) mock_lat.return_value = LatencyProbeResult( rtt_ms=45.0, jitter_ms=8.0, endpoints_reached=2, endpoints_tested=3, ) mock_check.return_value = (True, 10.0) result = run_network_probes(include_bandwidth=False) assert result.bandwidth is None