# HG changeset patch # User Adrien Di Mascio # Date 1253701915 -7200 # Node ID d1356e008b1994f7d6d77bd60d77606d2cf32ddf # Parent 089c4b71ac161e411a41996e4e415f971fb50360# Parent fb17a54b358ce941dca2f356f7aea44beb3c9fac merge diff -r 089c4b71ac16 -r d1356e008b19 server/checkintegrity.py --- a/server/checkintegrity.py Wed Sep 23 12:31:18 2009 +0200 +++ b/server/checkintegrity.py Wed Sep 23 12:31:55 2009 +0200 @@ -68,8 +68,6 @@ """reindex all entities in the repository""" # deactivate modification_date hook since we don't want them # to be updated due to the reindexation - from cubicweb.server.hooks import (setmtime_before_update_entity, - uniquecstrcheck_before_modification) from cubicweb.server.repository import FTIndexEntityOp repo = session.repo cursor = session.pool['system'] @@ -80,10 +78,8 @@ # XXX indexer.init_fti(cursor) once index 0.7 is out indexer.init_extensions(cursor) cursor.execute(indexer.sql_init_fti()) - repo.hm.unregister_hook(setmtime_before_update_entity, - 'before_update_entity', '') - repo.hm.unregister_hook(uniquecstrcheck_before_modification, - 'before_update_entity', '') + repo.config.disabled_hooks_categories.add('metadata') + repo.config.disabled_hooks_categories.add('integrity') repo.do_fti = True # ensure full-text indexation is activated etypes = set() for eschema in schema.entities(): diff -r 089c4b71ac16 -r d1356e008b19 server/hook.py --- a/server/hook.py Wed Sep 23 12:31:18 2009 +0200 +++ b/server/hook.py Wed Sep 23 12:31:55 2009 +0200 @@ -67,10 +67,12 @@ except AttributeError: raise except: - raise Exception('bad .events attribute %s on %s' % (obj.events, obj)) + raise Exception('bad .events attribute %s on %s.%s' % ( + obj.events, obj.__module__, obj.__name__)) for event in obj.events: if event not in ALL_HOOKS: - raise Exception('bad event %s on %s' % (event, obj)) + raise Exception('bad event %s on %s.%s' % ( + event, obj.__module__, obj.__name__)) super(HooksRegistry, self).register(obj, **kwargs) def call_hooks(self, event, req=None, **kwargs): @@ -101,7 +103,7 @@ config = kwargs['repo'].config else: config = req.vreg.config - if enabled_category in config.disabled_hooks_categories: + if cls.category in config.disabled_hooks_categories: return 0 return 1 diff -r 089c4b71ac16 -r d1356e008b19 server/test/unittest_hook.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/unittest_hook.py Wed Sep 23 12:31:55 2009 +0200 @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- +"""unit/functional tests for cubicweb.server.hook + +:organization: Logilab +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +""" + +from logilab.common.testlib import TestCase, unittest_main, mock_object + + +from cubicweb.devtools import TestServerConfiguration +from cubicweb.devtools.testlib import CubicWebTC +from cubicweb.selectors import implements +from cubicweb.server import hook +from cubicweb.hooks import integrity, syncschema + + +def clean_session_ops(func): + def wrapper(self, *args, **kwargs): + try: + return func(self, *args, **kwargs) + finally: + self.session.pending_operations[:] = [] + return wrapper + +class OperationsTC(CubicWebTC): + + def setUp(self): + CubicWebTC.setUp(self) + self.hm = self.repo.hm + + @clean_session_ops + def test_late_operation(self): + session = self.session + l1 = hook.LateOperation(session) + l2 = hook.LateOperation(session) + l3 = hook.Operation(session) + self.assertEquals(session.pending_operations, [l3, l1, l2]) + + @clean_session_ops + def test_single_last_operation(self): + session = self.session + l0 = hook.SingleLastOperation(session) + l1 = hook.LateOperation(session) + l2 = hook.LateOperation(session) + l3 = hook.Operation(session) + self.assertEquals(session.pending_operations, [l3, l1, l2, l0]) + l4 = hook.SingleLastOperation(session) + self.assertEquals(session.pending_operations, [l3, l1, l2, l4]) + + @clean_session_ops + def test_global_operation_order(self): + session = self.session + op1 = integrity._DelayedDeleteOp(session) + op2 = syncschema.MemSchemaRDefDel(session) + # equivalent operation generated by op2 but replace it here by op3 so we + # can check the result... + op3 = syncschema.MemSchemaNotifyChanges(session) + op4 = integrity._DelayedDeleteOp(session) + op5 = integrity._CheckORelationOp(session) + self.assertEquals(session.pending_operations, [op1, op2, op4, op5, op3]) + + +class HookCalled(Exception): pass + +config = TestServerConfiguration('data') +config.bootstrap_cubes() +schema = config.load_schema() + +class AddAnyHook(hook.Hook): + __regid__ = 'addany' + category = 'cat1' + events = ('before_add_entity',) + def __call__(self): + raise HookCalled() + + +class HooksManagerTC(TestCase): + + def setUp(self): + """ called before each test from this class """ + self.vreg = mock_object(config=config, schema=schema) + self.o = hook.HooksRegistry(self.vreg) + + def test_register_bad_hook1(self): + class _Hook(hook.Hook): + events = ('before_add_entiti',) + ex = self.assertRaises(Exception, self.o.register, _Hook) + self.assertEquals(str(ex), 'bad event before_add_entiti on unittest_hook._Hook') + + def test_register_bad_hook2(self): + class _Hook(hook.Hook): + events = None + ex = self.assertRaises(Exception, self.o.register, _Hook) + self.assertEquals(str(ex), 'bad .events attribute None on unittest_hook._Hook') + + def test_register_bad_hook3(self): + class _Hook(hook.Hook): + events = 'before_add_entity' + ex = self.assertRaises(Exception, self.o.register, _Hook) + self.assertEquals(str(ex), 'bad event b on unittest_hook._Hook') + + def test_call_hook(self): + self.o.register(AddAnyHook) + cw = mock_object(vreg=self.vreg) + self.assertRaises(HookCalled, self.o.call_hooks, 'before_add_entity', cw) + self.o.call_hooks('before_delete_entity', cw) # nothing to call + config.disabled_hooks_categories.add('cat1') + self.o.call_hooks('before_add_entity', cw) # disabled hooks category, not called + config.disabled_hooks_categories.remove('cat1') + self.assertRaises(HookCalled, self.o.call_hooks, 'before_add_entity', cw) + self.o.unregister(AddAnyHook) + self.o.call_hooks('before_add_entity', cw) # nothing to call + + +class SystemHooksTC(CubicWebTC): + + def test_startup_shutdown(self): + import hooks # cubicweb/server/test/data/hooks.py + self.assertEquals(hooks.CALLED_EVENTS['server_startup'], True) + # don't actually call repository.shutdown ! + self.repo.hm.call_hooks('server_shutdown', repo=self.repo) + self.assertEquals(hooks.CALLED_EVENTS['server_shutdown'], True) + + def test_session_open_close(self): + import hooks # cubicweb/server/test/data/hooks.py + cnx = self.login('anon') + self.assertEquals(hooks.CALLED_EVENTS['session_open'], 'anon') + cnx.close() + self.assertEquals(hooks.CALLED_EVENTS['session_close'], 'anon') + + +# class RelationHookTC(TestCase): +# """testcase for relation hooks grouping""" +# def setUp(self): +# """ called before each test from this class """ +# self.o = HooksManager(schema) +# self.called = [] + +# def test_before_add_relation(self): +# """make sure before_xxx_relation hooks are called directly""" +# self.o.register(self._before_relation_hook, +# 'before_add_relation', 'concerne') +# self.assertEquals(self.called, []) +# self.o.call_hooks('before_add_relation', 'concerne', 'USER', +# 1, 'concerne', 2) +# self.assertEquals(self.called, [(1, 'concerne', 2)]) + +# def test_after_add_relation(self): +# """make sure after_xxx_relation hooks are deferred""" +# self.o.register(self._after_relation_hook, +# 'after_add_relation', 'concerne') +# self.assertEquals(self.called, []) +# self.o.call_hooks('after_add_relation', 'concerne', 'USER', +# 1, 'concerne', 2) +# self.o.call_hooks('after_add_relation', 'concerne', 'USER', +# 3, 'concerne', 4) +# self.assertEquals(self.called, [(1, 'concerne', 2), (3, 'concerne', 4)]) + +# def test_before_delete_relation(self): +# """make sure before_xxx_relation hooks are called directly""" +# self.o.register(self._before_relation_hook, +# 'before_delete_relation', 'concerne') +# self.assertEquals(self.called, []) +# self.o.call_hooks('before_delete_relation', 'concerne', 'USER', +# 1, 'concerne', 2) +# self.assertEquals(self.called, [(1, 'concerne', 2)]) + +# def test_after_delete_relation(self): +# """make sure after_xxx_relation hooks are deferred""" +# self.o.register(self._after_relation_hook, +# 'after_delete_relation', 'concerne') +# self.o.call_hooks('after_delete_relation', 'concerne', 'USER', +# 1, 'concerne', 2) +# self.o.call_hooks('after_delete_relation', 'concerne', 'USER', +# 3, 'concerne', 4) +# self.assertEquals(self.called, [(1, 'concerne', 2), (3, 'concerne', 4)]) + + +# def _before_relation_hook(self, pool, subject, r_type, object): +# self.called.append((subject, r_type, object)) + +# def _after_relation_hook(self, pool, subject, r_type, object): +# self.called.append((subject, r_type, object)) + + +if __name__ == '__main__': + unittest_main() diff -r 089c4b71ac16 -r d1356e008b19 server/test/unittest_hookhelper.py --- a/server/test/unittest_hookhelper.py Wed Sep 23 12:31:18 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -"""unit/functional tests for cubicweb.server.hookhelper - -:organization: Logilab -:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. -:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr -:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses -""" - -from logilab.common.testlib import unittest_main -from cubicweb.devtools.testlib import CubicWebTC - -from cubicweb.server.pool import LateOperation, Operation, SingleLastOperation -from cubicweb.server.hookhelper import * -from cubicweb.server import hooks, schemahooks - - -def clean_session_ops(func): - def wrapper(self, *args, **kwargs): - try: - return func(self, *args, **kwargs) - finally: - self.session.pending_operations[:] = [] - return wrapper - -class HookHelpersTC(CubicWebTC): - - def setUp(self): - CubicWebTC.setUp(self) - self.hm = self.repo.hm - - @clean_session_ops - def test_late_operation(self): - session = self.session - l1 = LateOperation(session) - l2 = LateOperation(session) - l3 = Operation(session) - self.assertEquals(session.pending_operations, [l3, l1, l2]) - - @clean_session_ops - def test_single_last_operation(self): - session = self.session - l0 = SingleLastOperation(session) - l1 = LateOperation(session) - l2 = LateOperation(session) - l3 = Operation(session) - self.assertEquals(session.pending_operations, [l3, l1, l2, l0]) - l4 = SingleLastOperation(session) - self.assertEquals(session.pending_operations, [l3, l1, l2, l4]) - - @clean_session_ops - def test_global_operation_order(self): - session = self.session - op1 = hooks.DelayedDeleteOp(session) - op2 = schemahooks.MemSchemaRDefDel(session) - # equivalent operation generated by op2 but replace it here by op3 so we - # can check the result... - op3 = schemahooks.MemSchemaNotifyChanges(session) - op4 = hooks.DelayedDeleteOp(session) - op5 = hooks.CheckORelationOp(session) - self.assertEquals(session.pending_operations, [op1, op2, op4, op5, op3]) - -if __name__ == '__main__': - unittest_main() diff -r 089c4b71ac16 -r d1356e008b19 server/test/unittest_hooksmanager.py --- a/server/test/unittest_hooksmanager.py Wed Sep 23 12:31:18 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -"""unit tests for the hooks manager -:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses -""" - -from logilab.common.testlib import TestCase, unittest_main - -from cubicweb.server.hooksmanager import HooksManager, Hook -from cubicweb.devtools import TestServerConfiguration -from cubicweb.devtools.testlib import CubicWebTC - -class HookCalled(Exception): pass - -config = TestServerConfiguration('data') -config.bootstrap_cubes() -schema = config.load_schema() - -class HooksManagerTC(TestCase): - args = (None,) - kwargs = {'a': 1} - - def setUp(self): - """ called before each test from this class """ - self.o = HooksManager(schema) - - def test_register_hook_raise_keyerror(self): - self.assertRaises(AssertionError, - self.o.register_hook, self._hook, 'before_add_entiti') - self.assertRaises(AssertionError, - self.o.register_hook, self._hook, 'session_login', 'CWEType') - self.assertRaises(AssertionError, - self.o.register_hook, self._hook, 'session_logout', 'CWEType') - self.assertRaises(AssertionError, - self.o.register_hook, self._hook, 'server_startup', 'CWEType') - self.assertRaises(AssertionError, - self.o.register_hook, self._hook, 'server_shutdown', 'CWEType') - - def test_register_hook1(self): - self.o.register_hook(self._hook, 'before_add_entity') - self.o.register_hook(self._hook, 'before_delete_entity', 'Personne') - self._test_called_hooks() - - def test_register_hook2(self): - self.o.register_hook(self._hook, 'before_add_entity', '') - self.o.register_hook(self._hook, 'before_delete_entity', 'Personne') - self._test_called_hooks() - - def test_register_hook3(self): - self.o.register_hook(self._hook, 'before_add_entity', None) - self.o.register_hook(self._hook, 'before_delete_entity', 'Personne') - self._test_called_hooks() - - def test_register_hooks(self): - self.o.register_hooks({'before_add_entity' : {'': [self._hook]}, - 'before_delete_entity' : {'Personne': [self._hook]}, - }) - self._test_called_hooks() - - def test_unregister_hook(self): - self.o.register_hook(self._hook, 'after_delete_entity', 'Personne') - self.assertRaises(HookCalled, - self.o.call_hooks, 'after_delete_entity', 'Personne', - *self.args, **self.kwargs) - self.o.unregister_hook(self._hook, 'after_delete_entity', 'Personne') - # no hook should be called there - self.o.call_hooks('after_delete_entity', 'Personne') - - - def _test_called_hooks(self): - self.assertRaises(HookCalled, - self.o.call_hooks, 'before_add_entity', '', - *self.args, **self.kwargs) - self.assertRaises(HookCalled, - self.o.call_hooks, 'before_add_entity', None, - *self.args, **self.kwargs) - self.assertRaises(HookCalled, - self.o.call_hooks, 'before_add_entity', 'Personne', - *self.args, **self.kwargs) - self.assertRaises(HookCalled, - self.o.call_hooks, 'before_delete_entity', 'Personne', - *self.args, **self.kwargs) - # no hook should be called there - self.o.call_hooks('before_delete_entity', None) - self.o.call_hooks('before_delete_entity', 'Societe') - - - def _hook(self, *args, **kwargs): - # check arguments - self.assertEqual(args, self.args) - self.assertEqual(kwargs, self.kwargs) - raise HookCalled() - - -class RelationHookTC(TestCase): - """testcase for relation hooks grouping""" - def setUp(self): - """ called before each test from this class """ - self.o = HooksManager(schema) - self.called = [] - - def test_before_add_relation(self): - """make sure before_xxx_relation hooks are called directly""" - self.o.register_hook(self._before_relation_hook, - 'before_add_relation', 'concerne') - self.assertEquals(self.called, []) - self.o.call_hooks('before_add_relation', 'concerne', 'USER', - 1, 'concerne', 2) - self.assertEquals(self.called, [(1, 'concerne', 2)]) - - def test_after_add_relation(self): - """make sure after_xxx_relation hooks are deferred""" - self.o.register_hook(self._after_relation_hook, - 'after_add_relation', 'concerne') - self.assertEquals(self.called, []) - self.o.call_hooks('after_add_relation', 'concerne', 'USER', - 1, 'concerne', 2) - self.o.call_hooks('after_add_relation', 'concerne', 'USER', - 3, 'concerne', 4) - self.assertEquals(self.called, [(1, 'concerne', 2), (3, 'concerne', 4)]) - - def test_before_delete_relation(self): - """make sure before_xxx_relation hooks are called directly""" - self.o.register_hook(self._before_relation_hook, - 'before_delete_relation', 'concerne') - self.assertEquals(self.called, []) - self.o.call_hooks('before_delete_relation', 'concerne', 'USER', - 1, 'concerne', 2) - self.assertEquals(self.called, [(1, 'concerne', 2)]) - - def test_after_delete_relation(self): - """make sure after_xxx_relation hooks are deferred""" - self.o.register_hook(self._after_relation_hook, - 'after_delete_relation', 'concerne') - self.o.call_hooks('after_delete_relation', 'concerne', 'USER', - 1, 'concerne', 2) - self.o.call_hooks('after_delete_relation', 'concerne', 'USER', - 3, 'concerne', 4) - self.assertEquals(self.called, [(1, 'concerne', 2), (3, 'concerne', 4)]) - - - def _before_relation_hook(self, pool, subject, r_type, object): - self.called.append((subject, r_type, object)) - - def _after_relation_hook(self, pool, subject, r_type, object): - self.called.append((subject, r_type, object)) - - -class SystemHooksTC(CubicWebTC): - - def test_startup_shutdown(self): - import hooks # cubicweb/server/test/data/hooks.py - self.assertEquals(hooks.CALLED_EVENTS['server_startup'], True) - # don't actually call repository.shutdown ! - self.repo.hm.call_hooks('server_shutdown', repo=None) - self.assertEquals(hooks.CALLED_EVENTS['server_shutdown'], True) - - def test_session_open_close(self): - import hooks # cubicweb/server/test/data/hooks.py - cnx = self.login('anon') - self.assertEquals(hooks.CALLED_EVENTS['session_open'], 'anon') - cnx.close() - self.assertEquals(hooks.CALLED_EVENTS['session_close'], 'anon') - - -from itertools import repeat - -class MyHook(Hook): - schema = schema # set for actual hooks at registration time - events = ('whatever', 'another') - accepts = ('Societe', 'Division') - -class HookTC(CubicWebTC): - def test_inheritance(self): - self.assertEquals(list(MyHook.register_to(self.schema)), - zip(repeat('whatever'), ('Societe', 'Division', 'SubDivision')) - + zip(repeat('another'), ('Societe', 'Division', 'SubDivision'))) - - -if __name__ == '__main__': - unittest_main()