ForcePilot/backend/test/unit/channel/infrastructure/plugin/test_loader.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

86 lines
2.5 KiB
Python

from __future__ import annotations
import sys
import tempfile
from pathlib import Path
import pytest
from yuxi.channel.infrastructure.plugin.loader import PluginLoader
class FakeAdapterClass:
def __init__(self, **kwargs) -> None:
pass
async def open(self) -> None:
pass
async def close(self) -> None:
pass
@property
def capabilities(self):
return None
@classmethod
def get_default_config(cls) -> dict:
return {}
class TestPluginLoader:
@pytest.fixture
def loader(self):
return PluginLoader()
@pytest.mark.asyncio
async def test_load_module_by_path(self, loader):
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write("class MyAdapter:\n")
f.write(" def __init__(self, **kwargs): pass\n")
f.write(" async def open(self): pass\n")
f.write(" async def close(self): pass\n")
f.write(" @property\n")
f.write(" def capabilities(self): return None\n")
f.write(" @classmethod\n")
f.write(" def get_default_config(cls): return {}\n")
path = f.name
try:
module = await loader.load(path)
assert module is not None
assert hasattr(module, "MyAdapter")
finally:
Path(path).unlink()
@pytest.mark.asyncio
async def test_load_existing_module(self, loader):
module = await loader.load("sys")
assert module is sys
def test_extract_adapter_class_found(self, loader):
module = type("Module", (), {"MyAdapter": FakeAdapterClass})()
result = loader.extract_adapter_class(module)
assert result is FakeAdapterClass
def test_extract_adapter_class_none(self, loader):
module = type("Module", (), {"foo": "bar"})()
result = loader.extract_adapter_class(module)
assert result is None
def test_extract_adapter_class_skips_private(self, loader):
class _PrivateAdapter(FakeAdapterClass):
pass
module = type("Module", (), {"_PrivateAdapter": _PrivateAdapter})()
result = loader.extract_adapter_class(module)
assert result is None
def test_extract_adapter_class_requires_methods(self, loader):
class Incomplete:
pass
module = type("Module", (), {"Incomplete": Incomplete})()
result = loader.extract_adapter_class(module)
assert result is None