ForcePilot/backend/test/unit/channel/infrastructure/plugin/test_discovery.py
Kris 9e503becd3
Some checks failed
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
feat(plugin): 实现完整的插件注册管理系统
新增了插件相关的完整领域模型、应用服务、基础设施实现,包括:
1. 插件状态、注册模式、来源等基础枚举和数据结构
2. 插件清单解析、发现、加载工具类
3. 插件注册表领域服务和内存存储实现
4. 插件相关的命令、查询、事件定义
5. 插件REST API接口和DTO映射
6. 集成了原有通道适配器到插件系统
7. 新增内置插件注册和自动发现能力
2026-05-31 16:44:13 +08:00

88 lines
3.6 KiB
Python

from __future__ import annotations
import tempfile
from pathlib import Path
import pytest
from yuxi.channel.domain.model.plugin_registry.plugin_source import PluginOrigin
from yuxi.channel.infrastructure.plugin.discovery import PluginDiscovery
from yuxi.channel.infrastructure.plugin.manifest_parser import ManifestParser
class TestPluginDiscovery:
@pytest.fixture
def discovery(self):
return PluginDiscovery()
@pytest.mark.asyncio
async def test_discover_workspace_empty_dir(self, discovery):
with tempfile.TemporaryDirectory() as tmpdir:
candidates = await discovery.discover_workspace(tmpdir)
assert candidates == []
@pytest.mark.asyncio
async def test_discover_workspace_skips_no_manifest(self, discovery):
with tempfile.TemporaryDirectory() as tmpdir:
Path(tmpdir, "plugin1").mkdir()
candidates = await discovery.discover_workspace(tmpdir)
assert candidates == []
@pytest.mark.asyncio
async def test_discover_workspace_skips_hidden_dirs(self, discovery):
with tempfile.TemporaryDirectory() as tmpdir:
Path(tmpdir, ".hidden").mkdir()
Path(tmpdir, "_private").mkdir()
candidates = await discovery.discover_workspace(tmpdir)
assert candidates == []
@pytest.mark.asyncio
async def test_discover_workspace_finds_manifest(self, discovery):
with tempfile.TemporaryDirectory() as tmpdir:
plugin_dir = Path(tmpdir, "my_plugin")
plugin_dir.mkdir()
manifest_path = plugin_dir / "yuxi.plugin.yaml"
manifest_path.write_text(
"id: my_plugin\nname: My Plugin\nversion: 1.0.0\nchannel_type: test\nentry: adapter.py\n"
)
candidates = await discovery.discover_workspace(tmpdir)
assert len(candidates) == 1
assert candidates[0].plugin_id == "my_plugin"
assert candidates[0].source.origin == PluginOrigin.WORKSPACE
assert candidates[0].source.entry_file.endswith("adapter.py")
@pytest.mark.asyncio
async def test_discover_all_combines_sources(self, discovery):
with tempfile.TemporaryDirectory() as ws_dir, tempfile.TemporaryDirectory() as inst_dir:
for d, name in [(ws_dir, "ws_plugin"), (inst_dir, "inst_plugin")]:
plugin_dir = Path(d, name)
plugin_dir.mkdir()
manifest_path = plugin_dir / "yuxi.plugin.yaml"
manifest_path.write_text(f"id: {name}\nname: {name.capitalize()}\nversion: 1.0.0\nchannel_type: test\n")
discovery_ws = PluginDiscovery()
candidates_ws = await discovery_ws.discover_workspace(ws_dir)
candidates_inst = await discovery_ws.discover_installed(inst_dir)
assert len(candidates_ws) == 1
assert len(candidates_inst) == 1
@pytest.mark.asyncio
async def test_find_existing_plugin(self, discovery):
with tempfile.TemporaryDirectory() as tmpdir:
plugin_dir = Path(tmpdir, "target")
plugin_dir.mkdir()
manifest_path = plugin_dir / "yuxi.plugin.yaml"
manifest_path.write_text("id: target\nname: Target\nversion: 1.0.0\nchannel_type: test\n")
result = await discovery.find("target")
assert result is None
result = await PluginDiscovery().discover_workspace(tmpdir)
assert len(result) == 1
@pytest.mark.asyncio
async def test_find_nonexistent_plugin(self, discovery):
result = await discovery.find("nonexistent")
assert result is None