diff options
-rw-r--r-- | meta/classes/testsdk.bbclass | 4 | ||||
-rw-r--r-- | meta/lib/oeqa/core/decorator/depends.py | 7 | ||||
-rw-r--r-- | meta/lib/oeqa/core/decorator/oetimeout.py | 40 | ||||
-rw-r--r-- | meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py | 12 | ||||
-rw-r--r-- | meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py | 8 | ||||
-rw-r--r-- | meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py | 10 | ||||
-rw-r--r-- | meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py | 12 | ||||
-rw-r--r-- | meta/lib/oeqa/core/tests/common.py | 10 | ||||
-rwxr-xr-x | meta/lib/oeqa/core/tests/test_decorators.py | 12 | ||||
-rwxr-xr-x | meta/lib/oeqa/core/tests/test_loader.py | 30 | ||||
-rw-r--r-- | meta/lib/oeqa/core/threaded.py | 275 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/context.py | 5 |
12 files changed, 14 insertions, 411 deletions
diff --git a/meta/classes/testsdk.bbclass b/meta/classes/testsdk.bbclass index e6e3c74bdb..2b5d66b193 100644 --- a/meta/classes/testsdk.bbclass +++ b/meta/classes/testsdk.bbclass | |||
@@ -24,8 +24,6 @@ def testsdk_main(d): | |||
24 | from oeqa.sdk.context import OESDKTestContext, OESDKTestContextExecutor | 24 | from oeqa.sdk.context import OESDKTestContext, OESDKTestContextExecutor |
25 | from oeqa.utils import make_logger_bitbake_compatible | 25 | from oeqa.utils import make_logger_bitbake_compatible |
26 | 26 | ||
27 | bb.event.enable_threadlock() | ||
28 | |||
29 | pn = d.getVar("PN") | 27 | pn = d.getVar("PN") |
30 | logger = make_logger_bitbake_compatible(logging.getLogger("BitBake")) | 28 | logger = make_logger_bitbake_compatible(logging.getLogger("BitBake")) |
31 | 29 | ||
@@ -99,8 +97,6 @@ def testsdkext_main(d): | |||
99 | from oeqa.utils import avoid_paths_in_environ, make_logger_bitbake_compatible, subprocesstweak | 97 | from oeqa.utils import avoid_paths_in_environ, make_logger_bitbake_compatible, subprocesstweak |
100 | from oeqa.sdkext.context import OESDKExtTestContext, OESDKExtTestContextExecutor | 98 | from oeqa.sdkext.context import OESDKExtTestContext, OESDKExtTestContextExecutor |
101 | 99 | ||
102 | bb.event.enable_threadlock() | ||
103 | |||
104 | pn = d.getVar("PN") | 100 | pn = d.getVar("PN") |
105 | logger = make_logger_bitbake_compatible(logging.getLogger("BitBake")) | 101 | logger = make_logger_bitbake_compatible(logging.getLogger("BitBake")) |
106 | 102 | ||
diff --git a/meta/lib/oeqa/core/decorator/depends.py b/meta/lib/oeqa/core/decorator/depends.py index baa04341c7..99eccc1268 100644 --- a/meta/lib/oeqa/core/decorator/depends.py +++ b/meta/lib/oeqa/core/decorator/depends.py | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | from unittest import SkipTest | 4 | from unittest import SkipTest |
5 | 5 | ||
6 | from oeqa.core.threaded import OETestRunnerThreaded | ||
7 | from oeqa.core.exception import OEQADependency | 6 | from oeqa.core.exception import OEQADependency |
8 | 7 | ||
9 | from . import OETestDiscover, registerDecorator | 8 | from . import OETestDiscover, registerDecorator |
@@ -64,11 +63,7 @@ def _order_test_case_by_depends(cases, depends): | |||
64 | return [cases[case_id] for case_id in cases_ordered] | 63 | return [cases[case_id] for case_id in cases_ordered] |
65 | 64 | ||
66 | def _skipTestDependency(case, depends): | 65 | def _skipTestDependency(case, depends): |
67 | if isinstance(case.tc.runner, OETestRunnerThreaded): | 66 | results = case.tc._results |
68 | import threading | ||
69 | results = case.tc._results[threading.get_ident()] | ||
70 | else: | ||
71 | results = case.tc._results | ||
72 | 67 | ||
73 | skipReasons = ['errors', 'failures', 'skipped'] | 68 | skipReasons = ['errors', 'failures', 'skipped'] |
74 | 69 | ||
diff --git a/meta/lib/oeqa/core/decorator/oetimeout.py b/meta/lib/oeqa/core/decorator/oetimeout.py index f85e7d9792..a247583f7f 100644 --- a/meta/lib/oeqa/core/decorator/oetimeout.py +++ b/meta/lib/oeqa/core/decorator/oetimeout.py | |||
@@ -1,12 +1,8 @@ | |||
1 | # Copyright (C) 2016 Intel Corporation | 1 | # Copyright (C) 2016 Intel Corporation |
2 | # Released under the MIT license (see COPYING.MIT) | 2 | # Released under the MIT license (see COPYING.MIT) |
3 | 3 | ||
4 | from . import OETestDecorator, registerDecorator | ||
5 | |||
6 | import signal | 4 | import signal |
7 | from threading import Timer | 5 | from . import OETestDecorator, registerDecorator |
8 | |||
9 | from oeqa.core.threaded import OETestRunnerThreaded | ||
10 | from oeqa.core.exception import OEQATimeoutError | 6 | from oeqa.core.exception import OEQATimeoutError |
11 | 7 | ||
12 | @registerDecorator | 8 | @registerDecorator |
@@ -14,32 +10,16 @@ class OETimeout(OETestDecorator): | |||
14 | attrs = ('oetimeout',) | 10 | attrs = ('oetimeout',) |
15 | 11 | ||
16 | def setUpDecorator(self): | 12 | def setUpDecorator(self): |
17 | self.logger.debug("Setting up a %d second(s) timeout" % self.oetimeout) | 13 | timeout = self.oetimeout |
18 | 14 | def _timeoutHandler(signum, frame): | |
19 | if isinstance(self.case.tc.runner, OETestRunnerThreaded): | 15 | raise OEQATimeoutError("Timed out after %s " |
20 | self.timeouted = False | ||
21 | def _timeoutHandler(): | ||
22 | self.timeouted = True | ||
23 | |||
24 | self.timer = Timer(self.oetimeout, _timeoutHandler) | ||
25 | self.timer.start() | ||
26 | else: | ||
27 | timeout = self.oetimeout | ||
28 | def _timeoutHandler(signum, frame): | ||
29 | raise OEQATimeoutError("Timed out after %s " | ||
30 | "seconds of execution" % timeout) | 16 | "seconds of execution" % timeout) |
31 | 17 | ||
32 | self.alarmSignal = signal.signal(signal.SIGALRM, _timeoutHandler) | 18 | self.logger.debug("Setting up a %d second(s) timeout" % self.oetimeout) |
33 | signal.alarm(self.oetimeout) | 19 | self.alarmSignal = signal.signal(signal.SIGALRM, _timeoutHandler) |
20 | signal.alarm(self.oetimeout) | ||
34 | 21 | ||
35 | def tearDownDecorator(self): | 22 | def tearDownDecorator(self): |
36 | if isinstance(self.case.tc.runner, OETestRunnerThreaded): | 23 | signal.alarm(0) |
37 | self.timer.cancel() | 24 | signal.signal(signal.SIGALRM, self.alarmSignal) |
38 | self.logger.debug("Removed Timer handler") | 25 | self.logger.debug("Removed SIGALRM handler") |
39 | if self.timeouted: | ||
40 | raise OEQATimeoutError("Timed out after %s " | ||
41 | "seconds of execution" % self.oetimeout) | ||
42 | else: | ||
43 | signal.alarm(0) | ||
44 | signal.signal(signal.SIGALRM, self.alarmSignal) | ||
45 | self.logger.debug("Removed SIGALRM handler") | ||
diff --git a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py b/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py deleted file mode 100644 index 0fe4cb3f11..0000000000 --- a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | # Copyright (C) 2017 Intel Corporation | ||
2 | # Released under the MIT license (see COPYING.MIT) | ||
3 | |||
4 | from oeqa.core.case import OETestCase | ||
5 | |||
6 | class ThreadedTest(OETestCase): | ||
7 | def test_threaded_no_depends(self): | ||
8 | self.assertTrue(True, msg='How is this possible?') | ||
9 | |||
10 | class ThreadedTest2(OETestCase): | ||
11 | def test_threaded_same_module(self): | ||
12 | self.assertTrue(True, msg='How is this possible?') | ||
diff --git a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py b/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py deleted file mode 100644 index 905f397846..0000000000 --- a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | # Copyright (C) 2017 Intel Corporation | ||
2 | # Released under the MIT license (see COPYING.MIT) | ||
3 | |||
4 | from oeqa.core.case import OETestCase | ||
5 | |||
6 | class ThreadedTestAlone(OETestCase): | ||
7 | def test_threaded_alone(self): | ||
8 | self.assertTrue(True, msg='How is this possible?') | ||
diff --git a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py b/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py deleted file mode 100644 index 0c158d3bac..0000000000 --- a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | # Copyright (C) 2017 Intel Corporation | ||
2 | # Released under the MIT license (see COPYING.MIT) | ||
3 | |||
4 | from oeqa.core.case import OETestCase | ||
5 | from oeqa.core.decorator.depends import OETestDepends | ||
6 | |||
7 | class ThreadedTest3(OETestCase): | ||
8 | @OETestDepends(['threaded.ThreadedTest.test_threaded_no_depends']) | ||
9 | def test_threaded_depends(self): | ||
10 | self.assertTrue(True, msg='How is this possible?') | ||
diff --git a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py b/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py deleted file mode 100644 index 63d17e0401..0000000000 --- a/meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | # Copyright (C) 2017 Intel Corporation | ||
2 | # Released under the MIT license (see COPYING.MIT) | ||
3 | |||
4 | from oeqa.core.case import OETestCase | ||
5 | |||
6 | class ThreadedTestModule(OETestCase): | ||
7 | def test_threaded_module(self): | ||
8 | self.assertTrue(True, msg='How is this possible?') | ||
9 | |||
10 | class ThreadedTestModule2(OETestCase): | ||
11 | def test_threaded_module2(self): | ||
12 | self.assertTrue(True, msg='How is this possible?') | ||
diff --git a/meta/lib/oeqa/core/tests/common.py b/meta/lib/oeqa/core/tests/common.py index 1932323409..52b18a1c3e 100644 --- a/meta/lib/oeqa/core/tests/common.py +++ b/meta/lib/oeqa/core/tests/common.py | |||
@@ -33,13 +33,3 @@ class TestBase(unittest.TestCase): | |||
33 | tc.loadTests(self.cases_path, modules=modules, tests=tests, | 33 | tc.loadTests(self.cases_path, modules=modules, tests=tests, |
34 | filters=filters) | 34 | filters=filters) |
35 | return tc | 35 | return tc |
36 | |||
37 | def _testLoaderThreaded(self, d={}, modules=[], | ||
38 | tests=[], filters={}): | ||
39 | from oeqa.core.threaded import OETestContextThreaded | ||
40 | |||
41 | tc = OETestContextThreaded(d, self.logger) | ||
42 | tc.loadTests(self.cases_path, modules=modules, tests=tests, | ||
43 | filters=filters) | ||
44 | |||
45 | return tc | ||
diff --git a/meta/lib/oeqa/core/tests/test_decorators.py b/meta/lib/oeqa/core/tests/test_decorators.py index cf99e0d72d..f7d11e885a 100755 --- a/meta/lib/oeqa/core/tests/test_decorators.py +++ b/meta/lib/oeqa/core/tests/test_decorators.py | |||
@@ -131,17 +131,5 @@ class TestTimeoutDecorator(TestBase): | |||
131 | msg = "OETestTimeout didn't restore SIGALRM" | 131 | msg = "OETestTimeout didn't restore SIGALRM" |
132 | self.assertIs(alarm_signal, signal.getsignal(signal.SIGALRM), msg=msg) | 132 | self.assertIs(alarm_signal, signal.getsignal(signal.SIGALRM), msg=msg) |
133 | 133 | ||
134 | def test_timeout_thread(self): | ||
135 | tests = ['timeout.TimeoutTest.testTimeoutPass'] | ||
136 | msg = 'Failed to run test using OETestTimeout' | ||
137 | tc = self._testLoaderThreaded(modules=self.modules, tests=tests) | ||
138 | self.assertTrue(tc.runTests().wasSuccessful(), msg=msg) | ||
139 | |||
140 | def test_timeout_threaded_fail(self): | ||
141 | tests = ['timeout.TimeoutTest.testTimeoutFail'] | ||
142 | msg = "OETestTimeout test didn't timeout as expected" | ||
143 | tc = self._testLoaderThreaded(modules=self.modules, tests=tests) | ||
144 | self.assertFalse(tc.runTests().wasSuccessful(), msg=msg) | ||
145 | |||
146 | if __name__ == '__main__': | 134 | if __name__ == '__main__': |
147 | unittest.main() | 135 | unittest.main() |
diff --git a/meta/lib/oeqa/core/tests/test_loader.py b/meta/lib/oeqa/core/tests/test_loader.py index e0d917d317..b79b8bad4d 100755 --- a/meta/lib/oeqa/core/tests/test_loader.py +++ b/meta/lib/oeqa/core/tests/test_loader.py | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/usr/bin/env python3 | 1 | #!/usr/bin/env python3 |
2 | 2 | ||
3 | # Copyright (C) 2016-2017 Intel Corporation | 3 | # Copyright (C) 2016 Intel Corporation |
4 | # Released under the MIT license (see COPYING.MIT) | 4 | # Released under the MIT license (see COPYING.MIT) |
5 | 5 | ||
6 | import os | 6 | import os |
@@ -82,33 +82,5 @@ class TestLoader(TestBase): | |||
82 | msg = 'Expected modules from two different paths' | 82 | msg = 'Expected modules from two different paths' |
83 | self.assertEqual(modules, expected_modules, msg=msg) | 83 | self.assertEqual(modules, expected_modules, msg=msg) |
84 | 84 | ||
85 | def test_loader_threaded(self): | ||
86 | cases_path = self.cases_path | ||
87 | |||
88 | self.cases_path = [os.path.join(self.cases_path, 'loader', 'threaded')] | ||
89 | |||
90 | tc = self._testLoaderThreaded() | ||
91 | self.assertEqual(len(tc.suites), 3, "Expected to be 3 suites") | ||
92 | |||
93 | case_ids = ['threaded.ThreadedTest.test_threaded_no_depends', | ||
94 | 'threaded.ThreadedTest2.test_threaded_same_module', | ||
95 | 'threaded_depends.ThreadedTest3.test_threaded_depends'] | ||
96 | for case in tc.suites[0]._tests: | ||
97 | self.assertEqual(case.id(), | ||
98 | case_ids[tc.suites[0]._tests.index(case)]) | ||
99 | |||
100 | case_ids = ['threaded_alone.ThreadedTestAlone.test_threaded_alone'] | ||
101 | for case in tc.suites[1]._tests: | ||
102 | self.assertEqual(case.id(), | ||
103 | case_ids[tc.suites[1]._tests.index(case)]) | ||
104 | |||
105 | case_ids = ['threaded_module.ThreadedTestModule.test_threaded_module', | ||
106 | 'threaded_module.ThreadedTestModule2.test_threaded_module2'] | ||
107 | for case in tc.suites[2]._tests: | ||
108 | self.assertEqual(case.id(), | ||
109 | case_ids[tc.suites[2]._tests.index(case)]) | ||
110 | |||
111 | self.cases_path = cases_path | ||
112 | |||
113 | if __name__ == '__main__': | 85 | if __name__ == '__main__': |
114 | unittest.main() | 86 | unittest.main() |
diff --git a/meta/lib/oeqa/core/threaded.py b/meta/lib/oeqa/core/threaded.py deleted file mode 100644 index 2cafe03a21..0000000000 --- a/meta/lib/oeqa/core/threaded.py +++ /dev/null | |||
@@ -1,275 +0,0 @@ | |||
1 | # Copyright (C) 2017 Intel Corporation | ||
2 | # Released under the MIT license (see COPYING.MIT) | ||
3 | |||
4 | import threading | ||
5 | import multiprocessing | ||
6 | import queue | ||
7 | import time | ||
8 | |||
9 | from unittest.suite import TestSuite | ||
10 | |||
11 | from oeqa.core.loader import OETestLoader | ||
12 | from oeqa.core.runner import OEStreamLogger, OETestResult, OETestRunner | ||
13 | from oeqa.core.context import OETestContext | ||
14 | |||
15 | class OETestLoaderThreaded(OETestLoader): | ||
16 | def __init__(self, tc, module_paths, modules, tests, modules_required, | ||
17 | filters, process_num=0, *args, **kwargs): | ||
18 | super(OETestLoaderThreaded, self).__init__(tc, module_paths, modules, | ||
19 | tests, modules_required, filters, *args, **kwargs) | ||
20 | |||
21 | self.process_num = process_num | ||
22 | |||
23 | def discover(self): | ||
24 | suite = super(OETestLoaderThreaded, self).discover() | ||
25 | |||
26 | if self.process_num <= 0: | ||
27 | self.process_num = min(multiprocessing.cpu_count(), | ||
28 | len(suite._tests)) | ||
29 | |||
30 | suites = [] | ||
31 | for _ in range(self.process_num): | ||
32 | suites.append(self.suiteClass()) | ||
33 | |||
34 | def _search_for_module_idx(suites, case): | ||
35 | """ | ||
36 | Cases in the same module needs to be run | ||
37 | in the same thread because PyUnit keeps track | ||
38 | of setUp{Module, Class,} and tearDown{Module, Class,}. | ||
39 | """ | ||
40 | |||
41 | for idx in range(self.process_num): | ||
42 | suite = suites[idx] | ||
43 | for c in suite._tests: | ||
44 | if case.__module__ == c.__module__: | ||
45 | return idx | ||
46 | |||
47 | return -1 | ||
48 | |||
49 | def _search_for_depend_idx(suites, depends): | ||
50 | """ | ||
51 | Dependency cases needs to be run in the same | ||
52 | thread, because OEQA framework look at the state | ||
53 | of dependant test to figure out if skip or not. | ||
54 | """ | ||
55 | |||
56 | for idx in range(self.process_num): | ||
57 | suite = suites[idx] | ||
58 | |||
59 | for case in suite._tests: | ||
60 | if case.id() in depends: | ||
61 | return idx | ||
62 | return -1 | ||
63 | |||
64 | def _get_best_idx(suites): | ||
65 | sizes = [len(suite._tests) for suite in suites] | ||
66 | return sizes.index(min(sizes)) | ||
67 | |||
68 | def _fill_suites(suite): | ||
69 | idx = -1 | ||
70 | for case in suite: | ||
71 | if isinstance(case, TestSuite): | ||
72 | _fill_suites(case) | ||
73 | else: | ||
74 | idx = _search_for_module_idx(suites, case) | ||
75 | |||
76 | depends = {} | ||
77 | if 'depends' in self.tc._registry: | ||
78 | depends = self.tc._registry['depends'] | ||
79 | |||
80 | if idx == -1 and case.id() in depends: | ||
81 | case_depends = depends[case.id()] | ||
82 | idx = _search_for_depend_idx(suites, case_depends) | ||
83 | |||
84 | if idx == -1: | ||
85 | idx = _get_best_idx(suites) | ||
86 | |||
87 | suites[idx].addTest(case) | ||
88 | _fill_suites(suite) | ||
89 | |||
90 | suites_tmp = suites | ||
91 | suites = [] | ||
92 | for suite in suites_tmp: | ||
93 | if len(suite._tests) > 0: | ||
94 | suites.append(suite) | ||
95 | |||
96 | return suites | ||
97 | |||
98 | class OEStreamLoggerThreaded(OEStreamLogger): | ||
99 | _lock = threading.Lock() | ||
100 | buffers = {} | ||
101 | |||
102 | def write(self, msg): | ||
103 | tid = threading.get_ident() | ||
104 | |||
105 | if not tid in self.buffers: | ||
106 | self.buffers[tid] = "" | ||
107 | |||
108 | if msg: | ||
109 | self.buffers[tid] += msg | ||
110 | |||
111 | def finish(self): | ||
112 | tid = threading.get_ident() | ||
113 | |||
114 | self._lock.acquire() | ||
115 | self.logger.info('THREAD: %d' % tid) | ||
116 | self.logger.info('-' * 70) | ||
117 | for line in self.buffers[tid].split('\n'): | ||
118 | self.logger.info(line) | ||
119 | self._lock.release() | ||
120 | |||
121 | class OETestResultThreadedInternal(OETestResult): | ||
122 | def _tc_map_results(self): | ||
123 | tid = threading.get_ident() | ||
124 | |||
125 | # PyUnit generates a result for every test module run, test | ||
126 | # if the thread already has an entry to avoid lose the previous | ||
127 | # test module results. | ||
128 | if not tid in self.tc._results: | ||
129 | self.tc._results[tid] = {} | ||
130 | self.tc._results[tid]['failures'] = self.failures | ||
131 | self.tc._results[tid]['errors'] = self.errors | ||
132 | self.tc._results[tid]['skipped'] = self.skipped | ||
133 | self.tc._results[tid]['expectedFailures'] = self.expectedFailures | ||
134 | |||
135 | class OETestResultThreaded(object): | ||
136 | _results = {} | ||
137 | _lock = threading.Lock() | ||
138 | |||
139 | def __init__(self, tc): | ||
140 | self.tc = tc | ||
141 | |||
142 | def _fill_tc_results(self): | ||
143 | tids = list(self.tc._results.keys()) | ||
144 | fields = ['failures', 'errors', 'skipped', 'expectedFailures'] | ||
145 | |||
146 | for tid in tids: | ||
147 | result = self.tc._results[tid] | ||
148 | for field in fields: | ||
149 | if not field in self.tc._results: | ||
150 | self.tc._results[field] = [] | ||
151 | self.tc._results[field].extend(result[field]) | ||
152 | |||
153 | def addResult(self, result, run_start_time, run_end_time): | ||
154 | tid = threading.get_ident() | ||
155 | |||
156 | self._lock.acquire() | ||
157 | self._results[tid] = {} | ||
158 | self._results[tid]['result'] = result | ||
159 | self._results[tid]['run_start_time'] = run_start_time | ||
160 | self._results[tid]['run_end_time'] = run_end_time | ||
161 | self._results[tid]['result'] = result | ||
162 | self._lock.release() | ||
163 | |||
164 | def wasSuccessful(self): | ||
165 | wasSuccessful = True | ||
166 | for tid in self._results.keys(): | ||
167 | wasSuccessful = wasSuccessful and \ | ||
168 | self._results[tid]['result'].wasSuccessful() | ||
169 | return wasSuccessful | ||
170 | |||
171 | def stop(self): | ||
172 | for tid in self._results.keys(): | ||
173 | self._results[tid]['result'].stop() | ||
174 | |||
175 | def logSummary(self, component, context_msg=''): | ||
176 | elapsed_time = (self.tc._run_end_time - self.tc._run_start_time) | ||
177 | |||
178 | self.tc.logger.info("SUMMARY:") | ||
179 | self.tc.logger.info("%s (%s) - Ran %d tests in %.3fs" % (component, | ||
180 | context_msg, len(self.tc._registry['cases']), elapsed_time)) | ||
181 | if self.wasSuccessful(): | ||
182 | msg = "%s - OK - All required tests passed" % component | ||
183 | else: | ||
184 | msg = "%s - FAIL - Required tests failed" % component | ||
185 | self.tc.logger.info(msg) | ||
186 | |||
187 | def logDetails(self): | ||
188 | if list(self._results): | ||
189 | tid = list(self._results)[0] | ||
190 | result = self._results[tid]['result'] | ||
191 | result.logDetails() | ||
192 | |||
193 | class _Worker(threading.Thread): | ||
194 | """Thread executing tasks from a given tasks queue""" | ||
195 | def __init__(self, tasks, result, stream): | ||
196 | threading.Thread.__init__(self) | ||
197 | self.tasks = tasks | ||
198 | |||
199 | self.result = result | ||
200 | self.stream = stream | ||
201 | |||
202 | def run(self): | ||
203 | while True: | ||
204 | try: | ||
205 | func, args, kargs = self.tasks.get(block=False) | ||
206 | except queue.Empty: | ||
207 | break | ||
208 | |||
209 | try: | ||
210 | run_start_time = time.time() | ||
211 | rc = func(*args, **kargs) | ||
212 | run_end_time = time.time() | ||
213 | self.result.addResult(rc, run_start_time, run_end_time) | ||
214 | self.stream.finish() | ||
215 | except Exception as e: | ||
216 | print(e) | ||
217 | finally: | ||
218 | self.tasks.task_done() | ||
219 | |||
220 | class _ThreadedPool: | ||
221 | """Pool of threads consuming tasks from a queue""" | ||
222 | def __init__(self, num_workers, num_tasks, stream=None, result=None): | ||
223 | self.tasks = queue.Queue(num_tasks) | ||
224 | self.workers = [] | ||
225 | |||
226 | for _ in range(num_workers): | ||
227 | worker = _Worker(self.tasks, result, stream) | ||
228 | self.workers.append(worker) | ||
229 | |||
230 | def start(self): | ||
231 | for worker in self.workers: | ||
232 | worker.start() | ||
233 | |||
234 | def add_task(self, func, *args, **kargs): | ||
235 | """Add a task to the queue""" | ||
236 | self.tasks.put((func, args, kargs)) | ||
237 | |||
238 | def wait_completion(self): | ||
239 | """Wait for completion of all the tasks in the queue""" | ||
240 | self.tasks.join() | ||
241 | for worker in self.workers: | ||
242 | worker.join() | ||
243 | |||
244 | class OETestRunnerThreaded(OETestRunner): | ||
245 | streamLoggerClass = OEStreamLoggerThreaded | ||
246 | |||
247 | def __init__(self, tc, *args, **kwargs): | ||
248 | super(OETestRunnerThreaded, self).__init__(tc, *args, **kwargs) | ||
249 | self.resultclass = OETestResultThreadedInternal # XXX: XML reporting overrides at __init__ | ||
250 | |||
251 | def run(self, suites): | ||
252 | result = OETestResultThreaded(self.tc) | ||
253 | |||
254 | pool = _ThreadedPool(len(suites), len(suites), stream=self.stream, | ||
255 | result=result) | ||
256 | for s in suites: | ||
257 | pool.add_task(super(OETestRunnerThreaded, self).run, s) | ||
258 | pool.start() | ||
259 | pool.wait_completion() | ||
260 | result._fill_tc_results() | ||
261 | |||
262 | return result | ||
263 | |||
264 | class OETestContextThreaded(OETestContext): | ||
265 | loaderClass = OETestLoaderThreaded | ||
266 | runnerClass = OETestRunnerThreaded | ||
267 | |||
268 | def loadTests(self, module_paths, modules=[], tests=[], | ||
269 | modules_manifest="", modules_required=[], filters={}, process_num=0): | ||
270 | if modules_manifest: | ||
271 | modules = self._read_modules_from_manifest(modules_manifest) | ||
272 | |||
273 | self.loader = self.loaderClass(self, module_paths, modules, tests, | ||
274 | modules_required, filters, process_num) | ||
275 | self.suites = self.loader.discover() | ||
diff --git a/meta/lib/oeqa/sdk/context.py b/meta/lib/oeqa/sdk/context.py index b3d7c75183..82e4c19bfc 100644 --- a/meta/lib/oeqa/sdk/context.py +++ b/meta/lib/oeqa/sdk/context.py | |||
@@ -6,10 +6,9 @@ import sys | |||
6 | import glob | 6 | import glob |
7 | import re | 7 | import re |
8 | 8 | ||
9 | from oeqa.core.context import OETestContextExecutor | 9 | from oeqa.core.context import OETestContext, OETestContextExecutor |
10 | from oeqa.core.threaded import OETestContextThreaded | ||
11 | 10 | ||
12 | class OESDKTestContext(OETestContextThreaded): | 11 | class OESDKTestContext(OETestContext): |
13 | sdk_files_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") | 12 | sdk_files_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") |
14 | 13 | ||
15 | def __init__(self, td=None, logger=None, sdk_dir=None, sdk_env=None, | 14 | def __init__(self, td=None, logger=None, sdk_dir=None, sdk_env=None, |