166 lines
4.8 KiB
Python
166 lines
4.8 KiB
Python
"""Contract tests for the S4.3 session/message repository packet."""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from sqlalchemy.exc import IntegrityError
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db import Base, create_db_engine
|
|
from app.repositories import (
|
|
EntityNotFoundError,
|
|
SqlAlchemyGroupRepository,
|
|
SqlAlchemyOrganizationRepository,
|
|
SqlAlchemySessionRepository,
|
|
SqlAlchemyUserRepository,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def repository_session(tmp_path: Path):
|
|
engine = create_db_engine(f"sqlite:///{tmp_path / 'sessions.db'}")
|
|
Base.metadata.create_all(engine)
|
|
with Session(engine) as session:
|
|
yield session
|
|
|
|
|
|
def _seed_training_context(repository_session: Session):
|
|
organizations = SqlAlchemyOrganizationRepository(repository_session)
|
|
users = SqlAlchemyUserRepository(repository_session)
|
|
groups = SqlAlchemyGroupRepository(repository_session)
|
|
organizations.create(organization_id="org-a", name="Alpha")
|
|
organizations.create(organization_id="org-b", name="Beta")
|
|
users.create(
|
|
user_id="user-a",
|
|
org_id="org-a",
|
|
username="alice",
|
|
password_hash="hash-a",
|
|
name="Alice",
|
|
role="user",
|
|
)
|
|
groups.create(group_id="group-a", org_id="org-a", name="Alpha Group")
|
|
groups.create(group_id="group-b", org_id="org-b", name="Beta Group")
|
|
groups.create_persona(
|
|
persona_id="persona-a",
|
|
group_id="group-a",
|
|
tier="base",
|
|
public_json={"name": "Customer A"},
|
|
)
|
|
repository_session.flush()
|
|
|
|
|
|
def test_session_repository_scopes_session_and_messages(repository_session: Session):
|
|
_seed_training_context(repository_session)
|
|
sessions = SqlAlchemySessionRepository(repository_session)
|
|
|
|
training = sessions.create(
|
|
session_id="session-a",
|
|
org_id="org-a",
|
|
user_id="user-a",
|
|
group_id="group-a",
|
|
persona_id="persona-a",
|
|
scenario_json={"channel": "social"},
|
|
)
|
|
sessions.append_message(
|
|
session_id="session-a",
|
|
org_id="org-a",
|
|
message_id="message-a",
|
|
sequence=1,
|
|
role="customer",
|
|
text="Hello",
|
|
)
|
|
sessions.append_message(
|
|
session_id="session-a",
|
|
org_id="org-a",
|
|
message_id="message-b",
|
|
sequence=2,
|
|
role="trainee",
|
|
text="Hi",
|
|
)
|
|
repository_session.commit()
|
|
|
|
assert sessions.get("session-a", org_id="org-a") is training
|
|
assert sessions.get("session-a", org_id="org-b") is None
|
|
assert [item.id for item in sessions.list_for_user("org-a", "user-a")] == ["session-a"]
|
|
assert [item.sequence for item in sessions.list_messages("session-a", org_id="org-a")] == [1, 2]
|
|
|
|
updated = sessions.update(
|
|
"session-a",
|
|
org_id="org-a",
|
|
status="completed",
|
|
outcome="won",
|
|
debrief_json={"score": 90},
|
|
)
|
|
repository_session.commit()
|
|
assert updated.status == "completed"
|
|
assert updated.outcome == "won"
|
|
|
|
with pytest.raises(EntityNotFoundError):
|
|
sessions.update("session-a", org_id="org-b", status="completed")
|
|
with pytest.raises(EntityNotFoundError):
|
|
sessions.append_message(
|
|
session_id="session-a",
|
|
org_id="org-b",
|
|
message_id="message-cross",
|
|
sequence=3,
|
|
role="trainee",
|
|
text="blocked",
|
|
)
|
|
|
|
|
|
def test_session_repository_preserves_one_shot_and_message_constraints(repository_session: Session):
|
|
_seed_training_context(repository_session)
|
|
sessions = SqlAlchemySessionRepository(repository_session)
|
|
sessions.create(
|
|
session_id="session-a",
|
|
org_id="org-a",
|
|
user_id="user-a",
|
|
group_id="group-a",
|
|
persona_id="persona-a",
|
|
mode="trainee",
|
|
)
|
|
repository_session.commit()
|
|
|
|
with pytest.raises(IntegrityError):
|
|
sessions.create(
|
|
session_id="session-b",
|
|
org_id="org-a",
|
|
user_id="user-a",
|
|
group_id="group-a",
|
|
persona_id="persona-a",
|
|
mode="trainee",
|
|
)
|
|
repository_session.flush()
|
|
repository_session.rollback()
|
|
|
|
sessions.create(
|
|
session_id="preview-b",
|
|
org_id="org-a",
|
|
user_id="user-a",
|
|
group_id="group-a",
|
|
persona_id="persona-a",
|
|
mode="preview",
|
|
)
|
|
repository_session.commit()
|
|
|
|
sessions.append_message(
|
|
session_id="preview-b",
|
|
org_id="org-a",
|
|
message_id="message-a",
|
|
sequence=1,
|
|
role="customer",
|
|
text="Hello",
|
|
)
|
|
with pytest.raises(IntegrityError):
|
|
sessions.append_message(
|
|
session_id="preview-b",
|
|
org_id="org-a",
|
|
message_id="message-b",
|
|
sequence=1,
|
|
role="trainee",
|
|
text="duplicate sequence",
|
|
)
|
|
repository_session.flush()
|
|
repository_session.rollback()
|