Files
hermes-agent/tests/hermes_cli/test_data_dir_suffix.py
ethernet a41aabff6c fix: platform legs — docker arm64 bootstrap, win32-arm64 native builds, nix desktop-backend cleanup
- pm.environment owns _RESOLVER_MARKERS: the streaming uv runner imported
  pm.workspace, whose tomllib import fails on the 3.10 system python that
  bootstraps the Docker arm64 image (No module named 'tomllib'). Invariant test
  proves runtime staging needs neither tomllib nor pm.workspace.
- run_tests.sh forwards the MSVC/SDK/Rust/OpenSSL toolchain variables through
  its env -i scrub so PM tests that compile ruamel-yaml-clib on Windows arm64
  find cl.exe (previously 'Visual C++ 14.0 or greater is required').
- nix desktop-backend check: the spawned backend outlives cage's process group
  and kept writing under the temp HERMES_HOME during rmtree; stop every
  process bound to the throwaway HOME before cleanup.
- windows: test_launcher_runtime_selection imports runtime_state from
  hermes_cli (moved in bbec973514); the ' spaced ' suffix row loses its
  trailing space on win32 (the filesystem strips it).
- macOS: test_sealed_worker_command copies the interpreter into the payload
  (the escape guard resolves symlinks) and links the host lib tree.
2026-09-20 10:42:30 -04:00

102 lines
4.2 KiB
Python

"""Default-root isolation through the real Python resolution chain."""
import json
import os
from pathlib import Path
import subprocess
import sys
import pytest
# Win32 strips a trailing space from every path component, so the literal-suffix contract is
# only checkable with the leading space there.
_SPACED = " spaced" if sys.platform == "win32" else " spaced "
@pytest.mark.platforms("linux", "macos", "windows")
@pytest.mark.parametrize("suffix", ["", "-asdfasdf", "magic-test", _SPACED])
def test_suffix_scopes_default_home_and_profiles(tmp_path, suffix):
env = dict(os.environ)
env.pop("HERMES_HOME", None)
env.update(
HOME=str(tmp_path), USERPROFILE=str(tmp_path),
LOCALAPPDATA=str(tmp_path / "AppData" / "Local"),
HERMES_DATA_DIR_SUFFIX=suffix,
)
script = """
import json
import os
from pathlib import Path
from hermes_constants import get_hermes_home, get_process_hermes_home, get_default_hermes_root
from hermes_cli.profiles import _get_profiles_root, _get_active_profile_path, resolve_profile_env
root = get_default_hermes_root()
profile = root / 'profiles' / 'coder'
profile.mkdir(parents=True)
(profile / 'config.yaml').write_text('', encoding='utf-8')
result = [str(get_hermes_home()), str(get_process_hermes_home()), str(root),
str(_get_profiles_root()), str(_get_active_profile_path()), resolve_profile_env('coder')]
os.environ['HERMES_HOME'] = str(profile)
result.extend([str(get_hermes_home()), str(get_default_hermes_root())])
os.environ.pop('HERMES_HOME')
os.environ['HERMES_DATA_DIR_SUFFIX'] += '-changed'
result.append(str(get_default_hermes_root()))
print(json.dumps(result))
"""
result = subprocess.run(
[sys.executable, "-c", script], env=env,
cwd=Path(__file__).resolve().parents[2],
text=True, capture_output=True,
)
assert result.returncode == 0, result.stderr
base = tmp_path / "AppData" / "Local" / "hermes" if sys.platform == "win32" else tmp_path / ".hermes"
root = Path(str(base) + suffix)
profile = root / "profiles" / "coder"
assert json.loads(result.stdout) == list(map(str, [
root, root, root, root / "profiles", root / "active_profile", profile,
profile, root, Path(str(root) + "-changed"),
]))
@pytest.mark.platforms("linux", "macos", "windows")
def test_startup_readers_use_the_suffixed_home(tmp_path, monkeypatch):
from hermes_constants import get_process_hermes_home
from hermes_cli.dashboard_procs import _hermes_home_dir
from hermes_cli.env_loader import load_hermes_dotenv
from hermes_startup_watchdog import get_startup_watchdog_dump_path
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("LOCALAPPDATA", str(tmp_path / "AppData" / "Local"))
monkeypatch.delenv("HERMES_HOME", raising=False)
monkeypatch.setenv("HERMES_DATA_DIR_SUFFIX", "magic-test")
monkeypatch.delenv("SUFFIX_TEST_CREDENTIAL", raising=False)
home = get_process_hermes_home()
home.mkdir(parents=True)
(home / ".env").write_text("SUFFIX_TEST_CREDENTIAL=suffixed\n", encoding="utf-8")
load_hermes_dotenv(project_env=tmp_path / "absent.env", load_external_secrets=False)
assert os.environ.get("SUFFIX_TEST_CREDENTIAL") == "suffixed"
assert _hermes_home_dir() == home
assert get_startup_watchdog_dump_path() == home / "logs" / "gateway-startup-watchdog.log"
def test_suffix_does_not_change_explicit_or_context_home(tmp_path, monkeypatch):
from hermes_constants import (
get_default_hermes_root, get_hermes_home, get_process_hermes_home,
reset_hermes_home_override, set_hermes_home_override,
)
monkeypatch.setattr(Path, "home", lambda: tmp_path)
monkeypatch.setenv("LOCALAPPDATA", str(tmp_path / "AppData" / "Local"))
explicit = tmp_path / "explicit"
scoped = tmp_path / "scoped"
monkeypatch.setenv("HERMES_HOME", str(explicit))
monkeypatch.setenv("HERMES_DATA_DIR_SUFFIX", "magic-test")
assert get_hermes_home() == get_process_hermes_home() == get_default_hermes_root() == explicit
token = set_hermes_home_override(scoped)
try:
assert get_hermes_home() == scoped
assert get_process_hermes_home() == get_default_hermes_root() == explicit
finally:
reset_hermes_home_override(token)