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) | ||
