summaryrefslogtreecommitdiff
path: root/odoo/tests/common.py
diff options
context:
space:
mode:
Diffstat (limited to 'odoo/tests/common.py')
-rw-r--r--odoo/tests/common.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/odoo/tests/common.py b/odoo/tests/common.py
index 6035cf21d10..fcf02041518 100644
--- a/odoo/tests/common.py
+++ b/odoo/tests/common.py
@@ -19,6 +19,7 @@ import requests
import shutil
import signal
import subprocess
+import sys
import tempfile
import threading
import time
@@ -128,9 +129,126 @@ def new_test_user(env, login='', groups='base.group_user', context=None, **kwarg
# ------------------------------------------------------------
# Main classes
# ------------------------------------------------------------
+class OdooSuite(unittest.suite.TestSuite):
+
+ if sys.version_info < (3, 8):
+ # Partial backport of bpo-24412, merged in CPython 3.8
+
+ def _handleClassSetup(self, test, result):
+ previousClass = getattr(result, '_previousTestClass', None)
+ currentClass = test.__class__
+ if currentClass == previousClass:
+ return
+ if result._moduleSetUpFailed:
+ return
+ if getattr(currentClass, "__unittest_skip__", False):
+ return
+
+ try:
+ currentClass._classSetupFailed = False
+ except TypeError:
+ # test may actually be a function
+ # so its class will be a builtin-type
+ pass
+
+ setUpClass = getattr(currentClass, 'setUpClass', None)
+ if setUpClass is not None:
+ unittest.suite._call_if_exists(result, '_setupStdout')
+ try:
+ setUpClass()
+ except Exception as e:
+ if isinstance(result, unittest.suite._DebugResult):
+ raise
+ currentClass._classSetupFailed = True
+ className = unittest.util.strclass(currentClass)
+ self._createClassOrModuleLevelException(result, e,
+ 'setUpClass',
+ className)
+ finally:
+ unittest.suite._call_if_exists(result, '_restoreStdout')
+ if currentClass._classSetupFailed is True:
+ currentClass.doClassCleanups()
+ if len(currentClass.tearDown_exceptions) > 0:
+ for exc in currentClass.tearDown_exceptions:
+ self._createClassOrModuleLevelException(
+ result, exc[1], 'setUpClass', className,
+ info=exc)
+
+ def _createClassOrModuleLevelException(self, result, exc, method_name, parent, info=None):
+ errorName = f'{method_name} ({parent})'
+ self._addClassOrModuleLevelException(result, exc, errorName, info)
+
+ def _addClassOrModuleLevelException(self, result, exception, errorName, info=None):
+ error = unittest.suite._ErrorHolder(errorName)
+ addSkip = getattr(result, 'addSkip', None)
+ if addSkip is not None and isinstance(exception, unittest.case.SkipTest):
+ addSkip(error, str(exception))
+ else:
+ if not info:
+ result.addError(error, sys.exc_info())
+ else:
+ result.addError(error, info)
+
+ def _tearDownPreviousClass(self, test, result):
+ previousClass = getattr(result, '_previousTestClass', None)
+ currentClass = test.__class__
+ if currentClass == previousClass:
+ return
+ if getattr(previousClass, '_classSetupFailed', False):
+ return
+ if getattr(result, '_moduleSetUpFailed', False):
+ return
+ if getattr(previousClass, "__unittest_skip__", False):
+ return
+
+ tearDownClass = getattr(previousClass, 'tearDownClass', None)
+ if tearDownClass is not None:
+ unittest.suite._call_if_exists(result, '_setupStdout')
+ try:
+ tearDownClass()
+ except Exception as e:
+ if isinstance(result, unittest.suite._DebugResult):
+ raise
+ className = unittest.util.strclass(previousClass)
+ self._createClassOrModuleLevelException(result, e,
+ 'tearDownClass',
+ className)
+ finally:
+ unittest.suite._call_if_exists(result, '_restoreStdout')
+ previousClass.doClassCleanups()
+ if len(previousClass.tearDown_exceptions) > 0:
+ for exc in previousClass.tearDown_exceptions:
+ className = unittest.util.strclass(previousClass)
+ self._createClassOrModuleLevelException(result, exc[1],
+ 'tearDownClass',
+ className,
+ info=exc)
class TreeCase(unittest.TestCase):
+
+ if sys.version_info < (3, 8):
+ # Partial backport of bpo-24412, merged in CPython 3.8
+ _class_cleanups = []
+
+ @classmethod
+ def addClassCleanup(cls, function, *args, **kwargs):
+ """Same as addCleanup, except the cleanup items are called even if
+ setUpClass fails (unlike tearDownClass). Backport of bpo-24412."""
+ cls._class_cleanups.append((function, args, kwargs))
+
+ @classmethod
+ def doClassCleanups(cls):
+ """Execute all class cleanup functions. Normally called for you after tearDownClass.
+ Backport of bpo-24412."""
+ cls.tearDown_exceptions = []
+ while cls._class_cleanups:
+ function, args, kwargs = cls._class_cleanups.pop()
+ try:
+ function(*args, **kwargs)
+ except Exception as exc:
+ cls.tearDown_exceptions.append(sys.exc_info())
+
def __init__(self, methodName='runTest'):
super(TreeCase, self).__init__(methodName)
self.addTypeEqualityFunc(etree._Element, self.assertTreesEqual)