Files
hermes-webui/tests/test_issue5420_profile_switch_session_new.py
2026-07-02 16:34:37 +00:00

117 lines
3.4 KiB
Python

"""Regression tests for #5420 profile-switch /api/session/new failures."""
from __future__ import annotations
import ast
import inspect
from unittest.mock import MagicMock
from urllib.parse import urlparse
import api.routes as routes
def _post_session_new(body: dict, monkeypatch):
cap = {}
def _j(_handler, payload, *_, **__):
cap["ok"] = payload
return True
def _bad(_handler, msg, code=400):
cap["bad"] = (msg, code)
return True
handler = MagicMock()
handler.command = "POST"
handler.headers = {}
monkeypatch.setattr(routes, "read_body", lambda _h: body)
monkeypatch.setattr(routes, "_check_csrf", lambda _h: True)
monkeypatch.setattr(routes, "_csrf_exempt_path", lambda _p: False)
monkeypatch.setattr(routes, "_guard_request_session_visibility", lambda *_a, **_k: True)
monkeypatch.setattr(routes, "j", _j)
monkeypatch.setattr(routes, "bad", _bad)
routes.handle_post(handler, urlparse("/api/session/new"))
return cap
def test_handle_post_does_not_shadow_get_active_profile_name():
"""handle_post must not re-import get_active_profile_name locally (#5420)."""
src = inspect.getsource(routes.handle_post)
tree = ast.parse(src)
for node in ast.walk(tree):
if isinstance(node, ast.ImportFrom) and node.module == "api.profiles":
for alias in node.names:
assert alias.name != "get_active_profile_name", (
"local import shadows module-level get_active_profile_name"
)
def test_session_new_succeeds_with_cross_profile_prev_session_id(monkeypatch):
created = {}
class _Session:
def __init__(self):
self.session_id = "new123"
self.profile = "work"
self.messages = []
def compact(self):
return {"session_id": self.session_id, "profile": self.profile}
def _new_session(**_kwargs):
s = _Session()
created["session"] = s
return s
monkeypatch.setattr(routes, "new_session", _new_session)
monkeypatch.setattr(
routes,
"_session_id_visible_to_request_profile",
lambda *_a, **_k: False,
)
cap = _post_session_new(
{"profile": "work", "prev_session_id": "old-from-default"},
monkeypatch,
)
assert "bad" not in cap
assert "ok" in cap
assert cap["ok"]["session"]["session_id"] == "new123"
assert created["session"].profile == "work"
def test_session_new_still_commits_same_profile_prev_session_id(monkeypatch):
class _Session:
def __init__(self):
self.session_id = "new456"
self.profile = "default"
self.messages = []
def compact(self):
return {"session_id": self.session_id}
monkeypatch.setattr(routes, "new_session", lambda **_k: _Session())
monkeypatch.setattr(
routes,
"_session_id_visible_to_request_profile",
lambda *_a, **_k: True,
)
commit_calls = []
def _commit(prev_session_id, **kwargs):
commit_calls.append(prev_session_id)
import api.session_lifecycle as lifecycle
monkeypatch.setattr(lifecycle, "commit_session_memory", _commit)
cap = _post_session_new({"prev_session_id": "same-profile-old"}, monkeypatch)
assert "bad" not in cap
assert commit_calls == ["same-profile-old"]
assert cap["ok"]["session"]["session_id"] == "new456"