From 71259f09f46c68297907dea97627e628622a6955 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 18 Feb 2014 10:54:52 +0100 Subject: [PATCH] [ADD] hooks to enable/disable tests running during install also add flag for post_install run, but not used yet bzr revid: xmo@openerp.com-20140218095452-pptez5rlpdez1ttl --- openerp/addons/base/tests/test_base.py | 53 ++++++++++++++++++++++++++ openerp/modules/module.py | 30 ++++++++++++++- openerp/tests/common.py | 22 +++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 20382737529..fe8ddc411d7 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -375,6 +375,59 @@ class test_translation(common.TransactionCase): fr_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id, context={'lang':'fr_FR'}) self.assertEqual(fr_context_cat.name, 'Clients (copie)', "Did not used default value for translated value") +test_state = None +#: Stores state information across multiple test classes +def setUpModule(): + global test_state + test_state = {} +def tearDownModule(): + global test_state + test_state = None + +class TestPhaseInstall00(unittest2.TestCase): + """ + WARNING: Relies on tests being run in alphabetical order + """ + @classmethod + def setUpClass(cls): + cls.state = None + + def test_00_setup(self): + type(self).state = 'init' + + @common.at_install(False) + def test_01_no_install(self): + type(self).state = 'error' + + def test_02_check(self): + self.assertEqual( + self.state, 'init', + "Testcase state should not have been transitioned from 00") + +class TestPhaseInstall01(unittest2.TestCase): + at_install = False + + def test_default_norun(self): + self.fail("An unmarket test in a non-at-install case should not run") + + @common.at_install(True) + def test_set_run(self): + test_state['set_at_install'] = True + +class TestPhaseInstall02(unittest2.TestCase): + """ + Can't put the check for test_set_run in the same class: if + @common.at_install does not work for test_set_run, it won't work for + the other one either. Thus move checking of whether test_set_run has + correctly run indeed to a separate class. + + Warning: relies on *classes* being run in alphabetical order in test + modules + """ + def test_check_state(self): + self.assertTrue( + test_state.get('set_at_install'), + "The flag should be set if local overriding of runstate") if __name__ == '__main__': unittest2.main() diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 18d26945d76..210ca2a8f9e 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -20,6 +20,7 @@ # ############################################################################## +import functools import imp import itertools import logging @@ -364,7 +365,7 @@ def run_unit_tests(module_name, dbname): r = True for m in mods: tests = unwrap_suite(unittest2.TestLoader().loadTestsFromModule(m)) - suite = unittest2.TestSuite(tests) + suite = unittest2.TestSuite(itertools.ifilter(runs_at_install, tests)) _logger.info('module %s: running test %s.', module_name, m.__name__) result = unittest2.TextTestRunner(verbosity=2, stream=TestStream()).run(suite) @@ -374,7 +375,34 @@ def run_unit_tests(module_name, dbname): current_test = None return r +def runs_at(test, hook, default): + # by default, tests do not run post install + test_runs = getattr(test, hook, default) + + # for a test suite, we're done + if not isinstance(test, unittest.TestCase): + return test_runs + + # otherwise check the current test method to see it's been set to a + # different state + method = getattr(test, test._testMethodName) + return getattr(method, hook, test_runs) + +runs_at_install = functools.partial(runs_at, hook='at_install', default=True) +runs_post_install = functools.partial(runs_at, hook='post_install', default=False) + def unwrap_suite(test): + """ + Attempts to unpack testsuites (holding suites or cases) in order to + generate a single stream of terminals (either test cases or customized + test suites). These can then be checked for run/skip attributes + individually. + + An alternative would be to use a variant of @unittest2.skipIf with a state + flag of some sort e.g. @unittest2.skipIf(common.runstate != 'at_install'), + but then things become weird with post_install as tests should *not* run + by default there + """ if isinstance(test, unittest.TestCase): yield test return diff --git a/openerp/tests/common.py b/openerp/tests/common.py index ecfd4f84894..aac93ea1f7b 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -55,6 +55,28 @@ def release_test_cursor(session_id): return True return False +def at_install(flag): + """ Sets the at-install state of a test, the flag is a boolean specifying + whether the test should (``True``) or should not (``False``) run during + module installation. + + By default, tests are run at install. + """ + def decorator(obj): + obj.at_install = flag + return obj + return decorator +def post_install(flag): + """ Sets the post-install state of a test. The flag is a boolean + specifying whether the test should or should not run after a set of + module installations. + + By default, tests are *not* run after installation. + """ + def decorator(obj): + obj.post_install = flag + return obj + return decorator class BaseCase(unittest2.TestCase): """