Agent reviewer 'LGTM. Ship it.' - Bug A fix: _session_field helper handles dict-vs-object snapshot in pin-limit check - Bug B fix: removed stale client-side pinLimitReached short-circuit - Bug C recovery: renderSessionList() on pin/unpin failure refreshes from server Co-authored-by: franksong2702 <146128127+franksong2702@users.noreply.github.com>
103 lines
3.8 KiB
Python
103 lines
3.8 KiB
Python
"""Regression checks for configurable pinned session limits."""
|
|
|
|
import json
|
|
import pathlib
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
from tests._pytest_port import BASE
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
CONFIG_PY = (ROOT / "api" / "config.py").read_text(encoding="utf-8")
|
|
INDEX_HTML = (ROOT / "static" / "index.html").read_text(encoding="utf-8")
|
|
PANELS_JS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8")
|
|
BOOT_JS = (ROOT / "static" / "boot.js").read_text(encoding="utf-8")
|
|
SESSIONS_JS = (ROOT / "static" / "sessions.js").read_text(encoding="utf-8")
|
|
|
|
|
|
def post(path, body=None):
|
|
data = json.dumps(body or {}).encode()
|
|
req = urllib.request.Request(
|
|
BASE + path,
|
|
data=data,
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=10) as r:
|
|
return json.loads(r.read()), r.status
|
|
except urllib.error.HTTPError as e:
|
|
return json.loads(e.read()), e.code
|
|
|
|
|
|
def make_session(created, title):
|
|
payload = {
|
|
"title": title,
|
|
"messages": [{"role": "user", "content": "keep this conversation handy"}],
|
|
"model": "test/pin-limit-setting",
|
|
}
|
|
d, status = post("/api/session/import", payload)
|
|
assert status == 200
|
|
sid = d["session"]["session_id"]
|
|
created.append(sid)
|
|
return sid
|
|
|
|
|
|
def test_pin_limit_setting_is_exposed_and_wired_through_ui():
|
|
assert '"pinned_sessions_limit": 3' in CONFIG_PY
|
|
assert '"pinned_sessions_limit": (1, 99)' in CONFIG_PY
|
|
assert 'id="settingsPinnedSessionsLimit"' in INDEX_HTML
|
|
assert 'type="number"' in INDEX_HTML
|
|
assert 'min="1"' in INDEX_HTML
|
|
assert 'max="99"' in INDEX_HTML
|
|
assert 'payload.pinned_sessions_limit=parseInt(pinnedLimitField.value,10)' in PANELS_JS
|
|
assert "settings.pinned_sessions_limit" in PANELS_JS
|
|
assert "window._pinnedSessionsLimit=parseInt(s.pinned_sessions_limit||3,10)||3" in BOOT_JS
|
|
assert "function _getPinnedSessionsLimit()" in SESSIONS_JS
|
|
assert "function _pinnedSessionsLimit()" not in SESSIONS_JS
|
|
assert "_pinnedSessionCount()>=_getPinnedSessionsLimit()" not in SESSIONS_JS
|
|
assert "await api('/api/session/pin'" in SESSIONS_JS
|
|
|
|
|
|
def test_settings_api_persists_integer_pin_limit_and_rejects_invalid_values():
|
|
try:
|
|
d, status = post("/api/settings", {"pinned_sessions_limit": 5})
|
|
assert status == 200
|
|
assert d["pinned_sessions_limit"] == 5
|
|
|
|
d, status = post("/api/settings", {"pinned_sessions_limit": "7"})
|
|
assert status == 200
|
|
assert d["pinned_sessions_limit"] == 7
|
|
|
|
d, status = post("/api/settings", {"pinned_sessions_limit": 0})
|
|
assert status == 200
|
|
assert d["pinned_sessions_limit"] == 7
|
|
|
|
d, status = post("/api/settings", {"pinned_sessions_limit": 100})
|
|
assert status == 200
|
|
assert d["pinned_sessions_limit"] == 7
|
|
finally:
|
|
post("/api/settings", {"pinned_sessions_limit": 3})
|
|
|
|
|
|
def test_session_pin_endpoint_uses_configured_limit():
|
|
created = []
|
|
try:
|
|
d, status = post("/api/settings", {"pinned_sessions_limit": 4})
|
|
assert status == 200
|
|
assert d["pinned_sessions_limit"] == 4
|
|
|
|
pinned = [make_session(created, f"Configured pin cap {i}") for i in range(4)]
|
|
for sid in pinned:
|
|
d, status = post("/api/session/pin", {"session_id": sid, "pinned": True})
|
|
assert status == 200
|
|
assert d["session"]["pinned"] is True
|
|
|
|
fifth = make_session(created, "Configured pin cap overflow")
|
|
d, status = post("/api/session/pin", {"session_id": fifth, "pinned": True})
|
|
assert status == 400
|
|
assert "4 sessions" in d.get("error", "")
|
|
finally:
|
|
post("/api/settings", {"pinned_sessions_limit": 3})
|
|
for sid in created:
|
|
post("/api/session/delete", {"session_id": sid})
|