Files
MoviePilot/tests/test_agent_doctor_tool.py
2026-06-12 16:26:00 +08:00

110 lines
3.7 KiB
Python

import asyncio
import json
from datetime import datetime
from unittest.mock import patch
from app.agent.tools.factory import MoviePilotToolFactory
from app.agent.tools.impl.query_doctor_report import QueryDoctorReportTool
from app.agent.tools.manager import MoviePilotToolsManager
from app.doctor.models import (
DoctorFinding,
DoctorFindingStatus,
DoctorReport,
DoctorSeverity,
)
def _doctor_report() -> DoctorReport:
"""构造一份稳定的 doctor 测试报告。"""
report = DoctorReport(
generated_at=datetime(2026, 6, 12, 12, 0, 0),
version="v2.test",
environment={
"runtime": "Docker",
"config_path": "/config",
"is_docker": True,
},
)
report.add_finding(
DoctorFinding(
id="logs.moviepilot.recent_errors",
severity=DoctorSeverity.Warn,
status=DoctorFindingStatus.Degraded,
title="最近日志存在错误线索",
detail="ERROR demo Cookie: <REDACTED>",
recommendation="结合前后的启动日志定位异常。",
context={"log_file": "/config/logs/moviepilot.log", "matches": 1},
)
)
return report
def test_factory_registers_doctor_report_tool():
"""工具工厂应注册 doctor 诊断报告工具。"""
with patch(
"app.agent.tools.factory.PluginManager.get_plugin_agent_tools",
return_value=[],
):
tools = MoviePilotToolFactory.create_tools(
session_id="doctor-session",
user_id="10001",
)
tool_names = {tool.name for tool in tools}
assert "query_doctor_report" in tool_names
def test_query_doctor_report_returns_readonly_report():
"""doctor 工具应以只读方式返回结构化诊断报告。"""
tool = QueryDoctorReportTool(session_id="doctor-session", user_id="10001")
with patch(
"app.agent.tools.impl.query_doctor_report.run_doctor",
return_value=_doctor_report(),
) as run_doctor:
result = asyncio.run(tool.run(deep=True))
payload = json.loads(result)
assert payload["success"] is True
assert payload["deep"] is True
assert payload["include_details"] is True
assert payload["report"]["status"] == "degraded"
assert payload["report"]["environment"]["runtime"] == "Docker"
assert payload["report"]["findings"][0]["detail"] == "ERROR demo Cookie: <REDACTED>"
run_doctor.assert_called_once_with(deep=True)
def test_query_doctor_report_compact_mode_omits_details():
"""紧凑模式应保留诊断项概要并省略 detail 和 context。"""
tool = QueryDoctorReportTool(session_id="doctor-session", user_id="10001")
with patch(
"app.agent.tools.impl.query_doctor_report.run_doctor",
return_value=_doctor_report(),
):
result = asyncio.run(tool.run(include_details=False))
payload = json.loads(result)
finding = payload["report"]["findings"][0]
assert finding["id"] == "logs.moviepilot.recent_errors"
assert finding["title"] == "最近日志存在错误线索"
assert "detail" not in finding
assert "context" not in finding
def test_mcp_tool_manager_exposes_doctor_report_tool():
"""MCP 工具管理器应暴露 doctor 诊断报告工具。"""
tool = QueryDoctorReportTool(session_id="doctor-session", user_id="10001")
with patch(
"app.agent.tools.manager.MoviePilotToolFactory.create_tools",
return_value=[tool],
):
manager = MoviePilotToolsManager(is_admin=True)
tool_definitions = manager.list_tools()
assert [item.name for item in tool_definitions] == ["query_doctor_report"]
schema = tool_definitions[0].input_schema
assert "deep" in schema["properties"]
assert "include_details" in schema["properties"]