新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块 同时在测试配置中添加了测试用的OpenAI API密钥环境变量
233 lines
7.9 KiB
Python
233 lines
7.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from yuxi.channels.adapters.yuanbao.analysis.orchestrator import YuanbaoAnalyzer
|
|
from yuxi.channels.adapters.yuanbao.analysis.report_generator import GapReport, generate_gap_report
|
|
from yuxi.channels.adapters.yuanbao.analysis.sub_agents import (
|
|
AnalysisResult,
|
|
Finding,
|
|
SubAgentFunctionalResearch,
|
|
SubAgentIssueResearch,
|
|
SubAgentWebResearch,
|
|
)
|
|
|
|
|
|
class TestSubAgentWebResearch:
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_returns_analysis_result(self):
|
|
agent = SubAgentWebResearch()
|
|
result = await agent.research()
|
|
|
|
assert isinstance(result, AnalysisResult)
|
|
assert result.agent_name == "WebResearchAgent"
|
|
assert result.category == "external_research"
|
|
assert len(result.findings) > 0
|
|
assert result.summary
|
|
assert "critical" in result.severity_counts
|
|
assert "warning" in result.severity_counts
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_includes_platform_info(self):
|
|
agent = SubAgentWebResearch()
|
|
result = await agent.research()
|
|
|
|
titles = [f["title"] for f in result.findings]
|
|
assert any("月活" in t or "用户" in t or "MAU" in t for t in titles)
|
|
assert any("Hermes" in t or "OpenClaw" in t or "适配器" in t for t in titles)
|
|
|
|
|
|
class TestSubAgentFunctionalResearch:
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_returns_analysis_result(self):
|
|
agent = SubAgentFunctionalResearch()
|
|
result = await agent.research()
|
|
|
|
assert isinstance(result, AnalysisResult)
|
|
assert result.agent_name == "FunctionalResearchAgent"
|
|
assert result.category == "code_functional_analysis"
|
|
assert len(result.findings) > 0
|
|
assert result.summary
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_includes_module_files(self):
|
|
agent = SubAgentFunctionalResearch()
|
|
result = await agent.research()
|
|
|
|
files = [f for f in result.findings if f.get("file")]
|
|
file_names = [f["file"] for f in files]
|
|
assert "adapter.py" in file_names
|
|
assert "token.py" in file_names
|
|
assert "security.py" in file_names
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_identifies_missing_features(self):
|
|
agent = SubAgentFunctionalResearch()
|
|
result = await agent.research()
|
|
|
|
missing = [f for f in result.findings if f.get("status") == "missing"]
|
|
assert len(missing) > 0
|
|
missing_titles = [f["title"] for f in missing]
|
|
assert any("send_media" in t for t in missing_titles)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_identifies_dead_code(self):
|
|
agent = SubAgentFunctionalResearch()
|
|
result = await agent.research()
|
|
|
|
dead = [f for f in result.findings if f.get("status") == "dead_code"]
|
|
assert len(dead) > 0
|
|
|
|
|
|
class TestSubAgentIssueResearch:
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_returns_analysis_result(self):
|
|
agent = SubAgentIssueResearch()
|
|
result = await agent.research()
|
|
|
|
assert isinstance(result, AnalysisResult)
|
|
assert result.agent_name == "IssueResearchAgent"
|
|
assert result.category == "code_quality_and_bugs"
|
|
assert len(result.findings) > 0
|
|
assert result.summary
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_finds_high_severity_issues(self):
|
|
agent = SubAgentIssueResearch()
|
|
result = await agent.research()
|
|
|
|
critical_or_warning = [f for f in result.findings
|
|
if f.get("severity") in ("critical", "warning")]
|
|
assert len(critical_or_warning) > 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_research_finds_warning_issues(self):
|
|
agent = SubAgentIssueResearch()
|
|
result = await agent.research()
|
|
|
|
warnings = [f for f in result.findings if f.get("severity") == "warning"]
|
|
assert len(warnings) > 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_finding_severity_counts_are_accurate(self):
|
|
agent = SubAgentIssueResearch()
|
|
result = await agent.research()
|
|
|
|
total_by_count = sum(result.severity_counts.values())
|
|
assert total_by_count == len(result.findings)
|
|
|
|
|
|
class TestFinding:
|
|
|
|
def test_finding_creation(self):
|
|
f = Finding(
|
|
file="test.py",
|
|
line=10,
|
|
severity="warning",
|
|
category="error_handling",
|
|
title="Test issue",
|
|
description="A test description",
|
|
suggestion="Fix it",
|
|
code_snippet="print('hello')",
|
|
)
|
|
assert f.file == "test.py"
|
|
assert f.line == 10
|
|
assert f.severity == "warning"
|
|
|
|
|
|
class TestReportGenerator:
|
|
|
|
def test_generate_gap_report_basic(self):
|
|
results = [
|
|
AnalysisResult(
|
|
agent_name="WebAgent",
|
|
category="external_research",
|
|
findings=[],
|
|
summary="Web research done",
|
|
),
|
|
AnalysisResult(
|
|
agent_name="FuncAgent",
|
|
category="code_functional_analysis",
|
|
findings=[
|
|
{"title": "Missing Feature X", "status": "missing", "detail": "Not implemented"},
|
|
{"title": "Implemented Feature Y", "status": "implemented", "detail": "Done"},
|
|
],
|
|
summary="Functional analysis done",
|
|
),
|
|
AnalysisResult(
|
|
agent_name="IssueAgent",
|
|
category="code_quality_and_bugs",
|
|
findings=[
|
|
{"file": "x.py", "line": 1, "severity": "critical", "category": "bug",
|
|
"title": "Bug 1", "description": "Bad bug",
|
|
"suggestion": "Fix it"},
|
|
],
|
|
summary="Issues found",
|
|
),
|
|
]
|
|
report = generate_gap_report(results)
|
|
|
|
assert isinstance(report, GapReport)
|
|
assert report.title
|
|
assert report.module_path == "yuxi/channels/adapters/yuanbao"
|
|
assert len(report.missing_features) > 0
|
|
assert len(report.bug_list) > 0
|
|
assert len(report.fix_plan) > 0
|
|
assert report.summary
|
|
|
|
|
|
class TestYuanbaoAnalyzer:
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_run_full_analysis(self, tmp_path):
|
|
analyzer = YuanbaoAnalyzer(output_dir=str(tmp_path))
|
|
report = await analyzer.run_full_analysis()
|
|
|
|
assert isinstance(report, GapReport)
|
|
assert report.title
|
|
assert report.generated_at
|
|
assert report.summary
|
|
assert len(report.missing_features) > 0
|
|
assert len(report.unimplemented_interfaces) > 0
|
|
assert len(report.industry_gaps) > 0
|
|
assert len(report.security_issues) > 0
|
|
assert len(report.bug_list) > 0
|
|
assert len(report.fix_plan) > 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_run_full_analysis_saves_report(self, tmp_path):
|
|
analyzer = YuanbaoAnalyzer(output_dir=str(tmp_path))
|
|
report = await analyzer.run_full_analysis()
|
|
|
|
report_path = tmp_path / "gap_analysis_report.json"
|
|
assert report_path.exists()
|
|
|
|
data = json.loads(report_path.read_text(encoding="utf-8"))
|
|
assert data["title"] == report.title
|
|
assert data["summary"] == report.summary
|
|
|
|
def test_print_report_does_not_raise(self, capsys):
|
|
analyzer = YuanbaoAnalyzer()
|
|
report = GapReport(
|
|
title="Test Report",
|
|
generated_at="2026-01-01",
|
|
module_path="test",
|
|
summary="Test summary",
|
|
missing_features=[{"feature": "F1", "detail": "d", "priority": "high"}],
|
|
security_issues=[
|
|
{"severity": "critical", "location": "x.py:1", "issue": "Bad",
|
|
"fix": "Do better"}
|
|
],
|
|
fix_plan=[{"priority": "P0", "action": "Fix bug"}],
|
|
)
|
|
analyzer.print_report(report)
|
|
captured = capsys.readouterr()
|
|
assert "Test Report" in captured.out
|
|
assert "F1" in captured.out |