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