def test_devtool_add(self): # Check preconditions workspacedir = os.path.join(self.builddir, 'workspace') self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Fetch source tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2' result = runCmd('wget %s' % url, cwd=tempdir) result = runCmd('tar xfv pv-1.5.3.tar.bz2', cwd=tempdir) srcdir = os.path.join(tempdir, 'pv-1.5.3') self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory') # Test devtool add self.track_for_cleanup(workspacedir) self.add_command_to_tearDown('bitbake -c cleansstate pv') self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool add pv %s' % srcdir) self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') # Test devtool status result = runCmd('devtool status') self.assertIn('pv', result.output) self.assertIn(srcdir, result.output) # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then) bitbake('pv -c cleansstate') # Test devtool build result = runCmd('devtool build pv') installdir = get_bb_var('D', 'pv') self.assertTrue(installdir, 'Could not query installdir variable') bindir = get_bb_var('bindir', 'pv') self.assertTrue(bindir, 'Could not query bindir variable') if bindir[0] == '/': bindir = bindir[1:] self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
def test_sstate_allarch_samesigs(self): """ The sstate checksums off allarch packages should be independent of whichever MACHINE is set. Check this using bitbake -S. """ topdir = get_bb_var('TOPDIR') targetos = get_bb_var('TARGET_OS') targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" MACHINE = \"qemux86\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") bitbake("world -S none") self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" MACHINE = \"qemuarm\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") bitbake("world -S none") def get_files(d): f = [] for root, dirs, files in os.walk(d): for name in files: if "do_build" not in name: f.append(os.path.join(root, name)) return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/all" + targetvendor + "-" + targetos) files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/all" + targetvendor + "-" + targetos) files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] self.maxDiff = None self.assertItemsEqual(files1, files2)
def test_kernel_add_dts(self): testrecipe = 'virtual/kernel' srcdir = get_bb_var('S', testrecipe) workdir = get_bb_var('WORKDIR', testrecipe) if srcdir == get_bb_var('STAGING_KERNEL_DIR', testrecipe): # If S is directly set to STAGING_KERNEL_DIR, then we most likely # have a custom checkout or unpack process like linux-yocto, so we # don't know precisely where to place the files relative to # WORKDIR. We default to 'git' in this case. subdir = 'git' else: subdir = os.path.relpath(srcdir, workdir) arch = get_bb_var('ARCH', testrecipe) destdir = '%s/arch/%s/boot/dts' % (subdir, arch) expected_file_info = { os.path.basename(self.testfile): destdir, 'testfile2': destdir, } testfile2 = os.path.join(self.tempdir, 'testfile2') with open(testfile2, 'w') as f: f.write('Test File 2') cmd = 'recipetool kernel_add_dts %s %s %s' % (self.templayerdir, self.testfile, testfile2) self._test_kernel_cmd(cmd, testrecipe, expected_file_info) devtree = get_bb_var('KERNEL_DEVICETREE', testrecipe) if not devtree: self.fail('KERNEL_DEVICETREE not defined') devtree = devtree.split() for f in expected_file_info: self.assertIn(f.replace('dts', 'dtb'), devtree)
def sstate_allarch_samesigs(self, configA, configB): topdir = get_bb_var('TOPDIR') targetos = get_bb_var('TARGET_OS') targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(configA) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") bitbake("world meta-toolchain -S none") self.write_config(configB) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") bitbake("world meta-toolchain -S none") def get_files(d): f = {} for root, dirs, files in os.walk(d): for name in files: if "meta-environment" in root or "cross-canadian" in root: continue if "do_build" not in name: # 1.4.1+gitAUTOINC+302fca9f4c-r0.do_package_write_ipk.sigdata.f3a2a38697da743f0dbed8b56aafcf79 (_, task, _, shash) = name.rsplit(".", 3) f[os.path.join(os.path.basename(root), task)] = shash return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/all" + targetvendor + "-" + targetos) files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/all" + targetvendor + "-" + targetos) self.maxDiff = None self.assertEqual(files1, files2) nativesdkdir = os.path.basename(glob.glob(topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux")[0]) files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir) files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir) self.maxDiff = None self.assertEqual(files1, files2)
def test_devtool_reset_all(self): # Check preconditions workspacedir = os.path.join(self.builddir, 'workspace') self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) self.track_for_cleanup(workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') testrecipe1 = 'mdadm' testrecipe2 = 'cronie' result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1))) result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2))) result = runCmd('devtool build %s' % testrecipe1) result = runCmd('devtool build %s' % testrecipe2) stampprefix1 = get_bb_var('STAMP', testrecipe1) self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1) stampprefix2 = get_bb_var('STAMP', testrecipe2) self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2) result = runCmd('devtool reset -a') self.assertIn(testrecipe1, result.output) self.assertIn(testrecipe2, result.output) result = runCmd('devtool status') self.assertNotIn(testrecipe1, result.output) self.assertNotIn(testrecipe2, result.output) matches1 = glob.glob(stampprefix1 + '*') self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1) matches2 = glob.glob(stampprefix2 + '*') self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
def test_bmap(self): """ Summary: Check bmap support Expected: 1. core-image-minimal can be build with bmap support 2. core-image-minimal is sparse Product: oe-core Author: Ed Bartosh <*****@*****.**> """ features = 'IMAGE_FSTYPES += " ext4 ext4.bmap ext4.bmap.gz"' self.write_config(features) image_name = 'core-image-minimal' bitbake(image_name) deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') link_name = get_bb_var('IMAGE_LINK_NAME', image_name) image_path = os.path.join(deploy_dir_image, "%s.ext4" % link_name) bmap_path = "%s.bmap" % image_path gzip_path = "%s.gz" % bmap_path # check if result image, bmap and bmap.gz files are in deploy directory self.assertTrue(os.path.exists(image_path)) self.assertTrue(os.path.exists(bmap_path)) self.assertTrue(os.path.exists(gzip_path)) # check if result image is sparse image_stat = os.stat(image_path) self.assertTrue(image_stat.st_size > image_stat.st_blocks * 512) # check if the resulting gzip is valid self.assertTrue(runCmd('gzip -t %s' % gzip_path))
def run_test_sstate_cache_management_script( self, target, global_config=[""], target_config=[""], ignore_patterns=[] ): self.assertTrue(global_config) self.assertTrue(target_config) self.assertTrue( len(global_config) == len(target_config), msg="Lists global_config and target_config should have the same number of elements", ) self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path]) # If buildhistory is enabled, we need to disable version-going-backwards QA checks for this test. It may report errors otherwise. if ("buildhistory" in get_bb_var("USER_CLASSES")) or ("buildhistory" in get_bb_var("INHERIT")): remove_errors_config = 'ERROR_QA_remove = "version-going-backwards"' self.append_config(remove_errors_config) # For not this only checks if random sstate tasks are handled correctly as a group. # In the future we should add control over what tasks we check for. sstate_archs_list = [] expected_remaining_sstate = [] for idx in range(len(target_config)): self.append_config(global_config[idx]) self.append_recipeinc(target, target_config[idx]) sstate_arch = get_bb_var("SSTATE_PKGARCH", target) if not sstate_arch in sstate_archs_list: sstate_archs_list.append(sstate_arch) if target_config[idx] == target_config[-1]: target_sstate_before_build = self.search_sstate(target + ".*?\.tgz$") bitbake("-cclean %s" % target) result = bitbake(target, ignore_status=True) if target_config[idx] == target_config[-1]: target_sstate_after_build = self.search_sstate(target + ".*?\.tgz$") expected_remaining_sstate += [ x for x in target_sstate_after_build if x not in target_sstate_before_build if not any(pattern in x for pattern in ignore_patterns) ] self.remove_config(global_config[idx]) self.remove_recipeinc(target, target_config[idx]) self.assertEqual(result.status, 0) runCmd( "sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ",".join(map(str, sstate_archs_list))) ) actual_remaining_sstate = [ x for x in self.search_sstate(target + ".*?\.tgz$") if not any(pattern in x for pattern in ignore_patterns) ] actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate] self.assertFalse( actual_not_expected, msg="Files should have been removed but ware not: %s" % ", ".join(map(str, actual_not_expected)), ) expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate] self.assertFalse( expected_not_actual, msg="Extra files ware removed: %s" ", ".join(map(str, expected_not_actual)) )
def test_long_chain_conversion(self): """ Summary: Check for chaining many CONVERSION_CMDs together Expected: 1. core-image-minimal can be built with ext4.bmap.gz.bz2.lzo.xz.u-boot and also create a sha256sum 2. The above image has a valid sha256sum Product: oe-core Author: Tom Rini <*****@*****.**> """ conv = "ext4.bmap.gz.bz2.lzo.xz.u-boot" features = 'IMAGE_FSTYPES += "%s %s.sha256sum"' % (conv, conv) self.write_config(features) image_name = 'core-image-minimal' bitbake(image_name) deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') link_name = get_bb_var('IMAGE_LINK_NAME', image_name) image_path = os.path.join(deploy_dir_image, "%s.%s" % (link_name, conv)) # check if resulting image is in the deploy directory self.assertTrue(os.path.exists(image_path)) self.assertTrue(os.path.exists(image_path + ".sha256sum")) # check if the resulting sha256sum agrees self.assertTrue(runCmd('cd %s;sha256sum -c %s.%s.sha256sum' % (deploy_dir_image, link_name, conv)))
def test_image_fstypes(self): """ Summary: Check if image of supported image fstypes can be built Expected: core-image-minimal can be built for various image types Product: oe-core Author: Ed Bartosh <*****@*****.**> """ image_name = 'core-image-minimal' img_types = [itype for itype in get_bb_var("IMAGE_TYPES", image_name).split() \ if itype not in ('container', 'elf', 'f2fs', 'multiubi')] config = 'IMAGE_FSTYPES += "%s"\n'\ 'MKUBIFS_ARGS ?= "-m 2048 -e 129024 -c 2047"\n'\ 'UBINIZE_ARGS ?= "-m 2048 -p 128KiB -s 512"' % ' '.join(img_types) self.write_config(config) bitbake(image_name) deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') link_name = get_bb_var('IMAGE_LINK_NAME', image_name) for itype in img_types: image_path = os.path.join(deploy_dir_image, "%s.%s" % (link_name, itype)) # check if result image is in deploy directory self.assertTrue(os.path.exists(image_path), "%s image %s doesn't exist" % (itype, image_path))
def test_archiver_allows_to_filter_on_recipe_name(self): """ Summary: The archiver should offer the possibility to filter on the recipe. (#6929) Expected: 1. Included recipe (busybox) should be included 2. Excluded recipe (zlib) should be excluded Product: oe-core Author: Daniel Istrate <*****@*****.**> AutomatedBy: Daniel Istrate <*****@*****.**> """ include_recipe = 'busybox' exclude_recipe = 'zlib' features = 'INHERIT += "archiver"\n' features += 'ARCHIVER_MODE[src] = "original"\n' features += 'COPYLEFT_PN_INCLUDE = "%s"\n' % include_recipe features += 'COPYLEFT_PN_EXCLUDE = "%s"\n' % exclude_recipe self.write_config(features) shutil.rmtree(get_bb_var('TMPDIR')) bitbake("%s %s" % (include_recipe, exclude_recipe)) src_path = os.path.join(get_bb_var('DEPLOY_DIR_SRC'), get_bb_var('TARGET_SYS')) # Check that include_recipe was included included_present = len(glob.glob(src_path + '/%s-*' % include_recipe)) self.assertTrue(included_present, 'Recipe %s was not included.' % include_recipe) # Check that exclude_recipe was excluded excluded_present = len(glob.glob(src_path + '/%s-*' % exclude_recipe)) self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % exclude_recipe)
def test_hypervisor_fmts(self): """ Summary: Check various hypervisor formats Expected: 1. core-image-minimal can be built with vmdk, vdi and qcow2 support. 2. qemu-img says each image has the expected format Product: oe-core Author: Tom Rini <*****@*****.**> """ img_types = [ 'vmdk', 'vdi', 'qcow2' ] features = "" for itype in img_types: features += 'IMAGE_FSTYPES += "wic.%s"\n' % itype self.write_config(features) image_name = 'core-image-minimal' bitbake(image_name) deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') link_name = get_bb_var('IMAGE_LINK_NAME', image_name) for itype in img_types: image_path = os.path.join(deploy_dir_image, "%s.wic.%s" % (link_name, itype)) # check if result image file is in deploy directory self.assertTrue(os.path.exists(image_path)) # check if result image is vmdk sysroot = get_bb_var('STAGING_DIR_NATIVE', 'core-image-minimal') result = runCmd('qemu-img info --output json %s' % image_path, native_sysroot=sysroot) self.assertTrue(json.loads(result.output).get('format') == itype)
def test_copy_tree_xattr(self): """ Summary: oe.path.copytree() should preserve xattr on copied files Expected: testxattr file in destination should have user.oetest extended attribute Product: OE-Core Author: Joshua Lock <*****@*****.**> """ tmp_dir = get_bb_var('TMPDIR') testloc = oe.path.join(tmp_dir, 'liboetests') src = oe.path.join(testloc, 'src') dst = oe.path.join(testloc, 'dst') bb.utils.mkdirhier(testloc) bb.utils.mkdirhier(src) testfilename = 'testxattr' # ensure we have setfattr available bitbake("attr-native") destdir = get_bb_var('SYSROOT_DESTDIR', 'attr-native') bindir = get_bb_var('bindir', 'attr-native') bindir = destdir + bindir # create a file with xattr and copy it open(oe.path.join(src, testfilename), 'w+b').close() runCmd('%s/setfattr -n user.oetest -v "testing liboe" %s' % (bindir, oe.path.join(src, testfilename))) oe.path.copytree(src, dst) # ensure file in dest has user.oetest xattr result = runCmd('%s/getfattr -n user.oetest %s' % (bindir, oe.path.join(dst, testfilename))) self.assertIn('user.oetest="testing liboe"', result.output, 'Extended attribute not sert in dst') oe.path.remove(testloc)
def test_sstate_32_64_same_hash(self): """ The sstate checksums for both native and target should not vary whether they're built on a 32 or 64 bit system. Rather than requiring two different build machines and running a builds, override the variables calling uname() manually and check using bitbake -S. """ topdir = get_bb_var('TOPDIR') targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" BUILD_ARCH = \"x86_64\" BUILD_OS = \"linux\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") bitbake("core-image-sato -S printdiff", ignore_status=True) self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" BUILD_ARCH = \"i686\" BUILD_OS = \"linux\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") bitbake("core-image-sato -S printdiff", ignore_status=True) def get_files(d): f = [] for root, dirs, files in os.walk(d): f.extend(os.path.join(root, name) for name in files) return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash").replace("i686-linux", "x86_64-linux").replace("i686" + targetvendor + "-linux", "x86_64" + targetvendor + "-linux", ) for x in files2] self.assertItemsEqual(files1, files2)
def test_sstate_nativelsbstring_same_hash(self): """ The sstate checksums should be independent of whichever NATIVELSBSTRING is detected. Rather than requiring two different build machines and running builds, override the variables manually and check using bitbake -S. """ topdir = get_bb_var('TOPDIR') targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" NATIVELSBSTRING = \"DistroA\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") bitbake("core-image-sato -S printdiff", ignore_status=True) self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" NATIVELSBSTRING = \"DistroB\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") bitbake("core-image-sato -S printdiff", ignore_status=True) def get_files(d): f = [] for root, dirs, files in os.walk(d): f.extend(os.path.join(root, name) for name in files) return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] self.assertItemsEqual(files1, files2)
def setUpLocal(self): super(RunqemuTests, self).setUpLocal() self.recipe = 'core-image-minimal' self.machine = 'qemux86-64' self.fstypes = "ext4 iso hddimg wic.vmdk wic.qcow2 wic.vdi" self.cmd_common = "runqemu nographic" kvm = oe.types.qemu_use_kvm(get_bb_var('QEMU_USE_KVM'), 'x86_64') if kvm: self.cmd_common += " kvm" self.write_config( """ MACHINE = "%s" IMAGE_FSTYPES = "%s" # 10 means 1 second SYSLINUX_TIMEOUT = "10" """ % (self.machine, self.fstypes) ) if not RunqemuTests.image_is_ready: RunqemuTests.deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') bitbake(self.recipe) RunqemuTests.image_is_ready = True
def test_bmap(self): """ Summary: Check bmap support Expected: 1. core-image-minimal can be build with bmap support 2. core-image-minimal is sparse Product: oe-core Author: Ed Bartosh <*****@*****.**> """ features = 'IMAGE_FSTYPES += " ext4 ext4.bmap"' self.write_config(features) image_name = "core-image-minimal" bitbake(image_name) deploy_dir = get_bb_var("DEPLOY_DIR_IMAGE") link_name = get_bb_var("IMAGE_LINK_NAME", image_name) image_path = os.path.join(deploy_dir, "%s.ext4" % link_name) bmap_path = "%s.bmap" % image_path # check if result image and bmap file are in deploy directory self.assertTrue(os.path.exists(image_path)) self.assertTrue(os.path.exists(bmap_path)) # check if result image is sparse image_stat = os.stat(image_path) self.assertTrue(image_stat.st_size > image_stat.st_blocks * 512)
def test_rpm_version_4_support_on_image(self): """ Summary: Check rpm version 4 support on image Expected: Rpm version must be 4.x Product: oe-core Author: Ionut Chisanovici <*****@*****.**> AutomatedBy: Daniel Istrate <*****@*****.**> """ features = 'PREFERRED_VERSION_rpm = "4.%"\n' features += 'PREFERRED_VERSION_rpm-native = "4.%"\n' # Use openssh in IMAGE_INSTALL instead of ssh-server-openssh in EXTRA_IMAGE_FEATURES as a workaround for bug 8047 features += 'IMAGE_INSTALL_append = " openssh"\n' features += 'EXTRA_IMAGE_FEATURES = "empty-root-password allow-empty-password package-management"\n' features += 'RPMROOTFSDEPENDS_remove = "rpmresolve-native:do_populate_sysroot"' # Append 'features' to local.conf self.append_config(features) # Build a core-image-minimal bitbake("core-image-minimal") # Check the native version of rpm is correct native_bindir = get_bb_var("STAGING_BINDIR_NATIVE") result = runCmd(os.path.join(native_bindir, "rpm") + " --version") self.assertIn("version 4.", result.output) # Check manifest for the rpm package deploydir = get_bb_var("DEPLOY_DIR_IMAGE") imgname = get_bb_var("IMAGE_LINK_NAME", "core-image-minimal") with open(os.path.join(deploydir, imgname) + ".manifest", "r") as f: for line in f: splitline = line.split() if len(splitline) > 2: rpm_version = splitline[2] if splitline[0] == "rpm": if not rpm_version.startswith("4."): self.fail("rpm version %s found in image, expected 4.x" % rpm_version) break else: self.fail("No rpm package found in image") # Now do a couple of runtime tests with runqemu("core-image-minimal", self) as qemu: command = "rpm --version" status, output = qemu.run(command) self.assertEqual(0, status, 'Failed to run command "%s": %s' % (command, output)) found_rpm_version = output.strip() # Make sure the retrieved rpm version is the expected one if rpm_version not in found_rpm_version: self.fail("RPM version is not {}, found instead {}.".format(rpm_version, found_rpm_version)) # Test that the rpm database is there and working command = "rpm -qa" status, output = qemu.run(command) self.assertEqual(0, status, 'Failed to run command "%s": %s' % (command, output)) self.assertIn("packagegroup-core-boot", output) self.assertIn("busybox", output)
def test_rm_old_image(self): bitbake("core-image-minimal") deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal") imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal") oldimgpath = os.path.realpath(os.path.join(deploydir, imagename + ".ext3")) self.append_config("RM_OLD_IMAGE = \"1\"") bitbake("core-image-minimal") self.assertFalse(os.path.exists(oldimgpath), msg="Old image path still exists: %s" % oldimgpath)
def test_ccache_tool(self): bitbake("ccache-native") self.assertTrue(os.path.isfile(os.path.join(get_bb_var('STAGING_BINDIR_NATIVE', 'ccache-native'), "ccache"))) self.write_config('INHERIT += "ccache"') bitbake("m4 -c cleansstate") bitbake("m4 -c compile") res = runCmd("grep ccache %s" % (os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile")), ignore_status=True) self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile") bitbake("ccache-native -ccleansstate")
def setUpClass(cls): super(QemuTest, cls).setUpClass() cls.recipe = 'core-image-minimal' cls.machine = get_bb_var('MACHINE') cls.deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') cls.cmd_common = "runqemu nographic" cls.qemuboot_conf = "%s-%s.qemuboot.conf" % (cls.recipe, cls.machine) cls.qemuboot_conf = os.path.join(cls.deploy_dir_image, cls.qemuboot_conf) bitbake(cls.recipe)
def test_rename_downloaded_file(self): data = 'SRC_URI_append = ";downloadfilename=test-aspell.tar.gz"' self.write_recipeinc('aspell', data) bitbake('-ccleanall aspell') result = bitbake('-c fetch aspell', ignore_status=True) self.delete_recipeinc('aspell') self.assertEqual(result.status, 0) self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz'))) self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz.done'))) bitbake('-ccleanall aspell')
def test_ccache_tool(self): bitbake("ccache-native") p = get_bb_var('SYSROOT_DESTDIR', 'ccache-native') + get_bb_var('bindir', 'ccache-native') + "/" + "ccache" self.assertTrue(os.path.isfile(p), msg = "No ccache found (%s)" % p) self.write_config('INHERIT += "ccache"') bitbake("m4 -c cleansstate") bitbake("m4 -c compile") self.addCleanup(bitbake, 'ccache-native -ccleansstate') res = runCmd("grep ccache %s" % (os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile")), ignore_status=True) self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile. For further details: %s" % os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile"))
def test_recipetool_appendsrcfile_replace_file_srcdir(self): testrecipe = "bash" filepath = "Makefile.in" srcdir = get_bb_var("S", testrecipe) workdir = get_bb_var("WORKDIR", testrecipe) subdir = os.path.relpath(srcdir, workdir) self._test_appendsrcfile(testrecipe, filepath, srcdir=subdir) bitbake("%s:do_unpack" % testrecipe) self.assertEqual(open(self.testfile, "r").read(), open(os.path.join(srcdir, filepath), "r").read())
def test_recipetool_appendsrcfile_replace_file_srcdir(self): testrecipe = 'bash' filepath = 'Makefile.in' srcdir = get_bb_var('S', testrecipe) workdir = get_bb_var('WORKDIR', testrecipe) subdir = os.path.relpath(srcdir, workdir) self._test_appendsrcfile(testrecipe, filepath, srcdir=subdir) bitbake('%s:do_unpack' % testrecipe) self.assertEqual(open(self.testfile, 'r').read(), open(os.path.join(srcdir, filepath), 'r').read())
def test_devtool_deploy_target(self): # NOTE: Whilst this test would seemingly be better placed as a runtime test, # unfortunately the runtime tests run under bitbake and you can't run # devtool within bitbake (since devtool needs to run bitbake itself). # Additionally we are testing build-time functionality as well, so # really this has to be done as an oe-selftest test. # # Check preconditions machine = get_bb_var('MACHINE') if not machine.startswith('qemu'): self.skipTest('This test only works with qemu machines') if not os.path.exists('/etc/runqemu-nosudo'): self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') workspacedir = os.path.join(self.builddir, 'workspace') self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') import pexpect # Definitions testrecipe = 'mdadm' testfile = '/sbin/mdadm' testimage = 'oe-selftest-image' testhost = '192.168.7.2' testcommand = '/sbin/mdadm --help' # Build an image to run bitbake("%s qemu-native qemu-helper-native" % testimage) deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') self.add_command_to_tearDown('bitbake -c clean %s' % testimage) self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage)) # Clean recipe so the first deploy will fail bitbake("%s -c clean" % testrecipe) # Try devtool modify tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) self.track_for_cleanup(workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) # Test that deploy-target at this point fails (properly) result = runCmd('devtool deploy-target -n %s root@%s' % (testrecipe, testhost), ignore_status=True) self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output) self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output) result = runCmd('devtool build %s' % testrecipe) # First try a dry-run of deploy-target result = runCmd('devtool deploy-target -n %s root@%s' % (testrecipe, testhost)) self.assertIn(' %s' % testfile, result.output) # Boot the image console = pexpect.spawn('runqemu %s %s qemuparams="-snapshot" nographic' % (machine, testimage)) console.expect("login:", timeout=120) # Now really test deploy-target result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, testhost)) result = runCmd('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@%s %s' % (testhost, testcommand)) # Test undeploy-target result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, testhost)) result = runCmd('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@%s %s' % (testhost, testcommand), ignore_status=True) self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have') console.close()
def test_incremental_image_generation(self): bitbake("-c cleanall core-image-minimal") self.write_config('INC_RPM_IMAGE_GEN = "1"') self.append_config('IMAGE_FEATURES += "ssh-server-openssh"') bitbake("core-image-minimal") res = runCmd("grep 'Installing openssh-sshd' %s" % (os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs")), ignore_status=True) self.remove_config('IMAGE_FEATURES += "ssh-server-openssh"') self.assertEqual(0, res.status, msg="No match for openssh-sshd in log.do_rootfs") bitbake("core-image-minimal") res = runCmd("grep 'Removing openssh-sshd' %s" %(os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs")),ignore_status=True) self.assertEqual(0, res.status, msg="openssh-sshd was not removed from image")
def test_sstate_32_64_same_hash(self): """ The sstate checksums for both native and target should not vary whether they're built on a 32 or 64 bit system. Rather than requiring two different build machines and running a builds, override the variables calling uname() manually and check using bitbake -S. Also check that SDKMACHINE and PARALLEL_MAKE changing doesn't change any of these stamps. """ topdir = get_bb_var('TOPDIR') targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" MACHINE = "qemux86" TMPDIR = "${TOPDIR}/tmp-sstatesamehash" BUILD_ARCH = "x86_64" BUILD_OS = "linux" SDKMACHINE = "x86_64" PARALLEL_MAKE = "-j 1" DL_DIR = "${TOPDIR}/download1" TIME = "111111" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") bitbake("core-image-sato -S none") self.write_config(""" MACHINE = "qemux86" TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" BUILD_ARCH = "i686" BUILD_OS = "linux" SDKMACHINE = "i686" PARALLEL_MAKE = "-j 2" DL_DIR = "${TOPDIR}/download2" TIME = "222222" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") bitbake("core-image-sato -S none") def get_files(d): f = [] for root, dirs, files in os.walk(d): if "core-image-sato" in root: # SDKMACHINE changing will change # do_rootfs/do_testimage/do_build stamps of images which # is safe to ignore. continue f.extend(os.path.join(root, name) for name in files) return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash").replace("i686-linux", "x86_64-linux").replace("i686" + targetvendor + "-linux", "x86_64" + targetvendor + "-linux", ) for x in files2] self.maxDiff = None self.assertItemsEqual(files1, files2)
def setup_gpg(self): bitbake('gnupg-native -c addto_recipe_sysroot') self.gpg_dir = tempfile.mkdtemp(prefix="oeqa-signing-") self.track_for_cleanup(self.gpg_dir) self.pub_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.pub") self.secret_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.secret") nsysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native") runCmd('gpg --batch --homedir %s --import %s %s' % (self.gpg_dir, self.pub_key_path, self.secret_key_path), native_sysroot=nsysroot) return nsysroot + get_bb_var("bindir_native")
def test_build_artifacts(self): """Test wic create directdisk providing all artifacts.""" bbvars = dict((var.lower(), get_bb_var(var, 'core-image-minimal')) for var in ('STAGING_DATADIR', 'DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS')) bbvars['recipe_sysroot_native'] = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') status = runCmd("wic create directdisk " "-b %(staging_datadir)s " "-k %(deploy_dir_image)s " "-n %(recipe_sysroot_native)s " "-r %(image_rootfs)s" % bbvars).status self.assertEqual(0, status) self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
def test_wic_image_type(self): """Test building wic images by bitbake""" self.assertEqual(0, bitbake('wic-image-minimal').status) deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') machine = get_bb_var('MACHINE') prefix = os.path.join(deploy_dir, 'wic-image-minimal-%s.' % machine) # check if we have result image and manifests symlinks # pointing to existing files for suffix in ('wic', 'manifest'): path = prefix + suffix self.assertTrue(os.path.islink(path)) self.assertTrue(os.path.isfile(os.path.realpath(path)))
def test_rpm_version_4_support_on_image(self): """ Summary: Check rpm version 4 support on image Expected: Rpm version must be 4.x Product: oe-core Author: Ionut Chisanovici <*****@*****.**> AutomatedBy: Daniel Istrate <*****@*****.**> """ features = 'MACHINE = "qemux86"\n' features += 'PREFERRED_VERSION_rpm = "4.%"\n' features += 'PREFERRED_VERSION_rpm-native = "4.%"\n' # Use openssh in IMAGE_INSTALL instead of ssh-server-openssh in EXTRA_IMAGE_FEATURES as a workaround for bug 8047 features += 'IMAGE_INSTALL_append = " openssh"\n' features += 'EXTRA_IMAGE_FEATURES = "empty-root-password allow-empty-password package-management"\n' features += 'RPMROOTFSDEPENDS_remove = "rpmresolve-native:do_populate_sysroot"' self.write_config(features) # Build a core-image-minimal bitbake('core-image-minimal') # Check the native version of rpm is correct native_bindir = get_bb_var('STAGING_BINDIR_NATIVE') result = runCmd(os.path.join(native_bindir, 'rpm') + ' --version') self.assertIn('version 4.', result.output) # Check manifest for the rpm package deploydir = get_bb_var('DEPLOY_DIR_IMAGE') imgname = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal') with open(os.path.join(deploydir, imgname) + '.manifest', 'r') as f: for line in f: splitline = line.split() if len(splitline) > 2: rpm_version = splitline[2] if splitline[0] == 'rpm': if not rpm_version.startswith('4.'): self.fail( 'rpm version %s found in image, expected 4.x' % rpm_version) break else: self.fail('No rpm package found in image') # Now do a couple of runtime tests with runqemu("core-image-minimal", self) as qemu: command = "rpm --version" status, output = qemu.run(command) self.assertEqual( 0, status, 'Failed to run command "%s": %s' % (command, output)) found_rpm_version = output.strip() # Make sure the retrieved rpm version is the expected one if rpm_version not in found_rpm_version: self.fail('RPM version is not {}, found instead {}.'.format( rpm_version, found_rpm_version)) # Test that the rpm database is there and working command = "rpm -qa" status, output = qemu.run(command) self.assertEqual( 0, status, 'Failed to run command "%s": %s' % (command, output)) self.assertIn('packagegroup-core-boot', output) self.assertIn('busybox', output)
def test_sstate_samesigs(self): """ The sstate checksums off allarch packages should be independent of whichever MACHINE is set. Check this using bitbake -S. Also, rather than duplicate the test, check nativesdk stamps are the same between the two MACHINE values. Also, when building for multiple machines which share tune flag specific packages, those packages also need to have identical signatures. Based on oeqa.selftest.sstatetests.SStateTests.test_sstate_allarch_samesigs and extended to cover all Ostro OS machines. """ topdir = get_bb_var('TOPDIR') targetos = get_bb_var('TARGET_OS') targetvendor = get_bb_var('TARGET_VENDOR') libcappend = get_bb_var('TCLIBCAPPEND') # Select subset of the machines to speed up testing. # Edison/intel-core2-32 are particularly sensitive. machines = "edison intel-quark intel-core2-32 intel-corei7-64 beaglebone".split( ) # machines = "edison intel-core2-32".split() first = machines[0] workdir = os.getcwd() try: pending = [] for machine in machines: builddir = '%s/build-%s' % (topdir, machine) os.mkdir(builddir) self.track_for_cleanup(builddir) os.chdir(builddir) shutil.copytree('../conf', 'conf') ftools.write_file( 'conf/selftest.inc', """ TMPDIR = \"%s/tmp-sstatesamehash-%s\" MACHINE = \"%s\" """ % (topdir, machine, machine)) # Comment out to debug with bitbake-diffstat after running the test. # In that case, remember to "rm -r tmp-*" before the next run. self.track_for_cleanup(topdir + "/tmp-sstatesamehash-%s%s" % (machine, libcappend)) # Replace build targets with individual recipes to investigate just those. pending.append( (machine, subprocess.Popen( 'bitbake world meta-toolchain -S none'.split(), stdout=open('%s/bitbake.log' % builddir, 'w'), stderr=subprocess.STDOUT))) for machine, p in pending: returncode = p.wait() if returncode: raise AssertionError( "bitbake failed for machine %s with return code %d:\n%s" % (machine, returncode, open('%s/build-%s/bitbake.log' % (topdir, machine)).read())) finally: os.chdir(workdir) def get_hashes(d, subdir): f = {} for root, dirs, files in os.walk(os.path.join(d, subdir)): for name in files: # meta-toolchain depends on cross-canadian. # Not sure about adt-installer. Hash is different, but bitbake-diffstat # shows no difference. # do_deploy is allowed to differ, it just as a performance impact because of # unnecessary rebuilding (minor in our case, not many recipes hit this). if "meta-environment" in root or "cross-canadian" in root or \ "do_populate_adt" in name and "adt-installer" in root or \ "do_populate_sdk" in name and "meta-toolchain" in root or \ "do_build" in name or \ "do_deploy" in name: continue components = name.split('.sigdata.') # Map from 'all-ostro-linux/1_1.04-r4.do_build' to '95c22ae3e1c81cdc116db37b68db10be'. # All tasks that are shared by different machines must have the same hash. f[os.path.join(os.path.relpath(root, d), components[0])] = ''.join(components[1:]) return f # Will be found when building meta-toolchain, otherwise it won't. nativesdkdir = glob.glob( topdir + ("/tmp-sstatesamehash-%s%s/stamps/*-nativesdk*-linux" % (first, libcappend))) if nativesdkdir: nativesdkdir = os.path.basename(nativesdkdir[0]) hashes = {} tasks = set() for machine in machines: hashes[machine] = {} # Only some some packages are expected to have the same signature. subdirs = [ "all" + targetvendor + "-" + targetos, # allarch "core2-32" + targetvendor + "-" + targetos, # shared between edison and intel-core2-32 ] if nativesdkdir: subdirs.append(nativesdkdir) for subdir in subdirs: hashes[machine].update( get_hashes( topdir + ("/tmp-sstatesamehash-%s%s/stamps" % (machine, libcappend)), subdir)) tasks.update(hashes[machine].keys()) errors = ['Machines have different hashes:'] analysis = [] tasks = list(tasks) tasks.sort() for task in tasks: # Find all machines sharing the same value. values = {} for machine in machines: value = hashes[machine].get(task, None) if value: values.setdefault(value, []).append(machine) values = sorted(values.items()) if len(values) > 1: errors.append( 'Not the same hash for ' + task + ': ' + ' '.join(['/'.join(m) + '=' + v for v, m in values])) # Pick the initial two values and the first machine in each where # the task differed and compare the signatures. cmd = "set -x; bitbake-diffsigs tmp-sstatesamehash-*%s*/stamps/*%s.* tmp-sstatesamehash-*%s*/stamps/*%s.*" % \ (values[0][1][0], task, values[1][1][0], task) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout, stderr = p.communicate() analysis.append(stdout.decode("utf-8")) if len(errors) > 1: # If this fails, it often fails for a whole range of tasks where one depends on # the other. In this example, only the original source file was different: # # AssertionError: False is not true : Machines have different hashes: # Not the same hash for all-poky-linux/initramfs-boot/1.0-r2.do_compile: intel-core2-32=1efd21ed2f11a4a2aef1ade99e0ae523 edison=d4aa4f356187f0902cd5b9e1fed250c4 # ... # Not the same hash for all-ostro-linux/initramfs-boot/1.0-r2.do_fetch: edison=82a397e985e2c570714ab7dfa3e21a6c intel-core2-32=79b455328b0b298423cf52582cc12c7c # ... self.assertTrue(False, msg='\n'.join(errors) + '\n\n' + '\n\n'.join(analysis))
def check_skip(self, suite): targets = get_bb_var("RUNTIMETARGET", "gcc-runtime").split() if suite not in targets: self.skipTest("Target does not use {0}".format(suite))
def test_postinst_roofs_and_boot(self): """ Summary: The purpose of this test case is to verify Post-installation scripts are called when roofs is created and also test that script can be delayed to run at first boot. Dependencies: NA Steps: 1. Add proper configuration to local.conf file 2. Build a "core-image-minimal" image 3. Verify that file created by postinst_rootfs recipe is present on rootfs dir. 4. Boot the image created on qemu and verify that the file created by postinst_boot recipe is present on image. 5. Clean the packages and image created to test with different package managers Expected: The files are successfully created during rootfs and boot time for 3 different package managers: rpm,ipk,deb and for initialization managers: sysvinit and systemd. """ file_rootfs_name = "this-was-created-at-rootfstime" fileboot_name = "this-was-created-at-first-boot" rootfs_pkg = 'postinst-at-rootfs' boot_pkg = 'postinst-delayed-a' #Step 1 features = 'MACHINE = "qemux86"\n' features += 'CORE_IMAGE_EXTRA_INSTALL += "%s %s "\n' % (rootfs_pkg, boot_pkg) features += 'IMAGE_FEATURES += "ssh-server-openssh"\n' for init_manager in ("sysvinit", "systemd"): #for sysvinit no extra configuration is needed, if (init_manager is "systemd"): features += 'DISTRO_FEATURES_append = " systemd"\n' features += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n' features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n' features += 'VIRTUAL-RUNTIME_initscripts = ""\n' for classes in ("package_rpm package_deb package_ipk", "package_deb package_rpm package_ipk", "package_ipk package_deb package_rpm"): features += 'PACKAGE_CLASSES = "%s"\n' % classes self.write_config(features) #Step 2 bitbake('core-image-minimal') #Step 3 file_rootfs_created = os.path.join( get_bb_var('IMAGE_ROOTFS', "core-image-minimal"), file_rootfs_name) found = os.path.isfile(file_rootfs_created) self.assertTrue(found, "File %s was not created at rootfs time by %s" % \ (file_rootfs_name, rootfs_pkg)) #Step 4 testcommand = 'ls /etc/' + fileboot_name with runqemu('core-image-minimal') as qemu: sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand)) self.assertEqual( result.status, 0, 'File %s was not created at firts boot' % fileboot_name) #Step 5 bitbake(' %s %s -c cleanall' % (rootfs_pkg, boot_pkg)) bitbake('core-image-minimal -c cleanall')
def test_sstate_creation_distro_specific_fail(self): targetarch = get_bb_var('TUNE_ARCH') self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False)
def test_rebuild_distro_specific_sstate_cross_target(self): targetarch = get_bb_var('TUNE_ARCH') self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch], temp_sstate_location=True)
def test_signing_packages(self): """ Summary: Test that packages can be signed in the package feed Expected: Package should be signed with the correct key Expected: Images can be created from signed packages Product: oe-core Author: Daniel Istrate <*****@*****.**> Author: Alexander Kanavin <*****@*****.**> AutomatedBy: Daniel Istrate <*****@*****.**> """ import oe.packagedata self.setup_gpg() package_classes = get_bb_var('PACKAGE_CLASSES') if 'package_rpm' not in package_classes: self.skipTest('This test requires RPM Packaging.') test_recipe = 'ed' feature = 'INHERIT += "sign_rpm"\n' feature += 'RPM_GPG_PASSPHRASE = "test123"\n' feature += 'RPM_GPG_NAME = "testuser"\n' feature += 'GPG_PATH = "%s"\n' % self.gpg_dir self.write_config(feature) bitbake('-c clean %s' % test_recipe) bitbake('-f -c package_write_rpm %s' % test_recipe) self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe) needed_vars = ['PKGDATA_DIR', 'DEPLOY_DIR_RPM', 'PACKAGE_ARCH', 'STAGING_BINDIR_NATIVE'] bb_vars = get_bb_vars(needed_vars, test_recipe) pkgdatadir = bb_vars['PKGDATA_DIR'] pkgdata = oe.packagedata.read_pkgdatafile(pkgdatadir + "/runtime/ed") if 'PKGE' in pkgdata: pf = pkgdata['PN'] + "-" + pkgdata['PKGE'] + pkgdata['PKGV'] + '-' + pkgdata['PKGR'] else: pf = pkgdata['PN'] + "-" + pkgdata['PKGV'] + '-' + pkgdata['PKGR'] deploy_dir_rpm = bb_vars['DEPLOY_DIR_RPM'] package_arch = bb_vars['PACKAGE_ARCH'].replace('-', '_') staging_bindir_native = bb_vars['STAGING_BINDIR_NATIVE'] pkg_deploy = os.path.join(deploy_dir_rpm, package_arch, '.'.join((pf, package_arch, 'rpm'))) # Use a temporary rpmdb rpmdb = tempfile.mkdtemp(prefix='oeqa-rpmdb') runCmd('%s/rpmkeys --define "_dbpath %s" --import %s' % (staging_bindir_native, rpmdb, self.pub_key_path)) ret = runCmd('%s/rpmkeys --define "_dbpath %s" --checksig %s' % (staging_bindir_native, rpmdb, pkg_deploy)) # tmp/deploy/rpm/i586/ed-1.9-r0.i586.rpm: rsa sha1 md5 OK self.assertIn('digests signatures OK', ret.output, 'Package signed incorrectly.') shutil.rmtree(rpmdb) #Check that an image can be built from signed packages self.add_command_to_tearDown('bitbake -c clean core-image-minimal') bitbake('-c clean core-image-minimal') bitbake('core-image-minimal')
def test_sign_cascaded_uboot_fit_image(self): """ Summary: Check if U-Boot FIT image and Image Tree Source (its) are created and signed correctly for the scenario where both U-Boot proper and Kernel fitImages are being created and signed. Expected: 1) U-Boot its and FIT image are built successfully 2) Scanning the its file indicates signing is enabled as requested by SPL_SIGN_ENABLE (using keys generated via UBOOT_FIT_GENERATE_KEYS) 3) Dumping the FIT image indicates signature values are present 4) Examination of the do_uboot_assemble_fitimage runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and SPL_MKIMAGE_SIGN_ARGS are working as expected. Product: oe-core Author: Klaus Heinrich Kiwi <*****@*****.**> based upon work by Paul Eggleton <*****@*****.**> and Usama Arif <*****@*****.**> """ config = """ # There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at # least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set MACHINE = "qemuarm" UBOOT_MACHINE = "am57xx_evm_defconfig" SPL_BINARY = "MLO" # Enable creation and signing of the U-Boot fitImage UBOOT_FITIMAGE_ENABLE = "1" SPL_SIGN_ENABLE = "1" SPL_SIGN_KEYNAME = "spl-cascaded-oe-selftest" SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" UBOOT_DTB_BINARY = "u-boot.dtb" UBOOT_ENTRYPOINT = "0x80000000" UBOOT_LOADADDRESS = "0x80000000" UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded Kernel comment'" UBOOT_DTB_LOADADDRESS = "0x82000000" UBOOT_ARCH = "arm" SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded U-Boot comment'" UBOOT_EXTLINUX = "0" UBOOT_FIT_GENERATE_KEYS = "1" UBOOT_FIT_HASH_ALG = "sha256" KERNEL_IMAGETYPES += " fitImage " KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" UBOOT_SIGN_KEYNAME = "kernel-oe-selftest" FIT_SIGN_INDIVIDUAL = "1" """ self.write_config(config) # The U-Boot fitImage is created as part of linux recipe bitbake("virtual/kernel") image_type = "core-image-minimal" deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') machine = get_bb_var('MACHINE') fitimage_its_path = os.path.join(deploy_dir_image, "u-boot-its-%s" % (machine,)) fitimage_path = os.path.join(deploy_dir_image, "u-boot-fitImage-%s" % (machine,)) self.assertTrue(os.path.exists(fitimage_its_path), "%s image tree source doesn't exist" % (fitimage_its_path)) self.assertTrue(os.path.exists(fitimage_path), "%s FIT image doesn't exist" % (fitimage_path)) req_itspaths = [ ['/', 'images', 'uboot'], ['/', 'images', 'uboot', 'signature'], ['/', 'images', 'fdt'], ['/', 'images', 'fdt', 'signature'], ] itspath = [] itspaths = [] linect = 0 sigs = {} with open(fitimage_its_path) as its_file: linect += 1 for line in its_file: line = line.strip() if line.endswith('};'): itspath.pop() elif line.endswith('{'): itspath.append(line[:-1].strip()) itspaths.append(itspath[:]) elif itspath and itspath[-1] == 'signature': itsdotpath = '.'.join(itspath) if not itsdotpath in sigs: sigs[itsdotpath] = {} if not '=' in line or not line.endswith(';'): self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) key, value = line.split('=', 1) sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') for reqpath in req_itspaths: if not reqpath in itspaths: self.fail('Missing section in its file: %s' % reqpath) reqsigvalues_image = { 'algo': '"sha256,rsa2048"', 'key-name-hint': '"spl-cascaded-oe-selftest"', } for itspath, values in sigs.items(): reqsigvalues = reqsigvalues_image for reqkey, reqvalue in reqsigvalues.items(): value = values.get(reqkey, None) if value is None: self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) self.assertEqual(value, reqvalue) # Dump the image to see if it really got signed bitbake("u-boot-tools-native -c addto_recipe_sysroot") result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') recipe_sysroot_native = result.output.split('=')[1].strip('"') dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) in_signed = None signed_sections = {} for line in result.output.splitlines(): if line.startswith((' Image')): in_signed = re.search('\((.*)\)', line).groups()[0] elif re.match(' \w', line): in_signed = None elif in_signed: if not in_signed in signed_sections: signed_sections[in_signed] = {} key, value = line.split(':', 1) signed_sections[in_signed][key.strip()] = value.strip() self.assertIn('uboot', signed_sections) self.assertIn('fdt', signed_sections) for signed_section, values in signed_sections.items(): value = values.get('Sign algo', None) self.assertEqual(value, 'sha256,rsa2048:spl-cascaded-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) value = values.get('Sign value', None) self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) # Check for SPL_MKIMAGE_SIGN_ARGS result = runCmd('bitbake -e virtual/kernel | grep ^T=') tempdir = result.output.split('=', 1)[1].strip().strip('') result = runCmd('grep "a smart cascaded U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') # Check for evidence of test-mkimage-wrapper class result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
def test_uboot_sign_fit_image(self): """ Summary: Check if Uboot FIT image and Image Tree Source (its) are built and the Image Tree Source has the correct fields, in the scenario where the Kernel is also creating/signing it's fitImage. Expected: 1. u-boot-fitImage and u-boot-its can be built 2. The type, load address, entrypoint address and default values of U-boot image are correct in the Image Tree Source. Not all the fields are tested, only the key fields that wont vary between different architectures. Product: oe-core Author: Klaus Heinrich Kiwi <*****@*****.**> based on work by Usama Arif <*****@*****.**> """ config = """ # We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set MACHINE = "qemuarm" UBOOT_MACHINE = "am57xx_evm_defconfig" SPL_BINARY = "MLO" # Enable creation of the U-Boot fitImage UBOOT_FITIMAGE_ENABLE = "1" # (U-boot) fitImage properties UBOOT_LOADADDRESS = "0x80080000" UBOOT_ENTRYPOINT = "0x80080000" UBOOT_FIT_DESC = "A model description" KERNEL_IMAGETYPES += " fitImage " KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" UBOOT_SIGN_KEYNAME = "oe-selftest" FIT_SIGN_INDIVIDUAL = "1" UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" """ self.write_config(config) # The U-Boot fitImage is created as part of linux recipe bitbake("virtual/kernel") deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') machine = get_bb_var('MACHINE') fitimage_its_path = os.path.join(deploy_dir_image, "u-boot-its-%s" % (machine,)) fitimage_path = os.path.join(deploy_dir_image, "u-boot-fitImage-%s" % (machine,)) self.assertTrue(os.path.exists(fitimage_its_path), "%s image tree source doesn't exist" % (fitimage_its_path)) self.assertTrue(os.path.exists(fitimage_path), "%s FIT image doesn't exist" % (fitimage_path)) # Check that the type, load address, entrypoint address and default # values for kernel and ramdisk in Image Tree Source are as expected. # The order of fields in the below array is important. Not all the # fields are tested, only the key fields that wont vary between # different architectures. its_field_check = [ 'description = "A model description";', 'type = "standalone";', 'load = <0x80080000>;', 'entry = <0x80080000>;', 'default = "conf";', 'loadables = "uboot";', 'fdt = "fdt";' ] with open(fitimage_its_path) as its_file: field_index = 0 for line in its_file: if field_index == len(its_field_check): break if its_field_check[field_index] in line: field_index +=1 if field_index != len(its_field_check): # if its equal, the test passed self.assertTrue(field_index == len(its_field_check), "Fields in Image Tree Source File %s did not match, error in finding %s" % (fitimage_its_path, its_field_check[field_index]))
def test_fit_image(self): """ Summary: Check if FIT image and Image Tree Source (its) are built and the Image Tree Source has the correct fields. Expected: 1. fitImage and fitImage-its can be built 2. The type, load address, entrypoint address and default values of kernel and ramdisk are as expected in the Image Tree Source. Not all the fields are tested, only the key fields that wont vary between different architectures. Product: oe-core Author: Usama Arif <*****@*****.**> """ config = """ # Enable creation of fitImage KERNEL_IMAGETYPE = "Image" KERNEL_IMAGETYPES += " fitImage " KERNEL_CLASSES = " kernel-fitimage " # RAM disk variables including load address and entrypoint for kernel and RAM disk IMAGE_FSTYPES += "cpio.gz" INITRAMFS_IMAGE = "core-image-minimal" UBOOT_RD_LOADADDRESS = "0x88000000" UBOOT_RD_ENTRYPOINT = "0x88000000" UBOOT_LOADADDRESS = "0x80080000" UBOOT_ENTRYPOINT = "0x80080000" FIT_DESC = "A model description" """ self.write_config(config) # fitImage is created as part of linux recipe bitbake("virtual/kernel") image_type = "core-image-minimal" deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') machine = get_bb_var('MACHINE') fitimage_its_path = os.path.join(deploy_dir_image, "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) fitimage_path = os.path.join(deploy_dir_image, "fitImage-%s-%s-%s" % (image_type, machine, machine)) self.assertTrue(os.path.exists(fitimage_its_path), "%s image tree source doesn't exist" % (fitimage_its_path)) self.assertTrue(os.path.exists(fitimage_path), "%s FIT image doesn't exist" % (fitimage_path)) # Check that the type, load address, entrypoint address and default # values for kernel and ramdisk in Image Tree Source are as expected. # The order of fields in the below array is important. Not all the # fields are tested, only the key fields that wont vary between # different architectures. its_field_check = [ 'description = "A model description";', 'type = "kernel";', 'load = <0x80080000>;', 'entry = <0x80080000>;', 'type = "ramdisk";', 'load = <0x88000000>;', 'entry = <0x88000000>;', 'default = "conf-1";', 'kernel = "kernel-1";', 'ramdisk = "ramdisk-1";' ] with open(fitimage_its_path) as its_file: field_index = 0 for line in its_file: if field_index == len(its_field_check): break if its_field_check[field_index] in line: field_index +=1 if field_index != len(its_field_check): # if its equal, the test passed self.assertTrue(field_index == len(its_field_check), "Fields in Image Tree Source File %s did not match, error in finding %s" % (fitimage_its_path, its_field_check[field_index]))
def test_exclude_path(self): """Test --exclude-path wks option.""" oldpath = os.environ['PATH'] os.environ['PATH'] = get_bb_var("PATH", "wic-tools") try: wks_file = 'temp.wks' with open(wks_file, 'w') as wks: rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal') wks.write(""" part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr""" % (rootfs_dir, rootfs_dir)) runCmd("wic create %s -e core-image-minimal -o %s" \ % (wks_file, self.resultdir)) os.remove(wks_file) wicout = glob(self.resultdir + "%s-*direct" % 'temp') self.assertEqual(1, len(wicout)) wicimg = wicout[0] # verify partition size with wic res = runCmd("parted -m %s unit b p 2>/dev/null" % wicimg) # parse parted output which looks like this: # BYT;\n # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n # 1:0.00MiB:200MiB:200MiB:ext4::;\n partlns = res.output.splitlines()[2:] self.assertEqual(3, len(partlns)) for part in [1, 2, 3]: part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part) partln = partlns[part - 1].split(":") self.assertEqual(7, len(partln)) start = int(partln[1].rstrip("B")) / 512 length = int(partln[3].rstrip("B")) / 512 runCmd("dd if=%s of=%s skip=%d count=%d" % (wicimg, part_file, start, length)) # Test partition 1, should contain the normal root directories, except # /usr. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ os.path.join(self.resultdir, "selftest_img.part1")) files = extract_files(res.output) self.assertIn("etc", files) self.assertNotIn("usr", files) # Partition 2, should contain common directories for /usr, not root # directories. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ os.path.join(self.resultdir, "selftest_img.part2")) files = extract_files(res.output) self.assertNotIn("etc", files) self.assertNotIn("usr", files) self.assertIn("share", files) # Partition 3, should contain the same as partition 2, including the bin # directory, but not the files inside it. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ os.path.join(self.resultdir, "selftest_img.part3")) files = extract_files(res.output) self.assertNotIn("etc", files) self.assertNotIn("usr", files) self.assertIn("share", files) self.assertIn("bin", files) res = runCmd("debugfs -R 'ls -p bin' %s 2>/dev/null" % \ os.path.join(self.resultdir, "selftest_img.part3")) files = extract_files(res.output) self.assertIn(".", files) self.assertIn("..", files) self.assertEqual(2, len(files)) for part in [1, 2, 3]: part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part) os.remove(part_file) finally: os.environ['PATH'] = oldpath
def get_host_arch(recipe): """A cached call to get_bb_var('HOST_ARCH', <recipe>)""" return get_bb_var('HOST_ARCH', recipe)
def setUpClass(cls): super(BitbakePrTests, cls).setUpClass() cls.pkgdata_dir = get_bb_var('PKGDATA_DIR')
def test_specify_pkgdatadir(self): result = runCmd('oe-pkgdata-util -p %s lookup-pkg zlib' % get_bb_var('PKGDATA_DIR')) self.assertEqual(result.output, 'libz1')
def test_reproducible_builds(self): def strip_topdir(s): if s.startswith(self.topdir): return s[len(self.topdir):] return s # Build native utilities self.write_config('') bitbake("diffoscope-native diffutils-native jquery-native -c addto_recipe_sysroot") diffutils_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "diffutils-native") diffoscope_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "diffoscope-native") jquery_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "jquery-native") if self.save_results: os.makedirs(self.save_results, exist_ok=True) datestr = datetime.datetime.now().strftime('%Y%m%d') save_dir = tempfile.mkdtemp(prefix='oe-reproducible-%s-' % datestr, dir=self.save_results) os.chmod(save_dir, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) self.logger.info('Non-reproducible packages will be copied to %s', save_dir) vars_A = self.do_test_build('reproducibleA', self.build_from_sstate) vars_B = self.do_test_build('reproducibleB', False) # NOTE: The temp directories from the reproducible build are purposely # kept after the build so it can be diffed for debugging. fails = [] for c in self.package_classes: with self.subTest(package_class=c): package_class = 'package_' + c deploy_A = vars_A['DEPLOY_DIR_' + c.upper()] deploy_B = vars_B['DEPLOY_DIR_' + c.upper()] self.logger.info('Checking %s packages for differences...' % c) result = self.compare_packages(deploy_A, deploy_B, diffutils_sysroot) self.logger.info('Reproducibility summary for %s: %s' % (c, result)) self.append_to_log('\n'.join("%s: %s" % (r.status, r.test) for r in result.total)) self.write_package_list(package_class, 'missing', result.missing) self.write_package_list(package_class, 'different', result.different) self.write_package_list(package_class, 'same', result.same) if self.save_results: for d in result.different: self.copy_file(d.reference, '/'.join([save_dir, 'packages', strip_topdir(d.reference)])) self.copy_file(d.test, '/'.join([save_dir, 'packages', strip_topdir(d.test)])) if result.missing or result.different: fails.append("The following %s packages are missing or different: %s" % (c, '\n'.join(r.test for r in (result.missing + result.different)))) # Clean up empty directories if self.save_results: if not os.listdir(save_dir): os.rmdir(save_dir) else: self.logger.info('Running diffoscope') package_dir = os.path.join(save_dir, 'packages') package_html_dir = os.path.join(package_dir, 'diff-html') # Copy jquery to improve the diffoscope output usability self.copy_file(os.path.join(jquery_sysroot, 'usr/share/javascript/jquery/jquery.min.js'), os.path.join(package_html_dir, 'jquery.js')) runCmd(['diffoscope', '--no-default-limits', '--exclude-directory-metadata', '--html-dir', package_html_dir, 'reproducibleA', 'reproducibleB'], native_sysroot=diffoscope_sysroot, ignore_status=True, cwd=package_dir) if fails: self.fail('\n'.join(fails))
def test_initramfs_bundle(self): """ Summary: Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its) The FIT settings are set by the test case. The machine used is beaglebone-yocto. Expected: 1. The ITS is generated with initramfs bundle support 2. All the fields in the kernel node are as expected (matching the conf settings) 3. The kernel is included in all the available configurations and its hash is included in the configuration signature Product: oe-core Author: Abdellatif El Khlifi <*****@*****.**> """ config = """ DISTRO="poky" MACHINE = "beaglebone-yocto" INITRAMFS_IMAGE_BUNDLE = "1" INITRAMFS_IMAGE = "core-image-minimal-initramfs" INITRAMFS_SCRIPTS = "" UBOOT_MACHINE = "am335x_evm_defconfig" KERNEL_CLASSES = " kernel-fitimage " KERNEL_IMAGETYPES = "fitImage" UBOOT_SIGN_ENABLE = "1" UBOOT_SIGN_KEYNAME = "beaglebonekey" UBOOT_SIGN_KEYDIR ?= "${DEPLOY_DIR_IMAGE}" UBOOT_DTB_BINARY = "u-boot.dtb" UBOOT_ENTRYPOINT = "0x80000000" UBOOT_LOADADDRESS = "0x80000000" UBOOT_DTB_LOADADDRESS = "0x82000000" UBOOT_ARCH = "arm" UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" UBOOT_EXTLINUX = "0" FIT_GENERATE_KEYS = "1" KERNEL_IMAGETYPE_REPLACEMENT = "zImage" FIT_HASH_ALG = "sha256" """ self.write_config(config) # fitImage is created as part of linux recipe bitbake("virtual/kernel") image_type = get_bb_var('INITRAMFS_IMAGE') deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') machine = get_bb_var('MACHINE') fitimage_its_path = os.path.join(deploy_dir_image, "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) fitimage_path = os.path.join(deploy_dir_image,"fitImage") self.assertTrue(os.path.exists(fitimage_its_path), "%s image tree source doesn't exist" % (fitimage_its_path)) self.assertTrue(os.path.exists(fitimage_path), "%s FIT image doesn't exist" % (fitimage_path)) kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) initramfs_bundle_format = str(get_bb_var('KERNEL_IMAGETYPE_REPLACEMENT')) uboot_arch = str(get_bb_var('UBOOT_ARCH')) initramfs_bundle = "arch/" + uboot_arch + "/boot/" + initramfs_bundle_format + ".initramfs" fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) its_file = open(fitimage_its_path) its_lines = [line.strip() for line in its_file.readlines()] exp_node_lines = [ 'kernel-1 {', 'description = "Linux kernel";', 'data = /incbin/("' + initramfs_bundle + '");', 'type = "kernel";', 'arch = "' + uboot_arch + '";', 'os = "linux";', 'compression = "none";', 'load = <' + kernel_load + '>;', 'entry = <' + kernel_entry + '>;', 'hash-1 {', 'algo = "' + fit_hash_alg +'";', '};', '};' ] node_str = exp_node_lines[0] test_passed = False print ("checking kernel node\n") if node_str in its_lines: node_start_idx = its_lines.index(node_str) node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))] if node == exp_node_lines: print("kernel node verified") else: self.assertTrue(test_passed == True,"kernel node does not match expectation") rx_configs = re.compile("^conf-.*") its_configs = list(filter(rx_configs.match, its_lines)) for cfg_str in its_configs: cfg_start_idx = its_lines.index(cfg_str) line_idx = cfg_start_idx + 2 node_end = False while node_end == False: if its_lines[line_idx] == "};" and its_lines[line_idx-1] == "};" : node_end = True line_idx = line_idx + 1 node = its_lines[cfg_start_idx:line_idx] print("checking configuration " + cfg_str.rstrip(" {")) rx_desc_line = re.compile("^description.*1 Linux kernel.*") if len(list(filter(rx_desc_line.match, node))) != 1: self.assertTrue(test_passed == True,"kernel keyword not found in the description line") break else: print("kernel keyword found in the description line") if 'kernel = "kernel-1";' not in node: self.assertTrue(test_passed == True,"kernel line not found") break else: print("kernel line found") rx_sign_line = re.compile("^sign-images.*kernel.*") if len(list(filter(rx_sign_line.match, node))) != 1: self.assertTrue(test_passed == True,"kernel hash not signed") break else: print("kernel hash signed") test_passed = True self.assertTrue(test_passed == True,"Initramfs bundle test success")
def run_test_sstate_rebuild(self, primary_targets, relocate=False, rebuild_dependencies=False): buildA = os.path.join(self.builddir, 'buildA') if relocate: buildB = os.path.join(self.builddir, 'buildB') else: buildB = buildA if rebuild_dependencies: rebuild_targets = self.get_dep_targets(primary_targets) else: rebuild_targets = primary_targets self.configure_builddir(buildA) runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildA)) + 'bitbake ' + ' '.join(map(str, primary_targets)), shell=True, executable='/bin/bash') self.hardlink_tree(os.path.join(buildA, 'sstate-cache'), os.path.join(self.builddir, 'sstate-cache-buildA')) shutil.rmtree(buildA) failed_rebuild = [] failed_cleansstate = [] for target in rebuild_targets: self.configure_builddir(buildB) self.hardlink_tree( os.path.join(self.builddir, 'sstate-cache-buildA'), os.path.join(buildB, 'sstate-cache')) result_cleansstate = runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildB)) + 'bitbake -ccleansstate ' + target, ignore_status=True, shell=True, executable='/bin/bash') if not result_cleansstate.status == 0: failed_cleansstate.append(target) shutil.rmtree(buildB) continue result_build = runCmd( (". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildB)) + 'bitbake ' + target, ignore_status=True, shell=True, executable='/bin/bash') if not result_build.status == 0: failed_rebuild.append(target) shutil.rmtree(buildB) self.assertFalse( failed_rebuild, msg="The following recipes have failed to rebuild: %s" % ' '.join(map(str, failed_rebuild))) self.assertFalse( failed_cleansstate, msg= "The following recipes have failed cleansstate(all others have passed both cleansstate and rebuild from sstate tests): %s" % ' '.join(map(str, failed_cleansstate)))
def test_sign_fit_image(self): """ Summary: Check if FIT image and Image Tree Source (its) are created and signed correctly. Expected: 1) its and FIT image are built successfully 2) Scanning the its file indicates signing is enabled as requested by UBOOT_SIGN_ENABLE (using keys generated via FIT_GENERATE_KEYS) 3) Dumping the FIT image indicates signature values are present (including for images as enabled via FIT_SIGN_INDIVIDUAL) 4) Examination of the do_assemble_fitimage runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and UBOOT_MKIMAGE_SIGN_ARGS are working as expected. Product: oe-core Author: Paul Eggleton <*****@*****.**> based upon work by Usama Arif <*****@*****.**> """ config = """ # Enable creation of fitImage MACHINE = "beaglebone-yocto" KERNEL_IMAGETYPES += " fitImage " KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" UBOOT_SIGN_KEYNAME = "oe-selftest" FIT_SIGN_INDIVIDUAL = "1" UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" """ self.write_config(config) # fitImage is created as part of linux recipe bitbake("virtual/kernel") image_type = "core-image-minimal" deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') machine = get_bb_var('MACHINE') fitimage_its_path = os.path.join(deploy_dir_image, "fitImage-its-%s" % (machine,)) fitimage_path = os.path.join(deploy_dir_image, "fitImage-%s.bin" % (machine,)) self.assertTrue(os.path.exists(fitimage_its_path), "%s image tree source doesn't exist" % (fitimage_its_path)) self.assertTrue(os.path.exists(fitimage_path), "%s FIT image doesn't exist" % (fitimage_path)) req_itspaths = [ ['/', 'images', 'kernel-1'], ['/', 'images', 'kernel-1', 'signature-1'], ['/', 'images', 'fdt-am335x-boneblack.dtb'], ['/', 'images', 'fdt-am335x-boneblack.dtb', 'signature-1'], ['/', 'configurations', 'conf-am335x-boneblack.dtb'], ['/', 'configurations', 'conf-am335x-boneblack.dtb', 'signature-1'], ] itspath = [] itspaths = [] linect = 0 sigs = {} with open(fitimage_its_path) as its_file: linect += 1 for line in its_file: line = line.strip() if line.endswith('};'): itspath.pop() elif line.endswith('{'): itspath.append(line[:-1].strip()) itspaths.append(itspath[:]) elif itspath and itspath[-1] == 'signature-1': itsdotpath = '.'.join(itspath) if not itsdotpath in sigs: sigs[itsdotpath] = {} if not '=' in line or not line.endswith(';'): self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) key, value = line.split('=', 1) sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') for reqpath in req_itspaths: if not reqpath in itspaths: self.fail('Missing section in its file: %s' % reqpath) reqsigvalues_image = { 'algo': '"sha256,rsa2048"', 'key-name-hint': '"oe-selftest"', } reqsigvalues_config = { 'algo': '"sha256,rsa2048"', 'key-name-hint': '"oe-selftest"', 'sign-images': '"kernel", "fdt"', } for itspath, values in sigs.items(): if 'conf-' in itspath: reqsigvalues = reqsigvalues_config else: reqsigvalues = reqsigvalues_image for reqkey, reqvalue in reqsigvalues.items(): value = values.get(reqkey, None) if value is None: self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) self.assertEqual(value, reqvalue) # Dump the image to see if it really got signed bitbake("u-boot-tools-native -c addto_recipe_sysroot") result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') recipe_sysroot_native = result.output.split('=')[1].strip('"') dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) in_signed = None signed_sections = {} for line in result.output.splitlines(): if line.startswith((' Configuration', ' Image')): in_signed = re.search('\((.*)\)', line).groups()[0] elif re.match('^ *', line) in (' ', ''): in_signed = None elif in_signed: if not in_signed in signed_sections: signed_sections[in_signed] = {} key, value = line.split(':', 1) signed_sections[in_signed][key.strip()] = value.strip() self.assertIn('kernel-1', signed_sections) self.assertIn('fdt-am335x-boneblack.dtb', signed_sections) self.assertIn('conf-am335x-boneblack.dtb', signed_sections) for signed_section, values in signed_sections.items(): value = values.get('Sign algo', None) self.assertEqual(value, 'sha256,rsa2048:oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) value = values.get('Sign value', None) self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) # Check for UBOOT_MKIMAGE_SIGN_ARGS result = runCmd('bitbake -e virtual/kernel | grep ^T=') tempdir = result.output.split('=', 1)[1].strip().strip('') result = runCmd('grep "a smart comment" %s/run.do_assemble_fitimage' % tempdir, ignore_status=True) self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN_ARGS value did not get used') # Check for evidence of test-mkimage-wrapper class result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
def test_sstate_noop_samesigs(self): """ The sstate checksums of two builds with these variables changed or classes inherits should be the same. """ topdir = get_bb_var('TOPDIR') targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" TMPDIR = "${TOPDIR}/tmp-sstatesamehash" BB_NUMBER_THREADS = "1" PARALLEL_MAKE = "-j 1" DL_DIR = "${TOPDIR}/download1" TIME = "111111" DATE = "20161111" INHERIT_remove = "buildstats-summary buildhistory uninative" http_proxy = "" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") self.track_for_cleanup(topdir + "/download1") bitbake("world meta-toolchain -S none") self.write_config(""" TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" BB_NUMBER_THREADS = "2" PARALLEL_MAKE = "-j 2" DL_DIR = "${TOPDIR}/download2" TIME = "222222" DATE = "20161212" # Always remove uninative as we're changing proxies INHERIT_remove = "uninative" INHERIT += "buildstats-summary buildhistory" http_proxy = "http://example.com/" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") self.track_for_cleanup(topdir + "/download2") bitbake("world meta-toolchain -S none") def get_files(d): f = {} for root, dirs, files in os.walk(d): for name in files: name, shash = name.rsplit('.', 1) # Extract just the machine and recipe name base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name]) f[base] = shash return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") # Remove items that are identical in both sets for k,v in files1.items() & files2.items(): del files1[k] del files2[k] if not files1 and not files2: # No changes, so we're done return for k in files1.keys() | files2.keys(): if k in files1 and k in files2: print("%s differs:" % k) print(subprocess.check_output(("bitbake-diffsigs", topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k], topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]))) elif k in files1 and k not in files2: print("%s in files1" % k) elif k not in files1 and k in files2: print("%s in files2" % k) else: assert "shouldn't reach here" self.fail("sstate hashes not identical.")
def test_image_manifest(self): bitbake('core-image-minimal') deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal") imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal") manifest = os.path.join(deploydir, imagename + ".manifest") self.assertTrue(os.path.islink(manifest), msg="No manifest file created for image")
def test_buildhistory_basic(self): self.run_buildhistory_operation('xcursor-transparent-theme') self.assertTrue(os.path.isdir(get_bb_var('BUILDHISTORY_DIR')), "buildhistory dir was not created.")
def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]): self.assertTrue(global_config) self.assertTrue(target_config) self.assertTrue( len(global_config) == len(target_config), msg= 'Lists global_config and target_config should have the same number of elements' ) self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path]) # If buildhistory is enabled, we need to disable version-going-backwards # QA checks for this test. It may report errors otherwise. self.append_config('ERROR_QA_remove = "version-going-backwards"') # For not this only checks if random sstate tasks are handled correctly as a group. # In the future we should add control over what tasks we check for. sstate_archs_list = [] expected_remaining_sstate = [] for idx in range(len(target_config)): self.append_config(global_config[idx]) self.append_recipeinc(target, target_config[idx]) sstate_arch = get_bb_var('SSTATE_PKGARCH', target) if not sstate_arch in sstate_archs_list: sstate_archs_list.append(sstate_arch) if target_config[idx] == target_config[-1]: target_sstate_before_build = self.search_sstate(target + '.*?\.tgz$') bitbake("-cclean %s" % target) result = bitbake(target, ignore_status=True) if target_config[idx] == target_config[-1]: target_sstate_after_build = self.search_sstate(target + '.*?\.tgz$') expected_remaining_sstate += [ x for x in target_sstate_after_build if x not in target_sstate_before_build if not any(pattern in x for pattern in ignore_patterns) ] self.remove_config(global_config[idx]) self.remove_recipeinc(target, target_config[idx]) self.assertEqual(result.status, 0, msg="build of %s failed with %s" % (target, result.output)) runCmd( "sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ','.join(map(str, sstate_archs_list)))) actual_remaining_sstate = [ x for x in self.search_sstate(target + '.*?\.tgz$') if not any(pattern in x for pattern in ignore_patterns) ] actual_not_expected = [ x for x in actual_remaining_sstate if x not in expected_remaining_sstate ] self.assertFalse( actual_not_expected, msg="Files should have been removed but ware not: %s" % ', '.join(map(str, actual_not_expected))) expected_not_actual = [ x for x in expected_remaining_sstate if x not in actual_remaining_sstate ] self.assertFalse(expected_not_actual, msg="Extra files ware removed: %s" ', '.join(map(str, expected_not_actual)))
def secureboot_with_image(self, signing_key="", efishell=False, boot_timeout=600): """Boot the image with UEFI SecureBoot enabled and see the result. """ config = '' if signing_key: meta_refkit_base = get_bb_var('META_REFKIT_BASE') config += 'REFKIT_DB_KEY = "%s/files/secureboot/%s.key"\n' % ( meta_refkit_base, signing_key) config += 'REFKIT_DB_CERT = "%s/files/secureboot/%s.crt"\n' % ( meta_refkit_base, signing_key) config += 'REFKIT_IMAGE_EXTRA_FEATURES_append = " secureboot"\n' config += 'REFKIT_IMAGE_EXTRA_INSTALL_append = " efivar"\n' print('Building %s' % self.test_image) self.write_config(config) bitbake(self.test_image) self.remove_config(config) # Some of the cases depend on the timeout to expire. Allow overrides # so that we don't have to wait 1000s which is the default. overrides = { 'TEST_QEMUBOOT_TIMEOUT': boot_timeout, } print('Booting %s' % self.test_image) try: with runqemu(self.test_image, ssh=False, runqemuparams='slirp', qemuparams=self.ovmf_qemuparams, overrides=overrides, image_fstype='wic') as qemu: cmd = 'modprobe efivarfs ; mount -t efivarfs none /sys/firmware/efi/efivars/' cmd2 = 'SB_GUID_NAME=$(efivar -l|grep SecureBoot); efivar -d -n $SB_GUID_NAME' status, output = qemu.run_serial(cmd) self.assertTrue( status, 'Failed to mount efivarfs (status=%s):\n%s' % (status, output)) status, output = qemu.run_serial(cmd2) # Test if the signed image has booted and the BIOS says UEFI # Secure Boot is enabled. self.assertTrue( status, 'SecureBoot not enabled (status=%s):\n%s' % (status, output)) except Exception: # Currently runqemu() fails if 'login:'******'s # not possible to login as 'root'. Those conditions aren't met when # booting to EFI shell (See [YOCTO #11438]). We catch the failure # and parse the boot log to determine the success. Note: the # timeout triggers verbose bb.error() but that's normal with some # of the test cases. workdir = get_bb_var('WORKDIR', self.test_image) bootlog = "%s/testimage/qemu_boot_log" % workdir with open(bootlog, "r") as log: # This isn't right but all we can do at this point. The right # approach would run commands in the EFI shell to determine # the BIOS rejects unsigned and/or images signed with keys in # dbx key store but that needs changes in oeqa framework. output = log.read() # PASS if the test case wants EFI shell and we see it in logs if not (efishell and re.search('Shell>', output)): self.fail( 'The image did not boot properly. Boot log:\n%s' % output)
def test_recipetool_appendsrcfile_basic_wildcard(self): testrecipe = 'base-files' self._test_appendsrcfile(testrecipe, 'a-file', options='-w') recipefile = get_bb_var('FILE', testrecipe) bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir) self.assertEqual(os.path.basename(bbappendfile), '%s_%%.bbappend' % testrecipe)
def test_provisioning(self): print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') self.assertEqual( retcode, 0, "Unable to check hostname. " + "Is an ssh daemon (such as dropbear or openssh) installed on the device?" ) machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. value = stdout.decode()[:-1] self.assertEqual( value, machine, 'MACHINE does not match hostname: ' + machine + ', ' + value) verifyNotProvisioned(self, machine) # Verify that HSM is not yet initialized. pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' stdout, stderr, retcode = self.qemu_command(pkcs11_command) self.assertNotEqual( retcode, 0, 'pkcs11-tool succeeded before initialization: ' + stdout.decode() + stderr.decode()) softhsm2_command = 'softhsm2-util --show-slots' stdout, stderr, retcode = self.qemu_command(softhsm2_command) self.assertNotEqual( retcode, 0, 'softhsm2-tool succeeded before initialization: ' + stdout.decode() + stderr.decode()) # Run aktualizr-cert-provider. bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') creds = bb_vars['SOTA_PACKED_CREDENTIALS'] bb_vars_prov = get_bb_vars(['WORKDIR', 'libdir'], 'aktualizr-device-prov-hsm') config = bb_vars_prov['WORKDIR'] + '/sysroot-destdir' + bb_vars_prov[ 'libdir'] + '/sota/conf.d/20-sota-device-cred-hsm.toml' akt_native_run( self, 'aktualizr-cert-provider -c {creds} -t root@localhost -p {port} -r -s -u -g {config}' .format(creds=creds, port=self.qemu.ssh_port, config=config)) # Verify that HSM is able to initialize. for delay in [5, 5, 5, 5, 10]: sleep(delay) p11_out, p11_err, p11_ret = self.qemu_command(pkcs11_command) hsm_out, hsm_err, hsm_ret = self.qemu_command(softhsm2_command) if (p11_ret == 0 and hsm_ret == 0 and hsm_err == b'' and b'X.509 cert' in p11_out and b'present token' in p11_err): break else: self.fail('pkcs11-tool or softhsm2-tool failed: ' + p11_err.decode() + p11_out.decode() + hsm_err.decode() + hsm_out.decode()) self.assertIn( b'Initialized: yes', hsm_out, 'softhsm2-tool failed: ' + hsm_err.decode() + hsm_out.decode()) self.assertIn( b'User PIN init.: yes', hsm_out, 'softhsm2-tool failed: ' + hsm_err.decode() + hsm_out.decode()) # Check that pkcs11 output matches sofhsm output. p11_p = re.compile( r'Using slot [0-9] with a present token \((0x[0-9a-f]*)\)\s') p11_m = p11_p.search(p11_err.decode()) self.assertTrue( p11_m, 'Slot number not found with pkcs11-tool: ' + p11_err.decode() + p11_out.decode()) self.assertGreater( p11_m.lastindex, 0, 'Slot number not found with pkcs11-tool: ' + p11_err.decode() + p11_out.decode()) hsm_p = re.compile(r'Description:\s*SoftHSM slot ID (0x[0-9a-f]*)\s') hsm_m = hsm_p.search(hsm_out.decode()) self.assertTrue( hsm_m, 'Slot number not found with softhsm2-tool: ' + hsm_err.decode() + hsm_out.decode()) self.assertGreater( hsm_m.lastindex, 0, 'Slot number not found with softhsm2-tool: ' + hsm_err.decode() + hsm_out.decode()) self.assertEqual( p11_m.group(1), hsm_m.group(1), 'Slot number does not match: ' + p11_err.decode() + p11_out.decode() + hsm_err.decode() + hsm_out.decode()) verifyProvisioned(self, machine)
def test_recipetool_appendsrcfile_srcdir_basic(self): testrecipe = 'bash' srcdir = get_bb_var('S', testrecipe) workdir = get_bb_var('WORKDIR', testrecipe) subdir = os.path.relpath(srcdir, workdir) self._test_appendsrcfile(testrecipe, 'a-file', srcdir=subdir)
def test_read_only_image(self): distro_features = get_bb_var('DISTRO_FEATURES') if not ('x11' in distro_features and 'opengl' in distro_features): self.skipTest('core-image-sato requires x11 and opengl in distro features') self.write_config('IMAGE_FEATURES += "read-only-rootfs"') bitbake("core-image-sato")
def setUpClass(cls): super(LibOE, cls).setUpClass() cls.tmp_dir = get_bb_var('TMPDIR')
def test_expand_mbr_image(self): """Test wic write --expand command for mbr image""" # build an image config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "directdisk.wks"\n' self.append_config(config) self.assertEqual(0, bitbake('core-image-minimal').status) # get path to the image bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE']) deploy_dir = bb_vars['DEPLOY_DIR_IMAGE'] machine = bb_vars['MACHINE'] image_path = os.path.join(deploy_dir, 'core-image-minimal-%s.wic' % machine) self.remove_config(config) try: # expand image to 1G new_image_path = None with NamedTemporaryFile(mode='wb', suffix='.wic.exp', dir=deploy_dir, delete=False) as sparse: sparse.truncate(1024**3) new_image_path = sparse.name sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') cmd = "wic write -n %s --expand 1:0 %s %s" % (sysroot, image_path, new_image_path) runCmd(cmd) # check if partitions are expanded orig = runCmd("wic ls %s -n %s" % (image_path, sysroot)) exp = runCmd("wic ls %s -n %s" % (new_image_path, sysroot)) orig_sizes = [ int(line.split()[3]) for line in orig.output.split('\n')[1:] ] exp_sizes = [ int(line.split()[3]) for line in exp.output.split('\n')[1:] ] self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized self.assertTrue(orig_sizes[1] < exp_sizes[1]) # Check if all free space is partitioned result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path)) self.assertTrue("0 B, 0 bytes, 0 sectors" in result.output) os.rename(image_path, image_path + '.bak') os.rename(new_image_path, image_path) # Check if it boots in qemu with runqemu('core-image-minimal', ssh=False) as qemu: cmd = "ls /etc/" status, output = qemu.run_serial('true') self.assertEqual( 1, status, 'Failed to run command "%s": %s' % (cmd, output)) finally: if os.path.exists(new_image_path): os.unlink(new_image_path) if os.path.exists(image_path + '.bak'): os.rename(image_path + '.bak', image_path)
def get_eSDK_toolchain(image): pn_task = '%s -c populate_sdk_ext' % image sdk_deploy = get_bb_var('SDK_DEPLOY', pn_task) toolchain_name = get_bb_var('TOOLCHAINEXT_OUTPUTNAME', pn_task) return os.path.join(sdk_deploy, toolchain_name + '.sh')