setup_logging(hermes_home=get_hermes_home()) is the whole fix; the FileNotFoundError fallback chain guarded a home that is being served (it exists), and the two extra tests re-tested it. Keep the A->B routing invariant and the no-bare-handler guard.
110 lines
4.2 KiB
Python
110 lines
4.2 KiB
Python
"""#125974 — ``agent.agent_init._setup_logging`` must honor the active profile scope.
|
|
|
|
A Desktop serve backend (tui_gateway/compute_host.py) builds agents for several profiles
|
|
inside ``set_hermes_home_override(profile_home)``. ``_setup_logging`` used to pass the
|
|
import-time ``run_agent._hermes_home`` freeze, so the second profile's ``setup_logging``
|
|
call saw a home it already served, never adopted it, and every profile's records kept
|
|
landing in the launch profile's agent.log.
|
|
"""
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
import hermes_logging
|
|
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
|
|
from hermes_logging import RotatingFileHandler, _ProfileRoutingFileHandler
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _reset_logging_state():
|
|
"""Reset hermes_logging module globals so each test starts unconfigured."""
|
|
hermes_logging._logging_initialized = False
|
|
hermes_logging._reset_queued_handlers()
|
|
yield
|
|
hermes_logging._reset_queued_handlers()
|
|
hermes_logging._logging_initialized = False
|
|
hermes_logging.clear_session_context()
|
|
|
|
|
|
def _agent_stub() -> SimpleNamespace:
|
|
# _setup_logging only reads verbose_logging; quiet keeps console clean.
|
|
return SimpleNamespace(verbose_logging=False, quiet_mode=True)
|
|
|
|
|
|
def _witness(name: str, message: str) -> None:
|
|
logging.getLogger(name).info(message)
|
|
|
|
|
|
class TestSetupLoggingProfileScope:
|
|
def test_routes_agent_records_to_profile_scope(self, tmp_path: Path) -> None:
|
|
"""L1: an agent built under override B logs into B's agent.log, not A's."""
|
|
from agent.agent_init import _setup_logging
|
|
|
|
home_a = tmp_path / "home-a"
|
|
home_b = tmp_path / "home-b"
|
|
home_a.mkdir()
|
|
home_b.mkdir()
|
|
|
|
token = set_hermes_home_override(str(home_a))
|
|
try:
|
|
_setup_logging(_agent_stub())
|
|
finally:
|
|
reset_hermes_home_override(token)
|
|
|
|
token = set_hermes_home_override(str(home_b))
|
|
try:
|
|
_setup_logging(_agent_stub())
|
|
_witness("agent.test_profile_scope_125974", "scoped-witness-b")
|
|
finally:
|
|
reset_hermes_home_override(token)
|
|
hermes_logging.flush_log_queue()
|
|
|
|
log_b = home_b / "logs" / "agent.log"
|
|
assert log_b.is_file(), "the profile-scoped agent's records must reach its own logs/"
|
|
assert "scoped-witness-b" in log_b.read_text(encoding="utf-8-sig")
|
|
log_a = home_a / "logs" / "agent.log"
|
|
text_a = log_a.read_text(encoding="utf-8-sig") if log_a.is_file() else ""
|
|
assert "scoped-witness-b" not in text_a, "record must not leak into the launch home"
|
|
|
|
def test_under_routing_adds_no_bare_handler(self, tmp_path: Path) -> None:
|
|
"""L3 guard: with routing already live, a scoped _setup_logging adds no bare handler.
|
|
|
|
A bare RotatingFileHandler beside the profile routers would take every home's
|
|
records — exactly the leak this fix closes. Passing on both sides of the fix is
|
|
the point: it pins the blast radius.
|
|
"""
|
|
from agent.agent_init import _setup_logging
|
|
|
|
home_a = tmp_path / "home-a"
|
|
home_b = tmp_path / "home-b"
|
|
home_a.mkdir()
|
|
home_b.mkdir()
|
|
|
|
hermes_logging.setup_logging(hermes_home=home_a)
|
|
assert hermes_logging.enable_profile_log_routing([home_a, home_b]) is True
|
|
|
|
token = set_hermes_home_override(str(home_b))
|
|
try:
|
|
_setup_logging(_agent_stub())
|
|
_witness("agent.test_routing_guard_125974", "routing-guard-witness-b")
|
|
finally:
|
|
reset_hermes_home_override(token)
|
|
hermes_logging.flush_log_queue()
|
|
|
|
bare = [
|
|
h for h in hermes_logging._queued_file_handlers
|
|
if isinstance(h, RotatingFileHandler)
|
|
]
|
|
assert not bare, f"bare file handlers must not ride beside the routers: {bare}"
|
|
assert "routing-guard-witness-b" in (
|
|
home_b / "logs" / "agent.log"
|
|
).read_text(encoding="utf-8-sig")
|
|
# And the routers themselves must still be routing, not replaced.
|
|
assert any(
|
|
isinstance(h, _ProfileRoutingFileHandler)
|
|
for h in hermes_logging._queued_file_handlers
|
|
)
|