Files
sales-trainer/backend/tests/test_session_identity.py

140 lines
4.7 KiB
Python

"""Canonical session identity and one-shot scope regression tests."""
from __future__ import annotations
from pathlib import Path
import pytest
from app.services.sessions import SessionStore
def _start(store: SessionStore, *, org: str, user: str, group: str, persona: str):
return store.start(
org_id=org,
user_id=user,
group_id=group,
persona_id=persona,
persona_name=f"Persona {persona}",
)
def test_same_user_and_persona_in_different_groups_are_independent(tmp_path: Path):
store = SessionStore(tmp_path)
first, resumed_first = _start(
store, org="org-1", user="user-1", group="group-a", persona="persona-01"
)
store.update(first["id"], status="finished", outcome="won")
second, resumed_second = _start(
store, org="org-1", user="user-1", group="group-b", persona="persona-01"
)
assert resumed_first is False
assert resumed_second is False
assert second["id"] != first["id"]
assert second["group_id"] == "group-b"
def test_finished_session_blocks_only_the_same_scope(tmp_path: Path):
store = SessionStore(tmp_path)
session, _ = _start(
store, org="org-1", user="user-1", group="group-a", persona="persona-01"
)
store.update(session["id"], status="finished", outcome="lost")
with pytest.raises(ValueError, match="already trained"):
_start(store, org="org-1", user="user-1", group="group-a", persona="persona-01")
def test_active_session_resumes_only_for_same_org_user_group_and_persona(tmp_path: Path):
store = SessionStore(tmp_path)
original, resumed = _start(
store, org="org-1", user="user-1", group="group-a", persona="persona-01"
)
assert resumed is False
same, same_resumed = _start(
store, org="org-1", user="user-1", group="group-a", persona="persona-01"
)
different_group, group_resumed = _start(
store, org="org-1", user="user-1", group="group-b", persona="persona-01"
)
different_org, org_resumed = _start(
store, org="org-2", user="user-1", group="group-a", persona="persona-01"
)
different_user, user_resumed = _start(
store, org="org-1", user="user-2", group="group-a", persona="persona-01"
)
assert same_resumed is True
assert same["id"] == original["id"]
assert group_resumed is False
assert org_resumed is False
assert user_resumed is False
assert len({different_group["id"], different_org["id"], different_user["id"]}) == 3
def test_list_for_user_is_org_scoped_and_preview_is_opt_in(tmp_path: Path):
store = SessionStore(tmp_path)
_start(store, org="org-1", user="user-1", group="group-a", persona="persona-01")
preview, _ = store.start(
org_id="org-1",
user_id="user-1",
group_id="group-a",
persona_id="persona-02",
persona_name="Preview",
mode="preview",
)
other_org, _ = _start(
store, org="org-2", user="user-1", group="group-b", persona="persona-01"
)
visible = store.list_for_user("user-1", org_id="org-1")
assert {row["id"] for row in visible} != {other_org["id"]}
assert preview["id"] not in {row["id"] for row in visible}
assert preview["mode"] == "preview"
assert preview["org_id"] == "org-1"
assert len(store.list_for_user("user-1", org_id="org-1", include_preview=True)) == 2
def test_start_publishes_seeded_session_state_atomically(tmp_path: Path):
store = SessionStore(tmp_path)
session, resumed = store.start(
org_id="org-1",
user_id="user-1",
group_id="group-a",
persona_id="persona-01",
persona_name="Customer",
persona_meta={"scenario": "f2f_call", "locale": "th"},
scenario="f2f_call",
locale="th",
messages=[{"role": "customer", "text": "สวัสดีค่ะ"}],
internal={"turns": 0, "score": 50, "signals": []},
)
assert resumed is False
assert session["status"] == "active"
assert session["scenario"] == "f2f_call"
assert session["messages"] == [{"role": "customer", "text": "สวัสดีค่ะ"}]
assert session["internal"]["turns"] == 0
def test_scope_scans_ignore_non_mapping_rows(tmp_path: Path, monkeypatch):
store = SessionStore(tmp_path)
monkeypatch.setattr(store.sessions, "where", lambda _predicate: [object()])
assert store.active_for_scope(
org_id="org-1",
user_id="user-1",
group_id="group-a",
persona_id="persona-01",
) is None
assert store.latest_for_scope(
org_id="org-1",
user_id="user-1",
group_id="group-a",
persona_id="persona-01",
) is None
assert store.list_for_user("user-1", org_id="org-1") == []