hermes-agent/tests/test_hermes_constants.py
kshitijk4poor 66827f8947 chore: prune unused imports and duplicate import redefinitions
Remove unused imports (F401) and duplicate/shadowed import
redefinitions (F811) across the codebase using ruff's safe
autofixes. No behavioral changes -- imports only.

- ~1400 safe autofixes applied across 644 files (net -1072 lines)
- __init__.py re-exports preserved (excluded from F401 removal so
  public re-export surfaces stay intact)
- Re-exports that are imported or monkeypatched by tests but look
  unused in their defining module are kept with explicit # noqa:
  F401 (gateway/run.py load_dotenv; run_agent re-exports from
  agent.message_sanitization, agent.context_compressor,
  agent.retry_utils, agent.prompt_builder, agent.process_bootstrap,
  agent.codex_responses_adapter)
- Unsafe F841 (unused-variable) fixes deliberately skipped -- those
  can change behavior when the RHS has side effects
- ruff lints remain disabled in pyproject.toml (only PLW1514 is
  selected); this is a one-time cleanup, not a config change

Verification:
- python -m compileall: clean
- pytest --collect-only: all 27161 tests collect (zero import errors)
- core entry points import clean (run_agent, model_tools, cli,
  toolsets, hermes_state, batch_runner, gateway)
- static scan: every name any test imports directly from an edited
  module still resolves
2026-05-28 22:26:25 -07:00

265 lines
11 KiB
Python

