summaryrefslogtreecommitdiffstats
path: root/meta/classes/testimage.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/testimage.bbclass')
-rw-r--r--meta/classes/testimage.bbclass179
1 files changed, 179 insertions, 0 deletions
diff --git a/meta/classes/testimage.bbclass b/meta/classes/testimage.bbclass
new file mode 100644
index 0000000000..2f9c974554
--- /dev/null
+++ b/meta/classes/testimage.bbclass
@@ -0,0 +1,179 @@
1# Copyright (C) 2013 Intel Corporation
2#
3# Released under the MIT license (see COPYING.MIT)
4
5
6# testimage.bbclass enables testing of qemu images using python unittests.
7# Most of the tests are commands run on target image over ssh.
8# To use it add testimage to global inherit and call your target image with -c testimage
9# You can try it out like this:
10# - first build a qemu core-image-sato
11# - add INHERIT += "testimage" in local.conf
12# - then bitbake core-image-sato -c testimage. That will run a standard suite of tests.
13
14# You can set (or append to) TEST_SUITES in local.conf to select the tests
15# which you want to run for your target.
16# The test names are the module names in meta/lib/oeqa/runtime.
17# Each name in TEST_SUITES represents a required test for the image. (no skipping allowed)
18# Appending "auto" means that it will try to run all tests that are suitable for the image (each test decides that on it's own).
19# Note that order in TEST_SUITES is important (it's the order tests run) and it influences tests dependencies.
20# A layer can add its own tests in lib/oeqa/runtime, provided it extends BBPATH as normal in its layer.conf.
21
22# TEST_LOG_DIR contains a ssh log (what command is running, output and return codes) and a qemu boot log till login
23# Booting is handled by this class, and it's not a test in itself.
24# TEST_QEMUBOOT_TIMEOUT can be used to set the maximum time in seconds the launch code will wait for the login prompt.
25
26TEST_LOG_DIR ?= "${WORKDIR}/testimage"
27
28DEFAULT_TEST_SUITES = "ping auto"
29DEFAULT_TEST_SUITES_pn-core-image-minimal = "ping"
30DEFAULT_TEST_SUITES_pn-core-image-sato = "ping ssh df connman syslog xorg scp vnc date rpm smart dmesg"
31DEFAULT_TEST_SUITES_pn-core-image-sato-sdk = "ping ssh df connman syslog xorg scp vnc date perl ldd gcc rpm smart dmesg"
32
33TEST_SUITES ?= "${DEFAULT_TEST_SUITES}"
34
35TEST_QEMUBOOT_TIMEOUT ?= "1000"
36
37python do_testimage() {
38 testimage_main(d)
39}
40addtask testimage
41do_testimage[nostamp] = "1"
42do_testimage[depends] += "qemu-native:do_populate_sysroot"
43do_testimage[depends] += "qemu-helper-native:do_populate_sysroot"
44
45
46def get_tests_list(d):
47 testsuites = d.getVar("TEST_SUITES", True).split()
48 bbpath = d.getVar("BBPATH", True).split(':')
49
50 # This relies on lib/ under each directory in BBPATH being added to sys.path
51 # (as done by default in base.bbclass)
52 testslist = []
53 for testname in testsuites:
54 if testname != "auto":
55 found = False
56 for p in bbpath:
57 if os.path.exists(os.path.join(p, 'lib', 'oeqa', 'runtime', testname + '.py')):
58 testslist.append("oeqa.runtime." + testname)
59 found = True
60 break
61 if not found:
62 bb.error('Test %s specified in TEST_SUITES could not be found in lib/oeqa/runtime under BBPATH' % testname)
63
64 if "auto" in testsuites:
65 def add_auto_list(path):
66 if not os.path.exists(os.path.join(path, '__init__.py')):
67 bb.fatal('Tests directory %s exists but is missing __init__.py' % path)
68 files = sorted([f for f in os.listdir(path) if f.endswith('.py') and not f.startswith('_')])
69 for f in files:
70 module = 'oeqa.runtime.' + f[:-3]
71 if module not in testslist:
72 testslist.append(module)
73
74 for p in bbpath:
75 testpath = os.path.join(p, 'lib', 'oeqa', 'runtime')
76 bb.debug(2, 'Searching for tests in %s' % testpath)
77 if os.path.exists(testpath):
78 add_auto_list(testpath)
79
80 return testslist
81
82def testimage_main(d):
83 import unittest
84 import os
85 import oeqa.runtime
86 import re
87 import shutil
88 import time
89 from oeqa.oetest import runTests
90 from oeqa.utils.sshcontrol import SSHControl
91 from oeqa.utils.qemurunner import QemuRunner
92
93 testdir = d.getVar("TEST_LOG_DIR", True)
94 bb.utils.mkdirhier(testdir)
95
96 # tests in TEST_SUITES become required tests
97 # they won't be skipped even if they aren't suitable for a image (like xorg for minimal)
98 # testslist is what we'll actually pass to the unittest loader
99 testslist = get_tests_list(d)
100 testsrequired = [t for t in d.getVar("TEST_SUITES", True).split() if t != "auto"]
101
102 class TestContext:
103 def __init__(self):
104 self.d = d
105 self.testslist = testslist
106 self.testsrequired = testsrequired
107 self.filesdir = os.path.join(os.path.dirname(os.path.abspath(oeqa.runtime.__file__)),"files")
108
109 # test context
110 tc = TestContext()
111
112 # prepare qemu instance
113 # and boot each supported fs type
114 machine=d.getVar("MACHINE", True)
115 #will handle fs type eventually, stick with ext3 for now
116 #make a copy of the original rootfs and use that for tests
117 origrootfs=os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("IMAGE_LINK_NAME",True) + '.ext3')
118 testrootfs=os.path.join(testdir, d.getVar("IMAGE_LINK_NAME", True) + '-testimage.ext3')
119 try:
120 shutil.copyfile(origrootfs, testrootfs)
121 except Exception as e:
122 bb.fatal("Error copying rootfs: %s" % e)
123
124 try:
125 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT", True))
126 except ValueError:
127 boottime = 1000
128
129 qemu = QemuRunner(machine=machine, rootfs=testrootfs,
130 tmpdir = d.getVar("TMPDIR", True),
131 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE", True),
132 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY", True),
133 logfile = os.path.join(testdir, "qemu_boot_log.%s" % d.getVar('DATETIME', True)),
134 boottime = boottime)
135
136 qemuloglink = os.path.join(testdir, "qemu_boot_log")
137 if os.path.islink(qemuloglink):
138 os.unlink(qemuloglink)
139 os.symlink(qemu.logfile, qemuloglink)
140
141 sshlog = os.path.join(testdir, "ssh_target_log.%s" % d.getVar('DATETIME', True))
142 sshloglink = os.path.join(testdir, "ssh_target_log")
143 if os.path.islink(sshloglink):
144 os.unlink(sshloglink)
145 os.symlink(sshlog, sshloglink)
146
147 bb.note("DISPLAY value: %s" % qemu.display)
148 bb.note("rootfs file: %s" % qemu.rootfs)
149 bb.note("Qemu log file: %s" % qemu.logfile)
150 bb.note("SSH log file: %s" % sshlog)
151
152 pn = d.getVar("PN", True)
153 #catch exceptions when loading or running tests (mostly our own errors)
154 try:
155 if qemu.launch():
156
157 # set more context - ssh instance and qemu
158 # we do these here because we needed qemu to boot and get the ip
159 tc.qemu = qemu
160 tc.target = SSHControl(host=qemu.ip,logfile=sshlog)
161 # run tests and get the results
162 starttime = time.time()
163 result = runTests(tc)
164 stoptime = time.time()
165 if result.wasSuccessful():
166 bb.plain("%s - Ran %d test%s in %.3fs" % (pn, result.testsRun, result.testsRun != 1 and "s" or "", stoptime - starttime))
167 msg = "%s - OK - All required tests passed" % pn
168 skipped = len(result.skipped)
169 if skipped:
170 msg += " (skipped=%d)" % skipped
171 bb.plain(msg)
172 else:
173 raise bb.build.FuncFailed("%s - FAILED - check the task log and the ssh log" % pn )
174 else:
175 raise bb.build.FuncFailed("%s - FAILED to start qemu - check the task log and the boot log" % pn)
176 finally:
177 qemu.kill()
178
179testimage_main[vardepsexclude] =+ "BB_ORIGENV"