87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
from __future__ import annotations
|
|
|
|
from types import ModuleType
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from yuxi.channel.plugins.loader import load_plugins
|
|
|
|
|
|
class TestLoadPlugins:
|
|
def test_load_plugins_missing_package_returns_empty(self):
|
|
with patch("yuxi.channel.plugins.loader.logger") as mock_logger:
|
|
result = load_plugins("nonexistent.package")
|
|
assert result == []
|
|
mock_logger.warning.assert_called_once_with(
|
|
"Channel plugin package '%s' not found, skipping load", "nonexistent.package"
|
|
)
|
|
|
|
def test_loads_modules_and_skips_packages(self):
|
|
fake_package = ModuleType("fake.extensions")
|
|
fake_package.__path__ = ["/fake/path"]
|
|
|
|
imported_modules = []
|
|
|
|
def fake_import_module(name: str) -> ModuleType:
|
|
imported_modules.append(name)
|
|
if name == "fake.extensions":
|
|
return fake_package
|
|
return ModuleType(name)
|
|
|
|
fake_modules = [
|
|
(MagicMock(), "fake.extensions.wecom", False),
|
|
(MagicMock(), "fake.extensions.feishu", False),
|
|
(MagicMock(), "fake.extensions.subpackage", True),
|
|
]
|
|
|
|
with patch("yuxi.channel.plugins.loader.importlib.import_module", side_effect=fake_import_module):
|
|
with patch("yuxi.channel.plugins.loader.pkgutil.iter_modules", return_value=fake_modules):
|
|
loaded = load_plugins("fake.extensions")
|
|
|
|
assert loaded == ["fake.extensions.wecom", "fake.extensions.feishu"]
|
|
assert "fake.extensions.subpackage" not in loaded
|
|
|
|
def test_returns_empty_list_when_no_modules(self):
|
|
fake_package = ModuleType("fake.extensions")
|
|
fake_package.__path__ = ["/fake/path"]
|
|
|
|
with patch("yuxi.channel.plugins.loader.importlib.import_module", return_value=fake_package):
|
|
with patch("yuxi.channel.plugins.loader.pkgutil.iter_modules", return_value=[]):
|
|
assert load_plugins("fake.extensions") == []
|
|
|
|
def test_propagates_import_error(self):
|
|
fake_package = ModuleType("fake.extensions")
|
|
fake_package.__path__ = ["/fake/path"]
|
|
|
|
fake_modules = [(MagicMock(), "fake.extensions.broken", False)]
|
|
|
|
def fake_import_module(name: str) -> ModuleType:
|
|
if name == "fake.extensions":
|
|
return fake_package
|
|
raise ImportError("broken module")
|
|
|
|
with patch("yuxi.channel.plugins.loader.importlib.import_module", side_effect=fake_import_module):
|
|
with patch("yuxi.channel.plugins.loader.pkgutil.iter_modules", return_value=fake_modules):
|
|
with pytest.raises(ImportError, match="broken module"):
|
|
load_plugins("fake.extensions")
|
|
|
|
def test_uses_default_package_name(self):
|
|
fake_package = ModuleType("yuxi.channel.extensions")
|
|
fake_package.__path__ = ["/fake/path"]
|
|
|
|
imported = []
|
|
|
|
def fake_import_module(name: str) -> ModuleType:
|
|
imported.append(name)
|
|
if name == "yuxi.channel.extensions":
|
|
return fake_package
|
|
return ModuleType(name)
|
|
|
|
fake_modules = [(MagicMock(), "yuxi.channel.extensions.dummy", False)]
|
|
|
|
with patch("yuxi.channel.plugins.loader.importlib.import_module", side_effect=fake_import_module):
|
|
with patch("yuxi.channel.plugins.loader.pkgutil.iter_modules", return_value=fake_modules):
|
|
loaded = load_plugins()
|
|
|
|
assert loaded == ["yuxi.channel.extensions.dummy"]
|