Files
group_xinghuo_jinrong/tests/test_sprint2_template_library.py
T

184 lines
6.6 KiB
Python
Raw Normal View History

from uuid import uuid4
from fastapi.testclient import TestClient
from sqlalchemy import inspect
from app.advisor_db import AgentSessionLocal, agent_engine
from app.main import app
client = TestClient(app)
def token_for(username: str, password: str) -> str:
response = client.post(
"/api/v1/auth/login",
json={"username": username, "password": password},
)
assert response.status_code == 200
return response.json()["data"]["access_token"]
def advisor_token() -> str:
return token_for("advisor_test", "advisor_test")
def compliance_token() -> str:
return token_for("compliance_test", "compliance_test")
def create_template_payload(title: str | None = None) -> dict:
suffix = uuid4().hex[:8]
return {
"scene": "loss_comfort",
"customer_type": "C3",
"title": title or f"亏损安抚模板 {suffix}",
"content": f"您好,近期市场波动较大,请结合风险承受能力理性看待。{suffix}",
"tags": ["亏损", "安抚", "市场波动"],
}
def create_template(headers: dict, payload: dict | None = None) -> dict:
response = client.post(
"/api/advisor-agent/script-templates",
json=payload or create_template_payload(),
headers=headers,
)
assert response.status_code == 200
return response.json()["data"]
def latest_use_log(use_id: str):
from app.model.entities_advisor import TemplateUseLog
with AgentSessionLocal() as session:
row = session.query(TemplateUseLog).filter(TemplateUseLog.use_id == use_id).one()
session.expunge(row)
return row
def load_template(template_id: int):
from app.model.entities_advisor import ScriptTemplate
with AgentSessionLocal() as session:
row = session.get(ScriptTemplate, template_id)
assert row is not None
session.expunge(row)
return row
def test_template_migration_creates_template_and_use_log_tables():
inspector = inspect(agent_engine)
assert "script_template" in inspector.get_table_names()
assert "template_use_log" in inspector.get_table_names()
template_columns = {column["name"] for column in inspector.get_columns("script_template")}
use_log_columns = {column["name"] for column in inspector.get_columns("template_use_log")}
assert {
"scene",
"customer_type",
"title",
"content",
"tags",
"embedding_id",
"is_approved",
"approved_by",
"approved_at",
"version",
"usage_count",
"is_active",
"created_by",
}.issubset(template_columns)
assert {
"use_id",
"trace_id",
"template_id",
"advisor_id",
"is_modified",
"original_content",
"modified_content",
"content_diff",
}.issubset(use_log_columns)
def test_advisor_cannot_find_or_use_unapproved_template():
compliance_headers = {"Authorization": f"Bearer {compliance_token()}"}
advisor_headers = {"Authorization": f"Bearer {advisor_token()}"}
template = create_template(compliance_headers)
list_response = client.get("/api/advisor-agent/script-templates", headers=advisor_headers)
search_response = client.get(
"/api/advisor-agent/script-templates/search",
params={"q": template["title"]},
headers=advisor_headers,
)
use_response = client.post(
f"/api/advisor-agent/script-templates/{template['id']}/use",
json={"is_modified": False},
headers={**advisor_headers, "X-Trace-Id": f"trace-template-denied-{uuid4().hex}"},
)
assert list_response.status_code == 200
assert all(item["id"] != template["id"] for item in list_response.json()["data"]["items"])
assert search_response.status_code == 200
assert search_response.json()["data"]["items"] == []
assert use_response.status_code == 400
assert use_response.json()["code"] == "40002"
def test_compliance_can_approve_template_and_advisor_use_writes_log_and_increments_count():
compliance_headers = {"Authorization": f"Bearer {compliance_token()}"}
advisor_headers = {"Authorization": f"Bearer {advisor_token()}"}
template = create_template(compliance_headers)
approve_response = client.put(
f"/api/advisor-agent/script-templates/{template['id']}",
json={"is_approved": True},
headers=compliance_headers,
)
assert approve_response.status_code == 200
assert approve_response.json()["data"]["is_approved"] is True
use_trace_id = f"trace-template-use-{uuid4().hex}"
modified_content = template["content"] + " 客户可自行决定是否继续了解。"
use_response = client.post(
f"/api/advisor-agent/script-templates/{template['id']}/use",
json={"is_modified": True, "modified_content": modified_content},
headers={**advisor_headers, "X-Trace-Id": use_trace_id},
)
assert use_response.status_code == 200
body = use_response.json()["data"]
log = latest_use_log(body["use_id"])
stored_template = load_template(template["id"])
assert body["template_id"] == template["id"]
assert body["is_modified"] is True
assert "-您好,近期市场波动较大" in body["diff"]
assert "+您好,近期市场波动较大" in body["diff"]
assert log.trace_id == use_trace_id
assert log.advisor_id == "STAFF-10086"
assert log.original_content == template["content"]
assert log.modified_content == modified_content
assert stored_template.usage_count == 1
def test_template_update_resets_approval_and_increments_version():
compliance_headers = {"Authorization": f"Bearer {compliance_token()}"}
advisor_headers = {"Authorization": f"Bearer {advisor_token()}"}
template = create_template(compliance_headers)
approved = client.put(
f"/api/advisor-agent/script-templates/{template['id']}",
json={"is_approved": True},
headers=compliance_headers,
).json()["data"]
assert approved["version"] == 1
update_response = client.put(
f"/api/advisor-agent/script-templates/{template['id']}",
json={"content": "您好,市场短期波动较大,请先阅读风险揭示材料。"},
headers=compliance_headers,
)
search_response = client.get(
"/api/advisor-agent/script-templates/search",
params={"q": approved["title"]},
headers=advisor_headers,
)
assert update_response.status_code == 200
updated = update_response.json()["data"]
assert updated["is_approved"] is False
assert updated["approved_by"] is None
assert updated["version"] == 2
assert search_response.json()["data"]["items"] == []