PROJECT_MOVED -> https://lab.nexedi.com/nexedi/erp5
[erp5.git] / product / ERP5Type / tests / ERP5TypeTestSuite.py
1 import re, imp, sys, os, shlex, shutil, glob, random
2 from erp5.util.testsuite import TestSuite, SubprocessError
3
4 class ERP5TypeTestSuite(TestSuite):
5
6 FTEST_PASS_FAIL_RE = re.compile(
7 ".*Functional Tests (?P<total>\d+) Tests, (?P<failures>\d+) " + \
8 "Failures(\,\ (?P<expected_failure>\d+) Expected failures|)")
9
10 def setup(self):
11 instance_home = self.instance and 'unit_test.%u' % self.instance \
12 or 'unit_test'
13 tests = os.path.join(instance_home, 'tests')
14 if os.path.exists(tests):
15 shutil.rmtree(instance_home + '.previous', True)
16 shutil.move(tests, instance_home + '.previous')
17
18 def run(self, test):
19 return self.runUnitTest(test)
20
21 def runUnitTest(self, *args, **kw):
22 if self.instance:
23 args = ('--instance_home=unit_test.%u' % self.instance,) + args
24 if self.__dict__.has_key("bt5_path"):
25 args = ("--bt5_path=%s" % self.bt5_path,) + args
26 instance_number = self.instance or 1
27 mysql_db_list = self.mysql_db_list[
28 (instance_number-1) * self.mysql_db_count:
29 (instance_number) * self.mysql_db_count]
30 if len(mysql_db_list) > 1:
31 args = ('--extra_sql_connection_string_list=%s' % \
32 ','.join(mysql_db_list[1:]),) + args
33 firefox_bin = getattr(self, "firefox_bin", None)
34 xvfb_bin = getattr(self, "xvfb_bin", None)
35 if firefox_bin:
36 args = ("--firefox_bin=%s" % firefox_bin,) + args
37 if xvfb_bin:
38 args = ("--xvfb_bin=%s" % xvfb_bin,) + args
39 try:
40 runUnitTest = os.environ.get('RUN_UNIT_TEST',
41 'runUnitTest')
42 args = tuple(shlex.split(runUnitTest)) \
43 + ('--verbose', '--erp5_sql_connection_string=' + mysql_db_list[0]) \
44 + args
45 status_dict = self.spawn(*args, **kw)
46 except SubprocessError, e:
47 status_dict = e.status_dict
48 test_log = status_dict['stderr']
49 search = self.RUN_RE.search(test_log)
50 if search:
51 groupdict = search.groupdict()
52 status_dict.update(duration=float(groupdict['seconds']),
53 test_count=int(groupdict['all_tests']))
54 search = self.STATUS_RE.search(test_log)
55 if search:
56 groupdict = search.groupdict()
57 status_dict.update(
58 error_count=int(groupdict['errors'] or 0),
59 failure_count=int(groupdict['failures'] or 0)
60 +int(groupdict['unexpected_successes'] or 0),
61 skip_count=int(groupdict['skips'] or 0)
62 +int(groupdict['expected_failures'] or 0))
63 return status_dict
64
65 class ProjectTestSuite(ERP5TypeTestSuite):
66 """
67 Helper code to locate all tests in a path list.
68
69 To use this class, inherit from it and define the following properties:
70 _product_list
71 List of product names to search tests in.
72 _bt_list
73 List of bt names to search tests in.
74 _search_path_list:
75 List of base paths to search for products & bts.
76 Defaults to sys.path (upon getTestList execution).
77 """
78 _product_list = ()
79 _bt_list = ()
80 _search_path_list = None
81
82 def _searchDirectory(self, path, path_list):
83 """
84 Returns a iterator over directories matching <path> inside directories
85 given in <path list>.
86 """
87 _path = os.path
88 pjoin = _path.join
89 isdir = _path.isdir
90 return (y for y in (pjoin(x, path) for x in path_list) if isdir(y))
91
92 def getTestList(self):
93 _glob = glob.glob
94 path = os.path
95 pjoin = path.join
96 path_list = self._search_path_list or sys.path
97 product_test_file_glob = pjoin('tests', 'test*.py')
98 bt_test_file_glob = pjoin('TestTemplateItem', 'test*.py')
99 test_file_list = []
100 extend = test_file_list.extend
101 for product_dir in self._searchDirectory('product', path_list):
102 for product_id in self._product_list:
103 extend(_glob(pjoin(product_dir, product_id, product_test_file_glob)))
104 for bt_dir in self._searchDirectory('bt5', path_list):
105 for bt_id in self._bt_list:
106 extend(_glob(pjoin(bt_dir, bt_id, bt_test_file_glob)))
107 return list(frozenset((path.splitext(path.basename(name))[0]
108 for name in test_file_list)))
109
110 class SavedTestSuite(ERP5TypeTestSuite):
111 """
112 Helper code to use --save/--load to reduce execution time.
113
114 To use this class, inherit from it and define the following properties:
115 _saved_test_id
116 Name of the test to use for --save execution.
117 """
118 _saved_test_id = None
119
120 def __init__(self, *args, **kw):
121 # Use same portal id for all tests run by current instance
122 # but keep it (per-run) random.
123 self._portal_id = 'portal_%i' % (random.randint(0, sys.maxint), )
124 super(SavedTestSuite, self).__init__(*args, **kw)
125
126 def __runUnitTest(self, *args, **kw):
127 if self.__dict__.has_key("bt5_path"):
128 args = ("--bt5_path=%s" % self.bt5_path,) + args
129 return super(SavedTestSuite, self).runUnitTest(
130 '--portal_id=' + self._portal_id,
131 *args, **kw)
132
133 def runUnitTest(self, *args, **kw):
134 return self.__runUnitTest(
135 '--load',
136 *args, **kw)
137
138 def setup(self):
139 super(SavedTestSuite, self).setup()
140 self.__runUnitTest('--save', self._saved_test_id)
141
142 sys.modules['test_suite'] = module = imp.new_module('test_suite')
143 for var in SubprocessError, TestSuite, ERP5TypeTestSuite, ProjectTestSuite, \
144 SavedTestSuite:
145 setattr(module, var.__name__, var)