From f871e87e9d26a7e711cdf75d8076f12f26432c48 Mon Sep 17 00:00:00 2001 From: tobes Date: Fri, 5 Apr 2013 21:38:16 +0100 Subject: [PATCH] [#547] Fix core tests --- ckan/tests/__init__.py | 4 +- .../ckantestplugin.egg-info/entry_points.txt | 12 +- .../ckantestplugin/ckantestplugin/__init__.py | 164 +++++++++++++++-- ckan/tests/ckantestplugin/setup.py | 6 +- .../functional/api/model/test_package.py | 4 - ckan/tests/functional/api/test_util.py | 2 +- ckan/tests/functional/test_group.py | 56 ++---- ckan/tests/functional/test_package.py | 121 +++--------- .../functional/test_preview_interface.py | 46 +---- ckan/tests/functional/test_tag_vocab.py | 9 +- ckan/tests/mock_plugin.py | 7 +- ckan/tests/test_plugins.py | 173 ++++++++---------- test-core.ini | 2 +- 13 files changed, 294 insertions(+), 312 deletions(-) diff --git a/ckan/tests/__init__.py b/ckan/tests/__init__.py index 074522b7781..82d72bbd93e 100644 --- a/ckan/tests/__init__.py +++ b/ckan/tests/__init__.py @@ -312,11 +312,11 @@ def list(cls): return [model.Package.get(pkg_index.package_id).name for pkg_index in model.Session.query(model.PackageSearch)] def setup_test_search_index(): - from ckan import plugins + #from ckan import plugins if not is_search_supported(): raise SkipTest("Search not supported") search.clear() - plugins.load('synchronous_search') + #plugins.load('synchronous_search') def is_search_supported(): is_supported_db = not model.engine_is_sqlite() diff --git a/ckan/tests/ckantestplugin/ckantestplugin.egg-info/entry_points.txt b/ckan/tests/ckantestplugin/ckantestplugin.egg-info/entry_points.txt index cc2189702fb..8a3326fccb2 100644 --- a/ckan/tests/ckantestplugin/ckantestplugin.egg-info/entry_points.txt +++ b/ckan/tests/ckantestplugin/ckantestplugin.egg-info/entry_points.txt @@ -1,9 +1,13 @@ [ckan.plugins] routes_plugin = ckantestplugin:RoutesPlugin -authorizer_plugin = ckantestplugin:AuthorizerPlugin +auth_plugin = ckantestplugin:AuthPlugin mapper_plugin2 = ckantestplugin:MapperPlugin2 -mapper_plugin = ckantestplugin:MapperPlugin -test_observer_plugin = ckantestplugin:PluginObserverPlugin action_plugin = ckantestplugin:ActionPlugin -auth_plugin = ckantestplugin:AuthPlugin +test_observer_plugin = ckantestplugin:PluginObserverPlugin +test_resource_preview = ckantestplugin:MockResourcePreviewExtension +test_package_controller_plugin = ckantestplugin:MockPackageControllerPlugin +test_json_resource_preview = ckantestplugin:JsonMockResourcePreviewExtension +authorizer_plugin = ckantestplugin:AuthorizerPlugin +mapper_plugin = ckantestplugin:MapperPlugin +test_group_plugin = ckantestplugin:MockGroupControllerPlugin diff --git a/ckan/tests/ckantestplugin/ckantestplugin/__init__.py b/ckan/tests/ckantestplugin/ckantestplugin/__init__.py index 848c9648b0c..79fbef42a1b 100644 --- a/ckan/tests/ckantestplugin/ckantestplugin/__init__.py +++ b/ckan/tests/ckantestplugin/ckantestplugin/__init__.py @@ -1,12 +1,13 @@ -from ckan.plugins import SingletonPlugin, implements -from ckan.plugins import IMapper, IRoutes, IPluginObserver, IActions, IAuthFunctions -from ckan.tests.mock_plugin import MockSingletonPlugin +from collections import defaultdict +import ckan.plugins as p +import ckan.tests.mock_plugin as mock_plugin -class MapperPlugin(SingletonPlugin): - implements(IMapper, inherit=True) - def __init__(self): +class MapperPlugin(p.SingletonPlugin): + p.implements(p.IMapper, inherit=True) + + def __init__(self, *args, **kw): self.added = [] self.deleted = [] @@ -17,12 +18,12 @@ def before_delete(self, mapper, conn, instance): self.deleted.append(instance) class MapperPlugin2(MapperPlugin): - implements(IMapper) + p.implements(p.IMapper) -class RoutesPlugin(SingletonPlugin): - implements(IRoutes, inherit=True) +class RoutesPlugin(p.SingletonPlugin): + p.implements(p.IRoutes, inherit=True) - def __init__(self): + def __init__(self, *args, **kw): self.calls_made = [] def before_map(self, map): @@ -34,18 +35,149 @@ def after_map(self, map): return map -class PluginObserverPlugin(MockSingletonPlugin): - implements(IPluginObserver) +class PluginObserverPlugin(mock_plugin.MockSingletonPlugin): + p.implements(p.IPluginObserver) -class ActionPlugin(SingletonPlugin): - implements(IActions) +class ActionPlugin(p.SingletonPlugin): + p.implements(p.IActions) def get_actions(self): return {'status_show': lambda context, data_dict: {}} -class AuthPlugin(SingletonPlugin): - implements(IAuthFunctions) +class AuthPlugin(p.SingletonPlugin): + p.implements(p.IAuthFunctions) def get_auth_functions(self): return {'package_list': lambda context, data_dict: {}} +class MockGroupControllerPlugin(p.SingletonPlugin): + p.implements(p.IGroupController) + + def __init__(self, *args, **kw): + self.calls = defaultdict(int) + + def read(self, entity): + self.calls['read'] += 1 + + def create(self, entity): + self.calls['create'] += 1 + + def edit(self, entity): + self.calls['edit'] += 1 + + def authz_add_role(self, object_role): + self.calls['authz_add_role'] += 1 + + def authz_remove_role(self, object_role): + self.calls['authz_remove_role'] += 1 + + def delete(self, entity): + self.calls['delete'] += 1 + + def before_view(self, data_dict): + self.calls['before_view'] += 1 + return data_dict + + +class MockPackageControllerPlugin(p.SingletonPlugin): + p.implements(p.IPackageController) + + def __init__(self, *args, **kw): + self.calls = defaultdict(int) + + def read(self, entity): + self.calls['read'] += 1 + + def create(self, entity): + self.calls['create'] += 1 + + def edit(self, entity): + self.calls['edit'] += 1 + + def authz_add_role(self, object_role): + self.calls['authz_add_role'] += 1 + + def authz_remove_role(self, object_role): + self.calls['authz_remove_role'] += 1 + + def delete(self, entity): + self.calls['delete'] += 1 + + def before_search(self, search_params): + self.calls['before_search'] += 1 + return search_params + + def after_search(self, search_results, search_params): + self.calls['after_search'] += 1 + return search_results + + def before_index(self, data_dict): + self.calls['before_index'] += 1 + return data_dict + + def before_view(self, data_dict): + self.calls['before_view'] += 1 + return data_dict + + def after_create(self, context, data_dict): + self.calls['after_create'] += 1 + self.id_in_dict = 'id' in data_dict + + return data_dict + + def after_update(self, context, data_dict): + self.calls['after_update'] += 1 + return data_dict + + def after_delete(self, context, data_dict): + self.calls['after_delete'] += 1 + return data_dict + + def after_show(self, context, data_dict): + self.calls['after_show'] += 1 + return data_dict + + def update_facet_titles(self, facet_titles): + return facet_titles + + + +class MockResourcePreviewExtension(mock_plugin.MockSingletonPlugin): + p.implements(p.IResourcePreview) + + def __init__(self, *args, **kw): + self.calls = defaultdict(int) + + def can_preview(self, data_dict): + assert(isinstance(data_dict['resource'], dict)) + assert(isinstance(data_dict['package'], dict)) + assert('on_same_domain' in data_dict['resource']) + + self.calls['can_preview'] += 1 + return data_dict['resource']['format'].lower() == 'mock' + + def setup_template_variables(self, context, data_dict): + self.calls['setup_template_variables'] += 1 + + def preview_template(self, context, data_dict): + assert(isinstance(data_dict['resource'], dict)) + assert(isinstance(data_dict['package'], dict)) + + self.calls['preview_templates'] += 1 + return 'tests/mock_resource_preview_template.html' + + +class JsonMockResourcePreviewExtension(MockResourcePreviewExtension): + def can_preview(self, data_dict): + super(JsonMockResourcePreviewExtension, self).can_preview(data_dict) + return data_dict['resource']['format'].lower() == 'json' + + def preview_template(self, context, data_dict): + super(JsonMockResourcePreviewExtension, self).preview_template(context, data_dict) + self.calls['preview_templates'] += 1 + return 'tests/mock_json_resource_preview_template.html' + + +# importing this file loads all these extensions by default +# so clean up the extensions +p.plugins_update() diff --git a/ckan/tests/ckantestplugin/setup.py b/ckan/tests/ckantestplugin/setup.py index c06a99891e3..8219fda18a8 100644 --- a/ckan/tests/ckantestplugin/setup.py +++ b/ckan/tests/ckantestplugin/setup.py @@ -1,6 +1,5 @@ # After editing this file run python setup.py egg_info in this directory from setuptools import setup, find_packages -import sys, os version = '0.0' @@ -30,6 +29,11 @@ 'test_observer_plugin=ckantestplugin:PluginObserverPlugin', 'action_plugin=ckantestplugin:ActionPlugin', 'auth_plugin=ckantestplugin:AuthPlugin', + 'test_group_plugin=ckantestplugin:MockGroupControllerPlugin', + 'test_package_controller_plugin=ckantestplugin:MockPackageControllerPlugin', + 'test_resource_preview=ckantestplugin:MockResourcePreviewExtension', + 'test_json_resource_preview=ckantestplugin:JsonMockResourcePreviewExtension', + ] } ) diff --git a/ckan/tests/functional/api/model/test_package.py b/ckan/tests/functional/api/model/test_package.py index 82b3d125938..a5af988089f 100644 --- a/ckan/tests/functional/api/model/test_package.py +++ b/ckan/tests/functional/api/model/test_package.py @@ -3,7 +3,6 @@ from nose.tools import assert_equal, assert_raises from ckan.lib.create_test_data import CreateTestData -from ckan import plugins import ckan.lib.search as search from ckan.lib.search.common import SolrSettings @@ -268,7 +267,6 @@ def test_register_post_indexerror(self): bad_solr_url = 'http://127.0.0.1/badsolrurl' original_settings = SolrSettings.get()[0] try: - plugins.load('synchronous_search') SolrSettings.init(bad_solr_url) assert not self.get_package_by_name(self.package_fixture_data['name']) @@ -659,14 +657,12 @@ def test_entity_update_indexerror(self): bad_solr_url = 'http://127.0.0.1/badsolrurl' original_settings = SolrSettings.get()[0] try: - plugins.load('synchronous_search') SolrSettings.init(bad_solr_url) assert_raises( search.SearchIndexError, self.assert_package_update_ok, 'name', 'post' ) finally: - plugins.unload('synchronous_search') SolrSettings.init(original_settings) def test_package_update_delete_resource(self): diff --git a/ckan/tests/functional/api/test_util.py b/ckan/tests/functional/api/test_util.py index 8949760be32..746ee2f41a8 100644 --- a/ckan/tests/functional/api/test_util.py +++ b/ckan/tests/functional/api/test_util.py @@ -163,5 +163,5 @@ def test_status(self): assert_equal(res['locale_default'], 'en') assert_equal(type(res['extensions']), list) - expected_extensions = set(('stats', 'test_tag_vocab_plugin')) + expected_extensions = set(('stats',)) assert_equal(set(res['extensions']), expected_extensions) diff --git a/ckan/tests/functional/test_group.py b/ckan/tests/functional/test_group.py index 432d288eb69..fb02d886e75 100644 --- a/ckan/tests/functional/test_group.py +++ b/ckan/tests/functional/test_group.py @@ -17,35 +17,7 @@ from base import FunctionalTestCase from ckan.tests import search_related, is_search_supported - -class MockGroupControllerPlugin(SingletonPlugin): - implements(IGroupController) - - def __init__(self): - from collections import defaultdict - self.calls = defaultdict(int) - - def read(self, entity): - self.calls['read'] += 1 - - def create(self, entity): - self.calls['create'] += 1 - - def edit(self, entity): - self.calls['edit'] += 1 - - def authz_add_role(self, object_role): - self.calls['authz_add_role'] += 1 - - def authz_remove_role(self, object_role): - self.calls['authz_remove_role'] += 1 - - def delete(self, entity): - self.calls['delete'] += 1 - - def before_view(self, data_dict): - self.calls['before_view'] += 1 - return data_dict +import ckan.tests.test_plugins as test_plugins class TestGroup(FunctionalTestCase): @@ -55,6 +27,7 @@ def setup_class(self): search.clear() model.Session.remove() CreateTestData.create() + test_plugins.install_ckantestplugin() @classmethod def teardown_class(self): @@ -215,14 +188,14 @@ def test_read_non_existent(self): res = self.app.get(offset, status=404) def test_read_plugin_hook(self): - plugin = MockGroupControllerPlugin() - plugins.load(plugin) + plugins.load('test_group_plugin') name = u'david' offset = url_for(controller='group', action='read', id=name) res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'testsysadmin'}) - assert plugin.calls['read'] == 1, plugin.calls - plugins.unload(plugin) + p = plugins.get_plugin('test_group_plugin') + assert p.calls['read'] == 1, p.calls + plugins.unload('test_group_plugin') def test_read_and_authorized_to_edit(self): name = u'david' @@ -288,6 +261,7 @@ def setup_class(self): model.repo.new_revision() model.Session.add(model.Package(name=self.packagename)) model.repo.commit_and_remove() + test_plugins.install_ckantestplugin() @classmethod @@ -388,8 +362,7 @@ def test_4_new_duplicate_package(self): assert_equal(pkg_names, [self.packagename]) def test_edit_plugin_hook(self): - plugin = MockGroupControllerPlugin() - plugins.load(plugin) + plugins.load('test_group_plugin') offset = url_for(controller='group', action='edit', id=self.groupname) res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'testsysadmin'}) @@ -398,8 +371,9 @@ def test_edit_plugin_hook(self): form['title'] = "huhuhu" res = form.submit('save', status=302, extra_environ={'REMOTE_USER': 'testsysadmin'}) - assert plugin.calls['edit'] == 1, plugin.calls - plugins.unload(plugin) + p = plugins.get_plugin('test_group_plugin') + assert p.calls['edit'] == 1, p.calls + plugins.unload('test_group_plugin') def test_edit_image_url(self): group = model.Group.by_name(self.groupname) @@ -596,8 +570,7 @@ def test_3_new_duplicate_group(self): assert 'class="field_error"' in res, res def test_new_plugin_hook(self): - plugin = MockGroupControllerPlugin() - plugins.load(plugin) + plugins.load('test_group_plugin') offset = url_for(controller='group', action='new') res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'testsysadmin'}) @@ -606,8 +579,9 @@ def test_new_plugin_hook(self): form['title'] = "huhuhu" res = form.submit('save', status=302, extra_environ={'REMOTE_USER': 'testsysadmin'}) - assert plugin.calls['create'] == 1, plugin.calls - plugins.unload(plugin) + p = plugins.get_plugin('test_group_plugin') + assert p.calls['create'] == 1, p.calls + plugins.unload('test_group_plugin') def test_new_bad_param(self): offset = url_for(controller='group', action='new', diff --git a/ckan/tests/functional/test_package.py b/ckan/tests/functional/test_package.py index 56a1f3edf27..2326ac236e9 100644 --- a/ckan/tests/functional/test_package.py +++ b/ckan/tests/functional/test_package.py @@ -1,12 +1,8 @@ -import cgi import datetime -from paste.fixture import AppError -from pylons import config -from pylons import c +from pylons import config, c from genshi.core import escape as genshi_escape from difflib import unified_diff -from nose.plugins.skip import SkipTest from nose.tools import assert_equal from ckan.tests import * @@ -15,77 +11,11 @@ from base import FunctionalTestCase import ckan.model as model from ckan.lib.create_test_data import CreateTestData -import ckan.lib.helpers as h -import ckan.lib.search as search from ckan.logic.action import get, update -from ckan.controllers.package import PackageController -from ckan.plugins import SingletonPlugin, implements, IPackageController from ckan import plugins -from ckan.rating import set_rating from ckan.lib.search.common import SolrSettings -class MockPackageControllerPlugin(SingletonPlugin): - implements(IPackageController) - - def __init__(self): - from collections import defaultdict - self.calls = defaultdict(int) - - def read(self, entity): - self.calls['read'] += 1 - - def create(self, entity): - self.calls['create'] += 1 - - def edit(self, entity): - self.calls['edit'] += 1 - - def authz_add_role(self, object_role): - self.calls['authz_add_role'] += 1 - - def authz_remove_role(self, object_role): - self.calls['authz_remove_role'] += 1 - - def delete(self, entity): - self.calls['delete'] += 1 - - def before_search(self, search_params): - self.calls['before_search'] += 1 - return search_params - - def after_search(self, search_results, search_params): - self.calls['after_search'] += 1 - return search_results - - def before_index(self, data_dict): - self.calls['before_index'] += 1 - return data_dict - - def before_view(self, data_dict): - self.calls['before_view'] += 1 - return data_dict - - def after_create(self, context, data_dict): - self.calls['after_create'] += 1 - self.id_in_dict = 'id' in data_dict - - return data_dict - - def after_update(self, context, data_dict): - self.calls['after_update'] += 1 - return data_dict - - def after_delete(self, context, data_dict): - self.calls['after_delete'] += 1 - return data_dict - - def after_show(self, context, data_dict): - self.calls['after_show'] += 1 - return data_dict - - def update_facet_titles(self, facet_titles): - return facet_titles existing_extra_html = ('', '') @@ -386,15 +316,15 @@ def test_history(self): assert name in res def test_read_plugin_hook(self): - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') name = u'annakarenina' offset = url_for(controller='package', action='read', id=name) res = self.app.get(offset) assert plugin.calls['read'] == 1, plugin.calls assert plugin.calls['after_show'] == 1, plugin.calls - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') def test_resource_list(self): # TODO restore this test. It doesn't make much sense with the @@ -934,8 +864,8 @@ def test_edit_bad_name(self): def test_edit_plugin_hook(self): # just the absolute basics try: - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') res = self.app.get(self.offset, extra_environ=self.extra_environ_admin) new_name = u'new-name' new_title = u'New Title' @@ -946,15 +876,15 @@ def test_edit_plugin_hook(self): res = fv.submit('save', extra_environ=self.extra_environ_admin) # get redirected ... assert plugin.calls['edit'] == 1, plugin.calls - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') finally: self._reset_data() def test_after_update_plugin_hook(self): # just the absolute basics try: - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') res = self.app.get(self.offset, extra_environ=self.extra_environ_admin) new_name = u'new-name' new_title = u'New Title' @@ -966,7 +896,7 @@ def test_after_update_plugin_hook(self): # get redirected ... assert plugin.calls['after_update'] == 1, plugin.calls assert plugin.calls['after_create'] == 0, plugin.calls - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') finally: self._reset_data() @@ -1023,16 +953,13 @@ def test_edit_indexerror(self): bad_solr_url = 'http://127.0.0.1/badsolrurl' solr_url = SolrSettings.get()[0] try: - plugins.load('synchronous_search') SolrSettings.init(bad_solr_url) fv = self.res.forms['dataset-edit'] - prefix = '' fv['log_message'] = u'Test log message' res = fv.submit('save', status=500, extra_environ=self.extra_environ_admin) assert 'Unable to update search index' in res, res finally: - plugins.unload('synchronous_search') SolrSettings.init(solr_url) def test_edit_pkg_with_relationships(self): @@ -1085,8 +1012,8 @@ def teardown_class(self): model.repo.rebuild_db() def test_delete(self): - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') offset = url_for(controller='package', action='delete', id='warandpeace') @@ -1099,8 +1026,7 @@ def test_delete(self): assert plugin.calls['delete'] == 1 assert plugin.calls['after_delete'] == 1 - - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') class TestNew(TestPackageForm): @@ -1296,8 +1222,8 @@ def test_new_existing_name(self): self._assert_form_errors(res) def test_new_plugin_hook(self): - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') offset = url_for(controller='package', action='new') res = self.app.get(offset, extra_environ=self.extra_environ_tester) new_name = u'plugged' @@ -1308,11 +1234,11 @@ def test_new_plugin_hook(self): # get redirected ... assert plugin.calls['edit'] == 0, plugin.calls assert plugin.calls['create'] == 1, plugin.calls - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') def test_after_create_plugin_hook(self): - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') offset = url_for(controller='package', action='new') res = self.app.get(offset, extra_environ=self.extra_environ_tester) new_name = u'plugged2' @@ -1325,14 +1251,12 @@ def test_after_create_plugin_hook(self): assert plugin.calls['after_create'] == 1, plugin.calls assert plugin.id_in_dict - - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') def test_new_indexerror(self): bad_solr_url = 'http://127.0.0.1/badsolrurl' solr_url = SolrSettings.get()[0] try: - plugins.load('synchronous_search') SolrSettings.init(bad_solr_url) new_package_name = u'new-package-missing-solr' @@ -1348,7 +1272,6 @@ def test_new_indexerror(self): res = fv.submit('save', status=500, extra_environ=self.extra_environ_tester) assert 'Unable to add package to search index' in res, res finally: - plugins.unload('synchronous_search') SolrSettings.init(solr_url) def test_change_locale(self): @@ -1374,14 +1297,14 @@ def teardown_class(self): model.repo.rebuild_db() def test_search_plugin_hooks(self): - plugin = MockPackageControllerPlugin() - plugins.load(plugin) + plugins.load('test_package_controller_plugin') + plugin = plugins.get_plugin('test_package_controller_plugin') offset = url_for(controller='package', action='search') res = self.app.get(offset) # get redirected ... assert plugin.calls['before_search'] == 1, plugin.calls assert plugin.calls['after_search'] == 1, plugin.calls - plugins.unload(plugin) + plugins.unload('test_package_controller_plugin') class TestNewPreview(TestPackageBase): pkgname = u'testpkg' diff --git a/ckan/tests/functional/test_preview_interface.py b/ckan/tests/functional/test_preview_interface.py index 13f649a5337..d294e083b9d 100644 --- a/ckan/tests/functional/test_preview_interface.py +++ b/ckan/tests/functional/test_preview_interface.py @@ -6,54 +6,14 @@ import ckan.lib.create_test_data as create_test_data import ckan.tests.functional.base as base import ckan.plugins as plugins -import ckan.tests.mock_plugin as mock import ckan.lib.dictization.model_dictize as model_dictize -class MockResourcePreviewExtension(mock.MockSingletonPlugin): - plugins.implements(plugins.IResourcePreview) - - def __init__(self): - from collections import defaultdict - self.calls = defaultdict(int) - - def can_preview(self, data_dict): - assert(isinstance(data_dict['resource'], dict)) - assert(isinstance(data_dict['package'], dict)) - assert('on_same_domain' in data_dict['resource']) - - self.calls['can_preview'] += 1 - return data_dict['resource']['format'].lower() == 'mock' - - def setup_template_variables(self, context, data_dict): - self.calls['setup_template_variables'] += 1 - - def preview_template(self, context, data_dict): - assert(isinstance(data_dict['resource'], dict)) - assert(isinstance(data_dict['package'], dict)) - - self.calls['preview_templates'] += 1 - return 'tests/mock_resource_preview_template.html' - - -class JsonMockResourcePreviewExtension(MockResourcePreviewExtension): - def can_preview(self, data_dict): - super(JsonMockResourcePreviewExtension, self).can_preview(data_dict) - return data_dict['resource']['format'].lower() == 'json' - - def preview_template(self, context, data_dict): - super(JsonMockResourcePreviewExtension, self).preview_template(context, data_dict) - self.calls['preview_templates'] += 1 - return 'tests/mock_json_resource_preview_template.html' - - class TestPluggablePreviews(base.FunctionalTestCase): @classmethod def setup_class(cls): - cls.plugin = MockResourcePreviewExtension() - plugins.load(cls.plugin) - json_plugin = JsonMockResourcePreviewExtension() - plugins.load(json_plugin) + plugins.load('test_resource_preview', 'test_json_resource_preview') + cls.plugin = plugins.get_plugin('test_resource_preview') create_test_data.CreateTestData.create() @@ -71,7 +31,7 @@ def setup_class(cls): @classmethod def teardown_class(cls): model.repo.rebuild_db() - plugins.unload(cls.plugin) + plugins.unload('test_resource_preview', 'test_json_resource_preview') def test_hook(self): testpackage = self.package diff --git a/ckan/tests/functional/test_tag_vocab.py b/ckan/tests/functional/test_tag_vocab.py index a7ad0fa9135..04ca960a7bf 100644 --- a/ckan/tests/functional/test_tag_vocab.py +++ b/ckan/tests/functional/test_tag_vocab.py @@ -4,8 +4,7 @@ from ckan.lib.create_test_data import CreateTestData import ckan.lib.helpers as h from ckan.tests import WsgiAppCase -# ensure that test_tag_vocab_plugin is added as a plugin in the testing .ini file -from ckanext.test_tag_vocab_plugin import MockVocabTagsPlugin +import ckan.plugins as plugins TEST_VOCAB_NAME = 'test-vocab' @@ -72,7 +71,7 @@ def value__get(self): class TestWUI(WsgiAppCase): @classmethod def setup_class(cls): - MockVocabTagsPlugin().set_active(True) + plugins.load('test_tag_vocab_plugin') CreateTestData.create(package_type='mock_vocab_tags_plugin') cls.sysadmin_user = model.User.get('testsysadmin') cls.dset = model.Package.get('warandpeace') @@ -105,7 +104,7 @@ def setup_class(cls): @classmethod def teardown_class(cls): - MockVocabTagsPlugin().set_active(False) + plugins.unload('test_tag_vocab_plugin') paste.fixture.Field.classes['select'] = cls.old_select model.repo.rebuild_db() @@ -141,7 +140,7 @@ def test_01_dataset_view(self): self._add_vocab_tag_to_dataset(self.dset.id, vocab_id, self.tag1_name) response = self.app.get(h.url_for(controller='package', action='read', id=self.dset.id)) - assert self.tag1_name in response.body + assert self.tag1_name in response.body, self.tag1_name self._remove_vocab_tags(self.dset.id, vocab_id, self.tag1_name) def test_02_dataset_edit_add_vocab_tag(self): diff --git a/ckan/tests/mock_plugin.py b/ckan/tests/mock_plugin.py index edfbfbd941e..a8f074bb823 100644 --- a/ckan/tests/mock_plugin.py +++ b/ckan/tests/mock_plugin.py @@ -4,7 +4,7 @@ class _MockPlugin(object): """ MockPlugin tracks method calls via __getattr__ for rapid mocking of plugins. - + Use MockPlugin.calls or MockPlugin..calls to access call information """ @@ -19,8 +19,8 @@ def __init__(self, boundto, name): def __call__(self, *args, **kwargs): self.boundto.calls.append((self.name, args, kwargs)) self.calls.append((args, kwargs)) - - def __init__(self): + + def __init__(self, *arg, **kw): self.calls = [] self.__mockmethods__ = {} @@ -35,6 +35,7 @@ def reset_calls(self): """ for mockmethod in self.MockMethod.registry.values(): mockmethod.calls = [] + self.__mockmethods__ = {} self.calls = [] class MockPlugin(_MockPlugin, Plugin): diff --git a/ckan/tests/test_plugins.py b/ckan/tests/test_plugins.py index 816a84d218a..98c12f91283 100644 --- a/ckan/tests/test_plugins.py +++ b/ckan/tests/test_plugins.py @@ -5,21 +5,19 @@ from nose.tools import raises from unittest import TestCase -from paste.deploy import loadapp from pyutilib.component.core import PluginGlobals from pylons import config from pkg_resources import working_set, Distribution, PathMetadata import ckan.logic as logic import ckan.new_authz as new_authz -from ckan import plugins -from ckan.config.middleware import make_app -from ckan.tests import conf_dir -from ckan.tests.mock_plugin import MockSingletonPlugin +import ckan.plugins as plugins from ckan.plugins.core import find_system_plugins from ckan.plugins import Interface, implements from ckan.lib.create_test_data import CreateTestData +import ckantestplugin + def install_ckantestplugin(): # Create the ckantestplugin setuptools distribution @@ -31,6 +29,14 @@ def install_ckantestplugin(): ckantestplugin_dist = Distribution( base_dir, project_name=dist_name, metadata=metadata) working_set.add(ckantestplugin_dist) + # We have messed up the pluginns so lets clean up + plugins.plugins_update() + +def _make_calls(*args): + out = [] + for arg in args: + out.append(((arg,), {})) + return out class IFoo(Interface): @@ -65,139 +71,122 @@ def test_provided_by(self): assert IFoo.provided_by(FooBarImpl()) assert not IFoo.provided_by(BarImpl()) -class TestIPluginObserverPlugin(TestCase): +class TestIPluginObserverPlugin(object): - class PluginObserverPlugin(MockSingletonPlugin): - from ckan.plugins import IPluginObserver - implements(IPluginObserver) - class OtherPlugin(MockSingletonPlugin): - implements(IFoo) + @classmethod + def setup(cls): + cls.observer = plugins.load('test_observer_plugin') - def setUp(self): - plugins.unload_all() - plugins.load(self.PluginObserverPlugin) - self.PluginObserverPlugin().reset_calls() + @classmethod + def teardown(cls): + plugins.unload('test_observer_plugin') def test_notified_on_load(self): - observer = self.PluginObserverPlugin() - plugins.load(self.OtherPlugin) - assert observer.before_load.calls == [((self.OtherPlugin,), {})] - assert observer.after_load.calls == [((self.OtherPlugin(),), {})] - assert observer.before_unload.calls == [] - assert observer.after_unload.calls == [] - - def test_notified_on_unload(self): - - plugins.load(self.OtherPlugin) - observer = self.PluginObserverPlugin() + observer = self.observer observer.reset_calls() + with plugins.use_plugin('action_plugin') as action: + assert observer.before_load.calls == _make_calls(action), observer.before_load.calls + assert observer.after_load.calls == _make_calls(action), observer.after_load.calls + assert observer.before_unload.calls == [] + assert observer.after_unload.calls == [] - plugins.unload(self.OtherPlugin) + def test_notified_on_unload(self): + with plugins.use_plugin('action_plugin') as action: + observer = self.observer + observer.reset_calls() assert observer.before_load.calls == [] assert observer.after_load.calls == [] - assert observer.before_unload.calls == [((self.OtherPlugin(),), {})], observer.before_unload.calls - assert observer.after_unload.calls == [((self.OtherPlugin(),), {})] + assert observer.before_unload.calls == _make_calls(action) + assert observer.after_unload.calls == _make_calls(action) + +class TestPlugins(object): -class TestPlugins(TestCase): - def setUp(self): - self._saved_plugins_config = config.get('ckan.plugins', '') - config['ckan.plugins'] = '' - plugins.reset() + @classmethod + def setup(cls): install_ckantestplugin() - def tearDown(self): - # Ideally this would remove the ckantestplugin_dist from the working - # set, but I can't find a way to do that in setuptools. - plugins.unload_all() - config['ckan.plugins'] = self._saved_plugins_config - plugins.load_all(config) def test_plugins_load(self): + config_plugins = config['ckan.plugins'] config['ckan.plugins'] = 'mapper_plugin routes_plugin' plugins.load_all(config) - # Imported after call to plugins.load_all to ensure that we test the - # plugin loader starting from a blank slate. - from ckantestplugin import MapperPlugin, MapperPlugin2, RoutesPlugin - import ckan.lib.search as search - - system_plugins = set(plugin() for plugin in find_system_plugins()) - assert PluginGlobals.env().services == set([MapperPlugin(), RoutesPlugin(), search.SynchronousSearchPlugin()]) | system_plugins + # synchronous_search automatically gets loaded + current_plugins = set([plugins.get_plugin(p) for p in ['mapper_plugin', 'routes_plugin', 'synchronous_search'] + find_system_plugins()]) + assert PluginGlobals.env().services == current_plugins + # cleanup + config['ckan.plugins'] = config_plugins + plugins.load_all(config) def test_only_configured_plugins_loaded(self): - config['ckan.plugins'] = 'mapper_plugin' - plugins.load_all(config) - - from ckantestplugin import MapperPlugin, MapperPlugin2, RoutesPlugin from ckan.model.extension import PluginMapperExtension from ckan.config.routing import routing_plugins - - - # MapperPlugin should be loaded as it is listed in config['ckan.plugins'] - assert MapperPlugin() in iter(PluginMapperExtension.observers) - - # MapperPlugin2 and RoutesPlugin should NOT be loaded - assert MapperPlugin2() not in iter(PluginMapperExtension.observers) - assert RoutesPlugin() not in routing_plugins + with plugins.use_plugin('mapper_plugin'): + # MapperPlugin should be loaded as it is listed in + assert ckantestplugin.MapperPlugin() in iter(PluginMapperExtension.observers) + # MapperPlugin2 and RoutesPlugin should NOT be loaded + assert ckantestplugin.MapperPlugin2() not in iter(PluginMapperExtension.observers) + assert ckantestplugin.RoutesPlugin() not in routing_plugins def test_plugin_loading_order(self): """ Check that plugins are loaded in the order specified in the config """ - from ckantestplugin import MapperPlugin, MapperPlugin2, PluginObserverPlugin - - observerplugin = PluginObserverPlugin() - + config_plugins = config['ckan.plugins'] config['ckan.plugins'] = 'test_observer_plugin mapper_plugin mapper_plugin2' - expected_order = MapperPlugin, MapperPlugin2 - plugins.load_all(config) - print observerplugin.before_load.calls - assert observerplugin.before_load.calls[:-1] == [((p,), {}) for p in expected_order] - assert observerplugin.after_load.calls[:-1] == [((p.__instance__,), {}) for p in (observerplugin,) + expected_order] + + observerplugin = plugins.get_plugin('test_observer_plugin') + + expected_order = _make_calls(plugins.get_plugin('mapper_plugin'), + plugins.get_plugin('mapper_plugin2')) + assert observerplugin.before_load.calls[:-2] == expected_order + expected_order = _make_calls(plugins.get_plugin('test_observer_plugin'), + plugins.get_plugin('mapper_plugin'), + plugins.get_plugin('mapper_plugin2')) + assert observerplugin.after_load.calls[:-2] == expected_order config['ckan.plugins'] = 'test_observer_plugin mapper_plugin2 mapper_plugin' - expected_order = MapperPlugin2, MapperPlugin - observerplugin.reset_calls() + plugins.load_all(config) + expected_order = _make_calls(plugins.get_plugin('mapper_plugin2'), + plugins.get_plugin('mapper_plugin')) + assert observerplugin.before_load.calls[:-2] == expected_order + expected_order = _make_calls(plugins.get_plugin('test_observer_plugin'), + plugins.get_plugin('mapper_plugin2'), + plugins.get_plugin('mapper_plugin')) + assert observerplugin.after_load.calls[:-2] == expected_order + # cleanup + config['ckan.plugins'] = config_plugins plugins.load_all(config) - assert observerplugin.before_load.calls[:-1] == [((p,), {}) for p in expected_order] - assert observerplugin.after_load.calls[:-1] == [((p.__instance__,), {}) for p in (observerplugin,) + expected_order] def test_mapper_plugin_fired(self): - config['ckan.plugins'] = 'mapper_plugin' - plugins.load_all(config) - CreateTestData.create_arbitrary([{'name':u'testpkg'}]) - mapper_plugin = PluginGlobals.env_registry['pca'].plugin_registry['MapperPlugin'].__instance__ - assert len(mapper_plugin.added) == 2 # resource group table added automatically - assert mapper_plugin.added[0].name == 'testpkg' + with plugins.use_plugin('mapper_plugin') as mapper_plugin: + CreateTestData.create_arbitrary([{'name':u'testpkg'}]) + assert len(mapper_plugin.added) == 2 # resource group table added automatically + assert mapper_plugin.added[0].name == 'testpkg' def test_routes_plugin_fired(self): - config['ckan.plugins'] = 'routes_plugin' - app = make_app(config['global_conf'], **config) - routes_plugin = PluginGlobals.env_registry['pca'].plugin_registry['RoutesPlugin'].__instance__ - assert routes_plugin.calls_made == ['before_map', 'after_map'], \ - routes_plugin.calls_made + with plugins.use_plugin('routes_plugin'): + routes_plugin = PluginGlobals.env_registry['pca'].plugin_registry['RoutesPlugin'].__instance__ + assert routes_plugin.calls_made == ['before_map', 'after_map'], \ + routes_plugin.calls_made + def test_action_plugin_override(self): - plugins.load_all(config) status_show_original = logic.get_action('status_show')(None, {}) - plugins.load('action_plugin') - assert logic.get_action('status_show')(None, {}) != status_show_original - plugins.unload('action_plugin') + with plugins.use_plugin('action_plugin'): + assert logic.get_action('status_show')(None, {}) != status_show_original assert logic.get_action('status_show')(None, {}) == status_show_original def test_auth_plugin_override(self): - plugins.load_all(config) package_list_original = new_authz.is_authorized('package_list', {}) - plugins.load('auth_plugin') - assert new_authz.is_authorized('package_list', {}) != package_list_original - plugins.unload('auth_plugin') + with plugins.use_plugin('auth_plugin'): + assert new_authz.is_authorized('package_list', {}) != package_list_original assert new_authz.is_authorized('package_list', {}) == package_list_original - diff --git a/test-core.ini b/test-core.ini index d4372d234c2..7c99531ef46 100644 --- a/test-core.ini +++ b/test-core.ini @@ -54,7 +54,7 @@ search_backend = sql # Change API key HTTP header to something non-standard. apikey_header_name = X-Non-Standard-CKAN-API-Key -ckan.plugins = stats test_tag_vocab_plugin +ckan.plugins = stats # use so we can check that html is *not* escaped ckan.template_head_end =