diff options
Diffstat (limited to 'nova/tests/unit/test_hooks.py')
-rw-r--r-- | nova/tests/unit/test_hooks.py | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/nova/tests/unit/test_hooks.py b/nova/tests/unit/test_hooks.py new file mode 100644 index 0000000000..9017787151 --- /dev/null +++ b/nova/tests/unit/test_hooks.py @@ -0,0 +1,205 @@ +# Copyright (c) 2012 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Tests for hook customization.""" + +import stevedore + +from nova import hooks +from nova import test + + +class SampleHookA(object): + name = "a" + + def _add_called(self, op, kwargs): + called = kwargs.get('called', None) + if called is not None: + called.append(op + self.name) + + def pre(self, *args, **kwargs): + self._add_called("pre", kwargs) + + +class SampleHookB(SampleHookA): + name = "b" + + def post(self, rv, *args, **kwargs): + self._add_called("post", kwargs) + + +class SampleHookC(SampleHookA): + name = "c" + + def pre(self, f, *args, **kwargs): + self._add_called("pre" + f.__name__, kwargs) + + def post(self, f, rv, *args, **kwargs): + self._add_called("post" + f.__name__, kwargs) + + +class SampleHookExceptionPre(SampleHookA): + name = "epre" + exception = Exception() + + def pre(self, f, *args, **kwargs): + raise self.exception + + +class SampleHookExceptionPost(SampleHookA): + name = "epost" + exception = Exception() + + def post(self, f, rv, *args, **kwargs): + raise self.exception + + +class MockEntryPoint(object): + + def __init__(self, cls): + self.cls = cls + + def load(self): + return self.cls + + +class MockedHookTestCase(test.BaseHookTestCase): + def _mock_load_plugins(self, iload, *iargs, **ikwargs): + return [] + + def setUp(self): + super(MockedHookTestCase, self).setUp() + + hooks.reset() + + self.stubs.Set(stevedore.extension.ExtensionManager, '_load_plugins', + self._mock_load_plugins) + + +class HookTestCase(MockedHookTestCase): + def _mock_load_plugins(self, iload, *iargs, **ikwargs): + return [ + stevedore.extension.Extension('test_hook', + MockEntryPoint(SampleHookA), SampleHookA, SampleHookA()), + stevedore.extension.Extension('test_hook', + MockEntryPoint(SampleHookB), SampleHookB, SampleHookB()), + ] + + def setUp(self): + super(HookTestCase, self).setUp() + + hooks.reset() + + self.stubs.Set(stevedore.extension.ExtensionManager, '_load_plugins', + self._mock_load_plugins) + + @hooks.add_hook('test_hook') + def _hooked(self, a, b=1, c=2, called=None): + return 42 + + def test_basic(self): + self.assertEqual(42, self._hooked(1)) + + mgr = hooks._HOOKS['test_hook'] + self.assert_has_hook('test_hook', self._hooked) + self.assertEqual(2, len(mgr.extensions)) + self.assertEqual(SampleHookA, mgr.extensions[0].plugin) + self.assertEqual(SampleHookB, mgr.extensions[1].plugin) + + def test_order_of_execution(self): + called_order = [] + self._hooked(42, called=called_order) + self.assertEqual(['prea', 'preb', 'postb'], called_order) + + +class HookTestCaseWithFunction(MockedHookTestCase): + def _mock_load_plugins(self, iload, *iargs, **ikwargs): + return [ + stevedore.extension.Extension('function_hook', + MockEntryPoint(SampleHookC), SampleHookC, SampleHookC()), + ] + + @hooks.add_hook('function_hook', pass_function=True) + def _hooked(self, a, b=1, c=2, called=None): + return 42 + + def test_basic(self): + self.assertEqual(42, self._hooked(1)) + mgr = hooks._HOOKS['function_hook'] + + self.assert_has_hook('function_hook', self._hooked) + self.assertEqual(1, len(mgr.extensions)) + self.assertEqual(SampleHookC, mgr.extensions[0].plugin) + + def test_order_of_execution(self): + called_order = [] + self._hooked(42, called=called_order) + self.assertEqual(['pre_hookedc', 'post_hookedc'], called_order) + + +class HookFailPreTestCase(MockedHookTestCase): + def _mock_load_plugins(self, iload, *iargs, **ikwargs): + return [ + stevedore.extension.Extension('fail_pre', + MockEntryPoint(SampleHookExceptionPre), + SampleHookExceptionPre, SampleHookExceptionPre()), + ] + + @hooks.add_hook('fail_pre', pass_function=True) + def _hooked(self, a, b=1, c=2, called=None): + return 42 + + def test_hook_fail_should_still_return(self): + self.assertEqual(42, self._hooked(1)) + + mgr = hooks._HOOKS['fail_pre'] + self.assert_has_hook('fail_pre', self._hooked) + self.assertEqual(1, len(mgr.extensions)) + self.assertEqual(SampleHookExceptionPre, mgr.extensions[0].plugin) + + def test_hook_fail_should_raise_fatal(self): + self.stubs.Set(SampleHookExceptionPre, 'exception', + hooks.FatalHookException()) + + self.assertRaises(hooks.FatalHookException, + self._hooked, 1) + + +class HookFailPostTestCase(MockedHookTestCase): + def _mock_load_plugins(self, iload, *iargs, **ikwargs): + return [ + stevedore.extension.Extension('fail_post', + MockEntryPoint(SampleHookExceptionPost), + SampleHookExceptionPost, SampleHookExceptionPost()), + ] + + @hooks.add_hook('fail_post', pass_function=True) + def _hooked(self, a, b=1, c=2, called=None): + return 42 + + def test_hook_fail_should_still_return(self): + self.assertEqual(42, self._hooked(1)) + + mgr = hooks._HOOKS['fail_post'] + self.assert_has_hook('fail_post', self._hooked) + self.assertEqual(1, len(mgr.extensions)) + self.assertEqual(SampleHookExceptionPost, mgr.extensions[0].plugin) + + def test_hook_fail_should_raise_fatal(self): + self.stubs.Set(SampleHookExceptionPost, 'exception', + hooks.FatalHookException()) + + self.assertRaises(hooks.FatalHookException, + self._hooked, 1) |