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>
This commit is contained in:
parent
13c8c08b95
commit
95a2ec6aab
|
@ -0,0 +1,94 @@
|
|||
# Copyright (C) 2016 Intel Corporation
|
||||
# Released under the MIT license (see COPYING.MIT)
|
||||
|
||||
from unittest import SkipTest
|
||||
|
||||
from oeqa.core.exception import OEQADependency
|
||||
|
||||
from . import OETestDiscover, registerDecorator
|
||||
|
||||
def _add_depends(registry, case, depends):
|
||||
module_name = case.__module__
|
||||
class_name = case.__class__.__name__
|
||||
|
||||
case_id = case.id()
|
||||
|
||||
for depend in depends:
|
||||
dparts = depend.split('.')
|
||||
|
||||
if len(dparts) == 1:
|
||||
depend_id = ".".join((module_name, class_name, dparts[0]))
|
||||
elif len(dparts) == 2:
|
||||
depend_id = ".".join((module_name, dparts[0], dparts[1]))
|
||||
else:
|
||||
depend_id = depend
|
||||
|
||||
if not case_id in registry:
|
||||
registry[case_id] = []
|
||||
if not depend_id in registry[case_id]:
|
||||
registry[case_id].append(depend_id)
|
||||
|
||||
def _validate_test_case_depends(cases, depends):
|
||||
for case in depends:
|
||||
if not case in cases:
|
||||
continue
|
||||
for dep in depends[case]:
|
||||
if not dep in cases:
|
||||
raise OEQADependency("TestCase %s depends on %s and isn't available"\
|
||||
", cases available %s." % (case, dep, str(cases.keys())))
|
||||
|
||||
def _order_test_case_by_depends(cases, depends):
|
||||
def _dep_resolve(graph, node, resolved, seen):
|
||||
seen.append(node)
|
||||
for edge in graph[node]:
|
||||
if edge not in resolved:
|
||||
if edge in seen:
|
||||
raise OEQADependency("Test cases %s and %s have a circular" \
|
||||
" dependency." % (node, edge))
|
||||
_dep_resolve(graph, edge, resolved, seen)
|
||||
resolved.append(node)
|
||||
|
||||
dep_graph = {}
|
||||
dep_graph['__root__'] = cases.keys()
|
||||
for case in cases:
|
||||
if case in depends:
|
||||
dep_graph[case] = depends[case]
|
||||
else:
|
||||
dep_graph[case] = []
|
||||
|
||||
cases_ordered = []
|
||||
_dep_resolve(dep_graph, '__root__', cases_ordered, [])
|
||||
cases_ordered.remove('__root__')
|
||||
|
||||
return [cases[case_id] for case_id in cases_ordered]
|
||||
|
||||
def _skipTestDependency(case, depends):
|
||||
results = case.tc._results
|
||||
skipReasons = ['errors', 'failures', 'skipped']
|
||||
|
||||
for reason in skipReasons:
|
||||
for test, _ in results[reason]:
|
||||
if test.id() in depends:
|
||||
raise SkipTest("Test case %s depends on %s and was in %s." \
|
||||
% (case.id(), test.id(), reason))
|
||||
|
||||
@registerDecorator
|
||||
class OETestDepends(OETestDiscover):
|
||||
attrs = ('depends',)
|
||||
|
||||
def bind(self, registry, case):
|
||||
super(OETestDepends, self).bind(registry, case)
|
||||
if not registry.get('depends'):
|
||||
registry['depends'] = {}
|
||||
_add_depends(registry['depends'], case, self.depends)
|
||||
|
||||
@staticmethod
|
||||
def discover(registry):
|
||||
if registry.get('depends'):
|
||||
_validate_test_case_depends(registry['cases'], registry['depends'])
|
||||
return _order_test_case_by_depends(registry['cases'], registry['depends'])
|
||||
else:
|
||||
return [registry['cases'][case_id] for case_id in registry['cases']]
|
||||
|
||||
def setUpDecorator(self):
|
||||
_skipTestDependency(self.case, self.depends)
|
Loading…
Reference in New Issue