573 lines
22 KiB
Python
573 lines
22 KiB
Python
#
|
|
# tests.py -- Unit tests for extensions.
|
|
#
|
|
# Copyright (c) 2010-2011 Beanbag, Inc.
|
|
# Copyright (c) 2008-2010 Christian Hammond
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
import os
|
|
|
|
from django.conf import settings
|
|
from django.conf.urls.defaults import include, patterns
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
from mock import Mock
|
|
|
|
from djblets.extensions.base import _extension_managers, Extension, \
|
|
ExtensionHook, ExtensionHookPoint, \
|
|
ExtensionInfo, ExtensionManager, \
|
|
Settings
|
|
from djblets.extensions.hooks import TemplateHook, URLHook
|
|
from djblets.testing.testcases import TestCase
|
|
|
|
|
|
class SettingsTest(TestCase):
|
|
def setUp(self):
|
|
# Build up a mocked extension
|
|
self.extension = Mock()
|
|
self.extension.registration = Mock()
|
|
self.test_dict = {
|
|
'test_key1': 'test_value1',
|
|
'test_key2': 'test_value2',
|
|
}
|
|
self.extension.registration.settings = self.test_dict
|
|
self.settings = Settings(self.extension)
|
|
|
|
def test_constructor(self):
|
|
"""Testing the Extension's Settings constructor"""
|
|
# Build the Settings objects
|
|
self.assertEqual(self.extension, self.settings.extension)
|
|
|
|
# Ensure that the registration settings dict gets
|
|
# added to this Settings
|
|
self.assertEqual(self.test_dict['test_key1'],
|
|
self.settings['test_key1'])
|
|
|
|
def test_load_updates_dict(self):
|
|
"""Testing that Settings.load correctly updates core dict"""
|
|
new_dict = {
|
|
'test_new_key': 'test_new_value',
|
|
'test_key1': 'new_value',
|
|
}
|
|
self.extension.registration.settings = new_dict
|
|
self.settings.load()
|
|
|
|
# Should have added test_new_key, and modified test_key1
|
|
self.assertEqual(new_dict['test_new_key'],
|
|
self.settings['test_new_key'])
|
|
self.assertEqual(new_dict['test_key1'], self.settings['test_key1'])
|
|
|
|
# Should have left test_key2 alone
|
|
self.assertEqual(self.test_dict['test_key2'],
|
|
self.settings['test_key2'])
|
|
|
|
def test_load_silently_discards(self):
|
|
"""Testing that Settings.load silently ignores invalid settings"""
|
|
some_string = 'This is a string'
|
|
self.extension.registration.settings = some_string
|
|
|
|
try:
|
|
self.settings.load()
|
|
except Exception:
|
|
self.fail("Shouldn't have raised an exception")
|
|
|
|
def test_save_updates_database(self):
|
|
"""Testing that Settings.save will correctly update registration"""
|
|
registration = self.extension.registration
|
|
self.settings['test_new_key'] = 'Test new value'
|
|
generated_dict = dict(self.settings)
|
|
self.settings.save()
|
|
|
|
self.assertTrue(registration.save.called)
|
|
self.assertEqual(generated_dict, registration.settings)
|
|
|
|
|
|
class TestExtensionWithRegistration(Extension):
|
|
"""Dummy extension for testing."""
|
|
registration = Mock()
|
|
registration.settings = dict()
|
|
|
|
|
|
class ExtensionTest(TestCase):
|
|
def setUp(self):
|
|
manager = ExtensionManager('')
|
|
self.extension = \
|
|
TestExtensionWithRegistration(extension_manager=manager)
|
|
|
|
for index in range(0, 5):
|
|
self.extension.hooks.add(Mock())
|
|
|
|
def test_extension_constructor(self):
|
|
"""Testing Extension construction"""
|
|
self.assertEqual(type(self.extension.settings), Settings)
|
|
self.assertEqual(self.extension, self.extension.settings.extension)
|
|
|
|
def test_shutdown(self):
|
|
"""Testing Extension.shutdown"""
|
|
self.extension.shutdown()
|
|
|
|
for hook in self.extension.hooks:
|
|
self.assertTrue(hook.shutdown.called)
|
|
|
|
def test_get_admin_urlconf(self):
|
|
"""Testing Extension with admin URLConfs"""
|
|
did_fail = False
|
|
old_module = self.extension.__class__.__module__
|
|
self.extension.__class__.__module__ = 'djblets.extensions.test.test'
|
|
|
|
try:
|
|
self.extension._get_admin_urlconf()
|
|
except ImproperlyConfigured:
|
|
did_fail = True
|
|
finally:
|
|
self.extension.__class__.__module__ = old_module
|
|
|
|
if did_fail:
|
|
self.fail("Should have loaded admin_urls.py")
|
|
|
|
|
|
class ExtensionInfoTest(TestCase):
|
|
def test_metadata_from_package(self):
|
|
"""Testing ExtensionInfo metadata from package"""
|
|
entrypoint = Mock()
|
|
entrypoint.dist = Mock()
|
|
|
|
test_author = 'Test author lorem ipsum'
|
|
test_description = 'Test description lorem ipsum'
|
|
test_email = 'Test author@email.com'
|
|
test_home_page = 'http://www.example.com'
|
|
test_license = 'Test License MIT GPL Apache Drivers'
|
|
test_module_name = 'testextension.dummy.dummy'
|
|
test_module_to_app = 'testextension.dummy'
|
|
test_project_name = 'TestProjectName'
|
|
test_summary = 'Test summary lorem ipsum'
|
|
test_version = '1.0'
|
|
|
|
test_htdocs_path = os.path.join(settings.EXTENSIONS_STATIC_ROOT,
|
|
test_project_name)
|
|
|
|
test_metadata = {
|
|
'Name': test_project_name,
|
|
'Version': test_version,
|
|
'Summary': test_summary,
|
|
'Description': test_description,
|
|
'Author': test_author,
|
|
'Author-email': test_email,
|
|
'License': test_license,
|
|
'Home-page': test_home_page,
|
|
}
|
|
|
|
entrypoint.dist.get_metadata_lines = Mock(
|
|
return_value=[
|
|
"%s: %s" % (key, value)
|
|
for key, value in test_metadata.iteritems()
|
|
])
|
|
|
|
entrypoint.dist.project_name = test_project_name
|
|
entrypoint.dist.version = test_version
|
|
|
|
ext_class = Mock()
|
|
ext_class.__module__ = test_module_name
|
|
ext_class.metadata = None
|
|
extension_info = ExtensionInfo(entrypoint, ext_class)
|
|
|
|
self.assertEqual(extension_info.app_name, test_module_to_app)
|
|
self.assertEqual(extension_info.author, test_author)
|
|
self.assertEqual(extension_info.author_email, test_email)
|
|
self.assertEqual(extension_info.description, test_description)
|
|
self.assertFalse(extension_info.enabled)
|
|
self.assertEqual(extension_info.htdocs_path, test_htdocs_path)
|
|
self.assertFalse(extension_info.installed)
|
|
self.assertEqual(extension_info.license, test_license)
|
|
self.assertEqual(extension_info.metadata, test_metadata)
|
|
self.assertEqual(extension_info.name, test_project_name)
|
|
self.assertEqual(extension_info.summary, test_summary)
|
|
self.assertEqual(extension_info.url, test_home_page)
|
|
self.assertEqual(extension_info.version, test_version)
|
|
|
|
def test_custom_metadata(self):
|
|
"""Testing ExtensionInfo metadata from Extension.metadata"""
|
|
entrypoint = Mock()
|
|
entrypoint.dist = Mock()
|
|
|
|
test_author = 'Test author lorem ipsum'
|
|
test_description = 'Test description lorem ipsum'
|
|
test_email = 'Test author@email.com'
|
|
test_home_page = 'http://www.example.com'
|
|
test_license = 'Test License MIT GPL Apache Drivers'
|
|
test_module_name = 'testextension.dummy.dummy'
|
|
test_module_to_app = 'testextension.dummy'
|
|
test_project_name = 'TestProjectName'
|
|
test_summary = 'Test summary lorem ipsum'
|
|
test_version = '1.0'
|
|
|
|
test_htdocs_path = os.path.join(settings.EXTENSIONS_STATIC_ROOT,
|
|
test_project_name)
|
|
|
|
test_metadata = {
|
|
'Name': test_project_name,
|
|
'Version': test_version,
|
|
'Summary': test_summary,
|
|
'Description': test_description,
|
|
'Author': test_author,
|
|
'Author-email': test_email,
|
|
'License': test_license,
|
|
'Home-page': test_home_page,
|
|
}
|
|
|
|
entrypoint.dist.get_metadata_lines = Mock(
|
|
return_value=[
|
|
"%s: %s" % (key, 'Dummy')
|
|
for key, value in test_metadata.iteritems()
|
|
])
|
|
|
|
entrypoint.dist.project_name = 'Dummy'
|
|
entrypoint.dist.version = 'Dummy'
|
|
|
|
ext_class = Mock()
|
|
ext_class.__module__ = test_module_name
|
|
ext_class.metadata = test_metadata
|
|
|
|
extension_info = ExtensionInfo(entrypoint, ext_class)
|
|
|
|
self.assertEqual(extension_info.app_name, test_module_to_app)
|
|
self.assertEqual(extension_info.author, test_author)
|
|
self.assertEqual(extension_info.author_email, test_email)
|
|
self.assertEqual(extension_info.description, test_description)
|
|
self.assertFalse(extension_info.enabled)
|
|
self.assertEqual(extension_info.htdocs_path, test_htdocs_path)
|
|
self.assertFalse(extension_info.installed)
|
|
self.assertEqual(extension_info.license, test_license)
|
|
self.assertEqual(extension_info.metadata, test_metadata)
|
|
self.assertEqual(extension_info.name, test_project_name)
|
|
self.assertEqual(extension_info.summary, test_summary)
|
|
self.assertEqual(extension_info.url, test_home_page)
|
|
self.assertEqual(extension_info.version, test_version)
|
|
|
|
|
|
class TestExtensionHook(ExtensionHook):
|
|
"""A dummy ExtensionHook to test with"""
|
|
__metaclass__ = ExtensionHookPoint
|
|
|
|
|
|
class ExtensionHookTest(TestCase):
|
|
def setUp(self):
|
|
manager = ExtensionManager('')
|
|
self.extension = \
|
|
TestExtensionWithRegistration(extension_manager=manager)
|
|
self.extension_hook = TestExtensionHook(self.extension)
|
|
|
|
def test_registration(self):
|
|
"""Testing ExtensionHook registration"""
|
|
self.assertEqual(self.extension, self.extension_hook.extension)
|
|
self.assertTrue(self.extension_hook in self.extension.hooks)
|
|
self.assertTrue(self.extension_hook in
|
|
self.extension_hook.__class__.hooks)
|
|
|
|
def test_shutdown(self):
|
|
"""Testing ExtensionHook.shutdown"""
|
|
self.extension_hook.shutdown()
|
|
self.assertTrue(self.extension_hook not in
|
|
self.extension_hook.__class__.hooks)
|
|
|
|
|
|
class ExtensionHookPointTest(TestCase):
|
|
def setUp(self):
|
|
manager = ExtensionManager('')
|
|
self.extension = \
|
|
TestExtensionWithRegistration(extension_manager=manager)
|
|
self.extension_hook_class = TestExtensionHook
|
|
self.dummy_hook = Mock()
|
|
self.extension_hook_class.add_hook(self.dummy_hook)
|
|
|
|
def test_extension_hook_class_gets_hooks(self):
|
|
"""Testing ExtensionHookPoint.hooks"""
|
|
self.assertTrue(hasattr(self.extension_hook_class, "hooks"))
|
|
|
|
def test_add_hook(self):
|
|
"""Testing ExtensionHookPoint.add_hook"""
|
|
self.assertTrue(self.dummy_hook in self.extension_hook_class.hooks)
|
|
|
|
def test_remove_hook(self):
|
|
"""Testing ExtensionHookPoint.remove_hook"""
|
|
self.extension_hook_class.remove_hook(self.dummy_hook)
|
|
self.assertTrue(self.dummy_hook not in self.extension_hook_class.hooks)
|
|
|
|
|
|
class ExtensionManagerTest(TestCase):
|
|
def setUp(self):
|
|
class TestExtension(Extension):
|
|
"""An empty, dummy extension for testing"""
|
|
pass
|
|
|
|
self.key = 'test_key'
|
|
self.extension_class = TestExtension
|
|
self.manager = ExtensionManager(self.key)
|
|
self.fake_entrypoint = Mock()
|
|
self.fake_entrypoint.load = Mock(return_value=self.extension_class)
|
|
self.fake_entrypoint.dist = Mock()
|
|
|
|
self.test_author = 'Test author lorem ipsum'
|
|
self.test_description = 'Test description lorem ipsum'
|
|
self.test_email = 'Test author@email.com'
|
|
self.test_home_page = 'http://www.example.com'
|
|
self.test_license = 'Test License MIT GPL Apache Drivers'
|
|
self.test_module_name = 'testextension.dummy.dummy'
|
|
self.test_module_to_app = 'testextension.dummy'
|
|
self.test_project_name = 'TestProjectName'
|
|
self.test_summary = 'Test summary lorem ipsum'
|
|
self.test_version = '1.0'
|
|
|
|
self.test_htdocs_path = os.path.join(settings.EXTENSIONS_STATIC_ROOT,
|
|
self.test_project_name)
|
|
|
|
self.test_metadata = {
|
|
'Name': self.test_project_name,
|
|
'Version': self.test_version,
|
|
'Summary': self.test_summary,
|
|
'Description': self.test_description,
|
|
'Author': self.test_author,
|
|
'Author-email': self.test_email,
|
|
'License': self.test_license,
|
|
'Home-page': self.test_home_page,
|
|
}
|
|
|
|
self.fake_entrypoint.dist.get_metadata_lines = Mock(
|
|
return_value=[
|
|
"%s: %s" % (key, value)
|
|
for key, value in self.test_metadata.iteritems()
|
|
])
|
|
|
|
self.fake_entrypoint.dist.project_name = self.test_project_name
|
|
self.fake_entrypoint.dist.version = self.test_version
|
|
|
|
self.manager._entrypoint_iterator = Mock(
|
|
return_value=[self.fake_entrypoint]
|
|
)
|
|
self.manager.load()
|
|
|
|
def tearDown(self):
|
|
self.manager.clear_sync_cache()
|
|
|
|
def test_added_to_extension_managers(self):
|
|
"""Testing ExtensionManager registration"""
|
|
self.assertTrue(self.manager in _extension_managers)
|
|
|
|
def test_get_enabled_extensions_returns_empty(self):
|
|
"""Testing ExtensionManager.get_enabled_extensions with no extensions"""
|
|
self.assertEqual(len(self.manager.get_enabled_extensions()), 0)
|
|
|
|
def test_load(self):
|
|
"""Testing ExtensionManager.get_installed_extensions with loaded extensions"""
|
|
self.assertEqual(len(self.manager.get_installed_extensions()), 1)
|
|
self.assertTrue(self.extension_class in
|
|
self.manager.get_installed_extensions())
|
|
self.assertTrue(hasattr(self.extension_class, 'info'))
|
|
self.assertEqual(self.extension_class.info.name,
|
|
self.test_project_name)
|
|
self.assertTrue(hasattr(self.extension_class, 'registration'))
|
|
self.assertEqual(self.extension_class.registration.name,
|
|
self.test_project_name)
|
|
|
|
def test_load_full_reload_hooks(self):
|
|
"""Testing ExtensionManager.load with full_reload=True"""
|
|
self.assertEqual(len(self.manager.get_installed_extensions()), 1)
|
|
|
|
extension = self.extension_class(extension_manager=self.manager)
|
|
extension = self.manager.enable_extension(self.extension_class.id)
|
|
|
|
URLHook(extension, ())
|
|
self.assertEqual(len(URLHook.hooks), 1)
|
|
self.assertEqual(URLHook.hooks[0].extension, extension)
|
|
|
|
self.manager.load(full_reload=True)
|
|
|
|
self.assertEqual(len(URLHook.hooks), 0)
|
|
|
|
def test_extension_list_sync(self):
|
|
"""Testing ExtensionManager extension list synchronization cross-process."""
|
|
key = 'extension-list-sync'
|
|
|
|
manager1 = ExtensionManager(key)
|
|
manager2 = ExtensionManager(key)
|
|
|
|
for manager in (manager1, manager2):
|
|
manager._entrypoint_iterator = Mock(
|
|
return_value=[self.fake_entrypoint]
|
|
)
|
|
|
|
manager1.load()
|
|
manager2.load()
|
|
|
|
self.assertEqual(len(manager1.get_installed_extensions()), 1)
|
|
self.assertEqual(len(manager2.get_installed_extensions()), 1)
|
|
self.assertEqual(len(manager1.get_enabled_extensions()), 0)
|
|
self.assertEqual(len(manager2.get_enabled_extensions()), 0)
|
|
|
|
manager1.enable_extension(self.extension_class.id)
|
|
self.assertEqual(len(manager1.get_enabled_extensions()), 1)
|
|
self.assertEqual(len(manager2.get_enabled_extensions()), 0)
|
|
|
|
self.assertFalse(manager1.is_expired())
|
|
self.assertTrue(manager2.is_expired())
|
|
|
|
manager2.load(full_reload=True)
|
|
self.assertEqual(len(manager1.get_enabled_extensions()), 1)
|
|
self.assertEqual(len(manager2.get_enabled_extensions()), 1)
|
|
self.assertFalse(manager1.is_expired())
|
|
self.assertFalse(manager2.is_expired())
|
|
|
|
def test_extension_settings_sync(self):
|
|
"""Testing ExtensionManager extension settings synchronization cross-process."""
|
|
key = 'extension-settings-sync'
|
|
setting_key = 'foo'
|
|
setting_val = 'abc123'
|
|
|
|
manager1 = ExtensionManager(key)
|
|
manager2 = ExtensionManager(key)
|
|
|
|
for manager in (manager1, manager2):
|
|
manager._entrypoint_iterator = Mock(
|
|
return_value=[self.fake_entrypoint]
|
|
)
|
|
|
|
manager1.load()
|
|
|
|
extension1 = manager1.enable_extension(self.extension_class.id)
|
|
|
|
manager2.load()
|
|
|
|
self.assertFalse(manager1.is_expired())
|
|
self.assertFalse(manager2.is_expired())
|
|
|
|
extension2 = manager2.get_enabled_extension(self.extension_class.id)
|
|
self.assertNotEqual(extension2, None)
|
|
|
|
self.assertFalse(setting_key in extension1.settings)
|
|
self.assertFalse(setting_key in extension2.settings)
|
|
extension1.settings[setting_key] = setting_val
|
|
extension1.settings.save()
|
|
|
|
self.assertFalse(setting_key in extension2.settings)
|
|
|
|
self.assertFalse(manager1.is_expired())
|
|
self.assertTrue(manager2.is_expired())
|
|
|
|
manager2.load(full_reload=True)
|
|
extension2 = manager2.get_enabled_extension(self.extension_class.id)
|
|
|
|
self.assertFalse(manager1.is_expired())
|
|
self.assertFalse(manager2.is_expired())
|
|
self.assertTrue(setting_key in extension1.settings)
|
|
self.assertTrue(setting_key in extension2.settings)
|
|
self.assertEqual(extension1.settings[setting_key], setting_val)
|
|
self.assertEqual(extension2.settings[setting_key], setting_val)
|
|
|
|
|
|
class URLHookTest(TestCase):
|
|
def setUp(self):
|
|
manager = ExtensionManager('')
|
|
self.test_extension = \
|
|
TestExtensionWithRegistration(extension_manager=manager)
|
|
self.patterns = patterns('',
|
|
(r'^url_hook_test/', include('djblets.extensions.test.urls')))
|
|
self.url_hook = URLHook(self.test_extension, self.patterns)
|
|
|
|
def test_url_registration(self):
|
|
"""Testing URLHook URL registration"""
|
|
self.assertTrue(set(self.patterns)
|
|
.issubset(set(self.url_hook.dynamic_urls.url_patterns)))
|
|
# And the URLHook should be added to the extension's list of hooks
|
|
self.assertTrue(self.url_hook in self.test_extension.hooks)
|
|
|
|
def test_shutdown_removes_urls(self):
|
|
"""Testing URLHook.shutdown"""
|
|
# On shutdown, a URLHook's patterns should no longer be in its
|
|
# parent URL resolver's pattern collection.
|
|
self.url_hook.shutdown()
|
|
self.assertFalse(
|
|
set(self.patterns).issubset(
|
|
set(self.url_hook.dynamic_urls.url_patterns)))
|
|
|
|
# But the URLHook should still be in the extension's list of hooks
|
|
self.assertTrue(self.url_hook in self.test_extension.hooks)
|
|
|
|
|
|
class TemplateHookTest(TestCase):
|
|
def setUp(self):
|
|
manager = ExtensionManager('')
|
|
self.extension = \
|
|
TestExtensionWithRegistration(extension_manager=manager)
|
|
self.hook_with_applies_name = "template-hook-with-applies-name"
|
|
self.hook_no_applies_name = "template-hook-no-applies-name"
|
|
self.template_hook_no_applies = TemplateHook(self.extension,
|
|
self.hook_no_applies_name, "test_module/some_template.html", [])
|
|
self.template_hook_with_applies = TemplateHook(self.extension,
|
|
self.hook_with_applies_name, "test_module/some_template.html", [
|
|
'test-url-name',
|
|
'url_2',
|
|
'url_3',
|
|
]
|
|
)
|
|
|
|
self.fake_request = Mock()
|
|
self.fake_request._djblets_extensions_kwargs = {}
|
|
self.fake_request.path_info = '/'
|
|
self.context = {
|
|
'request': self.fake_request,
|
|
}
|
|
|
|
def test_hook_added_to_class_by_name(self):
|
|
"""Testing TemplateHook registration"""
|
|
self.assertTrue(self.template_hook_with_applies in
|
|
self.template_hook_with_applies.__class__
|
|
._by_name[self.hook_with_applies_name])
|
|
|
|
# The TemplateHook should also be added to the Extension's collection
|
|
# of hooks.
|
|
self.assertTrue(self.template_hook_with_applies in
|
|
self.extension.hooks)
|
|
|
|
def test_hook_shutdown(self):
|
|
"""Testing TemplateHook shutdown"""
|
|
self.template_hook_with_applies.shutdown()
|
|
self.assertTrue(self.template_hook_with_applies not in
|
|
self.template_hook_with_applies.__class__
|
|
._by_name[self.hook_with_applies_name])
|
|
|
|
# The TemplateHook should still be in the Extension's collection
|
|
# of hooks.
|
|
self.assertTrue(self.template_hook_with_applies in
|
|
self.extension.hooks)
|
|
|
|
def test_applies_to_default(self):
|
|
"""Testing TemplateHook.applies_to defaults to everything"""
|
|
self.assertTrue(self.template_hook_no_applies.applies_to(self.context))
|
|
self.assertTrue(self.template_hook_no_applies.applies_to(None))
|
|
|
|
def test_applies_to(self):
|
|
"""Testing TemplateHook.applies_to customization"""
|
|
self.fake_request.path_info = '/some_other/url'
|
|
self.assertFalse(
|
|
self.template_hook_with_applies.applies_to(self.context))
|
|
|
|
# A dummy function that acts as a View method
|
|
test_view_method = Mock()
|