"""Phase 4: lifecycle guard + per-profile observability.""" import pytest class TestServedProfilesStatus: def test_write_and_read_served_profiles(self, tmp_path, monkeypatch): monkeypatch.setenv("HERMES_HOME", str(tmp_path)) import importlib import gateway.status as status importlib.reload(status) try: status.write_runtime_status( gateway_state="running", served_profiles=["default", "coder"] ) rec = status.read_runtime_status() assert rec.get("served_profiles") == ["default", "coder"] finally: importlib.reload(status) def test_served_profiles_absent_by_default(self, tmp_path, monkeypatch): monkeypatch.setenv("HERMES_HOME", str(tmp_path)) import importlib import gateway.status as status importlib.reload(status) try: status.write_runtime_status(gateway_state="running") rec = status.read_runtime_status() assert "served_profiles" not in rec finally: importlib.reload(status) class TestNamedProfileMultiplexerGuard: """_guard_named_profile_under_multiplexer is inert unless all conditions hold.""" def test_inert_for_default_profile(self, monkeypatch): from hermes_cli import gateway as gw monkeypatch.setattr(gw, "_profile_suffix", lambda: "") # Should return without raising (default profile => guard N/A). gw._guard_named_profile_under_multiplexer(force=False) def test_force_bypasses(self, monkeypatch): from hermes_cli import gateway as gw # Even if it looks like a named profile, force returns immediately. monkeypatch.setattr(gw, "_profile_suffix", lambda: "coder") gw._guard_named_profile_under_multiplexer(force=True) def test_inert_when_no_default_gateway_running(self, monkeypatch, tmp_path): from hermes_cli import gateway as gw monkeypatch.setattr(gw, "_profile_suffix", lambda: "coder") monkeypatch.setattr( "hermes_constants.get_default_hermes_root", lambda: tmp_path ) # No gateway.pid in tmp_path => no running default gateway => no raise. gw._guard_named_profile_under_multiplexer(force=False)