Clean rebase of nankingjing's #5423 (rebase-first). Co-authored-by: nankingjing <nankingjing@users.noreply.github.com>
117 lines
3.4 KiB
Python
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"
|