mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
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
114 lines
4.2 KiB
Python
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
|