- Add complete pytest testing framework with conftest.py and test files - Add performance monitoring and benchmarking capabilities - Add plugin system with ccache plugin example - Add comprehensive documentation (API, deployment, testing, etc.) - Add Docker API wrapper for service deployment - Add advanced configuration examples - Remove old wget package file - Update core modules with enhanced functionality
632 lines
22 KiB
Python
632 lines
22 KiB
Python
"""
|
|
Tests for deb-mock plugin system
|
|
"""
|
|
|
|
import pytest
|
|
import tempfile
|
|
import os
|
|
import sys
|
|
from unittest.mock import Mock, patch, MagicMock
|
|
from pathlib import Path
|
|
|
|
from deb_mock.plugin import PluginManager, HookStages, BasePlugin
|
|
from deb_mock.exceptions import PluginError
|
|
|
|
|
|
class TestHookStages:
|
|
"""Test HookStages enum"""
|
|
|
|
def test_hook_stages_defined(self):
|
|
"""Test that all hook stages are defined"""
|
|
assert hasattr(HookStages, 'PREBUILD')
|
|
assert hasattr(HookStages, 'BUILD_START')
|
|
assert hasattr(HookStages, 'BUILD_END')
|
|
assert hasattr(HookStages, 'POSTBUILD')
|
|
assert hasattr(HookStages, 'PRECHROOT_INIT')
|
|
assert hasattr(HookStages, 'POSTCHROOT_INIT')
|
|
assert hasattr(HookStages, 'PRECACHE')
|
|
assert hasattr(HookStages, 'POSTCACHE')
|
|
|
|
def test_hook_stages_values(self):
|
|
"""Test that hook stages have string values"""
|
|
for stage_name in dir(HookStages):
|
|
if not stage_name.startswith('_'):
|
|
stage_value = getattr(HookStages, stage_name)
|
|
assert isinstance(stage_value, str)
|
|
assert stage_value == stage_name.lower()
|
|
|
|
|
|
class TestBasePlugin:
|
|
"""Test BasePlugin class"""
|
|
|
|
def test_base_plugin_creation(self):
|
|
"""Test creating a base plugin"""
|
|
plugin = BasePlugin()
|
|
|
|
assert plugin.name == "BasePlugin"
|
|
assert plugin.version == "1.0.0"
|
|
assert plugin.description == "Base plugin class"
|
|
assert plugin.enabled is True
|
|
|
|
def test_base_plugin_custom_values(self):
|
|
"""Test creating a base plugin with custom values"""
|
|
plugin = BasePlugin(
|
|
name="TestPlugin",
|
|
version="2.0.0",
|
|
description="Test plugin description",
|
|
enabled=False
|
|
)
|
|
|
|
assert plugin.name == "TestPlugin"
|
|
assert plugin.version == "2.0.0"
|
|
assert plugin.description == "Test plugin description"
|
|
assert plugin.enabled is False
|
|
|
|
def test_base_plugin_methods(self):
|
|
"""Test base plugin methods"""
|
|
plugin = BasePlugin()
|
|
|
|
# Test default implementations
|
|
assert plugin.init() is None
|
|
assert plugin.cleanup() is None
|
|
assert plugin.get_hooks() == {}
|
|
|
|
def test_base_plugin_hook_registration(self):
|
|
"""Test hook registration in base plugin"""
|
|
plugin = BasePlugin()
|
|
|
|
# Register a hook
|
|
plugin.register_hook(HookStages.PREBUILD, "test_hook")
|
|
|
|
hooks = plugin.get_hooks()
|
|
assert HookStages.PREBUILD in hooks
|
|
assert "test_hook" in hooks[HookStages.PREBUILD]
|
|
|
|
def test_base_plugin_multiple_hooks(self):
|
|
"""Test registering multiple hooks"""
|
|
plugin = BasePlugin()
|
|
|
|
# Register multiple hooks
|
|
plugin.register_hook(HookStages.PREBUILD, "hook1")
|
|
plugin.register_hook(HookStages.PREBUILD, "hook2")
|
|
plugin.register_hook(HookStages.POSTBUILD, "hook3")
|
|
|
|
hooks = plugin.get_hooks()
|
|
assert len(hooks[HookStages.PREBUILD]) == 2
|
|
assert len(hooks[HookStages.POSTBUILD]) == 1
|
|
assert "hook1" in hooks[HookStages.PREBUILD]
|
|
assert "hook2" in hooks[HookStages.PREBUILD]
|
|
assert "hook3" in hooks[HookStages.POSTBUILD]
|
|
|
|
|
|
class TestPluginManager:
|
|
"""Test PluginManager class"""
|
|
|
|
def test_initialization(self, test_config):
|
|
"""Test PluginManager initialization"""
|
|
manager = PluginManager(test_config)
|
|
|
|
assert manager.config == test_config
|
|
assert manager.plugins == {}
|
|
assert manager.hooks == {}
|
|
assert manager.plugin_dir == test_config.plugin_dir
|
|
|
|
def test_initialization_with_custom_plugin_dir(self, test_config):
|
|
"""Test PluginManager initialization with custom plugin directory"""
|
|
test_config.plugin_dir = "/custom/plugin/dir"
|
|
manager = PluginManager(test_config)
|
|
|
|
assert manager.plugin_dir == "/custom/plugin/dir"
|
|
|
|
def test_discover_plugins_no_directory(self, test_config):
|
|
"""Test plugin discovery when plugin directory doesn't exist"""
|
|
test_config.plugin_dir = "/nonexistent/directory"
|
|
manager = PluginManager(test_config)
|
|
|
|
plugins = manager.discover_plugins()
|
|
assert plugins == []
|
|
|
|
def test_discover_plugins_empty_directory(self, test_config, temp_dir):
|
|
"""Test plugin discovery in empty directory"""
|
|
plugin_dir = os.path.join(temp_dir, "plugins")
|
|
os.makedirs(plugin_dir)
|
|
|
|
test_config.plugin_dir = plugin_dir
|
|
manager = PluginManager(test_config)
|
|
|
|
plugins = manager.discover_plugins()
|
|
assert plugins == []
|
|
|
|
def test_discover_plugins_with_python_files(self, test_config, temp_dir):
|
|
"""Test plugin discovery with Python files"""
|
|
plugin_dir = os.path.join(temp_dir, "plugins")
|
|
os.makedirs(plugin_dir)
|
|
|
|
# Create a Python file that's not a plugin
|
|
with open(os.path.join(plugin_dir, "not_a_plugin.py"), "w") as f:
|
|
f.write("# This is not a plugin\n")
|
|
|
|
# Create a Python file that could be a plugin
|
|
with open(os.path.join(plugin_dir, "test_plugin.py"), "w") as f:
|
|
f.write("""
|
|
class TestPlugin:
|
|
pass
|
|
""")
|
|
|
|
test_config.plugin_dir = plugin_dir
|
|
manager = PluginManager(test_config)
|
|
|
|
plugins = manager.discover_plugins()
|
|
# Should find Python files but not load them as plugins
|
|
assert len(plugins) == 0
|
|
|
|
def test_load_plugin_success(self, test_config):
|
|
"""Test successfully loading a plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Create a mock plugin class
|
|
class MockPlugin(BasePlugin):
|
|
def __init__(self):
|
|
super().__init__(name="MockPlugin")
|
|
|
|
# Mock the plugin module
|
|
mock_module = Mock()
|
|
mock_module.MockPlugin = MockPlugin
|
|
|
|
with patch('builtins.__import__', return_value=mock_module):
|
|
plugin = manager.load_plugin("MockPlugin", "mock_plugin")
|
|
|
|
assert plugin is not None
|
|
assert plugin.name == "MockPlugin"
|
|
|
|
def test_load_plugin_missing_class(self, test_config):
|
|
"""Test loading a plugin with missing class"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock the plugin module without the expected class
|
|
mock_module = Mock()
|
|
mock_module.spec = None
|
|
|
|
with patch('builtins.__import__', return_value=mock_module):
|
|
with pytest.raises(PluginError, match="Plugin class 'TestPlugin' not found"):
|
|
manager.load_plugin("TestPlugin", "test_plugin")
|
|
|
|
def test_load_plugin_import_error(self, test_config):
|
|
"""Test loading a plugin with import error"""
|
|
manager = PluginManager(test_config)
|
|
|
|
with patch('builtins.__import__', side_effect=ImportError("Test import error")):
|
|
with pytest.raises(PluginError, match="Failed to import plugin 'test_plugin'"):
|
|
manager.load_plugin("TestPlugin", "test_plugin")
|
|
|
|
def test_load_plugin_instantiation_error(self, test_config):
|
|
"""Test loading a plugin with instantiation error"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Create a plugin class that raises an error when instantiated
|
|
class ErrorPlugin(BasePlugin):
|
|
def __init__(self):
|
|
raise Exception("Test instantiation error")
|
|
|
|
# Mock the plugin module
|
|
mock_module = Mock()
|
|
mock_module.ErrorPlugin = ErrorPlugin
|
|
|
|
with patch('builtins.__import__', return_value=mock_module):
|
|
with pytest.raises(PluginError, match="Failed to instantiate plugin 'ErrorPlugin'"):
|
|
manager.load_plugin("ErrorPlugin", "error_plugin")
|
|
|
|
def test_init_plugins(self, test_config):
|
|
"""Test initializing plugins"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin discovery and loading
|
|
mock_plugin = Mock()
|
|
mock_plugin.name = "TestPlugin"
|
|
mock_plugin.enabled = True
|
|
mock_plugin.init.return_value = None
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
# Mock deb_mock instance
|
|
mock_deb_mock = Mock()
|
|
|
|
result = manager.init_plugins(mock_deb_mock)
|
|
|
|
assert result is True
|
|
mock_plugin.init.assert_called_once_with(mock_deb_mock)
|
|
|
|
def test_init_plugins_disabled_plugin(self, test_config):
|
|
"""Test initializing plugins with disabled plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin discovery and loading
|
|
mock_plugin = Mock()
|
|
mock_plugin.name = "TestPlugin"
|
|
mock_plugin.enabled = False
|
|
mock_plugin.init.return_value = None
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
# Mock deb_mock instance
|
|
mock_deb_mock = Mock()
|
|
|
|
result = manager.init_plugins(mock_deb_mock)
|
|
|
|
assert result is True
|
|
mock_plugin.init.assert_not_called()
|
|
|
|
def test_init_plugins_with_error(self, test_config):
|
|
"""Test initializing plugins with plugin error"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin discovery and loading
|
|
mock_plugin = Mock()
|
|
mock_plugin.name = "TestPlugin"
|
|
mock_plugin.enabled = True
|
|
mock_plugin.init.side_effect = Exception("Test plugin error")
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
# Mock deb_mock instance
|
|
mock_deb_mock = Mock()
|
|
|
|
with pytest.raises(PluginError, match="Failed to initialize plugin 'TestPlugin'"):
|
|
manager.init_plugins(mock_deb_mock)
|
|
|
|
def test_register_hooks(self, test_config):
|
|
"""Test registering hooks from plugins"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin with hooks
|
|
mock_plugin = Mock()
|
|
mock_plugin.get_hooks.return_value = {
|
|
HookStages.PREBUILD: ["hook1", "hook2"],
|
|
HookStages.POSTBUILD: ["hook3"]
|
|
}
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
manager.register_hooks()
|
|
|
|
# Verify hooks were registered
|
|
assert HookStages.PREBUILD in manager.hooks
|
|
assert HookStages.POSTBUILD in manager.hooks
|
|
assert "hook1" in manager.hooks[HookStages.PREBUILD]
|
|
assert "hook2" in manager.hooks[HookStages.PREBUILD]
|
|
assert "hook3" in manager.hooks[HookStages.POSTBUILD]
|
|
|
|
def test_call_hooks(self, test_config):
|
|
"""Test calling hooks"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin with hooks
|
|
mock_plugin = Mock()
|
|
mock_plugin.get_hooks.return_value = {
|
|
HookStages.PREBUILD: ["hook1"]
|
|
}
|
|
|
|
# Mock hook methods
|
|
def hook1(*args, **kwargs):
|
|
return "hook1_result"
|
|
|
|
mock_plugin.hook1 = hook1
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
manager.register_hooks()
|
|
|
|
# Call hooks
|
|
results = manager.call_hooks(HookStages.PREBUILD, "arg1", kwarg1="value1")
|
|
|
|
assert len(results) == 1
|
|
assert results[0] == "hook1_result"
|
|
|
|
def test_call_hooks_no_hooks(self, test_config):
|
|
"""Test calling hooks when no hooks are registered"""
|
|
manager = PluginManager(test_config)
|
|
|
|
results = manager.call_hooks(HookStages.PREBUILD, "arg1")
|
|
|
|
assert results == []
|
|
|
|
def test_call_hooks_with_error(self, test_config):
|
|
"""Test calling hooks with hook error"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin with hooks
|
|
mock_plugin = Mock()
|
|
mock_plugin.get_hooks.return_value = {
|
|
HookStages.PREBUILD: ["hook1"]
|
|
}
|
|
|
|
# Mock hook method that raises an error
|
|
def hook1(*args, **kwargs):
|
|
raise Exception("Test hook error")
|
|
|
|
mock_plugin.hook1 = hook1
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
manager.register_hooks()
|
|
|
|
# Call hooks - should handle errors gracefully
|
|
results = manager.call_hooks(HookStages.PREBUILD, "arg1")
|
|
|
|
# Should return empty list when hooks fail
|
|
assert results == []
|
|
|
|
def test_cleanup_plugins(self, test_config):
|
|
"""Test cleaning up plugins"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin with cleanup method
|
|
mock_plugin = Mock()
|
|
mock_plugin.cleanup.return_value = None
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
result = manager.cleanup_plugins()
|
|
|
|
assert result is True
|
|
mock_plugin.cleanup.assert_called_once()
|
|
|
|
def test_cleanup_plugins_with_error(self, test_config):
|
|
"""Test cleaning up plugins with plugin error"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin with cleanup method that raises an error
|
|
mock_plugin = Mock()
|
|
mock_plugin.cleanup.side_effect = Exception("Test cleanup error")
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
with pytest.raises(PluginError, match="Failed to cleanup plugin 'test_plugin'"):
|
|
manager.cleanup_plugins()
|
|
|
|
def test_get_plugin_info(self, test_config):
|
|
"""Test getting plugin information"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin
|
|
mock_plugin = Mock()
|
|
mock_plugin.name = "TestPlugin"
|
|
mock_plugin.version = "1.0.0"
|
|
mock_plugin.description = "Test plugin description"
|
|
mock_plugin.enabled = True
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
info = manager.get_plugin_info("test_plugin")
|
|
|
|
assert info["name"] == "TestPlugin"
|
|
assert info["version"] == "1.0.0"
|
|
assert info["description"] == "Test plugin description"
|
|
assert info["enabled"] is True
|
|
|
|
def test_get_plugin_info_not_found(self, test_config):
|
|
"""Test getting plugin information for non-existent plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
with pytest.raises(PluginError, match="Plugin 'nonexistent' not found"):
|
|
manager.get_plugin_info("nonexistent")
|
|
|
|
def test_list_plugins(self, test_config):
|
|
"""Test listing all plugins"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugins
|
|
mock_plugin1 = Mock()
|
|
mock_plugin1.name = "Plugin1"
|
|
mock_plugin1.version = "1.0.0"
|
|
mock_plugin1.enabled = True
|
|
|
|
mock_plugin2 = Mock()
|
|
mock_plugin2.name = "Plugin2"
|
|
mock_plugin2.version = "2.0.0"
|
|
mock_plugin2.enabled = False
|
|
|
|
manager.plugins = {
|
|
"plugin1": mock_plugin1,
|
|
"plugin2": mock_plugin2
|
|
}
|
|
|
|
plugins = manager.list_plugins()
|
|
|
|
assert len(plugins) == 2
|
|
assert plugins["plugin1"]["name"] == "Plugin1"
|
|
assert plugins["plugin2"]["name"] == "Plugin2"
|
|
assert plugins["plugin1"]["enabled"] is True
|
|
assert plugins["plugin2"]["enabled"] is False
|
|
|
|
def test_enable_plugin(self, test_config):
|
|
"""Test enabling a plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin
|
|
mock_plugin = Mock()
|
|
mock_plugin.enabled = False
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
result = manager.enable_plugin("test_plugin")
|
|
|
|
assert result is True
|
|
assert mock_plugin.enabled is True
|
|
|
|
def test_enable_plugin_not_found(self, test_config):
|
|
"""Test enabling a non-existent plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
with pytest.raises(PluginError, match="Plugin 'nonexistent' not found"):
|
|
manager.enable_plugin("nonexistent")
|
|
|
|
def test_disable_plugin(self, test_config):
|
|
"""Test disabling a plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin
|
|
mock_plugin = Mock()
|
|
mock_plugin.enabled = True
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
result = manager.disable_plugin("test_plugin")
|
|
|
|
assert result is True
|
|
assert mock_plugin.enabled is False
|
|
|
|
def test_disable_plugin_not_found(self, test_config):
|
|
"""Test disabling a non-existent plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
with pytest.raises(PluginError, match="Plugin 'nonexistent' not found"):
|
|
manager.disable_plugin("nonexistent")
|
|
|
|
def test_reload_plugin(self, test_config):
|
|
"""Test reloading a plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Mock plugin
|
|
mock_plugin = Mock()
|
|
mock_plugin.name = "TestPlugin"
|
|
mock_plugin.cleanup.return_value = None
|
|
|
|
manager.plugins = {"test_plugin": mock_plugin}
|
|
|
|
# Mock plugin loading
|
|
with patch.object(manager, 'load_plugin', return_value=mock_plugin):
|
|
result = manager.reload_plugin("test_plugin")
|
|
|
|
assert result is True
|
|
mock_plugin.cleanup.assert_called_once()
|
|
|
|
def test_reload_plugin_not_found(self, test_config):
|
|
"""Test reloading a non-existent plugin"""
|
|
manager = PluginManager(test_config)
|
|
|
|
with pytest.raises(PluginError, match="Plugin 'nonexistent' not found"):
|
|
manager.reload_plugin("nonexistent")
|
|
|
|
|
|
class TestPluginIntegration:
|
|
"""Test plugin system integration"""
|
|
|
|
def test_plugin_lifecycle(self, test_config):
|
|
"""Test complete plugin lifecycle"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Create a test plugin
|
|
class TestPlugin(BasePlugin):
|
|
def __init__(self):
|
|
super().__init__(
|
|
name="TestPlugin",
|
|
version="1.0.0",
|
|
description="Test plugin for integration testing"
|
|
)
|
|
self.init_called = False
|
|
self.cleanup_called = False
|
|
|
|
def init(self, deb_mock):
|
|
self.init_called = True
|
|
return None
|
|
|
|
def cleanup(self):
|
|
self.cleanup_called = True
|
|
return None
|
|
|
|
def get_hooks(self):
|
|
return {
|
|
HookStages.PREBUILD: ["prebuild_hook"],
|
|
HookStages.POSTBUILD: ["postbuild_hook"]
|
|
}
|
|
|
|
def prebuild_hook(self, *args, **kwargs):
|
|
return "prebuild_result"
|
|
|
|
def postbuild_hook(self, *args, **kwargs):
|
|
return "postbuild_result"
|
|
|
|
# Mock plugin module
|
|
mock_module = Mock()
|
|
mock_module.TestPlugin = TestPlugin
|
|
|
|
with patch('builtins.__import__', return_value=mock_module):
|
|
# Load plugin
|
|
plugin = manager.load_plugin("TestPlugin", "test_plugin")
|
|
|
|
# Add to plugins
|
|
manager.plugins["test_plugin"] = plugin
|
|
|
|
# Initialize plugins
|
|
mock_deb_mock = Mock()
|
|
result = manager.init_plugins(mock_deb_mock)
|
|
|
|
assert result is True
|
|
assert plugin.init_called is True
|
|
|
|
# Register hooks
|
|
manager.register_hooks()
|
|
|
|
# Call hooks
|
|
prebuild_results = manager.call_hooks(HookStages.PREBUILD, "arg1")
|
|
postbuild_results = manager.call_hooks(HookStages.POSTBUILD, "arg2")
|
|
|
|
assert prebuild_results == ["prebuild_result"]
|
|
assert postbuild_results == ["postbuild_result"]
|
|
|
|
# Cleanup plugins
|
|
cleanup_result = manager.cleanup_plugins()
|
|
|
|
assert cleanup_result is True
|
|
assert plugin.cleanup_called is True
|
|
|
|
def test_plugin_configuration(self, plugin_test_config):
|
|
"""Test plugin configuration integration"""
|
|
manager = PluginManager(plugin_test_config)
|
|
|
|
# Mock plugin discovery
|
|
with patch.object(manager, 'discover_plugins', return_value=[]):
|
|
# Initialize plugins
|
|
mock_deb_mock = Mock()
|
|
result = manager.init_plugins(mock_deb_mock)
|
|
|
|
assert result is True
|
|
|
|
# Verify plugin configuration was loaded
|
|
assert "test_plugin" in plugin_test_config.plugin_conf
|
|
assert plugin_test_config.plugin_conf["test_plugin"]["enabled"] is True
|
|
assert plugin_test_config.plugin_conf["test_plugin"]["config_option"] == "test_value"
|
|
|
|
def test_plugin_error_handling(self, test_config):
|
|
"""Test plugin error handling"""
|
|
manager = PluginManager(test_config)
|
|
|
|
# Create a plugin that raises errors
|
|
class ErrorPlugin(BasePlugin):
|
|
def __init__(self):
|
|
super().__init__(name="ErrorPlugin")
|
|
|
|
def init(self, deb_mock):
|
|
raise Exception("Init error")
|
|
|
|
def cleanup(self):
|
|
raise Exception("Cleanup error")
|
|
|
|
# Mock plugin module
|
|
mock_module = Mock()
|
|
mock_module.ErrorPlugin = ErrorPlugin
|
|
|
|
with patch('builtins.__import__', return_value=mock_module):
|
|
# Load plugin
|
|
plugin = manager.load_plugin("ErrorPlugin", "error_plugin")
|
|
|
|
# Add to plugins
|
|
manager.plugins["error_plugin"] = plugin
|
|
|
|
# Initialize plugins should fail
|
|
mock_deb_mock = Mock()
|
|
with pytest.raises(PluginError, match="Failed to initialize plugin 'ErrorPlugin'"):
|
|
manager.init_plugins(mock_deb_mock)
|
|
|
|
# Cleanup plugins should fail
|
|
with pytest.raises(PluginError, match="Failed to cleanup plugin 'error_plugin'"):
|
|
manager.cleanup_plugins()
|