summaryrefslogtreecommitdiffstats
path: root/meta/lib
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2015-04-09 02:24:24 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-04-10 18:10:25 +0100
commitf626c58c325bfbf5fce1b5b2defafee9c6b74ea3 (patch)
tree9ef4e822c512b9b3c08a3fdba42605f7e7d3cf47 /meta/lib
parent206d532180eca9c32e86d1ee36d4b8c61b15436b (diff)
downloadpoky-f626c58c325bfbf5fce1b5b2defafee9c6b74ea3.tar.gz
testimage: sort modules based on dependencies
TEST_SUITES="auto" is useful to run all suitable tests without having to hard-code the list. However, it did not take test dependencies into account, which can be an issue for tests which really depend on some other test to run first. To fix this, modules get loaded in the order determined by TESTS_SUITES, but then get re-ordered based on dependencies derived from @skipUnlessPassed before running them. The original order is used to break ties when there are no dependencies, so reordering only occurs when really necessary. @skipUnlessPassed gets extended such that it makes the test name a method depends on available for inspection by the test loader in oetest.py. Unfortunately Python's unittest offers no API to inspect tests in a TestSuite, so the code has to rely on implementation details to find all tests. The worst that can happen when the implementation changes is that tests are not found and reordering does not happen. (From OE-Core rev: 6e4543a35836c572b23b9f8162b19d1e038d3ed2) Signed-off-by: Patrick Ohly <patrick.ohly@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib')
-rw-r--r--meta/lib/oeqa/oetest.py56
-rw-r--r--meta/lib/oeqa/utils/decorators.py1
2 files changed, 54 insertions, 3 deletions
diff --git a/meta/lib/oeqa/oetest.py b/meta/lib/oeqa/oetest.py
index a3c5c1d358..da9556a6da 100644
--- a/meta/lib/oeqa/oetest.py
+++ b/meta/lib/oeqa/oetest.py
@@ -27,9 +27,59 @@ def loadTests(tc, type="runtime"):
27 setattr(oeTest, "tc", tc) 27 setattr(oeTest, "tc", tc)
28 testloader = unittest.TestLoader() 28 testloader = unittest.TestLoader()
29 testloader.sortTestMethodsUsing = None 29 testloader.sortTestMethodsUsing = None
30 suite = testloader.loadTestsFromNames(tc.testslist) 30 suites = [testloader.loadTestsFromName(name) for name in tc.testslist]
31 31
32 return suite 32 def getTests(test):
33 '''Return all individual tests executed when running the suite.'''
34 # Unfortunately unittest does not have an API for this, so we have
35 # to rely on implementation details. This only needs to work
36 # for TestSuite containing TestCase.
37 method = getattr(test, '_testMethodName', None)
38 if method:
39 # leaf case: a TestCase
40 yield test
41 else:
42 # Look into TestSuite.
43 tests = getattr(test, '_tests', [])
44 for t1 in tests:
45 for t2 in getTests(t1):
46 yield t2
47
48 # Determine dependencies between suites by looking for @skipUnlessPassed
49 # method annotations. Suite A depends on suite B if any method in A
50 # depends on a method on B.
51 for suite in suites:
52 suite.dependencies = []
53 suite.depth = 0
54 for test in getTests(suite):
55 methodname = getattr(test, '_testMethodName', None)
56 if methodname:
57 method = getattr(test, methodname)
58 depends_on = getattr(method, '_depends_on', None)
59 if depends_on:
60 for dep_suite in suites:
61 if depends_on in [getattr(t, '_testMethodName', None) for t in getTests(dep_suite)]:
62 if dep_suite not in suite.dependencies and \
63 dep_suite is not suite:
64 suite.dependencies.append(dep_suite)
65 break
66 else:
67 bb.warn("Test %s was declared as @skipUnlessPassed('%s') but that test is either not defined or not active. Will run the test anyway." %
68 (test, depends_on))
69 # Use brute-force topological sort to determine ordering. Sort by
70 # depth (higher depth = must run later), with original ordering to
71 # break ties.
72 def set_suite_depth(suite):
73 for dep in suite.dependencies:
74 new_depth = set_suite_depth(dep) + 1
75 if new_depth > suite.depth:
76 suite.depth = new_depth
77 return suite.depth
78 for index, suite in enumerate(suites):
79 set_suite_depth(suite)
80 suite.index = index
81 suites.sort(cmp=lambda a,b: cmp((a.depth, a.index), (b.depth, b.index)))
82 return testloader.suiteClass(suites)
33 83
34def runTests(tc, type="runtime"): 84def runTests(tc, type="runtime"):
35 85
diff --git a/meta/lib/oeqa/utils/decorators.py b/meta/lib/oeqa/utils/decorators.py
index ff5f278bc1..1e5a890fdd 100644
--- a/meta/lib/oeqa/utils/decorators.py
+++ b/meta/lib/oeqa/utils/decorators.py
@@ -85,6 +85,7 @@ class skipUnlessPassed(object):
85 raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) 85 raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase)
86 return f(*args) 86 return f(*args)
87 wrapped_f.__name__ = f.__name__ 87 wrapped_f.__name__ = f.__name__
88 wrapped_f._depends_on = self.testcase
88 return wrapped_f 89 return wrapped_f
89 90
90class testcase(object): 91class testcase(object):