blob: 6f9edec58d74dc94775946ded106af5f0bd91119 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Copyright (C) 2013 Intel Corporation
2#
3# Released under the MIT license (see COPYING.MIT)
4
5# Main unittest module used by testimage.bbclass
6# This provides the oeRuntimeTest base class which is inherited by all tests in meta/lib/oeqa/runtime.
7
8# It also has some helper functions and it's responsible for actually starting the tests
9
10import os, re, mmap
11import unittest
12import inspect
13import subprocess
Patrick Williamsf1e5d692016-03-30 15:21:19 -050014try:
15 import bb
16except ImportError:
17 pass
18import logging
19from oeqa.utils.decorators import LogResults, gettag, getResults
20
21logger = logging.getLogger("BitBake")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022
23def getVar(obj):
24 #extend form dict, if a variable didn't exists, need find it in testcase
25 class VarDict(dict):
26 def __getitem__(self, key):
27 return gettag(obj, key)
28 return VarDict()
29
30def checkTags(tc, tagexp):
31 return eval(tagexp, None, getVar(tc))
32
33
34def filterByTagExp(testsuite, tagexp):
35 if not tagexp:
36 return testsuite
37 caseList = []
38 for each in testsuite:
39 if not isinstance(each, unittest.BaseTestSuite):
40 if checkTags(each, tagexp):
41 caseList.append(each)
42 else:
43 caseList.append(filterByTagExp(each, tagexp))
44 return testsuite.__class__(caseList)
45
46def loadTests(tc, type="runtime"):
47 if type == "runtime":
48 # set the context object passed from the test class
49 setattr(oeTest, "tc", tc)
50 # set ps command to use
51 setattr(oeRuntimeTest, "pscmd", "ps -ef" if oeTest.hasPackage("procps") else "ps")
52 # prepare test suite, loader and runner
53 suite = unittest.TestSuite()
54 elif type == "sdk":
55 # set the context object passed from the test class
56 setattr(oeTest, "tc", tc)
57 testloader = unittest.TestLoader()
58 testloader.sortTestMethodsUsing = None
59 suites = [testloader.loadTestsFromName(name) for name in tc.testslist]
60 suites = filterByTagExp(suites, getattr(tc, "tagexp", None))
61
62 def getTests(test):
63 '''Return all individual tests executed when running the suite.'''
64 # Unfortunately unittest does not have an API for this, so we have
65 # to rely on implementation details. This only needs to work
66 # for TestSuite containing TestCase.
67 method = getattr(test, '_testMethodName', None)
68 if method:
69 # leaf case: a TestCase
70 yield test
71 else:
72 # Look into TestSuite.
73 tests = getattr(test, '_tests', [])
74 for t1 in tests:
75 for t2 in getTests(t1):
76 yield t2
77
78 # Determine dependencies between suites by looking for @skipUnlessPassed
79 # method annotations. Suite A depends on suite B if any method in A
80 # depends on a method on B.
81 for suite in suites:
82 suite.dependencies = []
83 suite.depth = 0
84 for test in getTests(suite):
85 methodname = getattr(test, '_testMethodName', None)
86 if methodname:
87 method = getattr(test, methodname)
88 depends_on = getattr(method, '_depends_on', None)
89 if depends_on:
90 for dep_suite in suites:
91 if depends_on in [getattr(t, '_testMethodName', None) for t in getTests(dep_suite)]:
92 if dep_suite not in suite.dependencies and \
93 dep_suite is not suite:
94 suite.dependencies.append(dep_suite)
95 break
96 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050097 logger.warning("Test %s was declared as @skipUnlessPassed('%s') but that test is either not defined or not active. Will run the test anyway." %
Patrick Williamsc124f4f2015-09-15 14:41:29 -050098 (test, depends_on))
99 # Use brute-force topological sort to determine ordering. Sort by
100 # depth (higher depth = must run later), with original ordering to
101 # break ties.
102 def set_suite_depth(suite):
103 for dep in suite.dependencies:
104 new_depth = set_suite_depth(dep) + 1
105 if new_depth > suite.depth:
106 suite.depth = new_depth
107 return suite.depth
108 for index, suite in enumerate(suites):
109 set_suite_depth(suite)
110 suite.index = index
111 suites.sort(cmp=lambda a,b: cmp((a.depth, a.index), (b.depth, b.index)))
112 return testloader.suiteClass(suites)
113
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500114_buffer = ""
115
116def custom_verbose(msg, *args, **kwargs):
117 global _buffer
118 if msg[-1] != "\n":
119 _buffer += msg
120 else:
121 _buffer += msg
122 try:
123 bb.plain(_buffer.rstrip("\n"), *args, **kwargs)
124 except NameError:
125 logger.info(_buffer.rstrip("\n"), *args, **kwargs)
126 _buffer = ""
127
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500128def runTests(tc, type="runtime"):
129
130 suite = loadTests(tc, type)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500131 logger.info("Test modules %s" % tc.testslist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 if hasattr(tc, "tagexp") and tc.tagexp:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500133 logger.info("Filter test cases by tags: %s" % tc.tagexp)
134 logger.info("Found %s tests" % suite.countTestCases())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135 runner = unittest.TextTestRunner(verbosity=2)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500136 try:
137 if bb.msg.loggerDefaultVerbose:
138 runner.stream.write = custom_verbose
139 except NameError:
140 # Not in bb environment?
141 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142 result = runner.run(suite)
143
144 return result
145
146@LogResults
147class oeTest(unittest.TestCase):
148
149 longMessage = True
150
151 @classmethod
152 def hasPackage(self, pkg):
153 for item in oeTest.tc.pkgmanifest.split('\n'):
154 if re.match(pkg, item):
155 return True
156 return False
157
158 @classmethod
159 def hasFeature(self,feature):
160
161 if feature in oeTest.tc.imagefeatures or \
162 feature in oeTest.tc.distrofeatures:
163 return True
164 else:
165 return False
166
167class oeRuntimeTest(oeTest):
168 def __init__(self, methodName='runTest'):
169 self.target = oeRuntimeTest.tc.target
170 super(oeRuntimeTest, self).__init__(methodName)
171
172 def setUp(self):
173 # Check if test needs to run
174 if self.tc.sigterm:
175 self.fail("Got SIGTERM")
176 elif (type(self.target).__name__ == "QemuTarget"):
177 self.assertTrue(self.target.check(), msg = "Qemu not running?")
178
Patrick Williamsd7e96312015-09-22 08:09:05 -0500179 self.setUpLocal()
180
181 # a setup method before tests but after the class instantiation
182 def setUpLocal(self):
183 pass
184
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185 def tearDown(self):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500186 res = getResults()
187 # If a test fails or there is an exception dump
188 # for QemuTarget only
189 if (type(self.target).__name__ == "QemuTarget" and
190 (self.id() in res.getErrorList() or
191 self.id() in res.getFailList())):
192 self.tc.host_dumper.create_dir(self._testMethodName)
193 self.tc.host_dumper.dump_host()
194 self.target.target_dumper.dump_target(
195 self.tc.host_dumper.dump_dir)
196 print ("%s dump data stored in %s" % (self._testMethodName,
197 self.tc.host_dumper.dump_dir))
198
199 self.tearDownLocal()
200
201 # Method to be run after tearDown and implemented by child classes
202 def tearDownLocal(self):
203 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500204
205 #TODO: use package_manager.py to install packages on any type of image
206 def install_packages(self, packagelist):
207 for package in packagelist:
208 (status, result) = self.target.run("smart install -y "+package)
209 if status != 0:
210 return status
211
212class oeSDKTest(oeTest):
213 def __init__(self, methodName='runTest'):
214 self.sdktestdir = oeSDKTest.tc.sdktestdir
215 super(oeSDKTest, self).__init__(methodName)
216
217 @classmethod
218 def hasHostPackage(self, pkg):
219
220 if re.search(pkg, oeTest.tc.hostpkgmanifest):
221 return True
222 return False
223
224 def _run(self, cmd):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500225 return subprocess.check_output(". %s; " % self.tc.sdkenv + cmd, shell=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500226
227def getmodule(pos=2):
228 # stack returns a list of tuples containg frame information
229 # First element of the list the is current frame, caller is 1
230 frameinfo = inspect.stack()[pos]
231 modname = inspect.getmodulename(frameinfo[1])
232 #modname = inspect.getmodule(frameinfo[0]).__name__
233 return modname
234
235def skipModule(reason, pos=2):
236 modname = getmodule(pos)
237 if modname not in oeTest.tc.testsrequired:
238 raise unittest.SkipTest("%s: %s" % (modname, reason))
239 else:
240 raise Exception("\nTest %s wants to be skipped.\nReason is: %s" \
241 "\nTest was required in TEST_SUITES, so either the condition for skipping is wrong" \
242 "\nor the image really doesn't have the required feature/package when it should." % (modname, reason))
243
244def skipModuleIf(cond, reason):
245
246 if cond:
247 skipModule(reason, 3)
248
249def skipModuleUnless(cond, reason):
250
251 if not cond:
252 skipModule(reason, 3)