Files
nmfs-agents/tests/test_config.py
T
qiuruiandClaude Opus 4.6 bbea70dc9c docs: 刷新全量文档;修复 executor 成功/失败状态判断;添加三专项独立项目
文档刷新:
- CLAUDE.md/README.md/DEVELOP.md/RELEASE.md 同步 org v2 架构
  (Boss/GroupLeader/SeniorDev/Ops 组织层、EventBus/DailyReport/OpsHub/
   AgentScorer/VersionPipeline 工具层、nrf-dev/esp32-dev/market-* 新角色)
- 清除所有 /data/rockchip 路径引用 → /data/company(源码+测试+前端)
- 保留 "Rockchip" 芯片厂商名作为技术描述(hw_engineer/algo_vision 等)
- docs/plans/ 历史文档保持原样(反映当时路径状态)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 08:58:39 +08:00

148 lines
5.5 KiB
Python

from __future__ import annotations
import pytest
from pathlib import Path
from nmfs_agents.config import load_config, AgentsConfig
def _write_base_yamls(tmp_path: Path, projects_extra: str = "") -> None:
(tmp_path / "projects.yaml").write_text(
"projects:\n yolo:\n path: /data/company/yolo\n mode: confirm\n"
+ projects_extra
)
(tmp_path / "agents.yaml").write_text(
"scheduler:\n interval_hours: 1\n max_concurrent: 3\n"
"claude:\n model: claude-sonnet-4-6\n"
"feishu:\n callback_port: 8765\n"
)
(tmp_path / "devices.yaml").write_text(
"devices:\n rk3588:\n host: 192.168.0.127\n user: pi\n password: '123123'\n"
" workspace: /home/pi/Desktop\n pre_cmd: 'echo'\n"
)
def test_load_config_returns_typed_config(tmp_path):
_write_base_yamls(tmp_path)
cfg = load_config(tmp_path)
assert "yolo" in cfg.projects
assert cfg.projects["yolo"].mode == "confirm"
assert cfg.projects["yolo"].path == Path("/data/company/yolo")
assert cfg.scheduler.interval_hours == 1
assert cfg.claude.model == "claude-sonnet-4-6"
assert "rk3588" in cfg.devices
assert cfg.devices["rk3588"].host == "192.168.0.127"
def test_load_config_scan_dirs_resolves_path_for_explicit_project(tmp_path):
"""scan_dirs 仅用于为显式列出的项目解析路径,不自动引入未列出的项目。"""
# Create a parent dir with two sub-projects
parent = tmp_path / "repos"
(parent / "proj_a").mkdir(parents=True)
(parent / "proj_a" / "README.md").write_text("# Proj A\nsome text\n")
(parent / "proj_b").mkdir()
(parent / "proj_b" / "CLAUDE.md").write_text("# Proj B\n")
(tmp_path / "projects.yaml").write_text(
f"scan_dirs:\n - {parent}\n"
"projects:\n proj_a:\n mode: auto\n" # 只显式列出 proj_a
)
(tmp_path / "agents.yaml").write_text(
"scheduler:\n interval_hours: 1\n max_concurrent: 3\n"
"claude:\n model: claude-sonnet-4-6\n"
"feishu:\n callback_port: 8765\n"
)
(tmp_path / "devices.yaml").write_text("devices: {}\n")
cfg = load_config(tmp_path)
# 只有显式列出的 proj_a 应该存在
assert "proj_a" in cfg.projects
# proj_b 未在 projects: 中列出,不应自动引入
assert "proj_b" not in cfg.projects
# scan_dirs 帮助解析了 proj_a 的路径
assert cfg.projects["proj_a"].path == parent / "proj_a"
assert cfg.projects["proj_a"].mode == "auto"
def test_load_config_kind_field_present(tmp_path):
"""ProjectConfig must have a 'kind' field after loading."""
_write_base_yamls(tmp_path)
cfg = load_config(tmp_path)
assert hasattr(cfg.projects["yolo"], "kind")
assert cfg.projects["yolo"].kind == "host" # default when not specified
def test_claude_wx_project_in_config(tmp_path):
"""claude-wx 应在 projects 配置中,mode=auto"""
(tmp_path / "projects.yaml").write_text(
"projects:\n"
" claude-wx:\n"
" path: /data/test-platform/claude-wx\n"
" mode: auto\n"
" description: \"Claude Code 飞书监控控制系统\"\n"
)
(tmp_path / "agents.yaml").write_text(
"scheduler:\n interval_hours: 1\n max_concurrent: 3\n"
"claude:\n model: claude-sonnet-4-6\n"
"feishu:\n callback_port: 8765\n"
)
(tmp_path / "devices.yaml").write_text("devices: {}\n")
cfg = load_config(tmp_path)
assert "claude-wx" in cfg.projects
assert cfg.projects["claude-wx"].mode == "auto"
def test_load_mcp_tools_yaml():
"""load_mcp_tools() 应返回 registry 和 roles 两个 dict"""
from nmfs_agents.config import load_mcp_tools
tools = load_mcp_tools()
assert "registry" in tools
assert "roles" in tools
assert "sequential-thinking" in tools["registry"]
assert "dev-embedded" in tools["roles"]
def test_load_role_routing_yaml():
"""load_role_routing() 返回 role → keywords 映射"""
from nmfs_agents.config import load_role_routing, route_role
routing = load_role_routing()
assert "dev-kernel" in routing
assert "kernel" in routing["dev-kernel"]
role = route_role("修复 RKNN NPU 推理崩溃", routing)
assert role == "dev-embedded"
def test_route_role_fallback():
"""无匹配时返回 dev-embedded(嵌入式项目默认)"""
from nmfs_agents.config import load_role_routing, route_role
routing = load_role_routing()
role = route_role("随机任务无关键词", routing)
assert role == "dev-embedded"
def test_queue_configs_loaded():
"""load_config 能解析三组队列配置"""
from nmfs_agents.config import load_config, QueueConfig
cfg = load_config()
assert hasattr(cfg, "queues"), "AgentsConfig 缺少 queues 字段"
assert "base_opt" in cfg.queues, "缺少 base_opt 队列"
assert "project_delivery" in cfg.queues, "缺少 project_delivery 队列"
assert "insight" in cfg.queues, "缺少 insight 队列"
base = cfg.queues["base_opt"]
assert base.max_concurrent == 5
assert base.scan_interval_hours == 4
assert "hw-engineer" in base.roles
assert "algo-antishake" in base.roles
assert "algo-position" in base.roles
assert "algo-nav" in base.roles
def test_queue_config_dataclass():
"""QueueConfig dataclass 字段正确"""
from nmfs_agents.config import QueueConfig
q = QueueConfig(
db="data/test.db",
max_concurrent=2,
scan_interval_hours=6,
roles=frozenset({"developer", "tester"}),
)
assert q.max_concurrent == 2
assert "developer" in q.roles