1# 2# SPDX-License-Identifier: MIT 3# 4 5from oeqa.selftest.case import OESelftestTestCase 6from oeqa.utils.commands import bitbake, get_bb_vars, get_bb_var, runqemu 7import subprocess, os 8import oe.path 9import re 10 11class VersionOrdering(OESelftestTestCase): 12 # version1, version2, sort order 13 tests = ( 14 ("1.0", "1.0", 0), 15 ("1.0", "2.0", -1), 16 ("2.0", "1.0", 1), 17 ("2.0-rc", "2.0", 1), 18 ("2.0~rc", "2.0", -1), 19 ("1.2rc2", "1.2.0", -1) 20 ) 21 22 @classmethod 23 def setUpClass(cls): 24 super().setUpClass() 25 26 # Build the tools we need and populate a sysroot 27 bitbake("dpkg-native opkg-native rpm-native python3-native") 28 bitbake("build-sysroots -c build_native_sysroot") 29 30 # Get the paths so we can point into the sysroot correctly 31 vars = get_bb_vars(["STAGING_DIR", "BUILD_ARCH", "bindir_native", "libdir_native"]) 32 cls.staging = oe.path.join(vars["STAGING_DIR"], vars["BUILD_ARCH"]) 33 cls.bindir = oe.path.join(cls.staging, vars["bindir_native"]) 34 cls.libdir = oe.path.join(cls.staging, vars["libdir_native"]) 35 36 def setUpLocal(self): 37 # Just for convenience 38 self.staging = type(self).staging 39 self.bindir = type(self).bindir 40 self.libdir = type(self).libdir 41 42 def test_dpkg(self): 43 for ver1, ver2, sort in self.tests: 44 op = { -1: "<<", 0: "=", 1: ">>" }[sort] 45 status = subprocess.call((oe.path.join(self.bindir, "dpkg"), "--compare-versions", ver1, op, ver2)) 46 self.assertEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2)) 47 48 # Now do it again but with incorrect operations 49 op = { -1: ">>", 0: ">>", 1: "<<" }[sort] 50 status = subprocess.call((oe.path.join(self.bindir, "dpkg"), "--compare-versions", ver1, op, ver2)) 51 self.assertNotEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2)) 52 53 # Now do it again but with incorrect operations 54 op = { -1: "=", 0: "<<", 1: "=" }[sort] 55 status = subprocess.call((oe.path.join(self.bindir, "dpkg"), "--compare-versions", ver1, op, ver2)) 56 self.assertNotEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2)) 57 58 def test_opkg(self): 59 for ver1, ver2, sort in self.tests: 60 op = { -1: "<<", 0: "=", 1: ">>" }[sort] 61 status = subprocess.call((oe.path.join(self.bindir, "opkg"), "compare-versions", ver1, op, ver2)) 62 self.assertEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2)) 63 64 # Now do it again but with incorrect operations 65 op = { -1: ">>", 0: ">>", 1: "<<" }[sort] 66 status = subprocess.call((oe.path.join(self.bindir, "opkg"), "compare-versions", ver1, op, ver2)) 67 self.assertNotEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2)) 68 69 # Now do it again but with incorrect operations 70 op = { -1: "=", 0: "<<", 1: "=" }[sort] 71 status = subprocess.call((oe.path.join(self.bindir, "opkg"), "compare-versions", ver1, op, ver2)) 72 self.assertNotEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2)) 73 74 def test_rpm(self): 75 # Need to tell the Python bindings where to find its configuration 76 env = os.environ.copy() 77 env["RPM_CONFIGDIR"] = oe.path.join(self.libdir, "rpm") 78 79 for ver1, ver2, sort in self.tests: 80 # The only way to test rpm is via the Python module, so we need to 81 # execute python3-native. labelCompare returns -1/0/1 (like strcmp) 82 # so add 100 and use that as the exit code. 83 command = (oe.path.join(self.bindir, "python3-native", "python3"), "-c", 84 "import sys, rpm; v1=(None, \"%s\", None); v2=(None, \"%s\", None); sys.exit(rpm.labelCompare(v1, v2) + 100)" % (ver1, ver2)) 85 status = subprocess.call(command, env=env) 86 self.assertIn(status, (99, 100, 101)) 87 self.assertEqual(status - 100, sort, "%s %s (%d) failed" % (ver1, ver2, sort)) 88 89class PackageTests(OESelftestTestCase): 90 # Verify that a recipe which sets up hardlink files has those preserved into split packages 91 # Also test file sparseness is preserved 92 def test_preserve_sparse_hardlinks(self): 93 bitbake("selftest-hardlink -c package") 94 95 dest = get_bb_var('PKGDEST', 'selftest-hardlink') 96 bindir = get_bb_var('bindir', 'selftest-hardlink') 97 98 def checkfiles(): 99 # Recipe creates 4 hardlinked files, there is a copy in package/ and a copy in packages-split/ 100 # so expect 8 in total. 101 self.assertEqual(os.stat(dest + "/selftest-hardlink" + bindir + "/hello1").st_nlink, 8) 102 103 # Test a sparse file remains sparse 104 sparsestat = os.stat(dest + "/selftest-hardlink" + bindir + "/sparsetest") 105 self.assertEqual(sparsestat.st_blocks, 0) 106 self.assertEqual(sparsestat.st_size, 1048576) 107 108 checkfiles() 109 110 # Clean and reinstall so its now definitely from sstate, then retest. 111 bitbake("selftest-hardlink -c clean") 112 bitbake("selftest-hardlink -c package") 113 114 checkfiles() 115 116 # Verify gdb to read symbols from separated debug hardlink file correctly 117 def test_gdb_hardlink_debug(self): 118 features = 'IMAGE_INSTALL:append = " selftest-hardlink"\n' 119 features += 'IMAGE_INSTALL:append = " selftest-hardlink-dbg"\n' 120 features += 'IMAGE_INSTALL:append = " selftest-hardlink-gdb"\n' 121 self.write_config(features) 122 bitbake("core-image-minimal") 123 124 def gdbtest(qemu, binary): 125 """ 126 Check that gdb ``binary`` to read symbols from separated debug file 127 """ 128 self.logger.info("gdbtest %s" % binary) 129 status, output = qemu.run_serial('/usr/bin/gdb.sh %s' % binary, timeout=60) 130 for l in output.split('\n'): 131 # Check debugging symbols exists 132 if '(no debugging symbols found)' in l: 133 self.logger.error("No debugging symbols found. GDB result:\n%s" % output) 134 return False 135 136 # Check debugging symbols works correctly 137 elif re.match(r"Breakpoint 1.*hello\.c.*4", l): 138 return True 139 140 self.logger.error("GDB result:\n%d: %s", status, output) 141 return False 142 143 with runqemu('core-image-minimal') as qemu: 144 for binary in ['/usr/bin/hello1', 145 '/usr/bin/hello2', 146 '/usr/libexec/hello3', 147 '/usr/libexec/hello4']: 148 if not gdbtest(qemu, binary): 149 self.fail('GDB %s failed' % binary) 150 151 def test_preserve_ownership(self): 152 import os, stat, oe.cachedpath 153 features = 'IMAGE_INSTALL:append = " selftest-chown"\n' 154 self.write_config(features) 155 bitbake("core-image-minimal") 156 157 sysconfdir = get_bb_var('sysconfdir', 'selftest-chown') 158 def check_ownership(qemu, gid, uid, path): 159 self.logger.info("Check ownership of %s", path) 160 status, output = qemu.run_serial(r'/bin/stat -c "%U %G" ' + path, timeout=60) 161 output = output.split(" ") 162 if output[0] != uid or output[1] != gid : 163 self.logger.error("Incrrect ownership %s [%s:%s]", path, output[0], output[1]) 164 return False 165 return True 166 167 with runqemu('core-image-minimal') as qemu: 168 for path in [ sysconfdir + "/selftest-chown/file", 169 sysconfdir + "/selftest-chown/dir", 170 sysconfdir + "/selftest-chown/symlink", 171 sysconfdir + "/selftest-chown/fifotest/fifo"]: 172 if not check_ownership(qemu, "test", "test", path): 173 self.fail('Test ownership %s failed' % path) 174