test(backend): update orchestrator service tests
- test_orchestrator_service.py: update orchestrator service tests
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine, func, select
|
||||
@@ -70,6 +71,106 @@ def test_orchestrator_routes_user_query_to_user_agent() -> None:
|
||||
assert run_detail["tool_calls"][0]["tool_type"] == "database"
|
||||
|
||||
|
||||
def test_orchestrator_scopes_my_expense_query_to_current_user() -> None:
|
||||
client, session_factory = build_client()
|
||||
user_id = "zhaoliu@example.com"
|
||||
|
||||
with session_factory() as db:
|
||||
employee = Employee(
|
||||
employee_no="E9001",
|
||||
name="赵六",
|
||||
email=user_id,
|
||||
)
|
||||
db.add(employee)
|
||||
db.flush()
|
||||
db.add_all(
|
||||
[
|
||||
ExpenseClaim(
|
||||
claim_no="EXP-TEST-001",
|
||||
employee_id=employee.id,
|
||||
employee_name="赵六",
|
||||
department_name="测试部",
|
||||
project_code="PRJ-TEST-01",
|
||||
expense_type="travel",
|
||||
reason="上海客户拜访",
|
||||
location="上海",
|
||||
amount=Decimal("120.00"),
|
||||
currency="CNY",
|
||||
invoice_count=1,
|
||||
occurred_at=datetime(2026, 5, 10, 9, 0, tzinfo=UTC),
|
||||
submitted_at=datetime(2026, 5, 10, 18, 0, tzinfo=UTC),
|
||||
status="submitted",
|
||||
approval_stage="finance_review",
|
||||
risk_flags_json=[],
|
||||
),
|
||||
ExpenseClaim(
|
||||
claim_no="EXP-TEST-002",
|
||||
employee_name=user_id,
|
||||
department_name="测试部",
|
||||
project_code="PRJ-TEST-02",
|
||||
expense_type="meal",
|
||||
reason="客户午餐",
|
||||
location="杭州",
|
||||
amount=Decimal("300.00"),
|
||||
currency="CNY",
|
||||
invoice_count=1,
|
||||
occurred_at=datetime(2026, 5, 11, 12, 0, tzinfo=UTC),
|
||||
submitted_at=datetime(2026, 5, 11, 13, 0, tzinfo=UTC),
|
||||
status="draft",
|
||||
approval_stage=None,
|
||||
risk_flags_json=[],
|
||||
),
|
||||
ExpenseClaim(
|
||||
claim_no="EXP-TEST-003",
|
||||
employee_name="张三",
|
||||
department_name="财务部",
|
||||
project_code="PRJ-OTHER-01",
|
||||
expense_type="hotel",
|
||||
reason="外地出差住宿",
|
||||
location="深圳",
|
||||
amount=Decimal("999.00"),
|
||||
currency="CNY",
|
||||
invoice_count=1,
|
||||
occurred_at=datetime(2026, 5, 12, 8, 30, tzinfo=UTC),
|
||||
submitted_at=datetime(2026, 5, 12, 9, 30, tzinfo=UTC),
|
||||
status="approved",
|
||||
approval_stage="completed",
|
||||
risk_flags_json=[],
|
||||
),
|
||||
]
|
||||
)
|
||||
db.commit()
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": user_id,
|
||||
"message": "请查询我的报销单",
|
||||
"context_json": {
|
||||
"role_codes": ["employee"],
|
||||
"name": "赵六",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["selected_agent"] == "user_agent"
|
||||
assert payload["status"] == "succeeded"
|
||||
assert "查到你的报销单共 2 笔" in payload["result"]["answer"]
|
||||
assert "EXP-TEST-001" in payload["result"]["answer"]
|
||||
assert "EXP-TEST-002" in payload["result"]["answer"]
|
||||
assert "EXP-TEST-003" not in payload["result"]["answer"]
|
||||
|
||||
run_detail = client.get(f"/api/v1/agent-runs/{payload['run_id']}").json()
|
||||
tool_response = run_detail["tool_calls"][0]["response_json"]
|
||||
assert tool_response["record_count"] == 2
|
||||
assert tool_response["total_amount"] == 420.0
|
||||
assert tool_response["scoped_to_current_user"] is True
|
||||
assert tool_response["scope_label"] == "你的报销单"
|
||||
|
||||
|
||||
def test_orchestrator_routes_schedule_to_hermes() -> None:
|
||||
client, session_factory = build_client()
|
||||
|
||||
@@ -640,6 +741,109 @@ def test_orchestrator_can_delete_all_user_conversations() -> None:
|
||||
assert other_count == 1
|
||||
|
||||
|
||||
def test_orchestrator_can_delete_current_user_single_conversation() -> None:
|
||||
client, session_factory = build_client()
|
||||
|
||||
first_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": "single_delete_user",
|
||||
"message": "查一下本周报销金额",
|
||||
"context_json": {"role_codes": ["finance"]},
|
||||
},
|
||||
)
|
||||
second_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": "single_delete_user",
|
||||
"message": "帮我生成差旅报销草稿",
|
||||
"context_json": {"role_codes": ["finance"]},
|
||||
},
|
||||
)
|
||||
|
||||
assert first_response.status_code == 200
|
||||
assert second_response.status_code == 200
|
||||
|
||||
first_conversation_id = first_response.json()["conversation_id"]
|
||||
second_conversation_id = second_response.json()["conversation_id"]
|
||||
|
||||
delete_response = client.delete(
|
||||
f"/api/v1/orchestrator/conversations/{first_conversation_id}",
|
||||
params={"user_id": "single_delete_user"},
|
||||
)
|
||||
|
||||
assert delete_response.status_code == 200
|
||||
assert delete_response.json()["deleted_count"] == 1
|
||||
|
||||
with session_factory() as db:
|
||||
remaining_ids = list(
|
||||
db.scalars(
|
||||
select(AgentConversation.conversation_id)
|
||||
.where(AgentConversation.user_id == "single_delete_user")
|
||||
.order_by(AgentConversation.created_at.asc())
|
||||
).all()
|
||||
)
|
||||
assert first_conversation_id not in remaining_ids
|
||||
assert second_conversation_id in remaining_ids
|
||||
|
||||
|
||||
def test_orchestrator_can_delete_user_conversations_by_session_type() -> None:
|
||||
client, session_factory = build_client()
|
||||
|
||||
expense_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": "typed_delete_user",
|
||||
"message": "帮我生成差旅报销草稿",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"session_type": "expense",
|
||||
},
|
||||
},
|
||||
)
|
||||
knowledge_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": "typed_delete_user",
|
||||
"message": "发票抬头不一致还能报销吗",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"session_type": "knowledge",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert expense_response.status_code == 200
|
||||
assert knowledge_response.status_code == 200
|
||||
|
||||
delete_response = client.delete(
|
||||
"/api/v1/orchestrator/conversations",
|
||||
params={
|
||||
"user_id": "typed_delete_user",
|
||||
"session_type": "knowledge",
|
||||
},
|
||||
)
|
||||
|
||||
assert delete_response.status_code == 200
|
||||
assert delete_response.json()["deleted_count"] == 1
|
||||
|
||||
with session_factory() as db:
|
||||
remaining = list(
|
||||
db.scalars(
|
||||
select(AgentConversation)
|
||||
.where(AgentConversation.user_id == "typed_delete_user")
|
||||
.order_by(AgentConversation.created_at.asc())
|
||||
).all()
|
||||
)
|
||||
assert len(remaining) == 1
|
||||
remaining_session_type = str((remaining[0].state_json or {}).get("session_type") or "").strip() or "expense"
|
||||
assert remaining_session_type == "expense"
|
||||
|
||||
|
||||
def test_orchestrator_tool_failure_is_logged_and_degraded() -> None:
|
||||
client, _ = build_client()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user