新增了插件相关的完整领域模型、应用服务、基础设施实现,包括: 1. 插件状态、注册模式、来源等基础枚举和数据结构 2. 插件清单解析、发现、加载工具类 3. 插件注册表领域服务和内存存储实现 4. 插件相关的命令、查询、事件定义 5. 插件REST API接口和DTO映射 6. 集成了原有通道适配器到插件系统 7. 新增内置插件注册和自动发现能力
115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from yuxi.channel.domain.model.plugin_registry.plugin_manifest import PluginManifest
|
|
from yuxi.channel.domain.model.plugin_registry.plugin_record import PluginRecord, PluginRecordId
|
|
from yuxi.channel.domain.model.plugin_registry.plugin_registry import PluginRegistry, RegistrySnapshot
|
|
from yuxi.channel.domain.model.plugin_registry.plugin_source import PluginOrigin, PluginSource
|
|
from yuxi.channel.domain.model.plugin_registry.plugin_status import PluginStatus
|
|
from yuxi.channel.domain.model.shared.channel_capabilities import ChannelCapabilities
|
|
from yuxi.channel.infrastructure.plugin.snapshot import restore_snapshot, take_snapshot
|
|
|
|
|
|
class FakeAdapter:
|
|
def __init__(self, **kwargs) -> None:
|
|
pass
|
|
|
|
async def open(self) -> None:
|
|
pass
|
|
|
|
async def close(self) -> None:
|
|
pass
|
|
|
|
|
|
class TestSnapshot:
|
|
def test_take_snapshot(self):
|
|
registry = PluginRegistry()
|
|
record = PluginRecord(
|
|
record_id=PluginRecordId.generate(),
|
|
plugin_id="test",
|
|
name="Test",
|
|
version="1.0.0",
|
|
channel_type="test",
|
|
source=PluginSource(
|
|
origin=PluginOrigin.BUNDLED,
|
|
root_dir="channels/test",
|
|
entry_file="channels/test/adapter.py",
|
|
),
|
|
manifest=PluginManifest(
|
|
id="test",
|
|
name="Test",
|
|
version="1.0.0",
|
|
channel_type="test",
|
|
capabilities=ChannelCapabilities(),
|
|
),
|
|
capabilities=ChannelCapabilities(),
|
|
)
|
|
registry.register_builtin(record)
|
|
|
|
result = take_snapshot(registry)
|
|
assert result.plugin_count == 1
|
|
assert result.adapter_count == 0
|
|
assert isinstance(result.snapshot, RegistrySnapshot)
|
|
|
|
def test_restore_snapshot(self):
|
|
registry = PluginRegistry()
|
|
record = PluginRecord(
|
|
record_id=PluginRecordId.generate(),
|
|
plugin_id="test",
|
|
name="Test",
|
|
version="1.0.0",
|
|
channel_type="test",
|
|
source=PluginSource(
|
|
origin=PluginOrigin.BUNDLED,
|
|
root_dir="channels/test",
|
|
entry_file="channels/test/adapter.py",
|
|
),
|
|
manifest=PluginManifest(
|
|
id="test",
|
|
name="Test",
|
|
version="1.0.0",
|
|
channel_type="test",
|
|
capabilities=ChannelCapabilities(),
|
|
),
|
|
capabilities=ChannelCapabilities(),
|
|
)
|
|
registry.register_builtin(record)
|
|
|
|
snap = take_snapshot(registry)
|
|
registry.register_builtin(
|
|
PluginRecord(
|
|
record_id=PluginRecordId.generate(),
|
|
plugin_id="extra",
|
|
name="Extra",
|
|
version="1.0.0",
|
|
channel_type="extra",
|
|
source=PluginSource(
|
|
origin=PluginOrigin.BUNDLED,
|
|
root_dir="channels/extra",
|
|
entry_file="channels/extra/adapter.py",
|
|
),
|
|
manifest=PluginManifest(
|
|
id="extra",
|
|
name="Extra",
|
|
version="1.0.0",
|
|
channel_type="extra",
|
|
capabilities=ChannelCapabilities(),
|
|
),
|
|
capabilities=ChannelCapabilities(),
|
|
)
|
|
)
|
|
assert len(registry.list_records()) == 2
|
|
|
|
restore_snapshot(registry, snap.snapshot)
|
|
assert len(registry.list_records()) == 1
|
|
assert registry.get_record("test") is not None
|
|
|
|
def test_take_snapshot_invalid_type_raises(self):
|
|
with pytest.raises(TypeError, match="registry must be PluginRegistry"):
|
|
take_snapshot(object())
|
|
|
|
def test_restore_snapshot_invalid_type_raises(self):
|
|
with pytest.raises(TypeError, match="registry must be PluginRegistry"):
|
|
restore_snapshot(object(), RegistrySnapshot(plugins={}, adapters={}))
|