Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion astrbot/core/star/star_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1022,12 +1022,15 @@ async def reload(self, specified_plugin_name=None):
"""
async with self._pm_lock:
specified_module_path = None
if specified_plugin_name:
if specified_plugin_name is not None:
for smd in star_registry:
if smd.name == specified_plugin_name:
specified_module_path = smd.module_path
break

if not specified_module_path:
return False, f"Plugin '{specified_plugin_name}' not found."

# 终止插件
if not specified_module_path:
# 重载所有插件
Expand Down
84 changes: 84 additions & 0 deletions tests/test_plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,90 @@ async def mock_load(
assert unbound == plugin_names


@pytest.mark.asyncio
@pytest.mark.parametrize("unknown_name", ["non_existent_plugin", ""])
async def test_reload_unknown_plugin_has_no_lifecycle_side_effects(
plugin_manager_pm: PluginManager, monkeypatch, unknown_name
):
_clear_star_runtime_state()
plugin_names = ["plugin_one", "plugin_two"]
for pname in plugin_names:
module_path = f"data.plugins.{pname}.main"
metadata = star_manager_module.StarMetadata(
name=pname,
root_dir_name=pname,
module_path=module_path,
)
star_manager_module.star_map[module_path] = metadata
star_manager_module.star_registry.append(metadata)

# Seed a sentinel handler so that clearing the handler registry would
# be detected by the snapshot comparison.
async def _noop_handler():
pass

sentinel_handler = StarHandlerMetadata(
event_type=EventType.AdapterMessageEvent,
handler_full_name="sentinel_module.sentinel_handler",
handler_name="sentinel_handler",
handler_module_path="data.plugins.sentinel.main",
handler=_noop_handler,
event_filters=[],
)
star_manager_module.star_handlers_registry.append(sentinel_handler)

# Snapshot registries before the call.
registry_before = list(star_manager_module.star_registry)
map_before = dict(star_manager_module.star_map)
handlers_before = list(star_manager_module.star_handlers_registry)
handlers_map_before = dict(
star_manager_module.star_handlers_registry.star_handlers_map
)

terminated = []
unbound = []
loaded = []

async def mock_terminate(plugin):
terminated.append(plugin.name)

async def mock_unbind(plugin_name, plugin_module_path):
unbound.append(plugin_name)

async def mock_load(
specified_module_path=None,
specified_dir_name=None,
ignore_version_check=False,
):
del specified_module_path, specified_dir_name, ignore_version_check
loaded.append(True)
return True, None

monkeypatch.setattr(plugin_manager_pm, "_terminate_plugin", mock_terminate)
monkeypatch.setattr(plugin_manager_pm, "_unbind_plugin", mock_unbind)
monkeypatch.setattr(plugin_manager_pm, "load", mock_load)

try:
success, message = await plugin_manager_pm.reload(unknown_name)
finally:
registries_unchanged = (
list(star_manager_module.star_registry) == registry_before
and dict(star_manager_module.star_map) == map_before
and list(star_manager_module.star_handlers_registry) == handlers_before
and dict(star_manager_module.star_handlers_registry.star_handlers_map)
== handlers_map_before
)
_clear_star_runtime_state()

assert success is False
assert message is not None
assert "not found" in message.lower() or "不存在" in message
assert terminated == []
assert unbound == []
assert loaded == []
assert registries_unchanged


@pytest.mark.asyncio
async def test_turn_plugin_toggles_llm_tools_from_plugin_child_module(
plugin_manager_pm: PluginManager,
Expand Down