hermes-agent/tests/test_ipv4_preference.py
alt-glitch a1e667b9f2 fix(restructure): fix test regressions from import rewrite
Fix variable name breakage (run_agent, hermes_constants, etc.) where
import rewriter changed 'import X' to 'import hermes_agent.Y' but
test code still referenced 'X' as a variable name.

Fix package-vs-module confusion (cli.auth, cli.models, cli.ui) where
single files became directories.

Fix hardcoded file paths in tests pointing to old locations.
Fix tool registry to discover tools in subpackage directories.
Fix stale import in hermes_agent/tools/__init__.py.

Part of #14182, #14183
2026-04-23 12:05:10 +05:30

114 lines
4.2 KiB
Python

"""Tests for network.force_ipv4 — the socket.getaddrinfo monkey-patch."""
import importlib
import socket
from unittest.mock import patch, MagicMock
import pytest
def _reload_constants():
"""Reload hermes_constants to get a fresh apply_ipv4_preference."""
from hermes_agent import constants as hermes_constants
importlib.reload(hermes_constants)
return hermes_constants
class TestApplyIPv4Preference:
"""Tests for apply_ipv4_preference()."""
def setup_method(self):
"""Save the original getaddrinfo before each test."""
self._original = socket.getaddrinfo
def teardown_method(self):
"""Restore the original getaddrinfo after each test."""
socket.getaddrinfo = self._original
def test_noop_when_force_false(self):
"""No patch when force=False."""
from hermes_agent.constants import apply_ipv4_preference
original = socket.getaddrinfo
apply_ipv4_preference(force=False)
assert socket.getaddrinfo is original
def test_patches_getaddrinfo_when_forced(self):
"""Patches socket.getaddrinfo when force=True."""
from hermes_agent.constants import apply_ipv4_preference
original = socket.getaddrinfo
apply_ipv4_preference(force=True)
assert socket.getaddrinfo is not original
assert getattr(socket.getaddrinfo, "_hermes_ipv4_patched", False) is True
def test_double_patch_is_safe(self):
"""Calling apply twice doesn't double-wrap."""
from hermes_agent.constants import apply_ipv4_preference
apply_ipv4_preference(force=True)
first_patch = socket.getaddrinfo
apply_ipv4_preference(force=True)
assert socket.getaddrinfo is first_patch
def test_af_unspec_becomes_af_inet(self):
"""AF_UNSPEC (default) calls get rewritten to AF_INET."""
from hermes_agent.constants import apply_ipv4_preference
calls = []
original = socket.getaddrinfo
def mock_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
calls.append(family)
return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", ("93.184.216.34", 80))]
socket.getaddrinfo = mock_getaddrinfo
apply_ipv4_preference(force=True)
# Call with default family (AF_UNSPEC = 0)
socket.getaddrinfo("example.com", 80)
assert calls[-1] == socket.AF_INET, "AF_UNSPEC should be rewritten to AF_INET"
def test_explicit_family_preserved(self):
"""Explicit AF_INET6 requests are not intercepted."""
from hermes_agent.constants import apply_ipv4_preference
calls = []
original = socket.getaddrinfo
def mock_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
calls.append(family)
return [(family, socket.SOCK_STREAM, 6, "", ("::1", 80))]
socket.getaddrinfo = mock_getaddrinfo
apply_ipv4_preference(force=True)
socket.getaddrinfo("example.com", 80, family=socket.AF_INET6)
assert calls[-1] == socket.AF_INET6, "Explicit AF_INET6 should pass through"
def test_fallback_on_gaierror(self):
"""Falls back to AF_UNSPEC if AF_INET resolution fails."""
from hermes_agent.constants import apply_ipv4_preference
call_families = []
def mock_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
call_families.append(family)
if family == socket.AF_INET:
raise socket.gaierror("No A record")
# AF_UNSPEC fallback returns IPv6
return [(socket.AF_INET6, socket.SOCK_STREAM, 6, "", ("::1", 80))]
socket.getaddrinfo = mock_getaddrinfo
apply_ipv4_preference(force=True)
result = socket.getaddrinfo("ipv6only.example.com", 80)
# Should have tried AF_INET first, then fallen back to AF_UNSPEC
assert call_families == [socket.AF_INET, 0]
assert result[0][0] == socket.AF_INET6
class TestConfigDefault:
"""Verify network section exists in DEFAULT_CONFIG."""
def test_network_section_in_default_config(self):
from hermes_agent.cli.config import DEFAULT_CONFIG
assert "network" in DEFAULT_CONFIG
assert DEFAULT_CONFIG["network"]["force_ipv4"] is False