Files
aiturk-hermes-ide/tests/tui_gateway/test_resume_live_profile_scope.py

109 lines
3.9 KiB
Python

"""``session.resume`` reuses a live session only within the requested profile.
The live registry is keyed by bare stored session id, and stored ids are
timestamp-based, so the same id can legitimately be live under profile A while
profile B's store also holds it. The resume fast path (and the post-build
re-check / ``_claim_or_reuse_live``) used to hand profile B's resume profile
A's runtime — the turn then ran with A's persona and wrote A's memory
(#100029). Pinned here:
* resume with profile B never reuses profile A's live session of the same id;
* the launch profile (no ``profile``) still matches live records that carry
no ``profile_home`` — the pre-existing single-profile contract.
"""
from __future__ import annotations
import pytest
from tui_gateway import server
class _DB:
"""Minimal ``SessionDB`` stand-in: every profile store knows ``s1``."""
def __init__(self, db_path=None, **_kwargs):
self.db_path = db_path
def close(self):
pass
def get_session(self, target):
return {"id": "s1", "cwd": ""} if target == "s1" else None
def get_session_by_title(self, _target):
return None
def resolve_resume_session_id(self, target):
return target
def reopen_session(self, _target):
pass
def get_resume_conversations(self, _target):
return ([], [])
def get_ancestor_display_prefix(self, _target):
return []
def get_messages_as_conversation(self, _target, **_kwargs):
return []
@pytest.fixture()
def homes(monkeypatch, tmp_path):
homes = {name: tmp_path / name for name in ("a", "b")}
for home in homes.values():
home.mkdir()
monkeypatch.setattr("hermes_state.get_shared_session_db", _DB)
monkeypatch.setattr(server, "_get_db", lambda: _DB())
monkeypatch.setattr(server, "_profile_home", lambda p: homes.get(p) if p else None)
monkeypatch.setattr(server, "_profile_configured_cwd", lambda _home: str(tmp_path))
monkeypatch.setattr(server, "_enable_gateway_prompts", lambda: None)
monkeypatch.setattr(server, "_schedule_agent_build", lambda *a, **k: None)
monkeypatch.setattr(server, "_schedule_session_cap_enforcement", lambda *a, **k: None)
monkeypatch.setattr(server, "_maybe_schedule_auto_continue", lambda *a, **k: None)
monkeypatch.setattr(server, "_default_session_cwd", lambda *a, **k: str(tmp_path))
monkeypatch.setattr(server, "_child_run_active", lambda _key: False)
monkeypatch.setattr(
server, "_live_session_payload", lambda sid, session, **_k: {"session_id": sid}
)
known = set(server._sessions)
yield homes
with server._sessions_lock:
for sid in [s for s in server._sessions if s not in known]:
server._sessions.pop(sid, None)
def _resume(**params):
return server.handle_request({"id": "1", "method": "session.resume", "params": params})
def _register_live(sid: str, profile_home) -> dict:
record = {"session_key": "s1", "history": [], "last_active": 0.0}
if profile_home is not None:
record["profile_home"] = str(profile_home)
with server._sessions_lock:
server._sessions[sid] = record
return record
def test_resume_with_other_profile_never_reuses_live_session(homes):
_register_live("live-a", homes["a"])
same = _resume(session_id="s1", profile="a", source="desktop")
assert same["result"]["session_id"] == "live-a"
other = _resume(session_id="s1", profile="b", source="desktop")
new_sid = other["result"]["session_id"]
assert new_sid != "live-a"
assert server._sessions[new_sid]["profile_home"] == str(homes["b"])
def test_launch_profile_still_matches_records_without_profile_home(homes):
_register_live("live-launch", None)
_register_live("live-a", homes["a"])
assert _resume(session_id="s1", source="desktop")["result"]["session_id"] == "live-launch"
assert _resume(session_id="s1", profile="a", source="desktop")["result"]["session_id"] == "live-a"