summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oeqa')
-rw-r--r--meta/lib/oeqa/manual/oe-core.json2
-rw-r--r--meta/lib/oeqa/runtime/cases/df.py2
-rw-r--r--meta/lib/oeqa/runtime/cases/pam.py3
-rw-r--r--meta/lib/oeqa/selftest/cases/buildoptions.py6
-rw-r--r--meta/lib/oeqa/selftest/cases/cve_check.py44
-rw-r--r--meta/lib/oeqa/selftest/cases/devtool.py4
-rw-r--r--meta/lib/oeqa/selftest/cases/pseudo.py27
-rw-r--r--meta/lib/oeqa/selftest/cases/reproducible.py7
-rw-r--r--meta/lib/oeqa/selftest/cases/tinfoil.py6
-rw-r--r--meta/lib/oeqa/selftest/cases/wic.py36
-rw-r--r--meta/lib/oeqa/selftest/context.py17
-rw-r--r--meta/lib/oeqa/utils/commands.py7
12 files changed, 138 insertions, 23 deletions
diff --git a/meta/lib/oeqa/manual/oe-core.json b/meta/lib/oeqa/manual/oe-core.json
index fb47c5ec36..4ad524d89b 100644
--- a/meta/lib/oeqa/manual/oe-core.json
+++ b/meta/lib/oeqa/manual/oe-core.json
@@ -80,7 +80,7 @@
80 "expected_results": "" 80 "expected_results": ""
81 }, 81 },
82 "7": { 82 "7": {
83 "action": "Run command:./configure && make ", 83 "action": "Run command:./configure ${CONFIGUREOPTS} && make ",
84 "expected_results": "Verify that \"matchbox-desktop\" binary file was created successfully under \"src/\" directory " 84 "expected_results": "Verify that \"matchbox-desktop\" binary file was created successfully under \"src/\" directory "
85 }, 85 },
86 "8": { 86 "8": {
diff --git a/meta/lib/oeqa/runtime/cases/df.py b/meta/lib/oeqa/runtime/cases/df.py
index 89fd0fb901..bb155c9cf9 100644
--- a/meta/lib/oeqa/runtime/cases/df.py
+++ b/meta/lib/oeqa/runtime/cases/df.py
@@ -4,12 +4,14 @@
4 4
5from oeqa.runtime.case import OERuntimeTestCase 5from oeqa.runtime.case import OERuntimeTestCase
6from oeqa.core.decorator.depends import OETestDepends 6from oeqa.core.decorator.depends import OETestDepends
7from oeqa.core.decorator.data import skipIfDataVar, skipIfInDataVar
7from oeqa.runtime.decorator.package import OEHasPackage 8from oeqa.runtime.decorator.package import OEHasPackage
8 9
9class DfTest(OERuntimeTestCase): 10class DfTest(OERuntimeTestCase):
10 11
11 @OETestDepends(['ssh.SSHTest.test_ssh']) 12 @OETestDepends(['ssh.SSHTest.test_ssh'])
12 @OEHasPackage(['coreutils', 'busybox']) 13 @OEHasPackage(['coreutils', 'busybox'])
14 @skipIfInDataVar('IMAGE_FEATURES', 'read-only-rootfs', 'Test case df requires a writable rootfs')
13 def test_df(self): 15 def test_df(self):
14 cmd = "df -P / | sed -n '2p' | awk '{print $4}'" 16 cmd = "df -P / | sed -n '2p' | awk '{print $4}'"
15 (status,output) = self.target.run(cmd) 17 (status,output) = self.target.run(cmd)
diff --git a/meta/lib/oeqa/runtime/cases/pam.py b/meta/lib/oeqa/runtime/cases/pam.py
index 271a1943e3..a482ded945 100644
--- a/meta/lib/oeqa/runtime/cases/pam.py
+++ b/meta/lib/oeqa/runtime/cases/pam.py
@@ -8,11 +8,14 @@
8from oeqa.runtime.case import OERuntimeTestCase 8from oeqa.runtime.case import OERuntimeTestCase
9from oeqa.core.decorator.depends import OETestDepends 9from oeqa.core.decorator.depends import OETestDepends
10from oeqa.core.decorator.data import skipIfNotFeature 10from oeqa.core.decorator.data import skipIfNotFeature
11from oeqa.runtime.decorator.package import OEHasPackage
11 12
12class PamBasicTest(OERuntimeTestCase): 13class PamBasicTest(OERuntimeTestCase):
13 14
14 @skipIfNotFeature('pam', 'Test requires pam to be in DISTRO_FEATURES') 15 @skipIfNotFeature('pam', 'Test requires pam to be in DISTRO_FEATURES')
15 @OETestDepends(['ssh.SSHTest.test_ssh']) 16 @OETestDepends(['ssh.SSHTest.test_ssh'])
17 @OEHasPackage(['shadow'])
18 @OEHasPackage(['shadow-base'])
16 def test_pam(self): 19 def test_pam(self):
17 status, output = self.target.run('login --help') 20 status, output = self.target.run('login --help')
18 msg = ('login command does not work as expected. ' 21 msg = ('login command does not work as expected. '
diff --git a/meta/lib/oeqa/selftest/cases/buildoptions.py b/meta/lib/oeqa/selftest/cases/buildoptions.py
index e91f0bd18f..b1b9ea7e55 100644
--- a/meta/lib/oeqa/selftest/cases/buildoptions.py
+++ b/meta/lib/oeqa/selftest/cases/buildoptions.py
@@ -57,15 +57,15 @@ class ImageOptionsTests(OESelftestTestCase):
57class DiskMonTest(OESelftestTestCase): 57class DiskMonTest(OESelftestTestCase):
58 58
59 def test_stoptask_behavior(self): 59 def test_stoptask_behavior(self):
60 self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"') 60 self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
61 res = bitbake("delay -c delay", ignore_status = True) 61 res = bitbake("delay -c delay", ignore_status = True)
62 self.assertTrue('ERROR: No new tasks can be executed since the disk space monitor action is "STOPTASKS"!' in res.output, msg = "Tasks should have stopped. Disk monitor is set to STOPTASK: %s" % res.output) 62 self.assertTrue('ERROR: No new tasks can be executed since the disk space monitor action is "STOPTASKS"!' in res.output, msg = "Tasks should have stopped. Disk monitor is set to STOPTASK: %s" % res.output)
63 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output)) 63 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output))
64 self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"') 64 self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
65 res = bitbake("delay -c delay", ignore_status = True) 65 res = bitbake("delay -c delay", ignore_status = True)
66 self.assertTrue('ERROR: Immediately abort since the disk space monitor action is "ABORT"!' in res.output, "Tasks should have been aborted immediatelly. Disk monitor is set to ABORT: %s" % res.output) 66 self.assertTrue('ERROR: Immediately abort since the disk space monitor action is "ABORT"!' in res.output, "Tasks should have been aborted immediatelly. Disk monitor is set to ABORT: %s" % res.output)
67 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output)) 67 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output))
68 self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"') 68 self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
69 res = bitbake("delay -c delay") 69 res = bitbake("delay -c delay")
70 self.assertTrue('WARNING: The free space' in res.output, msg = "A warning should have been displayed for disk monitor is set to WARN: %s" %res.output) 70 self.assertTrue('WARNING: The free space' in res.output, msg = "A warning should have been displayed for disk monitor is set to WARN: %s" %res.output)
71 71
diff --git a/meta/lib/oeqa/selftest/cases/cve_check.py b/meta/lib/oeqa/selftest/cases/cve_check.py
new file mode 100644
index 0000000000..d1947baffc
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/cve_check.py
@@ -0,0 +1,44 @@
1from oe.cve_check import Version
2from oeqa.selftest.case import OESelftestTestCase
3
4class CVECheck(OESelftestTestCase):
5
6 def test_version_compare(self):
7 result = Version("100") > Version("99")
8 self.assertTrue( result, msg="Failed to compare version '100' > '99'")
9 result = Version("2.3.1") > Version("2.2.3")
10 self.assertTrue( result, msg="Failed to compare version '2.3.1' > '2.2.3'")
11 result = Version("2021-01-21") > Version("2020-12-25")
12 self.assertTrue( result, msg="Failed to compare version '2021-01-21' > '2020-12-25'")
13 result = Version("1.2-20200910") < Version("1.2-20200920")
14 self.assertTrue( result, msg="Failed to compare version '1.2-20200910' < '1.2-20200920'")
15
16 result = Version("1.0") >= Version("1.0beta")
17 self.assertTrue( result, msg="Failed to compare version '1.0' >= '1.0beta'")
18 result = Version("1.0-rc2") > Version("1.0-rc1")
19 self.assertTrue( result, msg="Failed to compare version '1.0-rc2' > '1.0-rc1'")
20 result = Version("1.0.alpha1") < Version("1.0")
21 self.assertTrue( result, msg="Failed to compare version '1.0.alpha1' < '1.0'")
22 result = Version("1.0_dev") <= Version("1.0")
23 self.assertTrue( result, msg="Failed to compare version '1.0_dev' <= '1.0'")
24
25 # ignore "p1" and "p2", so these should be equal
26 result = Version("1.0p2") == Version("1.0p1")
27 self.assertTrue( result ,msg="Failed to compare version '1.0p2' to '1.0p1'")
28 # ignore the "b" and "r"
29 result = Version("1.0b") == Version("1.0r")
30 self.assertTrue( result ,msg="Failed to compare version '1.0b' to '1.0r'")
31
32 # consider the trailing alphabet as patched level when comparing
33 result = Version("1.0b","alphabetical") < Version("1.0r","alphabetical")
34 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'")
35 result = Version("1.0b","alphabetical") > Version("1.0","alphabetical")
36 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'")
37
38 # consider the trailing "p" and "patch" as patched released when comparing
39 result = Version("1.0","patch") < Version("1.0p1","patch")
40 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0' < '1.0p1'")
41 result = Version("1.0p2","patch") > Version("1.0p1","patch")
42 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0p2' > '1.0p1'")
43 result = Version("1.0_patch2","patch") < Version("1.0_patch3","patch")
44 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0_patch2' < '1.0_patch3'")
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index d3d2e04c20..4eba23890f 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -57,7 +57,7 @@ def setUpModule():
57 if relpth.endswith('/'): 57 if relpth.endswith('/'):
58 destdir = os.path.join(corecopydir, relpth) 58 destdir = os.path.join(corecopydir, relpth)
59 # avoid race condition by not copying .pyc files YPBZ#13421,13803 59 # avoid race condition by not copying .pyc files YPBZ#13421,13803
60 shutil.copytree(pth, destdir, ignore=ignore_patterns('*.pyc', '__pycache__')) 60 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
61 else: 61 else:
62 destdir = os.path.join(corecopydir, os.path.dirname(relpth)) 62 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
63 bb.utils.mkdirhier(destdir) 63 bb.utils.mkdirhier(destdir)
@@ -269,7 +269,7 @@ class DevtoolAddTests(DevtoolBase):
269 self.track_for_cleanup(tempdir) 269 self.track_for_cleanup(tempdir)
270 pn = 'pv' 270 pn = 'pv'
271 pv = '1.5.3' 271 pv = '1.5.3'
272 url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2' 272 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
273 result = runCmd('wget %s' % url, cwd=tempdir) 273 result = runCmd('wget %s' % url, cwd=tempdir)
274 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir) 274 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
275 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv)) 275 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
diff --git a/meta/lib/oeqa/selftest/cases/pseudo.py b/meta/lib/oeqa/selftest/cases/pseudo.py
new file mode 100644
index 0000000000..33593d5ce9
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/pseudo.py
@@ -0,0 +1,27 @@
1#
2# SPDX-License-Identifier: MIT
3#
4
5import glob
6import os
7import shutil
8from oeqa.utils.commands import bitbake, get_test_layer
9from oeqa.selftest.case import OESelftestTestCase
10
11class Pseudo(OESelftestTestCase):
12
13 def test_pseudo_pyc_creation(self):
14 self.write_config("")
15
16 metaselftestpath = get_test_layer()
17 pycache_path = os.path.join(metaselftestpath, 'lib/__pycache__')
18 if os.path.exists(pycache_path):
19 shutil.rmtree(pycache_path)
20
21 bitbake('pseudo-pyc-test -c install')
22
23 test1_pyc_present = len(glob.glob(os.path.join(pycache_path, 'pseudo_pyc_test1.*.pyc')))
24 self.assertTrue(test1_pyc_present, 'test1 pyc file missing, should be created outside of pseudo context.')
25
26 test2_pyc_present = len(glob.glob(os.path.join(pycache_path, 'pseudo_pyc_test2.*.pyc')))
27 self.assertFalse(test2_pyc_present, 'test2 pyc file present, should not be created in pseudo context.')
diff --git a/meta/lib/oeqa/selftest/cases/reproducible.py b/meta/lib/oeqa/selftest/cases/reproducible.py
index a7ef336143..cd7be7d436 100644
--- a/meta/lib/oeqa/selftest/cases/reproducible.py
+++ b/meta/lib/oeqa/selftest/cases/reproducible.py
@@ -68,7 +68,7 @@ def compare_file(reference, test, diffutils_sysroot):
68 result.status = MISSING 68 result.status = MISSING
69 return result 69 return result
70 70
71 r = runCmd(['cmp', '--quiet', reference, test], native_sysroot=diffutils_sysroot, ignore_status=True) 71 r = runCmd(['cmp', '--quiet', reference, test], native_sysroot=diffutils_sysroot, ignore_status=True, sync=False)
72 72
73 if r.status: 73 if r.status:
74 result.status = DIFFERENT 74 result.status = DIFFERENT
@@ -184,9 +184,10 @@ class ReproducibleTests(OESelftestTestCase):
184 # mirror, forcing a complete build from scratch 184 # mirror, forcing a complete build from scratch
185 config += textwrap.dedent('''\ 185 config += textwrap.dedent('''\
186 SSTATE_DIR = "${TMPDIR}/sstate" 186 SSTATE_DIR = "${TMPDIR}/sstate"
187 SSTATE_MIRROR = "" 187 SSTATE_MIRRORS = ""
188 ''') 188 ''')
189 189
190 self.logger.info("Building %s (sstate%s allowed)..." % (name, '' if use_sstate else ' NOT'))
190 self.write_config(config) 191 self.write_config(config)
191 d = get_bb_vars(capture_vars) 192 d = get_bb_vars(capture_vars)
192 bitbake(' '.join(self.images)) 193 bitbake(' '.join(self.images))
@@ -213,6 +214,7 @@ class ReproducibleTests(OESelftestTestCase):
213 self.logger.info('Non-reproducible packages will be copied to %s', save_dir) 214 self.logger.info('Non-reproducible packages will be copied to %s', save_dir)
214 215
215 vars_A = self.do_test_build('reproducibleA', self.build_from_sstate) 216 vars_A = self.do_test_build('reproducibleA', self.build_from_sstate)
217
216 vars_B = self.do_test_build('reproducibleB', False) 218 vars_B = self.do_test_build('reproducibleB', False)
217 219
218 # NOTE: The temp directories from the reproducible build are purposely 220 # NOTE: The temp directories from the reproducible build are purposely
@@ -227,6 +229,7 @@ class ReproducibleTests(OESelftestTestCase):
227 deploy_A = vars_A['DEPLOY_DIR_' + c.upper()] 229 deploy_A = vars_A['DEPLOY_DIR_' + c.upper()]
228 deploy_B = vars_B['DEPLOY_DIR_' + c.upper()] 230 deploy_B = vars_B['DEPLOY_DIR_' + c.upper()]
229 231
232 self.logger.info('Checking %s packages for differences...' % c)
230 result = self.compare_packages(deploy_A, deploy_B, diffutils_sysroot) 233 result = self.compare_packages(deploy_A, deploy_B, diffutils_sysroot)
231 234
232 self.logger.info('Reproducibility summary for %s: %s' % (c, result)) 235 self.logger.info('Reproducibility summary for %s: %s' % (c, result))
diff --git a/meta/lib/oeqa/selftest/cases/tinfoil.py b/meta/lib/oeqa/selftest/cases/tinfoil.py
index 206168ed00..a51c6048d3 100644
--- a/meta/lib/oeqa/selftest/cases/tinfoil.py
+++ b/meta/lib/oeqa/selftest/cases/tinfoil.py
@@ -100,9 +100,11 @@ class TinfoilTests(OESelftestTestCase):
100 eventreceived = False 100 eventreceived = False
101 commandcomplete = False 101 commandcomplete = False
102 start = time.time() 102 start = time.time()
103 # Wait for 10s in total so we'd detect spurious heartbeat events for example 103 # Wait for maximum 60s in total so we'd detect spurious heartbeat events for example
104 # The test is IO load sensitive too 104 # The test is IO load sensitive too
105 while time.time() - start < 10: 105 while (not (eventreceived == True and commandcomplete == True)
106 and (time.time() - start < 60)):
107 # if we received both events (on let's say a good day), we are done
106 event = tinfoil.wait_event(1) 108 event = tinfoil.wait_event(1)
107 if event: 109 if event:
108 if isinstance(event, bb.command.CommandCompleted): 110 if isinstance(event, bb.command.CommandCompleted):
diff --git a/meta/lib/oeqa/selftest/cases/wic.py b/meta/lib/oeqa/selftest/cases/wic.py
index 714637ec1e..39c6828f59 100644
--- a/meta/lib/oeqa/selftest/cases/wic.py
+++ b/meta/lib/oeqa/selftest/cases/wic.py
@@ -318,6 +318,7 @@ class Wic(WicTestCase):
318 "--image-name=core-image-minimal " 318 "--image-name=core-image-minimal "
319 "-D -o %s" % self.resultdir) 319 "-D -o %s" % self.resultdir)
320 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) 320 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
321 self.assertEqual(1, len(glob(self.resultdir + "tmp.wic*")))
321 322
322 def test_debug_long(self): 323 def test_debug_long(self):
323 """Test --debug option""" 324 """Test --debug option"""
@@ -325,6 +326,7 @@ class Wic(WicTestCase):
325 "--image-name=core-image-minimal " 326 "--image-name=core-image-minimal "
326 "--debug -o %s" % self.resultdir) 327 "--debug -o %s" % self.resultdir)
327 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) 328 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
329 self.assertEqual(1, len(glob(self.resultdir + "tmp.wic*")))
328 330
329 def test_skip_build_check_short(self): 331 def test_skip_build_check_short(self):
330 """Test -s option""" 332 """Test -s option"""
@@ -588,6 +590,9 @@ part / --source rootfs --fstype=ext4 --include-path %s --include-path core-imag
588 def test_permissions(self): 590 def test_permissions(self):
589 """Test permissions are respected""" 591 """Test permissions are respected"""
590 592
593 # prepare wicenv and rootfs
594 bitbake('core-image-minimal core-image-minimal-mtdutils -c do_rootfs_wicenv')
595
591 oldpath = os.environ['PATH'] 596 oldpath = os.environ['PATH']
592 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 597 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
593 598
@@ -621,6 +626,19 @@ part /etc --source rootfs --fstype=ext4 --change-directory=etc
621 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part)) 626 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part))
622 self.assertEqual(True, files_own_by_root(res.output)) 627 self.assertEqual(True, files_own_by_root(res.output))
623 628
629 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "%s"\n' % wks_file
630 self.append_config(config)
631 bitbake('core-image-minimal')
632 tmpdir = os.path.join(get_bb_var('WORKDIR', 'core-image-minimal'),'build-wic')
633
634 # check each partition for permission
635 for part in glob(os.path.join(tmpdir, 'temp-*.direct.p*')):
636 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part))
637 self.assertTrue(files_own_by_root(res.output)
638 ,msg='Files permission incorrect using wks set "%s"' % test)
639
640 # clean config and result directory for next cases
641 self.remove_config(config)
624 rmtree(self.resultdir, ignore_errors=True) 642 rmtree(self.resultdir, ignore_errors=True)
625 643
626 finally: 644 finally:
@@ -961,14 +979,18 @@ class Wic2(WicTestCase):
961 @only_for_arch(['i586', 'i686', 'x86_64']) 979 @only_for_arch(['i586', 'i686', 'x86_64'])
962 def test_rawcopy_plugin_qemu(self): 980 def test_rawcopy_plugin_qemu(self):
963 """Test rawcopy plugin in qemu""" 981 """Test rawcopy plugin in qemu"""
964 # build ext4 and wic images 982 # build ext4 and then use it for a wic image
965 for fstype in ("ext4", "wic"): 983 config = 'IMAGE_FSTYPES = "ext4"\n'
966 config = 'IMAGE_FSTYPES = "%s"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' % fstype 984 self.append_config(config)
967 self.append_config(config) 985 self.assertEqual(0, bitbake('core-image-minimal').status)
968 self.assertEqual(0, bitbake('core-image-minimal').status) 986 self.remove_config(config)
969 self.remove_config(config)
970 987
971 with runqemu('core-image-minimal', ssh=False, image_fstype='wic') as qemu: 988 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n'
989 self.append_config(config)
990 self.assertEqual(0, bitbake('core-image-minimal-mtdutils').status)
991 self.remove_config(config)
992
993 with runqemu('core-image-minimal-mtdutils', ssh=False, image_fstype='wic') as qemu:
972 cmd = "grep sda. /proc/partitions |wc -l" 994 cmd = "grep sda. /proc/partitions |wc -l"
973 status, output = qemu.run_serial(cmd) 995 status, output = qemu.run_serial(cmd)
974 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 996 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
diff --git a/meta/lib/oeqa/selftest/context.py b/meta/lib/oeqa/selftest/context.py
index dd3609c1d6..1659926975 100644
--- a/meta/lib/oeqa/selftest/context.py
+++ b/meta/lib/oeqa/selftest/context.py
@@ -34,7 +34,7 @@ class NonConcurrentTestSuite(unittest.TestSuite):
34 (builddir, newbuilddir) = self.setupfunc("-st", None, self.suite) 34 (builddir, newbuilddir) = self.setupfunc("-st", None, self.suite)
35 ret = super().run(result) 35 ret = super().run(result)
36 os.chdir(builddir) 36 os.chdir(builddir)
37 if newbuilddir and ret.wasSuccessful(): 37 if newbuilddir and ret.wasSuccessful() and self.removefunc:
38 self.removefunc(newbuilddir) 38 self.removefunc(newbuilddir)
39 39
40def removebuilddir(d): 40def removebuilddir(d):
@@ -54,7 +54,7 @@ def removebuilddir(d):
54 bb.utils.prunedir(d, ionice=True) 54 bb.utils.prunedir(d, ionice=True)
55 55
56class OESelftestTestContext(OETestContext): 56class OESelftestTestContext(OETestContext):
57 def __init__(self, td=None, logger=None, machines=None, config_paths=None, newbuilddir=None): 57 def __init__(self, td=None, logger=None, machines=None, config_paths=None, newbuilddir=None, keep_builddir=None):
58 super(OESelftestTestContext, self).__init__(td, logger) 58 super(OESelftestTestContext, self).__init__(td, logger)
59 59
60 self.machines = machines 60 self.machines = machines
@@ -62,6 +62,11 @@ class OESelftestTestContext(OETestContext):
62 self.config_paths = config_paths 62 self.config_paths = config_paths
63 self.newbuilddir = newbuilddir 63 self.newbuilddir = newbuilddir
64 64
65 if keep_builddir:
66 self.removebuilddir = None
67 else:
68 self.removebuilddir = removebuilddir
69
65 def setup_builddir(self, suffix, selftestdir, suite): 70 def setup_builddir(self, suffix, selftestdir, suite):
66 builddir = os.environ['BUILDDIR'] 71 builddir = os.environ['BUILDDIR']
67 if not selftestdir: 72 if not selftestdir:
@@ -119,9 +124,9 @@ class OESelftestTestContext(OETestContext):
119 if processes: 124 if processes:
120 from oeqa.core.utils.concurrencytest import ConcurrentTestSuite 125 from oeqa.core.utils.concurrencytest import ConcurrentTestSuite
121 126
122 return ConcurrentTestSuite(suites, processes, self.setup_builddir, removebuilddir) 127 return ConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
123 else: 128 else:
124 return NonConcurrentTestSuite(suites, processes, self.setup_builddir, removebuilddir) 129 return NonConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
125 130
126 def runTests(self, processes=None, machine=None, skips=[]): 131 def runTests(self, processes=None, machine=None, skips=[]):
127 if machine: 132 if machine:
@@ -179,6 +184,9 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
179 action='append', default=None, 184 action='append', default=None,
180 help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)') 185 help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)')
181 186
187 parser.add_argument('-K', '--keep-builddir', action='store_true',
188 help='Keep the test build directory even if all tests pass')
189
182 parser.add_argument('-B', '--newbuilddir', help='New build directory to use for tests.') 190 parser.add_argument('-B', '--newbuilddir', help='New build directory to use for tests.')
183 parser.add_argument('-v', '--verbose', action='store_true') 191 parser.add_argument('-v', '--verbose', action='store_true')
184 parser.set_defaults(func=self.run) 192 parser.set_defaults(func=self.run)
@@ -236,6 +244,7 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
236 self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf") 244 self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf")
237 self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf") 245 self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf")
238 self.tc_kwargs['init']['newbuilddir'] = args.newbuilddir 246 self.tc_kwargs['init']['newbuilddir'] = args.newbuilddir
247 self.tc_kwargs['init']['keep_builddir'] = args.keep_builddir
239 248
240 def tag_filter(tags): 249 def tag_filter(tags):
241 if args.exclude_tags: 250 if args.exclude_tags:
diff --git a/meta/lib/oeqa/utils/commands.py b/meta/lib/oeqa/utils/commands.py
index 8059cbce3e..a71c16ab14 100644
--- a/meta/lib/oeqa/utils/commands.py
+++ b/meta/lib/oeqa/utils/commands.py
@@ -125,11 +125,11 @@ class Command(object):
125 125
126 def stop(self): 126 def stop(self):
127 for thread in self.threads: 127 for thread in self.threads:
128 if thread.isAlive(): 128 if thread.is_alive():
129 self.process.terminate() 129 self.process.terminate()
130 # let's give it more time to terminate gracefully before killing it 130 # let's give it more time to terminate gracefully before killing it
131 thread.join(5) 131 thread.join(5)
132 if thread.isAlive(): 132 if thread.is_alive():
133 self.process.kill() 133 self.process.kill()
134 thread.join() 134 thread.join()
135 135
@@ -188,7 +188,10 @@ def runCmd(command, ignore_status=False, timeout=None, assert_error=True, sync=T
188 # call sync around the tests to ensure the IO queue doesn't get too large, taking any IO 188 # call sync around the tests to ensure the IO queue doesn't get too large, taking any IO
189 # hit here rather than in bitbake shutdown. 189 # hit here rather than in bitbake shutdown.
190 if sync: 190 if sync:
191 p = os.environ['PATH']
192 os.environ['PATH'] = "/usr/bin:/bin:/usr/sbin:/sbin:" + p
191 os.system("sync") 193 os.system("sync")
194 os.environ['PATH'] = p
192 195
193 result.command = command 196 result.command = command
194 result.status = cmd.status 197 result.status = cmd.status