"""Tests for hermes_constants module."""
import os
from pathlib import Path
import pytest
import hermes_constants
from hermes_constants import (
VALID_REASONING_EFFORTS,
get_default_hermes_root,
is_container,
parse_reasoning_effort,
secure_parent_dir,
)
class TestGetDefaultHermesRoot:
"""Tests for get_default_hermes_root() — Docker/custom deployment awareness."""
def test_no_hermes_home_returns_native(self, tmp_path, monkeypatch):
"""When HERMES_HOME is not set, returns ~/.hermes."""
monkeypatch.delenv("HERMES_HOME", raising=False)
monkeypatch.setattr(Path, "home", lambda: tmp_path)
assert get_default_hermes_root() == tmp_path / ".hermes"
def test_hermes_home_is_native(self, tmp_path, monkeypatch):
"""When HERMES_HOME = ~/.hermes, returns ~/.hermes."""
native = tmp_path / ".hermes"
native.mkdir()
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("HERMES_HOME", str(native))
assert get_default_hermes_root() == native
def test_hermes_home_is_profile(self, tmp_path, monkeypatch):
"""When HERMES_HOME is a profile under ~/.hermes, returns ~/.hermes."""
native = tmp_path / ".hermes"
profile = native / "profiles" / "coder"
profile.mkdir(parents=True)
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("HERMES_HOME", str(profile))
assert get_default_hermes_root() == native
def test_hermes_home_is_docker(self, tmp_path, monkeypatch):
"""When HERMES_HOME points outside ~/.hermes (Docker), returns HERMES_HOME."""
docker_home = tmp_path / "opt" / "data"
docker_home.mkdir(parents=True)
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("HERMES_HOME", str(docker_home))
assert get_default_hermes_root() == docker_home
def test_hermes_home_is_custom_path(self, tmp_path, monkeypatch):
"""Any HERMES_HOME outside ~/.hermes is treated as the root."""
custom = tmp_path / "my-hermes-data"
custom.mkdir()
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("HERMES_HOME", str(custom))
assert get_default_hermes_root() == custom
def test_docker_profile_active(self, tmp_path, monkeypatch):
"""When a Docker profile is active (HERMES_HOME=<root>/profiles/<name>),
returns the Docker root, not the profile dir."""
docker_root = tmp_path / "opt" / "data"
profile = docker_root / "profiles" / "coder"
profile.mkdir(parents=True)
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("HERMES_HOME", str(profile))
assert get_default_hermes_root() == docker_root
class TestIsContainer:
"""Tests for is_container() — Docker/Podman detection."""
def _reset_cache(self, monkeypatch):
"""Reset the cached detection result before each test."""
monkeypatch.setattr(hermes_constants, "_container_detected", None)
def test_detects_dockerenv(self, monkeypatch, tmp_path):
"""/.dockerenv triggers container detection."""
self._reset_cache(monkeypatch)
monkeypatch.setattr(os.path, "exists", lambda p: p == "/.dockerenv")
assert is_container() is True
def test_detects_containerenv(self, monkeypatch, tmp_path):
"""/run/.containerenv triggers container detection (Podman)."""
self._reset_cache(monkeypatch)
monkeypatch.setattr(os.path, "exists", lambda p: p == "/run/.containerenv")
assert is_container() is True
def test_detects_cgroup_docker(self, monkeypatch, tmp_path):
"""/proc/1/cgroup containing 'docker' triggers detection."""
import builtins
self._reset_cache(monkeypatch)
monkeypatch.setattr(os.path, "exists", lambda p: False)
cgroup_file = tmp_path / "cgroup"
cgroup_file.write_text("12:memory:/docker/abc123\n")
_real_open = builtins.open
monkeypatch.setattr("builtins.open", lambda p, *a, **kw: _real_open(str(cgroup_file), *a, **kw) if p == "/proc/1/cgroup" else _real_open(p, *a, **kw))
assert is_container() is True
def test_negative_case(self, monkeypatch, tmp_path):
"""Returns False on a regular Linux host."""
import builtins
self._reset_cache(monkeypatch)
monkeypatch.setattr(os.path, "exists", lambda p: False)
cgroup_file = tmp_path / "cgroup"
cgroup_file.write_text("12:memory:/\n")
_real_open = builtins.open
monkeypatch.setattr("builtins.open", lambda p, *a, **kw: _real_open(str(cgroup_file), *a, **kw) if p == "/proc/1/cgroup" else _real_open(p, *a, **kw))
assert is_container() is False
def test_caches_result(self, monkeypatch):
"""Second call uses cached value without re-probing."""
monkeypatch.setattr(hermes_constants, "_container_detected", True)
assert is_container() is True
# Even if we make os.path.exists return False, cached value wins
monkeypatch.setattr(os.path, "exists", lambda p: False)
assert is_container() is True
class TestParseReasoningEffort:
"""Tests for parse_reasoning_effort() — string → reasoning config dict."""
@pytest.mark.parametrize("value", ["", " ", "\t", "\n"])
def test_empty_or_whitespace_returns_none(self, value):
"""Empty / whitespace-only input falls back to caller default (None)."""
assert parse_reasoning_effort(value) is None
def test_none_disables_reasoning(self):
"""The literal "none" disables reasoning explicitly."""
assert parse_reasoning_effort("none") == {"enabled": False}
@pytest.mark.parametrize("level", list(VALID_REASONING_EFFORTS))
def test_each_valid_level(self, level):
"""Every level listed in VALID_REASONING_EFFORTS is accepted as-is."""
assert parse_reasoning_effort(level) == {"enabled": True, "effort": level}
@pytest.mark.parametrize(
"raw, expected_effort",
[
("MEDIUM", "medium"),
("High", "high"),
(" low ", "low"),
("\tXHIGH\n", "xhigh"),
("None", False),
],
)
def test_case_and_whitespace_normalized(self, raw, expected_effort):
"""Mixed case and surrounding whitespace are normalized before lookup."""
result = parse_reasoning_effort(raw)
if expected_effort is False:
assert result == {"enabled": False}
else:
assert result == {"enabled": True, "effort": expected_effort}
@pytest.mark.parametrize(
"value",
["bogus", "very-high", "max", "0", "off", "true", "default"],
)
def test_unknown_levels_return_none(self, value):
"""Unrecognized strings fall back to the caller default (None)."""
assert parse_reasoning_effort(value) is None
def test_known_supported_levels_are_documented(self):
"""Guard against silently dropping a documented level.
The docstring promises "minimal", "low", "medium", "high", "xhigh".
If someone removes one from VALID_REASONING_EFFORTS without updating
the docstring, this test will fail and force the call out.
"""
documented = {"minimal", "low", "medium", "high", "xhigh"}
assert documented.issubset(set(VALID_REASONING_EFFORTS))
class TestSecureParentDir:
"""Tests for secure_parent_dir() — prevents chmod on / or top-level dirs."""
def test_safe_path_calls_chmod(self, tmp_path, monkeypatch):
"""Normal nested path (depth >= 3) should call os.chmod."""
safe_dir = tmp_path / "home" / "user" / ".hermes"
safe_dir.mkdir(parents=True)
target = safe_dir / "auth.json"
target.touch()
called_with = []
monkeypatch.setattr(os, "chmod", lambda p, m: called_with.append((str(p), m)))
secure_parent_dir(target)
assert len(called_with) == 1
assert called_with[0] == (str(safe_dir), 0o700)
def test_root_dir_skipped(self, monkeypatch):
"""Parent resolving to / must NOT be chmod'd."""
called_with = []
monkeypatch.setattr(os, "chmod", lambda p, m: called_with.append((str(p), m)))
# Path("/foo").parent == Path("/")
secure_parent_dir(Path("/foo"))
assert called_with == []
def test_top_level_dir_skipped(self, monkeypatch):
"""Parent resolving to a top-level dir (depth 2) must NOT be chmod'd."""
called_with = []
monkeypatch.setattr(os, "chmod", lambda p, m: called_with.append((str(p), m)))
# Path("/usr/foo").parent == Path("/usr") — depth 2
secure_parent_dir(Path("/usr/foo"))
assert called_with == []
def test_two_component_path_skipped(self, monkeypatch):
"""Parent with < 3 resolved parts must NOT be chmod'd.
Uses monkeypatch to avoid macOS firmlink resolution of /home.
"""
called_with = []
monkeypatch.setattr(os, "chmod", lambda p, m: called_with.append((str(p), m)))
# Mock Path.resolve to return a short path regardless of OS quirks
original_resolve = Path.resolve
def mock_resolve(self):
if str(self) == "/x/y":
return Path("/x")
return original_resolve(self)
monkeypatch.setattr(Path, "resolve", mock_resolve)
secure_parent_dir(Path("/x/y"))
assert called_with == []
def test_oserror_suppressed(self, tmp_path, monkeypatch):
"""OSError from chmod should be silently caught."""
safe_dir = tmp_path / "a" / "b" / "c"
safe_dir.mkdir(parents=True)
target = safe_dir / "file.json"
target.touch()
def raise_oserror(p, m):
raise OSError("permission denied")
monkeypatch.setattr(os, "chmod", raise_oserror)
# Should not raise
secure_parent_dir(target)
def test_symlink_resolved(self, tmp_path, monkeypatch):
"""Symlinks should be resolved before checking depth."""
real_dir = tmp_path / "a" / "b"
real_dir.mkdir(parents=True)
target = real_dir / "file.json"
target.touch()
# Create a symlink with fewer path components
link = tmp_path / "link"
link.symlink_to(real_dir)
link_target = link / "file.json"
called_with = []
monkeypatch.setattr(os, "chmod", lambda p, m: called_with.append((str(p), m)))
# Even though /tmp/link has only 3 parts, the resolved path has 4
# The resolved parent (real_dir) has depth 4, so it should be chmod'd
secure_parent_dir(link_target)
assert len(called_with) == 1
assert called_with[0] == (str(real_dir), 0o700)