Files
hermes-agent/tests/plugins/memory/test_holographic_profile_db_path.py
ethernet 16652eea18 Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts:
#	gateway/config.py
#	gateway/config_loader.py
#	gateway/readiness.py
#	hermes_cli/managed_scope.py
#	hermes_cli/plugin_python_deps.py
#	hermes_cli/plugins_cmd.py
#	hermes_cli/update_cmd_maint.py
#	plugin-catalog/hindsight.yaml
#	plugins/plugin_loader.py
#	providers/__init__.py
#	scripts/run_tests.sh
#	tests/gateway/test_control_socket_windows_live.py
#	tests/gateway/test_gateway_streaming_nested_config.py
#	tests/hermes_cli/test_doctor.py
#	tests/hermes_cli/test_plan_reconciliation_windows_live.py
#	tests/hermes_cli/test_update_apply_shallow_count.py
#	tests/hermes_cli/test_update_concurrent_quarantine.py
#	tests/hermes_cli/test_update_shim_self_lock.py
#	tests/hermes_cli/test_verify_console_scripts.py
#	tests/tools/test_lazy_deps.py
#	tests/tui_gateway/test_subprocess_encoding.py
#	tools/lazy_deps.py
2026-09-23 15:26:34 -04:00

94 lines
4.1 KiB
Python

"""The holographic fact DB set up with the default path belongs to whichever profile opens it.
Setup used to offer, and store, the active profile's concrete path (``~/.hermes/memory_store.db``).
``profile create --clone`` copies config.yaml verbatim, so the clone opened the source profile's
facts; ``profile rename`` moves the directory, so the renamed profile opened an empty DB in a
re-created directory under its old name.
"""
from __future__ import annotations
import io
import sys
from pathlib import Path
from unittest.mock import patch
import pytest
import hermes_yaml as yaml
import hermes_cli.memory_setup as memory_setup
from hermes_cli.profiles import create_profile, rename_profile
from plugins.memory.holographic import HolographicMemoryProvider, _load_plugin_config
@pytest.fixture()
def root(tmp_path, monkeypatch):
# A ``~/`` path is displayed through Path.home() and expanded through HOME; both name the sandbox.
monkeypatch.setenv("HOME", str(tmp_path))
monkeypatch.setattr(Path, "home", lambda: tmp_path)
home = tmp_path / ".hermes"
home.mkdir()
monkeypatch.setenv("HERMES_HOME", str(home))
return home
def _setup_with_defaults(monkeypatch, home: Path) -> dict:
"""``hermes memory setup`` for holographic with Enter on every field, saved as ``cmd_setup`` does."""
monkeypatch.setenv("HERMES_HOME", str(home))
provider = HolographicMemoryProvider(config={"hrr_dim": 64})
monkeypatch.setattr(memory_setup, "_curses_select", lambda *_a, default=0, **_k: default)
monkeypatch.setattr(sys, "stdin", io.StringIO("\n" * 10))
answers: dict = {}
assert memory_setup._prompt_schema_fields("holographic", provider.get_config_schema(), answers, {})
provider.save_config(answers, str(home))
return answers
def _opened_db(monkeypatch, home: Path) -> Path:
"""The DB a session started with ``hermes -p <profile>`` opens."""
monkeypatch.setenv("HERMES_HOME", str(home))
provider = HolographicMemoryProvider(config=_load_plugin_config())
provider.initialize("s")
try:
return provider._store.db_path.resolve()
finally:
provider.shutdown()
@pytest.mark.parametrize("lifecycle", ["clone", "rename"])
def test_default_db_path_follows_the_profile_that_opens_it(root, monkeypatch, lifecycle):
if lifecycle == "clone":
answers = _setup_with_defaults(monkeypatch, root)
monkeypatch.setenv("HERMES_HOME", str(root))
profile = create_profile("work", clone_config=True, no_alias=True)
else:
source = create_profile("alpha", no_alias=True)
answers = _setup_with_defaults(monkeypatch, source)
monkeypatch.setenv("HERMES_HOME", str(root))
with patch("hermes_cli.profiles.check_alias_collision", return_value="skip"):
profile = rename_profile("alpha", "beta")
assert _opened_db(monkeypatch, profile) == (profile / "memory_store.db").resolve()
if lifecycle == "rename":
assert not (root / "profiles" / "alpha").exists()
# The prompt offers the value it stores, so what the user accepted is what config.yaml says.
assert answers["db_path"] == "$HERMES_HOME/memory_store.db"
@pytest.mark.parametrize("spelling", ["display", "absolute", "elsewhere"])
def test_save_config_stores_only_this_profiles_default_path_as_the_placeholder(root, monkeypatch, spelling):
# "display"/"absolute": the concrete value an older setup wrote, and the dashboard form re-submits on
# its next save. "elsewhere": a deliberately shared store (#4726) is kept as given.
profile = create_profile("work", no_alias=True)
monkeypatch.setenv("HERMES_HOME", str(profile))
given = {
"display": "~/.hermes/profiles/work/memory_store.db",
"absolute": str(profile / "memory_store.db"),
"elsewhere": str(root / "shared" / "facts.db"),
}[spelling]
expected = given if spelling == "elsewhere" else "$HERMES_HOME/memory_store.db"
HolographicMemoryProvider(config={"hrr_dim": 64}).save_config({"db_path": given, "hrr_dim": "64"}, str(profile))
stored = yaml.safe_load((profile / "config.yaml").read_text(encoding="utf-8"))["plugins"]["hermes-memory-store"]
assert stored == {"db_path": expected, "hrr_dim": "64"}