chore: 整理项目结构,清理归档文件,更新部署配置
This commit is contained in:
@@ -38,6 +38,7 @@ from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.agent import Agent
|
||||
@@ -49,20 +50,57 @@ from tests.conftest import create_test_conversation, create_test_agent, MockRedi
|
||||
# 辅助函数
|
||||
# =============================================================================
|
||||
|
||||
async def login_agent(client, user_id: str, name: str) -> dict:
|
||||
async def login_agent(client, user_id: str, name: str, db_session=None) -> dict:
|
||||
"""登录坐席并返回认证头字典。
|
||||
|
||||
做什么:调用登录 API 获取 token,组装 Authorization 头
|
||||
为什么:invite-participant 和 remove-participant 端点需要坐席认证
|
||||
做什么:
|
||||
1. 如果提供 db_session,确保 Agent + UserRole(agent) 存在
|
||||
2. 调用登录 API 获取 token,组装 Authorization 头
|
||||
为什么:leave-participant 等端点需要 agent 角色(RBAC 检查 user_roles 表)
|
||||
|
||||
Args:
|
||||
client: httpx 异步测试客户端
|
||||
user_id: 坐席ID
|
||||
name: 坐席名称
|
||||
db_session: 数据库会话(可选,传入时会创建 UserRole 确保 agent 角色)
|
||||
|
||||
Returns:
|
||||
dict: {"Authorization": "Bearer xxx"}
|
||||
"""
|
||||
from app.models.role import Role
|
||||
from app.models.user_role import UserRole
|
||||
|
||||
# 如果提供了 db_session,确保 agent 角色和 UserRole 记录存在
|
||||
if db_session is not None:
|
||||
# 确保 agent 角色存在
|
||||
stmt = select(Role).where(Role.name == "agent")
|
||||
result = await db_session.execute(stmt)
|
||||
agent_role = result.scalars().first()
|
||||
if not agent_role:
|
||||
agent_role = Role(
|
||||
name="agent",
|
||||
display_name="坐席",
|
||||
description="IT 坐席角色",
|
||||
permissions=[],
|
||||
)
|
||||
db_session.add(agent_role)
|
||||
await db_session.flush()
|
||||
|
||||
# 确保 UserRole 关联存在
|
||||
ur_stmt = select(UserRole).where(
|
||||
UserRole.employee_id == user_id,
|
||||
UserRole.role_id == agent_role.id,
|
||||
)
|
||||
ur_result = await db_session.execute(ur_stmt)
|
||||
if not ur_result.scalars().first():
|
||||
db_session.add(UserRole(
|
||||
employee_id=user_id,
|
||||
role_id=agent_role.id,
|
||||
source="manual",
|
||||
assigned_by="test_fixture",
|
||||
))
|
||||
await db_session.flush()
|
||||
|
||||
response = await client.post(
|
||||
"/agents/login",
|
||||
json={"user_id": user_id, "name": name},
|
||||
@@ -568,10 +606,14 @@ class TestLeaveAsParticipant:
|
||||
],
|
||||
)
|
||||
|
||||
# 添加认证(传入 db_session 确保 agent 角色)
|
||||
headers = await login_agent(client, "agent_leave", "坐席", db_session)
|
||||
|
||||
with patch("app.services.ws_manager.manager.broadcast", new_callable=AsyncMock):
|
||||
response = await client.post(
|
||||
f"/conversations/{conv.id}/leave-participant",
|
||||
json={"employee_id": "emp_leaver"},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
@@ -597,9 +639,13 @@ class TestLeaveAsParticipant:
|
||||
agent_user_id="agent_leave_002",
|
||||
)
|
||||
|
||||
# 添加认证(传入 db_session 确保 agent 角色)
|
||||
headers = await login_agent(client, "agent_leave_002", "坐席", db_session)
|
||||
|
||||
response = await client.post(
|
||||
f"/conversations/{conv.id}/leave-participant",
|
||||
json={"employee_id": "emp_stranger"},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
@@ -611,9 +657,12 @@ class TestLeaveAsParticipant:
|
||||
):
|
||||
"""验证退出不存在的会话 → 错误码 3003。"""
|
||||
fake_id = str(uuid.uuid4())
|
||||
# 添加认证(传入 db_session 确保 agent 角色)
|
||||
headers = await login_agent(client, "agent_leave_999", "坐席", db_session)
|
||||
response = await client.post(
|
||||
f"/conversations/{fake_id}/leave-participant",
|
||||
json={"employee_id": "emp_ghost"},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
@@ -648,7 +697,7 @@ class TestInviteEndToEnd:
|
||||
agent_user_id="owner_e2e",
|
||||
)
|
||||
|
||||
headers = await login_agent(client, "owner_e2e", "坐席E2E")
|
||||
headers = await login_agent(client, "owner_e2e", "坐席E2E", db_session)
|
||||
|
||||
# Step 1: 邀请
|
||||
with patch("app.services.ws_manager.manager.broadcast", new_callable=AsyncMock):
|
||||
@@ -680,11 +729,12 @@ class TestInviteEndToEnd:
|
||||
zhang = next(p for p in participants_after_join if p["id"] == "emp_e2e_zhang")
|
||||
assert zhang["joined"] is True
|
||||
|
||||
# Step 3: 退出
|
||||
# Step 3: 退出(需要 agent 认证)
|
||||
with patch("app.services.ws_manager.manager.broadcast", new_callable=AsyncMock):
|
||||
leave_resp = await client.post(
|
||||
f"/conversations/{conv.id}/leave-participant",
|
||||
json={"employee_id": "emp_e2e_zhang"},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
assert leave_resp.status_code == 200
|
||||
|
||||
Reference in New Issue
Block a user