feat: AirPlan V2 — 全专家插件强制路由 + 事件系统规范化
P0-8 扩大: do_mode.py finish_worker 全专家插件强制路由 - GUI→XDB, network→NDB, C/C++→SDB, done→Rvr, blocked/failed→Dbg - 证据去重: 已有 xdbSessions/ndbSessions/sdbReports/rvrReviewed 则跳过 P1-GAP17: 事件 emit 规范化 - 新增 7 个事件常量 (TASK_ENTERED, TASK_FINISHED, ENGINE_ENTERED 等) - 全部 emit 调用替换字符串字面量为常量,零残留 - 30 个事件类型常量全部定义且唯一 P1-GAP18: 事件日志原子轮转 - emit 计数器每 128 次检查轮转,避免每次 emit 读文件 - 清除未使用的 _emit_with_completion/_pending_merge_complete - 原子轮转: tempfile+os.replace 保证不损坏 eng 极端接管: 强制调用全部专家插件 (Dbg/XDB/NDB/SDB/Rvr) commands/do.md: 更新为全专家插件路由文档 全量测试: 69 通过, 0 失败 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
152
test_p1_19_20.py
Executable file
152
test_p1_19_20.py
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
"""P1-19 P1-20 功能测试"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
# 添加 lib 路径
|
||||
sys.path.insert(0, str(Path(__file__).parent / "lib"))
|
||||
|
||||
def test_task_graph_test_required():
|
||||
"""P1-19.1: 测试 TaskNode 的 test_required 字段"""
|
||||
from air_runtime.task_graph import TaskNode
|
||||
|
||||
node = TaskNode(id="T-001", task="test", test_required=True)
|
||||
assert node.test_required == True, "test_required should be True"
|
||||
|
||||
node2 = TaskNode(id="T-002", task="test2")
|
||||
assert node2.test_required == False, "test_required should default to False"
|
||||
|
||||
# 测试序列化/反序列化
|
||||
data = {"id": "T-003", "testRequired": True, "status": "TODO", "task": "test", "filesDirs": "", "doneWhen": "", "inDegree": 0, "outEdges": [], "writeSet": []}
|
||||
node3 = TaskNode(
|
||||
id=data["id"], status=data["status"], task=data["task"],
|
||||
files_dirs=data["filesDirs"], done_when=data["doneWhen"],
|
||||
test_required=data["testRequired"]
|
||||
)
|
||||
assert node3.test_required == True, "test_required should deserialize correctly"
|
||||
|
||||
print("✓ P1-19.1 test_required 字段测试通过")
|
||||
return True
|
||||
|
||||
|
||||
def test_arc_boundary_test_injection():
|
||||
"""P1-19.1: 测试边界测试任务注入"""
|
||||
from air_runtime.modes.arc_mode import _inject_boundary_tests, _build_graph_from_todo
|
||||
from air_runtime.task_graph import TaskGraph, TaskNode
|
||||
from air_runtime.todo_parser import TodoTask
|
||||
|
||||
# 创建模拟 tasks
|
||||
tasks = [
|
||||
TodoTask(task_id="T-001", task="实现模块A", files_dirs="src/moduleA/", status="TODO"),
|
||||
TodoTask(task_id="T-002", task="实现模块B", files_dirs="src/moduleB/", status="TODO"),
|
||||
]
|
||||
|
||||
graph = TaskGraph()
|
||||
for t in tasks:
|
||||
graph.add_node(TaskNode(id=t.task_id, task=t.task, files_dirs=t.files_dirs))
|
||||
|
||||
# 注入边界测试
|
||||
_inject_boundary_tests(graph, tasks)
|
||||
|
||||
# 检查是否生成了测试任务
|
||||
test_nodes = [n for n in graph.nodes.values() if n.test_required]
|
||||
assert len(test_nodes) >= 2, f"应该生成至少2个测试任务,实际: {len(test_nodes)}"
|
||||
|
||||
# 检查测试任务的 done_when
|
||||
for node in test_nodes:
|
||||
assert "测试通过" in node.done_when, f"测试任务的 done_when 应包含'测试通过': {node.done_when}"
|
||||
|
||||
print(f"✓ P1-19.1 边界测试注入测试通过,生成了 {len(test_nodes)} 个测试任务")
|
||||
return True
|
||||
|
||||
|
||||
def test_review_runtime_high_risk_audit():
|
||||
"""P1-19.2: 测试高风险审计数据结构"""
|
||||
from air_runtime.review_runtime import ReviewReport, HighRiskAudit, HighRiskFinding
|
||||
|
||||
# 创建带 highRiskAudit 的报告
|
||||
finding = HighRiskFinding(file="src/test.cpp", line=100, severity="high", issue="空指针风险")
|
||||
hra = HighRiskAudit(
|
||||
lifecycle=[finding],
|
||||
nullPointer=[finding],
|
||||
overallRisk="high",
|
||||
deliveryVerdict="needs-fix"
|
||||
)
|
||||
|
||||
report = ReviewReport(
|
||||
task_id="T-001",
|
||||
verdict="pass",
|
||||
high_risk_audit=hra
|
||||
)
|
||||
|
||||
assert report.high_risk_audit.overallRisk == "high"
|
||||
assert report.high_risk_audit.deliveryVerdict == "needs-fix"
|
||||
assert len(report.high_risk_audit.lifecycle) == 1
|
||||
|
||||
# 测试序列化
|
||||
from air_runtime.review_runtime import ReviewRuntime
|
||||
d = ReviewRuntime._report_to_dict(report)
|
||||
assert d["highRiskAudit"]["overallRisk"] == "high"
|
||||
assert d["highRiskAudit"]["deliveryVerdict"] == "needs-fix"
|
||||
|
||||
# 测试反序列化
|
||||
report2 = ReviewRuntime._dict_to_report(d)
|
||||
assert report2.high_risk_audit.deliveryVerdict == "needs-fix"
|
||||
|
||||
print("✓ P1-19.2 highRiskAudit 测试通过")
|
||||
return True
|
||||
|
||||
|
||||
def test_do_ui_task_detection():
|
||||
"""P1-20: 测试 UI 任务检测"""
|
||||
from air_runtime.modes.do_mode import is_ui_task, route_ui_task
|
||||
|
||||
# UI 任务检测
|
||||
assert is_ui_task("实现登录界面UI") == True, "应该检测为 UI 任务"
|
||||
assert is_ui_task("实现按钮组件") == True, "应该检测为 UI 任务"
|
||||
assert is_ui_task("React 前端开发") == True, "应该检测为 UI 任务"
|
||||
assert is_ui_task("实现后端API") == False, "不应该检测为 UI 任务"
|
||||
assert is_ui_task("数据库优化") == False, "不应该检测为 UI 任务"
|
||||
|
||||
print("✓ P1-20 is_ui_task 测试通过")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print("P1-19 P1-20 功能测试")
|
||||
print("=" * 50)
|
||||
|
||||
tests = [
|
||||
("P1-19.1 test_required 字段", test_task_graph_test_required),
|
||||
("P1-19.1 边界测试注入", test_arc_boundary_test_injection),
|
||||
("P1-19.2 highRiskAudit", test_review_runtime_high_risk_audit),
|
||||
("P1-20 UI 任务检测", test_do_ui_task_detection),
|
||||
]
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for name, test_fn in tests:
|
||||
try:
|
||||
test_fn()
|
||||
passed += 1
|
||||
except Exception as e:
|
||||
print(f"✗ {name} 失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
failed += 1
|
||||
|
||||
print("=" * 50)
|
||||
print(f"测试结果: {passed} 通过, {failed} 失败")
|
||||
print("=" * 50)
|
||||
|
||||
return failed == 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = main()
|
||||
sys.exit(0 if success else 1)
|
||||
Reference in New Issue
Block a user