diff options
-rw-r--r-- | meta/classes/testimage.bbclass | 186 |
1 files changed, 144 insertions, 42 deletions
diff --git a/meta/classes/testimage.bbclass b/meta/classes/testimage.bbclass index 62ecaef502..016c1c136a 100644 --- a/meta/classes/testimage.bbclass +++ b/meta/classes/testimage.bbclass | |||
@@ -77,6 +77,7 @@ TESTIMAGEDEPENDS_qemuall += "${@bb.utils.contains('IMAGE_PKGTYPE', 'rpm', 'creat | |||
77 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'rpm', 'python-smartpm-native:do_populate_sysroot', '', d)}" | 77 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'rpm', 'python-smartpm-native:do_populate_sysroot', '', d)}" |
78 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'ipk', 'opkg-utils-native:do_populate_sysroot', '', d)}" | 78 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'ipk', 'opkg-utils-native:do_populate_sysroot', '', d)}" |
79 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'deb', 'apt-native:do_populate_sysroot', '', d)}" | 79 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'deb', 'apt-native:do_populate_sysroot', '', d)}" |
80 | TESTIMAGEDEPENDS += "${@bb.utils.contains('IMAGE_PKGTYPE', 'rpm', 'python-smartpm-native:do_populate_sysroot', '', d)}" | ||
80 | 81 | ||
81 | 82 | ||
82 | TESTIMAGELOCK = "${TMPDIR}/testimage.lock" | 83 | TESTIMAGELOCK = "${TMPDIR}/testimage.lock" |
@@ -112,6 +113,9 @@ testimage_dump_host () { | |||
112 | } | 113 | } |
113 | 114 | ||
114 | python do_testimage() { | 115 | python do_testimage() { |
116 | |||
117 | testimage_sanity(d) | ||
118 | |||
115 | testimage_main(d) | 119 | testimage_main(d) |
116 | } | 120 | } |
117 | 121 | ||
@@ -120,67 +124,165 @@ do_testimage[nostamp] = "1" | |||
120 | do_testimage[depends] += "${TESTIMAGEDEPENDS}" | 124 | do_testimage[depends] += "${TESTIMAGEDEPENDS}" |
121 | do_testimage[lockfiles] += "${TESTIMAGELOCK}" | 125 | do_testimage[lockfiles] += "${TESTIMAGELOCK}" |
122 | 126 | ||
127 | def testimage_sanity(d): | ||
128 | if (d.getVar('TEST_TARGET') == 'simpleremote' | ||
129 | and (not d.getVar('TEST_TARGET_IP') | ||
130 | or not d.getVar('TEST_SERVER_IP'))): | ||
131 | bb.fatal('When TEST_TARGET is set to "simpleremote" ' | ||
132 | 'TEST_TARGET_IP and TEST_SERVER_IP are needed too.') | ||
133 | |||
123 | def testimage_main(d): | 134 | def testimage_main(d): |
124 | import unittest | ||
125 | import os | 135 | import os |
126 | import oeqa.runtime | ||
127 | import time | ||
128 | import signal | 136 | import signal |
129 | from oeqa.oetest import ImageTestContext | 137 | import json |
130 | from oeqa.targetcontrol import get_target_controller | 138 | import sys |
131 | from bb.utils import export_proxies | 139 | import logging |
132 | from oeqa.utils.dump import HostDumper | 140 | import time |
133 | 141 | ||
142 | from bb.utils import export_proxies | ||
143 | from oeqa.runtime.context import OERuntimeTestContext | ||
144 | from oeqa.runtime.context import OERuntimeTestContextExecutor | ||
145 | from oeqa.core.target.qemu import supported_fstypes | ||
146 | from oeqa.utils import make_logger_bitbake_compatible | ||
147 | |||
148 | def sigterm_exception(signum, stackframe): | ||
149 | """ | ||
150 | Catch SIGTERM from worker in order to stop qemu. | ||
151 | """ | ||
152 | raise RuntimeError | ||
153 | |||
154 | logger = make_logger_bitbake_compatible(logging.getLogger("BitBake")) | ||
134 | pn = d.getVar("PN") | 155 | pn = d.getVar("PN") |
156 | |||
135 | bb.utils.mkdirhier(d.getVar("TEST_LOG_DIR")) | 157 | bb.utils.mkdirhier(d.getVar("TEST_LOG_DIR")) |
136 | test_create_extract_dirs(d) | 158 | #test_create_extract_dirs(d) |
159 | |||
160 | image_name = ("%s/%s" % (d.getVar('DEPLOY_DIR_IMAGE'), | ||
161 | d.getVar('IMAGE_LINK_NAME'))) | ||
162 | |||
163 | tdname = "%s.testdata.json" % image_name | ||
164 | td = json.load(open(tdname, "r")) | ||
165 | |||
166 | image_manifest = "%s.manifest" % image_name | ||
167 | image_packages = OERuntimeTestContextExecutor.readPackagesManifest(image_manifest) | ||
168 | |||
169 | # Get machine | ||
170 | machine = d.getVar("MACHINE") | ||
171 | |||
172 | # Get rootfs | ||
173 | fstypes = [fs for fs in d.getVar('IMAGE_FSTYPES').split(' ') | ||
174 | if fs in supported_fstypes] | ||
175 | if not fstypes: | ||
176 | bb.fatal('Unsupported image type built. Add a comptible image to ' | ||
177 | 'IMAGE_FSTYPES. Supported types: %s' % | ||
178 | ', '.join(supported_fstypes)) | ||
179 | rootfs = '%s.%s' % (image_name, fstypes[0]) | ||
180 | |||
181 | # Get tmpdir (not really used, just for compatibility) | ||
182 | tmpdir = d.getVar("TMPDIR") | ||
183 | |||
184 | # Get deploy_dir_image (not really used, just for compatibility) | ||
185 | dir_image = d.getVar("DEPLOY_DIR_IMAGE") | ||
186 | |||
187 | # Get bootlog | ||
188 | bootlog = os.path.join(d.getVar("TEST_LOG_DIR"), | ||
189 | 'qemu_boot_log.%s' % d.getVar('DATETIME')) | ||
190 | |||
191 | # Get display | ||
192 | display = d.getVar("BB_ORIGENV").getVar("DISPLAY") | ||
193 | |||
194 | # Get kernel | ||
195 | kernel_name = ('%s-%s.bin' % (d.getVar("KERNEL_IMAGETYPE"), machine)) | ||
196 | kernel = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), kernel_name) | ||
197 | |||
198 | # Get boottime | ||
199 | boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")) | ||
200 | |||
201 | # Get use_kvm | ||
202 | qemu_use_kvm = d.getVar("QEMU_USE_KVM") | ||
203 | if qemu_use_kvm and qemu_use_kvm == 'True' and 'x86' in machine: | ||
204 | kvm = True | ||
205 | else: | ||
206 | kvm = False | ||
207 | |||
208 | # TODO: We use the current implementatin of qemu runner because of | ||
209 | # time constrains, qemu runner really needs a refactor too. | ||
210 | target_kwargs = { 'machine' : machine, | ||
211 | 'rootfs' : rootfs, | ||
212 | 'tmpdir' : tmpdir, | ||
213 | 'dir_image' : dir_image, | ||
214 | 'display' : display, | ||
215 | 'kernel' : kernel, | ||
216 | 'boottime' : boottime, | ||
217 | 'bootlog' : bootlog, | ||
218 | 'kvm' : kvm, | ||
219 | } | ||
137 | 220 | ||
138 | # runtime use network for download projects for build | 221 | # runtime use network for download projects for build |
139 | export_proxies(d) | 222 | export_proxies(d) |
140 | 223 | ||
141 | # we need the host dumper in test context | 224 | # we need the host dumper in test context |
142 | host_dumper = HostDumper(d.getVar("testimage_dump_host", True), | 225 | host_dumper = OERuntimeTestContextExecutor.getHostDumper( |
143 | d.getVar("TESTIMAGE_DUMP_DIR", True)) | 226 | d.getVar("testimage_dump_host"), |
227 | d.getVar("TESTIMAGE_DUMP_DIR")) | ||
144 | 228 | ||
145 | # the robot dance | 229 | # the robot dance |
146 | target = get_target_controller(d) | 230 | target = OERuntimeTestContextExecutor.getTarget( |
231 | d.getVar("TEST_TARGET"), None, d.getVar("TEST_TARGET_IP"), | ||
232 | d.getVar("TEST_SERVER_IP"), **target_kwargs) | ||
147 | 233 | ||
148 | # test context | 234 | # test context |
149 | tc = ImageTestContext(d, target, host_dumper) | 235 | tc = OERuntimeTestContext(td, logger, target, host_dumper, image_packages) |
150 | 236 | ||
151 | # this is a dummy load of tests | 237 | # Load tests before starting the target |
152 | # we are doing that to find compile errors in the tests themselves | 238 | test_paths = get_runtime_paths(d) |
153 | # before booting the image | 239 | test_modules = d.getVar('TEST_SUITES') |
154 | try: | 240 | tc.loadTests(test_paths, modules=test_modules) |
155 | tc.loadTests() | 241 | |
156 | except Exception as e: | 242 | bootparams = None |
157 | import traceback | 243 | if d.getVar('VIRTUAL-RUNTIME_init_manager', '') == 'systemd': |
158 | bb.fatal("Loading tests failed:\n%s" % traceback.format_exc()) | 244 | bootparams = 'systemd.log_level=debug systemd.log_target=console' |
159 | 245 | ||
160 | tc.extract_packages() | 246 | results = None |
161 | target.deploy() | 247 | orig_sigterm_handler = signal.signal(signal.SIGTERM, sigterm_exception) |
162 | try: | 248 | try: |
163 | bootparams = None | 249 | # We need to check if runqemu ends unexpectedly |
164 | if d.getVar('VIRTUAL-RUNTIME_init_manager', '') == 'systemd': | 250 | # or if the worker send us a SIGTERM |
165 | bootparams = 'systemd.log_level=debug systemd.log_target=console' | 251 | tc.target.start(extra_bootparams=bootparams) |
166 | target.start(extra_bootparams=bootparams) | 252 | results = tc.runTests() |
167 | starttime = time.time() | 253 | except (RuntimeError, BlockingIOError) as err: |
168 | result = tc.runTests() | 254 | if isinstance(err, RuntimeError): |
169 | stoptime = time.time() | 255 | bb.error('testimage received SIGTERM, shutting down...') |
170 | if result.wasSuccessful(): | ||
171 | bb.plain("%s - Ran %d test%s in %.3fs" % (pn, result.testsRun, result.testsRun != 1 and "s" or "", stoptime - starttime)) | ||
172 | msg = "%s - OK - All required tests passed" % pn | ||
173 | skipped = len(result.skipped) | ||
174 | if skipped: | ||
175 | msg += " (skipped=%d)" % skipped | ||
176 | bb.plain(msg) | ||
177 | else: | 256 | else: |
178 | bb.fatal("%s - FAILED - check the task log and the ssh log" % pn) | 257 | bb.error('runqemu failed, shutting down...') |
179 | except BlockingIOError as err: | 258 | if results: |
180 | bb.error('runqemu failed, shutting down...') | 259 | results.stop() |
260 | results = None | ||
181 | finally: | 261 | finally: |
182 | signal.signal(signal.SIGTERM, tc.origsigtermhandler) | 262 | signal.signal(signal.SIGTERM, orig_sigterm_handler) |
183 | target.stop() | 263 | tc.target.stop() |
264 | |||
265 | # Show results (if we have them) | ||
266 | if not results: | ||
267 | bb.fatal('%s - FAILED - tests were interrupted during execution' % pn) | ||
268 | tc.logSummary(results, pn) | ||
269 | tc.logDetails() | ||
270 | if not results.wasSuccessful(): | ||
271 | bb.fatal('%s - FAILED - check the task log and the ssh log' % pn) | ||
272 | |||
273 | def get_runtime_paths(d): | ||
274 | """ | ||
275 | Returns a list of paths where runtime test must reside. | ||
276 | |||
277 | Runtime tests are expected in <LAYER_DIR>/lib/oeqa/runtime/cases/ | ||
278 | """ | ||
279 | paths = [] | ||
280 | |||
281 | for layer in d.getVar('BBLAYERS').split(): | ||
282 | path = os.path.join(layer, 'lib/oeqa/runtime/cases') | ||
283 | if os.path.isdir(path): | ||
284 | paths.append(path) | ||
285 | return paths | ||
184 | 286 | ||
185 | def test_create_extract_dirs(d): | 287 | def test_create_extract_dirs(d): |
186 | install_path = d.getVar("TEST_INSTALL_TMP_DIR") | 288 | install_path = d.getVar("TEST_INSTALL_TMP_DIR") |
@@ -193,6 +295,6 @@ def test_create_extract_dirs(d): | |||
193 | bb.utils.mkdirhier(extracted_path) | 295 | bb.utils.mkdirhier(extracted_path) |
194 | 296 | ||
195 | 297 | ||
196 | testimage_main[vardepsexclude] =+ "BB_ORIGENV" | 298 | testimage_main[vardepsexclude] += "BB_ORIGENV DATETIME" |
197 | 299 | ||
198 | inherit testsdk | 300 | inherit testsdk |