root c62156af53 feat(backend): 数字员工平台 B1+B2 批次实现
B1: 项目脚手架 + 数据模型 + 租户管理
- Task 1.1: FastAPI 项目脚手架、SQLite + async SQLAlchemy
- Task 1.2: 7 个数据模型 (Tenant, TenantConfig, DigitalEmployee, Conversation, Message, KnowledgeBase, Document)
- Task 1.3: 租户 CRUD API + LLM 配置(含 API Key AES 加密)

B2: 数字员工配置 + LLM Provider 抽象层
- Task 2.1: 数字员工 CRUD API(关联知识库)
- Task 2.2: BaseLLMProvider 抽象接口 + OpenAI/Qwen Provider
- Task 2.3: Provider 动态实例化 + test-provider 端点

验证: 26 个测试全部通过

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 11:29:48 +08:00

189 lines
5.3 KiB
Python

import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_create_employee(client: AsyncClient):
"""创建数字员工"""
# 先创建租户
tenant_resp = await client.post(
"/api/v1/tenants",
json={"name": "Employee Test", "slug": "employee-test"},
)
tenant_id = tenant_resp.json()["id"]
response = await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "客服助手",
"role": "customer_service",
"system_prompt": "你是一个专业的客服助手。",
"greeting": "你好,有什么可以帮助您的?",
"temperature": 0.7,
"max_context_messages": 20,
"knowledge_base_ids": [],
},
)
assert response.status_code == 201
data = response.json()
assert data["name"] == "客服助手"
assert data["role"] == "customer_service"
assert data["status"] == "active"
assert "id" in data
@pytest.mark.asyncio
async def test_create_employee_with_knowledge_bases(client: AsyncClient):
"""创建数字员工时关联知识库"""
tenant_resp = await client.post(
"/api/v1/tenants",
json={"name": "KB Test", "slug": "kb-test"},
)
tenant_id = tenant_resp.json()["id"]
# 创建知识库
from app.models import KnowledgeBase
from tests.conftest import TestSession
async with TestSession() as session:
kb1 = KnowledgeBase(tenant_id=tenant_id, name="产品文档")
kb2 = KnowledgeBase(tenant_id=tenant_id, name="FAQ")
session.add_all([kb1, kb2])
await session.commit()
kb1_id = kb1.id
kb2_id = kb2.id
response = await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "智能客服",
"role": "customer_service",
"system_prompt": "你是一个智能客服。",
"knowledge_base_ids": [kb1_id, kb2_id],
},
)
assert response.status_code == 201
data = response.json()
assert len(data["knowledge_base_ids"]) == 2
@pytest.mark.asyncio
async def test_list_employees(client: AsyncClient):
"""列出数字员工"""
tenant_resp = await client.post(
"/api/v1/tenants",
json={"name": "List Test", "slug": "list-test"},
)
tenant_id = tenant_resp.json()["id"]
await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "员工A",
"role": "sales",
"system_prompt": "销售助手",
},
)
await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "员工B",
"role": "support",
"system_prompt": "支持助手",
},
)
response = await client.get(f"/api/v1/employees?tenant_id={tenant_id}")
assert response.status_code == 200
data = response.json()
assert len(data) >= 2
@pytest.mark.asyncio
async def test_get_employee(client: AsyncClient):
"""获取单个数字员工"""
tenant_resp = await client.post(
"/api/v1/tenants",
json={"name": "Get Emp Test", "slug": "get-emp-test"},
)
tenant_id = tenant_resp.json()["id"]
create_resp = await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "测试员工",
"role": "test",
"system_prompt": "测试",
},
)
employee_id = create_resp.json()["id"]
response = await client.get(f"/api/v1/employees/{employee_id}")
assert response.status_code == 200
assert response.json()["name"] == "测试员工"
@pytest.mark.asyncio
async def test_update_employee(client: AsyncClient):
"""更新数字员工"""
tenant_resp = await client.post(
"/api/v1/tenants",
json={"name": "Update Emp Test", "slug": "update-emp-test"},
)
tenant_id = tenant_resp.json()["id"]
create_resp = await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "旧名称",
"role": "old_role",
"system_prompt": "旧提示词",
},
)
employee_id = create_resp.json()["id"]
response = await client.patch(
f"/api/v1/employees/{employee_id}",
json={
"name": "新名称",
"temperature": 0.5,
},
)
assert response.status_code == 200
data = response.json()
assert data["name"] == "新名称"
assert data["temperature"] == 0.5
@pytest.mark.asyncio
async def test_delete_employee(client: AsyncClient):
"""删除数字员工"""
tenant_resp = await client.post(
"/api/v1/tenants",
json={"name": "Delete Emp Test", "slug": "delete-emp-test"},
)
tenant_id = tenant_resp.json()["id"]
create_resp = await client.post(
"/api/v1/employees",
json={
"tenant_id": tenant_id,
"name": "待删除",
"role": "temp",
"system_prompt": "临时",
},
)
employee_id = create_resp.json()["id"]
response = await client.delete(f"/api/v1/employees/{employee_id}")
assert response.status_code == 204
get_resp = await client.get(f"/api/v1/employees/{employee_id}")
assert get_resp.status_code == 404