CurrentThread is now really deprecated in Python 3.10 ... Time to change. Part-of: odoo/odoo#91927
108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
import importlib
|
|
import inspect
|
|
import itertools
|
|
import logging
|
|
import threading
|
|
import unittest
|
|
|
|
from .. import tools
|
|
from .common import TagsSelector, OdooSuite
|
|
from .runner import OdooTestResult
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
def get_test_modules(module):
|
|
""" Return a list of module for the addons potentially containing tests to
|
|
feed unittest.TestLoader.loadTestsFromModule() """
|
|
# Try to import the module
|
|
results = _get_tests_modules('odoo.addons', module)
|
|
|
|
try:
|
|
importlib.import_module('odoo.upgrade.%s' % module)
|
|
except ImportError:
|
|
pass
|
|
else:
|
|
results += _get_tests_modules('odoo.upgrade', module)
|
|
|
|
return results
|
|
|
|
|
|
def _get_tests_modules(path, module):
|
|
modpath = '%s.%s' % (path, module)
|
|
try:
|
|
mod = importlib.import_module('.tests', modpath)
|
|
except ImportError as e: # will also catch subclass ModuleNotFoundError of P3.6
|
|
# Hide ImportErrors on `tests` sub-module, but display other exceptions
|
|
if e.name == modpath + '.tests' and e.msg.startswith('No module named'):
|
|
return []
|
|
_logger.exception('Can not `import %s`.', module)
|
|
return []
|
|
except Exception as e:
|
|
_logger.exception('Can not `import %s`.', module)
|
|
return []
|
|
if hasattr(mod, 'fast_suite') or hasattr(mod, 'checks'):
|
|
_logger.warning(
|
|
"Found deprecated fast_suite or checks attribute in test module "
|
|
"%s. These have no effect in or after version 8.0.",
|
|
mod.__name__)
|
|
|
|
result = [mod_obj for name, mod_obj in inspect.getmembers(mod, inspect.ismodule)
|
|
if name.startswith('test_')]
|
|
return result
|
|
|
|
def make_suite(module_names, position='at_install'):
|
|
""" Creates a test suite for all the tests in the specified modules,
|
|
filtered by the provided ``position`` and the current test tags
|
|
|
|
:param list[str] module_names: modules to load tests from
|
|
:param str position: "at_install" or "post_install"
|
|
"""
|
|
config_tags = TagsSelector(tools.config['test_tags'])
|
|
position_tag = TagsSelector(position)
|
|
tests = (
|
|
t
|
|
for module_name in module_names
|
|
for m in get_test_modules(module_name)
|
|
for t in unwrap_suite(unittest.TestLoader().loadTestsFromModule(m))
|
|
if position_tag.check(t) and config_tags.check(t)
|
|
)
|
|
return OdooSuite(sorted(tests, key=lambda t: t.test_sequence))
|
|
|
|
def run_suite(suite, module_name=None):
|
|
# avoid dependency hell
|
|
from ..modules import module
|
|
module.current_test = module_name
|
|
threading.current_thread().testing = True
|
|
|
|
results = OdooTestResult()
|
|
suite(results)
|
|
|
|
threading.current_thread().testing = False
|
|
module.current_test = None
|
|
return results
|
|
|
|
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 @unittest.skipIf with a state
|
|
flag of some sort e.g. @unittest.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
|
|
|
|
subtests = list(test)
|
|
# custom test suite (no test cases)
|
|
if not len(subtests):
|
|
yield test
|
|
return
|
|
|
|
for item in itertools.chain.from_iterable(unwrap_suite(t) for t in subtests):
|
|
yield item
|