openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #19303
[Merge] lp:~raoul-snyman/openlp/imp into lp:openlp
Raoul Snyman has proposed merging lp:~raoul-snyman/openlp/imp into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~raoul-snyman/openlp/imp/+merge/147660
Modify the way plugins are imported to use the "imp" module
PyUNO, the LibreOffice bridge module, monkey-patches the __import__ magic function which causes problems with some interface tests and possibly also the check_dependencies script. This changes the PluginManager to use the "imp" module instead, in the hopes that this is not affected by the __import__ issue.
Some functional tests around the PluginManager have also been added.
http://ci.openlp.org/view/Specific%20Branch/job/OpenLP-Pull_and_Run_Functional_Tests/42/console
--
https://code.launchpad.net/~raoul-snyman/openlp/imp/+merge/147660
Your team OpenLP Core is requested to review the proposed merge of lp:~raoul-snyman/openlp/imp into lp:openlp.
=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py 2013-02-03 16:40:39 +0000
+++ openlp/core/lib/pluginmanager.py 2013-02-11 13:36:35 +0000
@@ -32,6 +32,7 @@
import os
import sys
import logging
+import imp
from openlp.core.lib import Plugin, PluginStatus, Registry
@@ -55,11 +56,8 @@
"""
log.info(u'Plugin manager Initialising')
Registry().register(u'plugin_manager', self)
- if not plugin_dir in sys.path:
- log.debug(u'Inserting %s into sys.path', plugin_dir)
- sys.path.insert(0, plugin_dir)
- self.basepath = os.path.abspath(plugin_dir)
- log.debug(u'Base path %s ', self.basepath)
+ self.base_path = os.path.abspath(plugin_dir)
+ log.debug(u'Base path %s ', self.base_path)
self.plugins = []
log.info(u'Plugin manager Initialised')
@@ -73,9 +71,8 @@
"""
log.info(u'Finding plugins')
- startdepth = len(os.path.abspath(plugin_dir).split(os.sep))
- log.debug(u'finding plugins in %s at depth %d',
- unicode(plugin_dir), startdepth)
+ start_depth = len(os.path.abspath(plugin_dir).split(os.sep))
+ log.debug(u'finding plugins in %s at depth %d', unicode(plugin_dir), start_depth)
for root, dirs, files in os.walk(plugin_dir):
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it. The following code will hide it
@@ -88,22 +85,23 @@
for name in files:
if name.endswith(u'.py') and not name.startswith(u'__'):
path = os.path.abspath(os.path.join(root, name))
- thisdepth = len(path.split(os.sep))
- if thisdepth - startdepth > 2:
+ this_depth = len(path.split(os.sep))
+ if this_depth - start_depth > 2:
# skip anything lower down
break
- modulename = os.path.splitext(path)[0]
- prefix = os.path.commonprefix([self.basepath, path])
- # hack off the plugin base path
- modulename = modulename[len(prefix) + 1:]
- modulename = modulename.replace(os.path.sep, '.')
+ module_name = name[:-3]
# import the modules
- log.debug(u'Importing %s from %s. Depth %d', modulename, path, thisdepth)
+ log.debug(u'Importing %s from %s. Depth %d', module_name, root, this_depth)
try:
- __import__(modulename, globals(), locals(), [])
+ # Use the "imp" library to try to get around a problem with the PyUNO library which
+ # monkey-patches the __import__ function to do some magic. This causes issues with our tests.
+ # First, try to find the module we want to import, searching the directory in ``root``
+ fp, path_name, description = imp.find_module(module_name, [root])
+ # Then load the module (do the actual import) using the details from ``find_module()``
+ imp.load_module(module_name, fp, path_name, description)
except ImportError, e:
log.exception(u'Failed to import module %s on path %s for reason %s',
- modulename, path, e.args[0])
+ module_name, path, e.args[0])
plugin_classes = Plugin.__subclasses__()
plugin_objects = []
for p in plugin_classes:
@@ -142,7 +140,8 @@
for plugin in self.plugins:
if plugin.status is not PluginStatus.Disabled:
plugin.createSettingsTab(settings_form)
- settings_form.plugins = self.plugins
+ if settings_form:
+ settings_form.plugins = self.plugins
def hook_import_menu(self, import_menu):
"""
=== added file 'tests/functional/openlp_core_lib/test_pluginmanager.py'
--- tests/functional/openlp_core_lib/test_pluginmanager.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_lib/test_pluginmanager.py 2013-02-11 13:36:35 +0000
@@ -0,0 +1,373 @@
+"""
+Package to test the openlp.core.lib.pluginmanager package.
+"""
+from unittest import TestCase
+
+from mock import MagicMock
+
+from openlp.core.lib.pluginmanager import PluginManager
+from openlp.core.lib import Registry, PluginStatus
+
+
+class TestPluginManager(TestCase):
+ """
+ Test the PluginManager class
+ """
+
+ def setUp(self):
+ """
+ Some pre-test setup required.
+ """
+ Registry.create()
+ Registry().register(u'service_list', MagicMock())
+
+ def hook_media_manager_with_disabled_plugin_test(self):
+ """
+ Test running the hook_media_manager() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_media_manager()
+ plugin_manager.hook_media_manager()
+
+ # THEN: The createMediaManagerItem() method should have been called
+ assert mocked_plugin.createMediaManagerItem.call_count == 0, \
+ u'The createMediaManagerItem() method should not have been called.'
+
+ def hook_media_manager_with_active_plugin_test(self):
+ """
+ Test running the hook_media_manager() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_media_manager()
+ plugin_manager.hook_media_manager()
+
+ # THEN: The createMediaManagerItem() method should have been called
+ mocked_plugin.createMediaManagerItem.assert_called_with()
+
+ def hook_settings_tabs_with_disabled_plugin_and_no_form_test(self):
+ """
+ Test running the hook_settings_tabs() method with a disabled plugin and no form
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_settings_tabs()
+ plugin_manager.hook_settings_tabs()
+
+ # THEN: The createSettingsTab() method should have been called
+ assert mocked_plugin.createMediaManagerItem.call_count == 0, \
+ u'The createMediaManagerItem() method should not have been called.'
+
+ def hook_settings_tabs_with_disabled_plugin_and_mocked_form_test(self):
+ """
+ Test running the hook_settings_tabs() method with a disabled plugin and a mocked form
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_settings_form = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_settings_tabs()
+ plugin_manager.hook_settings_tabs(mocked_settings_form)
+
+ # THEN: The createSettingsTab() method should not have been called, but the plugins lists should be the same
+ assert mocked_plugin.createSettingsTab.call_count == 0, \
+ u'The createMediaManagerItem() method should not have been called.'
+ self.assertEqual(mocked_settings_form.plugins, plugin_manager.plugins,
+ u'The plugins on the settings form should be the same as the plugins in the plugin manager')
+
+ def hook_settings_tabs_with_active_plugin_and_no_form_test(self):
+ """
+ Test running the hook_settings_tabs() method with an active plugin and no settings form
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_settings_tabs()
+ plugin_manager.hook_settings_tabs()
+
+ # THEN: The createSettingsTab() method should have been called
+ mocked_plugin.createSettingsTab.assert_called_with(None)
+
+ def hook_settings_tabs_with_active_plugin_and_mocked_form_test(self):
+ """
+ Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_settings_form = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_settings_tabs()
+ plugin_manager.hook_settings_tabs(mocked_settings_form)
+
+ # THEN: The createMediaManagerItem() method should have been called with the mocked settings form
+ mocked_plugin.createSettingsTab.assert_called_with(mocked_settings_form)
+ self.assertEqual(mocked_settings_form.plugins, plugin_manager.plugins,
+ u'The plugins on the settings form should be the same as the plugins in the plugin manager')
+
+ def hook_import_menu_with_disabled_plugin_test(self):
+ """
+ Test running the hook_import_menu() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_import_menu = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_import_menu()
+ plugin_manager.hook_import_menu(mocked_import_menu)
+
+ # THEN: The createMediaManagerItem() method should have been called
+ assert mocked_plugin.addImportMenuItem.call_count == 0, \
+ u'The addImportMenuItem() method should not have been called.'
+
+ def hook_import_menu_with_active_plugin_test(self):
+ """
+ Test running the hook_import_menu() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_import_menu = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_import_menu()
+ plugin_manager.hook_import_menu(mocked_import_menu)
+
+ # THEN: The addImportMenuItem() method should have been called
+ mocked_plugin.addImportMenuItem.assert_called_with(mocked_import_menu)
+
+ def hook_export_menu_with_disabled_plugin_test(self):
+ """
+ Test running the hook_export_menu() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_export_menu = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_export_menu()
+ plugin_manager.hook_export_menu(mocked_export_menu)
+
+ # THEN: The addExportMenuItem() method should have been called
+ assert mocked_plugin.addExportMenuItem.call_count == 0, \
+ u'The addExportMenuItem() method should not have been called.'
+
+ def hook_export_menu_with_active_plugin_test(self):
+ """
+ Test running the hook_export_menu() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_export_menu = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_export_menu()
+ plugin_manager.hook_export_menu(mocked_export_menu)
+
+ # THEN: The addExportMenuItem() method should have been called
+ mocked_plugin.addExportMenuItem.assert_called_with(mocked_export_menu)
+
+ def hook_tools_menu_with_disabled_plugin_test(self):
+ """
+ Test running the hook_tools_menu() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_tools_menu = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_tools_menu()
+ plugin_manager.hook_tools_menu(mocked_tools_menu)
+
+ # THEN: The addToolsMenuItem() method should have been called
+ assert mocked_plugin.addToolsMenuItem.call_count == 0, \
+ u'The addToolsMenuItem() method should not have been called.'
+
+ def hook_tools_menu_with_active_plugin_test(self):
+ """
+ Test running the hook_tools_menu() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_tools_menu = MagicMock()
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run hook_tools_menu()
+ plugin_manager.hook_tools_menu(mocked_tools_menu)
+
+ # THEN: The addToolsMenuItem() method should have been called
+ mocked_plugin.addToolsMenuItem.assert_called_with(mocked_tools_menu)
+
+ def initialise_plugins_with_disabled_plugin_test(self):
+ """
+ Test running the initialise_plugins() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_plugin.isActive.return_value = False
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run initialise_plugins()
+ plugin_manager.initialise_plugins()
+
+ # THEN: The isActive() method should have been called, and initialise() method should NOT have been called
+ mocked_plugin.isActive.assert_called_with()
+ assert mocked_plugin.initialise.call_count == 0, u'The initialise() method should not have been called.'
+
+ def initialise_plugins_with_active_plugin_test(self):
+ """
+ Test running the initialise_plugins() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_plugin.isActive.return_value = True
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run initialise_plugins()
+ plugin_manager.initialise_plugins()
+
+ # THEN: The isActive() and initialise() methods should have been called
+ mocked_plugin.isActive.assert_called_with()
+ mocked_plugin.initialise.assert_called_with()
+
+ def finalise_plugins_with_disabled_plugin_test(self):
+ """
+ Test running the finalise_plugins() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_plugin.isActive.return_value = False
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run finalise_plugins()
+ plugin_manager.finalise_plugins()
+
+ # THEN: The isActive() method should have been called, and initialise() method should NOT have been called
+ mocked_plugin.isActive.assert_called_with()
+ assert mocked_plugin.finalise.call_count == 0, u'The finalise() method should not have been called.'
+
+ def finalise_plugins_with_active_plugin_test(self):
+ """
+ Test running the finalise_plugins() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_plugin.isActive.return_value = True
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run finalise_plugins()
+ plugin_manager.finalise_plugins()
+
+ # THEN: The isActive() and finalise() methods should have been called
+ mocked_plugin.isActive.assert_called_with()
+ mocked_plugin.finalise.assert_called_with()
+
+ def get_plugin_by_name_does_not_exist_test(self):
+ """
+ Test running the get_plugin_by_name() method to find a plugin that does not exist
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.name = 'Mocked Plugin'
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run finalise_plugins()
+ result = plugin_manager.get_plugin_by_name('Missing Plugin')
+
+ # THEN: The isActive() and finalise() methods should have been called
+ self.assertIsNone(result, u'The result for get_plugin_by_name should be None')
+
+ def get_plugin_by_name_exists_test(self):
+ """
+ Test running the get_plugin_by_name() method to find a plugin that exists
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.name = 'Mocked Plugin'
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run finalise_plugins()
+ result = plugin_manager.get_plugin_by_name('Mocked Plugin')
+
+ # THEN: The isActive() and finalise() methods should have been called
+ self.assertEqual(result, mocked_plugin, u'The result for get_plugin_by_name should be the mocked plugin')
+
+ def new_service_created_with_disabled_plugin_test(self):
+ """
+ Test running the new_service_created() method with a disabled plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Disabled
+ mocked_plugin.isActive.return_value = False
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run finalise_plugins()
+ plugin_manager.new_service_created()
+
+ # THEN: The isActive() method should have been called, and initialise() method should NOT have been called
+ mocked_plugin.isActive.assert_called_with()
+ assert mocked_plugin.new_service_created.call_count == 0,\
+ u'The new_service_created() method should not have been called.'
+
+ def new_service_created_with_active_plugin_test(self):
+ """
+ Test running the new_service_created() method with an active plugin
+ """
+ # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
+ mocked_plugin = MagicMock()
+ mocked_plugin.status = PluginStatus.Active
+ mocked_plugin.isActive.return_value = True
+ plugin_manager = PluginManager('')
+ plugin_manager.plugins = [mocked_plugin]
+
+ # WHEN: We run new_service_created()
+ plugin_manager.new_service_created()
+
+ # THEN: The isActive() and finalise() methods should have been called
+ mocked_plugin.isActive.assert_called_with()
+ mocked_plugin.new_service_created.assert_called_with()
=== modified file 'tests/functional/openlp_core_lib/test_registry.py'
--- tests/functional/openlp_core_lib/test_registry.py 2013-01-30 18:18:28 +0000
+++ tests/functional/openlp_core_lib/test_registry.py 2013-02-11 13:36:35 +0000
@@ -1,13 +1,15 @@
"""
- Package to test the openlp.core.lib package.
+Package to test the openlp.core.lib package.
"""
import os
-
from unittest import TestCase
+
from mock import MagicMock
+
from openlp.core.lib import Registry
-TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
+TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
+
class TestRegistry(TestCase):