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