summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
Diffstat (limited to 'meta')
-rw-r--r--meta/classes/testimage-auto.bbclass3
-rw-r--r--meta/classes/testimage.bbclass104
-rw-r--r--meta/lib/oeqa/oetest.py20
-rw-r--r--meta/lib/oeqa/runtime/ping.py2
-rw-r--r--meta/lib/oeqa/runtime/smart.py4
-rw-r--r--meta/lib/oeqa/utils/qemurunner.py50
-rw-r--r--meta/lib/oeqa/utils/sshcontrol.py20
7 files changed, 87 insertions, 116 deletions
diff --git a/meta/classes/testimage-auto.bbclass b/meta/classes/testimage-auto.bbclass
index 3d0e28994a..a5b8f7f14a 100644
--- a/meta/classes/testimage-auto.bbclass
+++ b/meta/classes/testimage-auto.bbclass
@@ -19,5 +19,4 @@ python do_testimage_auto() {
19 testimage_main(d) 19 testimage_main(d)
20} 20}
21addtask testimage_auto before do_build after do_rootfs 21addtask testimage_auto before do_build after do_rootfs
22do_testimage_auto[depends] += "qemu-native:do_populate_sysroot" 22do_testimage_auto[depends] += "${TESTIMAGEDEPENDS}"
23do_testimage_auto[depends] += "qemu-helper-native:do_populate_sysroot"
diff --git a/meta/classes/testimage.bbclass b/meta/classes/testimage.bbclass
index 5d61c2baee..add8009d47 100644
--- a/meta/classes/testimage.bbclass
+++ b/meta/classes/testimage.bbclass
@@ -34,13 +34,19 @@ TEST_SUITES ?= "${DEFAULT_TEST_SUITES}"
34 34
35TEST_QEMUBOOT_TIMEOUT ?= "1000" 35TEST_QEMUBOOT_TIMEOUT ?= "1000"
36 36
37TEST_TARGET ?= "qemu"
38TEST_TARGET_IP ?= ""
39TEST_SERVER_IP ?= ""
40
41TESTIMAGEDEPENDS = ""
42TESTIMAGEDEPENDS_qemuall = "qemu-native:do_populate_sysroot qemu-helper-native:do_populate_sysroot"
43
37python do_testimage() { 44python do_testimage() {
38 testimage_main(d) 45 testimage_main(d)
39} 46}
40addtask testimage 47addtask testimage
41do_testimage[nostamp] = "1" 48do_testimage[nostamp] = "1"
42do_testimage[depends] += "qemu-native:do_populate_sysroot" 49do_testimage[depends] += "${TESTIMAGEDEPENDS}"
43do_testimage[depends] += "qemu-helper-native:do_populate_sysroot"
44 50
45 51
46def get_tests_list(d): 52def get_tests_list(d):
@@ -83,15 +89,12 @@ def testimage_main(d):
83 import unittest 89 import unittest
84 import os 90 import os
85 import oeqa.runtime 91 import oeqa.runtime
86 import re
87 import shutil
88 import time 92 import time
89 from oeqa.oetest import runTests 93 from oeqa.oetest import loadTests, runTests
90 from oeqa.utils.sshcontrol import SSHControl 94 from oeqa.targetcontrol import get_target_controller
91 from oeqa.utils.qemurunner import QemuRunner
92 95
93 testdir = d.getVar("TEST_LOG_DIR", True) 96 pn = d.getVar("PN", True)
94 bb.utils.mkdirhier(testdir) 97 bb.utils.mkdirhier(d.getVar("TEST_LOG_DIR", True))
95 98
96 # tests in TEST_SUITES become required tests 99 # 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) 100 # they won't be skipped even if they aren't suitable for a image (like xorg for minimal)
@@ -99,81 +102,46 @@ def testimage_main(d):
99 testslist = get_tests_list(d) 102 testslist = get_tests_list(d)
100 testsrequired = [t for t in d.getVar("TEST_SUITES", True).split() if t != "auto"] 103 testsrequired = [t for t in d.getVar("TEST_SUITES", True).split() if t != "auto"]
101 104
105 # the robot dance
106 target = get_target_controller(d)
107
102 class TestContext: 108 class TestContext:
103 def __init__(self): 109 def __init__(self):
104 self.d = d 110 self.d = d
105 self.testslist = testslist 111 self.testslist = testslist
106 self.testsrequired = testsrequired 112 self.testsrequired = testsrequired
107 self.filesdir = os.path.join(os.path.dirname(os.path.abspath(oeqa.runtime.__file__)),"files") 113 self.filesdir = os.path.join(os.path.dirname(os.path.abspath(oeqa.runtime.__file__)),"files")
114 self.target = target
108 115
109 # test context 116 # test context
110 tc = TestContext() 117 tc = TestContext()
111 118
112 # prepare qemu instance 119 # this is a dummy load of tests
113 # and boot each supported fs type 120 # we are doing that to find compile errors in the tests themselves
114 machine=d.getVar("MACHINE", True) 121 # before booting the image
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: 122 try:
120 shutil.copyfile(origrootfs, testrootfs) 123 loadTests(tc)
121 except Exception as e: 124 except Exception as e:
122 bb.fatal("Error copying rootfs: %s" % e) 125 bb.fatal("Loading tests failed:\n %s" % e)
123 126
124 try: 127 target.deploy()
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 128
152 pn = d.getVar("PN", True)
153 #catch exceptions when loading or running tests (mostly our own errors)
154 try: 129 try:
155 if qemu.launch(): 130 target.start()
156 131 # run tests and get the results
157 # set more context - ssh instance and qemu 132 starttime = time.time()
158 # we do these here because we needed qemu to boot and get the ip 133 result = runTests(tc)
159 tc.qemu = qemu 134 stoptime = time.time()
160 tc.target = SSHControl(host=qemu.ip,logfile=sshlog) 135 if result.wasSuccessful():
161 # run tests and get the results 136 bb.plain("%s - Ran %d test%s in %.3fs" % (pn, result.testsRun, result.testsRun != 1 and "s" or "", stoptime - starttime))
162 starttime = time.time() 137 msg = "%s - OK - All required tests passed" % pn
163 result = runTests(tc) 138 skipped = len(result.skipped)
164 stoptime = time.time() 139 if skipped:
165 if result.wasSuccessful(): 140 msg += " (skipped=%d)" % skipped
166 bb.plain("%s - Ran %d test%s in %.3fs" % (pn, result.testsRun, result.testsRun != 1 and "s" or "", stoptime - starttime)) 141 bb.plain(msg)
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: 142 else:
175 raise bb.build.FuncFailed("%s - FAILED to start qemu - check the task log and the boot log" % pn) 143 raise bb.build.FuncFailed("%s - FAILED - check the task log and the ssh log" % pn )
176 finally: 144 finally:
177 qemu.kill() 145 target.stop()
178 146
179testimage_main[vardepsexclude] =+ "BB_ORIGENV" 147testimage_main[vardepsexclude] =+ "BB_ORIGENV"
diff --git a/meta/lib/oeqa/oetest.py b/meta/lib/oeqa/oetest.py
index 95661506e3..70d12a225e 100644
--- a/meta/lib/oeqa/oetest.py
+++ b/meta/lib/oeqa/oetest.py
@@ -14,7 +14,7 @@ import bb
14from oeqa.utils.sshcontrol import SSHControl 14from oeqa.utils.sshcontrol import SSHControl
15 15
16 16
17def runTests(tc): 17def loadTests(tc):
18 18
19 # set the context object passed from the test class 19 # set the context object passed from the test class
20 setattr(oeTest, "tc", tc) 20 setattr(oeTest, "tc", tc)
@@ -24,12 +24,16 @@ def runTests(tc):
24 suite = unittest.TestSuite() 24 suite = unittest.TestSuite()
25 testloader = unittest.TestLoader() 25 testloader = unittest.TestLoader()
26 testloader.sortTestMethodsUsing = None 26 testloader.sortTestMethodsUsing = None
27 runner = unittest.TextTestRunner(verbosity=2) 27 suite = testloader.loadTestsFromNames(tc.testslist)
28
29 return suite
30
31def runTests(tc):
28 32
33 suite = loadTests(tc)
29 bb.note("Test modules %s" % tc.testslist) 34 bb.note("Test modules %s" % tc.testslist)
30 suite = testloader.loadTestsFromNames(tc.testslist)
31 bb.note("Found %s tests" % suite.countTestCases()) 35 bb.note("Found %s tests" % suite.countTestCases())
32 36 runner = unittest.TextTestRunner(verbosity=2)
33 result = runner.run(suite) 37 result = runner.run(suite)
34 38
35 return result 39 return result
@@ -81,11 +85,7 @@ class oeRuntimeTest(oeTest):
81 85
82 @classmethod 86 @classmethod
83 def restartTarget(self,params=None): 87 def restartTarget(self,params=None):
84 88 oeRuntimeTest.tc.target.restart(params)
85 if oeRuntimeTest.tc.qemu.restart(params):
86 oeRuntimeTest.tc.target.host = oeRuntimeTest.tc.qemu.ip
87 else:
88 raise Exception("Restarting target failed")
89 89
90 90
91def getmodule(pos=2): 91def getmodule(pos=2):
@@ -103,7 +103,7 @@ def skipModule(reason, pos=2):
103 else: 103 else:
104 raise Exception("\nTest %s wants to be skipped.\nReason is: %s" \ 104 raise Exception("\nTest %s wants to be skipped.\nReason is: %s" \
105 "\nTest was required in TEST_SUITES, so either the condition for skipping is wrong" \ 105 "\nTest was required in TEST_SUITES, so either the condition for skipping is wrong" \
106 "\nor the image really doesn't have the requred feature/package when it should." % (modname, reason)) 106 "\nor the image really doesn't have the required feature/package when it should." % (modname, reason))
107 107
108def skipModuleIf(cond, reason): 108def skipModuleIf(cond, reason):
109 109
diff --git a/meta/lib/oeqa/runtime/ping.py b/meta/lib/oeqa/runtime/ping.py
index 0d028f9b22..a73c72402a 100644
--- a/meta/lib/oeqa/runtime/ping.py
+++ b/meta/lib/oeqa/runtime/ping.py
@@ -11,7 +11,7 @@ class PingTest(oeRuntimeTest):
11 count = 0 11 count = 0
12 endtime = time.time() + 60 12 endtime = time.time() + 60
13 while count < 5 and time.time() < endtime: 13 while count < 5 and time.time() < endtime:
14 proc = subprocess.Popen("ping -c 1 %s" % oeRuntimeTest.tc.qemu.ip, shell=True, stdout=subprocess.PIPE) 14 proc = subprocess.Popen("ping -c 1 %s" % self.target.ip, shell=True, stdout=subprocess.PIPE)
15 output += proc.communicate()[0] 15 output += proc.communicate()[0]
16 if proc.poll() == 0: 16 if proc.poll() == 0:
17 count += 1 17 count += 1
diff --git a/meta/lib/oeqa/runtime/smart.py b/meta/lib/oeqa/runtime/smart.py
index c3fdf7d499..7ef4b0e649 100644
--- a/meta/lib/oeqa/runtime/smart.py
+++ b/meta/lib/oeqa/runtime/smart.py
@@ -46,7 +46,7 @@ class SmartRepoTest(SmartTest):
46 46
47 @classmethod 47 @classmethod
48 def setUpClass(self): 48 def setUpClass(self):
49 self.repo_server = HTTPService(oeRuntimeTest.tc.d.getVar('DEPLOY_DIR', True), oeRuntimeTest.tc.qemu.host_ip) 49 self.repo_server = HTTPService(oeRuntimeTest.tc.d.getVar('DEPLOY_DIR', True), oeRuntimeTest.tc.target.server_ip)
50 self.repo_server.start() 50 self.repo_server.start()
51 51
52 @classmethod 52 @classmethod
@@ -58,7 +58,7 @@ class SmartRepoTest(SmartTest):
58 58
59 def test_smart_channel_add(self): 59 def test_smart_channel_add(self):
60 image_pkgtype = self.tc.d.getVar('IMAGE_PKGTYPE', True) 60 image_pkgtype = self.tc.d.getVar('IMAGE_PKGTYPE', True)
61 deploy_url = 'http://%s:%s/%s' %(self.tc.qemu.host_ip, self.repo_server.port, image_pkgtype) 61 deploy_url = 'http://%s:%s/%s' %(self.target.server_ip, self.repo_server.port, image_pkgtype)
62 pkgarchs = self.tc.d.getVar('PACKAGE_ARCHS', True) 62 pkgarchs = self.tc.d.getVar('PACKAGE_ARCHS', True)
63 for arch in os.listdir('%s/%s' % (self.repo_server.root_dir, image_pkgtype)): 63 for arch in os.listdir('%s/%s' % (self.repo_server.root_dir, image_pkgtype)):
64 if arch in pkgarchs: 64 if arch in pkgarchs:
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py
index 256cf3c6a8..5366a635fe 100644
--- a/meta/lib/oeqa/utils/qemurunner.py
+++ b/meta/lib/oeqa/utils/qemurunner.py
@@ -16,25 +16,30 @@ import bb
16 16
17class QemuRunner: 17class QemuRunner:
18 18
19 def __init__(self, machine, rootfs, display = None, tmpdir = None, deploy_dir_image = None, logfile = None, boottime = 400, runqemutime = 60): 19 def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime):
20 # Popen object
21 self.runqemu = None
22
23 self.machine = machine
24 self.rootfs = rootfs
25 20
21 # Popen object for runqemu
22 self.runqemu = None
23 # pid of the qemu process that runqemu will start
26 self.qemupid = None 24 self.qemupid = None
25 # target ip - from the command line
27 self.ip = None 26 self.ip = None
27 # host ip - where qemu is running
28 self.server_ip = None
28 29
30 self.machine = machine
31 self.rootfs = rootfs
29 self.display = display 32 self.display = display
30 self.tmpdir = tmpdir 33 self.tmpdir = tmpdir
31 self.deploy_dir_image = deploy_dir_image 34 self.deploy_dir_image = deploy_dir_image
32 self.logfile = logfile 35 self.logfile = logfile
33 self.boottime = boottime 36 self.boottime = boottime
34 self.runqemutime = runqemutime 37
38 self.runqemutime = 60
35 39
36 self.create_socket() 40 self.create_socket()
37 41
42
38 def create_socket(self): 43 def create_socket(self):
39 44
40 self.bootlog = '' 45 self.bootlog = ''
@@ -57,7 +62,7 @@ class QemuRunner:
57 with open(self.logfile, "a") as f: 62 with open(self.logfile, "a") as f:
58 f.write("%s" % msg) 63 f.write("%s" % msg)
59 64
60 def launch(self, qemuparams = None): 65 def start(self, qemuparams = None):
61 66
62 if self.display: 67 if self.display:
63 os.environ["DISPLAY"] = self.display 68 os.environ["DISPLAY"] = self.display
@@ -96,14 +101,19 @@ class QemuRunner:
96 101
97 if self.is_alive(): 102 if self.is_alive():
98 bb.note("qemu started - qemu procces pid is %s" % self.qemupid) 103 bb.note("qemu started - qemu procces pid is %s" % self.qemupid)
99 cmdline = open('/proc/%s/cmdline' % self.qemupid).read() 104 cmdline = ''
100 self.ip, _, self.host_ip = cmdline.split('ip=')[1].split(' ')[0].split(':')[0:3] 105 with open('/proc/%s/cmdline' % self.qemupid) as p:
101 if not re.search("^((?:[0-9]{1,3}\.){3}[0-9]{1,3})$", self.ip): 106 cmdline = p.read()
102 bb.note("Couldn't get ip from qemu process arguments, I got '%s'" % self.ip) 107 ips = re.findall("((?:[0-9]{1,3}\.){3}[0-9]{1,3})", cmdline.split("ip=")[1])
103 bb.note("Here is the ps output:\n%s" % cmdline) 108 if not ips or len(ips) != 3:
104 self.kill() 109 bb.note("Couldn't get ip from qemu process arguments! Here is the qemu command line used: %s" % cmdline)
110 self.stop()
105 return False 111 return False
106 bb.note("IP found: %s" % self.ip) 112 else:
113 self.ip = ips[0]
114 self.server_ip = ips[1]
115 bb.note("Target IP: %s" % self.ip)
116 bb.note("Server IP: %s" % self.server_ip)
107 bb.note("Waiting at most %d seconds for login banner" % self.boottime ) 117 bb.note("Waiting at most %d seconds for login banner" % self.boottime )
108 endtime = time.time() + self.boottime 118 endtime = time.time() + self.boottime
109 socklist = [self.server_socket] 119 socklist = [self.server_socket]
@@ -138,18 +148,18 @@ class QemuRunner:
138 lines = "\n".join(self.bootlog.splitlines()[-5:]) 148 lines = "\n".join(self.bootlog.splitlines()[-5:])
139 bb.note("Last 5 lines of text:\n%s" % lines) 149 bb.note("Last 5 lines of text:\n%s" % lines)
140 bb.note("Check full boot log: %s" % self.logfile) 150 bb.note("Check full boot log: %s" % self.logfile)
141 self.kill() 151 self.stop()
142 return False 152 return False
143 else: 153 else:
144 bb.note("Qemu pid didn't appeared in %s seconds" % self.runqemutime) 154 bb.note("Qemu pid didn't appeared in %s seconds" % self.runqemutime)
145 output = self.runqemu.stdout 155 output = self.runqemu.stdout
146 self.kill() 156 self.stop()
147 bb.note("Output from runqemu:\n%s" % output.read()) 157 bb.note("Output from runqemu:\n%s" % output.read())
148 return False 158 return False
149 159
150 return self.is_alive() 160 return self.is_alive()
151 161
152 def kill(self): 162 def stop(self):
153 163
154 if self.runqemu: 164 if self.runqemu:
155 bb.note("Sending SIGTERM to runqemu") 165 bb.note("Sending SIGTERM to runqemu")
@@ -170,9 +180,9 @@ class QemuRunner:
170 def restart(self, qemuparams = None): 180 def restart(self, qemuparams = None):
171 bb.note("Restarting qemu process") 181 bb.note("Restarting qemu process")
172 if self.runqemu.poll() is None: 182 if self.runqemu.poll() is None:
173 self.kill() 183 self.stop()
174 self.create_socket() 184 self.create_socket()
175 if self.launch(qemuparams): 185 if self.start(qemuparams):
176 return True 186 return True
177 return False 187 return False
178 188
diff --git a/meta/lib/oeqa/utils/sshcontrol.py b/meta/lib/oeqa/utils/sshcontrol.py
index 07257b8948..a0dcf023bd 100644
--- a/meta/lib/oeqa/utils/sshcontrol.py
+++ b/meta/lib/oeqa/utils/sshcontrol.py
@@ -13,8 +13,8 @@ import select
13 13
14class SSHControl(object): 14class SSHControl(object):
15 15
16 def __init__(self, host=None, timeout=300, logfile=None): 16 def __init__(self, ip=None, timeout=300, logfile=None):
17 self.host = host 17 self.ip = ip
18 self.timeout = timeout 18 self.timeout = timeout
19 self._starttime = None 19 self._starttime = None
20 self._out = '' 20 self._out = ''
@@ -35,7 +35,7 @@ class SSHControl(object):
35 def _internal_run(self, cmd): 35 def _internal_run(self, cmd):
36 # We need this for a proper PATH 36 # We need this for a proper PATH
37 cmd = ". /etc/profile; " + cmd 37 cmd = ". /etc/profile; " + cmd
38 command = self.ssh + [self.host, cmd] 38 command = self.ssh + [self.ip, cmd]
39 self.log("[Running]$ %s" % " ".join(command)) 39 self.log("[Running]$ %s" % " ".join(command))
40 self._starttime = time.time() 40 self._starttime = time.time()
41 # ssh hangs without os.setsid 41 # ssh hangs without os.setsid
@@ -48,10 +48,10 @@ class SSHControl(object):
48 if time is 0 will let cmd run until it finishes. 48 if time is 0 will let cmd run until it finishes.
49 Time can be passed to here or can be set per class instance.""" 49 Time can be passed to here or can be set per class instance."""
50 50
51 if self.host: 51 if self.ip:
52 sshconn = self._internal_run(cmd) 52 sshconn = self._internal_run(cmd)
53 else: 53 else:
54 raise Exception("Remote IP/host hasn't been set, I can't run ssh without one.") 54 raise Exception("Remote IP hasn't been set, I can't run ssh without one.")
55 55
56 # run the command forever 56 # run the command forever
57 if timeout == 0: 57 if timeout == 0:
@@ -108,15 +108,9 @@ class SSHControl(object):
108 return (ret, out) 108 return (ret, out)
109 109
110 def copy_to(self, localpath, remotepath): 110 def copy_to(self, localpath, remotepath):
111 actualcmd = [localpath, 'root@%s:%s' % (self.host, remotepath)] 111 actualcmd = [localpath, 'root@%s:%s' % (self.ip, remotepath)]
112 return self._internal_scp(actualcmd) 112 return self._internal_scp(actualcmd)
113 113
114 def copy_from(self, remotepath, localpath): 114 def copy_from(self, remotepath, localpath):
115 actualcmd = ['root@%s:%s' % (self.host, remotepath), localpath] 115 actualcmd = ['root@%s:%s' % (self.ip, remotepath), localpath]
116 return self._internal_scp(actualcmd) 116 return self._internal_scp(actualcmd)
117
118 def get_status(self):
119 return self._ret
120
121 def get_output(self):
122 return self._out