diff options
author | Aníbal Limón <anibal.limon@linux.intel.com> | 2016-11-09 11:09:07 -0600 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2017-01-23 12:05:18 +0000 |
commit | 95a2ec6aab25a666a7163e7ddb9fcbf51bfa4c7e (patch) | |
tree | 0a5924adafd2d2246d2420c5bc09ad802373f0e7 | |
parent | 13c8c08b95191829705b5a4c8f0d368c251f0174 (diff) | |
download | poky-95a2ec6aab25a666a7163e7ddb9fcbf51bfa4c7e.tar.gz |
oeqa/core/decorator: Add support for OETestDepends
The OETestDepends decorator could be used over test cases to
define some dependency between them.
At loading time sorting the tests to grauntee that a test case
executes before also raise an exception if found a circular
dependency between test cases.
At before test case run reviews if the dependency if meet, in the
case of don't it skips the test case run.
(From OE-Core rev: 2385bd3c8a7c012fd1cad5465ec7d34675552c75)
Signed-off-by: Aníbal Limón <anibal.limon@linux.intel.com>
Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | meta/lib/oeqa/core/decorator/depends.py | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/meta/lib/oeqa/core/decorator/depends.py b/meta/lib/oeqa/core/decorator/depends.py new file mode 100644 index 0000000000..195711cf1e --- /dev/null +++ b/meta/lib/oeqa/core/decorator/depends.py | |||
@@ -0,0 +1,94 @@ | |||
1 | # Copyright (C) 2016 Intel Corporation | ||
2 | # Released under the MIT license (see COPYING.MIT) | ||
3 | |||
4 | from unittest import SkipTest | ||
5 | |||
6 | from oeqa.core.exception import OEQADependency | ||
7 | |||
8 | from . import OETestDiscover, registerDecorator | ||
9 | |||
10 | def _add_depends(registry, case, depends): | ||
11 | module_name = case.__module__ | ||
12 | class_name = case.__class__.__name__ | ||
13 | |||
14 | case_id = case.id() | ||
15 | |||
16 | for depend in depends: | ||
17 | dparts = depend.split('.') | ||
18 | |||
19 | if len(dparts) == 1: | ||
20 | depend_id = ".".join((module_name, class_name, dparts[0])) | ||
21 | elif len(dparts) == 2: | ||
22 | depend_id = ".".join((module_name, dparts[0], dparts[1])) | ||
23 | else: | ||
24 | depend_id = depend | ||
25 | |||
26 | if not case_id in registry: | ||
27 | registry[case_id] = [] | ||
28 | if not depend_id in registry[case_id]: | ||
29 | registry[case_id].append(depend_id) | ||
30 | |||
31 | def _validate_test_case_depends(cases, depends): | ||
32 | for case in depends: | ||
33 | if not case in cases: | ||
34 | continue | ||
35 | for dep in depends[case]: | ||
36 | if not dep in cases: | ||
37 | raise OEQADependency("TestCase %s depends on %s and isn't available"\ | ||
38 | ", cases available %s." % (case, dep, str(cases.keys()))) | ||
39 | |||
40 | def _order_test_case_by_depends(cases, depends): | ||
41 | def _dep_resolve(graph, node, resolved, seen): | ||
42 | seen.append(node) | ||
43 | for edge in graph[node]: | ||
44 | if edge not in resolved: | ||
45 | if edge in seen: | ||
46 | raise OEQADependency("Test cases %s and %s have a circular" \ | ||
47 | " dependency." % (node, edge)) | ||
48 | _dep_resolve(graph, edge, resolved, seen) | ||
49 | resolved.append(node) | ||
50 | |||
51 | dep_graph = {} | ||
52 | dep_graph['__root__'] = cases.keys() | ||
53 | for case in cases: | ||
54 | if case in depends: | ||
55 | dep_graph[case] = depends[case] | ||
56 | else: | ||
57 | dep_graph[case] = [] | ||
58 | |||
59 | cases_ordered = [] | ||
60 | _dep_resolve(dep_graph, '__root__', cases_ordered, []) | ||
61 | cases_ordered.remove('__root__') | ||
62 | |||
63 | return [cases[case_id] for case_id in cases_ordered] | ||
64 | |||
65 | def _skipTestDependency(case, depends): | ||
66 | results = case.tc._results | ||
67 | skipReasons = ['errors', 'failures', 'skipped'] | ||
68 | |||
69 | for reason in skipReasons: | ||
70 | for test, _ in results[reason]: | ||
71 | if test.id() in depends: | ||
72 | raise SkipTest("Test case %s depends on %s and was in %s." \ | ||
73 | % (case.id(), test.id(), reason)) | ||
74 | |||
75 | @registerDecorator | ||
76 | class OETestDepends(OETestDiscover): | ||
77 | attrs = ('depends',) | ||
78 | |||
79 | def bind(self, registry, case): | ||
80 | super(OETestDepends, self).bind(registry, case) | ||
81 | if not registry.get('depends'): | ||
82 | registry['depends'] = {} | ||
83 | _add_depends(registry['depends'], case, self.depends) | ||
84 | |||
85 | @staticmethod | ||
86 | def discover(registry): | ||
87 | if registry.get('depends'): | ||
88 | _validate_test_case_depends(registry['cases'], registry['depends']) | ||
89 | return _order_test_case_by_depends(registry['cases'], registry['depends']) | ||
90 | else: | ||
91 | return [registry['cases'][case_id] for case_id in registry['cases']] | ||
92 | |||
93 | def setUpDecorator(self): | ||
94 | _skipTestDependency(self.case, self.depends) | ||