diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases')
27 files changed, 941 insertions, 352 deletions
diff --git a/meta/lib/oeqa/selftest/cases/bbclasses.py b/meta/lib/oeqa/selftest/cases/bbclasses.py new file mode 100644 index 0000000000..10545ebe65 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/bbclasses.py @@ -0,0 +1,106 @@ +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: MIT +# + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import get_bb_vars, bitbake + +class Systemd(OESelftestTestCase): + """ + Tests related to the systemd bbclass. + """ + + def getVars(self, recipe): + self.bb_vars = get_bb_vars( + [ + 'BPN', + 'D', + 'INIT_D_DIR', + 'prefix', + 'systemd_system_unitdir', + 'sysconfdir', + ], + recipe, + ) + + def fileExists(self, filename): + self.assertExists(filename.format(**self.bb_vars)) + + def fileNotExists(self, filename): + self.assertNotExists(filename.format(**self.bb_vars)) + + def test_systemd_in_distro(self): + """ + Summary: Verify that no sysvinit files are installed when the + systemd distro feature is enabled, but sysvinit is not. + Expected: Systemd service file exists, but /etc does not. + Product: OE-Core + Author: Peter Kjellerstedt <peter.kjellerstedt@axis.com> + """ + + self.write_config(""" +DISTRO_FEATURES:append = " systemd usrmerge" +DISTRO_FEATURES:remove = "sysvinit" +VIRTUAL-RUNTIME_init_manager = "systemd" +""") + bitbake("systemd-only systemd-and-sysvinit -c install") + + self.getVars("systemd-only") + self.fileExists("{D}{systemd_system_unitdir}/{BPN}.service") + + self.getVars("systemd-and-sysvinit") + self.fileExists("{D}{systemd_system_unitdir}/{BPN}.service") + self.fileNotExists("{D}{sysconfdir}") + + def test_systemd_and_sysvinit_in_distro(self): + """ + Summary: Verify that both systemd and sysvinit files are installed + when both the systemd and sysvinit distro features are + enabled. + Expected: Systemd service file and sysvinit initscript exist. + Product: OE-Core + Author: Peter Kjellerstedt <peter.kjellerstedt@axis.com> + """ + + self.write_config(""" +DISTRO_FEATURES:append = " systemd sysvinit usrmerge" +VIRTUAL-RUNTIME_init_manager = "systemd" +""") + bitbake("systemd-only systemd-and-sysvinit -c install") + + self.getVars("systemd-only") + self.fileExists("{D}{systemd_system_unitdir}/{BPN}.service") + + self.getVars("systemd-and-sysvinit") + self.fileExists("{D}{systemd_system_unitdir}/{BPN}.service") + self.fileExists("{D}{INIT_D_DIR}/{BPN}") + + def test_sysvinit_in_distro(self): + """ + Summary: Verify that no systemd service files are installed when the + sysvinit distro feature is enabled, but systemd is not. + Expected: The systemd service file does not exist, nor does /usr. + The sysvinit initscript exists. + Product: OE-Core + Author: Peter Kjellerstedt <peter.kjellerstedt@axis.com> + """ + + self.write_config(""" +DISTRO_FEATURES:remove = "systemd" +DISTRO_FEATURES:append = " sysvinit usrmerge" +VIRTUAL-RUNTIME_init_manager = "sysvinit" +""") + bitbake("systemd-only systemd-and-sysvinit -c install") + + self.getVars("systemd-only") + self.fileNotExists("{D}{systemd_system_unitdir}/{BPN}.service") + self.fileNotExists("{D}{prefix}") + self.fileNotExists("{D}{sysconfdir}") + self.fileExists("{D}") + + self.getVars("systemd-and-sysvinit") + self.fileNotExists("{D}{systemd_system_unitdir}/{BPN}.service") + self.fileNotExists("{D}{prefix}") + self.fileExists("{D}{INIT_D_DIR}/{BPN}") diff --git a/meta/lib/oeqa/selftest/cases/binutils.py b/meta/lib/oeqa/selftest/cases/binutils.py index 1688eabe4e..5ff263d342 100644 --- a/meta/lib/oeqa/selftest/cases/binutils.py +++ b/meta/lib/oeqa/selftest/cases/binutils.py @@ -33,7 +33,7 @@ class BinutilsCrossSelfTest(OESelftestTestCase, OEPTestResultTestCase): features.append('CHECK_TARGETS = "{0}"'.format(suite)) self.write_config("\n".join(features)) - recipe = "binutils-cross-testsuite" + recipe = "binutils-testsuite" bb_vars = get_bb_vars(["B", "TARGET_SYS", "T"], recipe) builddir, target_sys, tdir = bb_vars["B"], bb_vars["TARGET_SYS"], bb_vars["T"] diff --git a/meta/lib/oeqa/selftest/cases/buildoptions.py b/meta/lib/oeqa/selftest/cases/buildoptions.py index 31dafaa9c5..423c31e189 100644 --- a/meta/lib/oeqa/selftest/cases/buildoptions.py +++ b/meta/lib/oeqa/selftest/cases/buildoptions.py @@ -84,7 +84,7 @@ class SanityOptionsTest(OESelftestTestCase): self.write_config("INHERIT:remove = \"report-error\"") if "packages-list" not in get_bb_var("ERROR_QA"): - self.append_config("ERROR_QA:append = \" packages-list\"") + self.append_config("ERROR_QA:append:pn-xcursor-transparent-theme = \" packages-list\"") self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"') self.add_command_to_tearDown('bitbake -c clean xcursor-transparent-theme') @@ -94,8 +94,8 @@ class SanityOptionsTest(OESelftestTestCase): self.assertTrue(line and line.startswith("ERROR:"), msg=res.output) self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output)) self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"') - self.append_config('ERROR_QA:remove = "packages-list"') - self.append_config('WARN_QA:append = " packages-list"') + self.append_config('ERROR_QA:remove:pn-xcursor-transparent-theme = "packages-list"') + self.append_config('WARN_QA:append:pn-xcursor-transparent-theme = " packages-list"') res = bitbake("xcursor-transparent-theme -f -c package") self.delete_recipeinc('xcursor-transparent-theme') line = self.getline(res, "QA Issue: xcursor-transparent-theme-dbg is listed in PACKAGES multiple times, this leads to packaging errors.") @@ -173,8 +173,8 @@ class BuildhistoryTests(BuildhistoryBase): data = load_bh(os.path.join(history_dir, 'hicolor-icon-theme-dev', 'latest')) if 'FILELIST' in data: - self.assertEqual(data['FILELIST'], '') - self.assertEqual(int(data['PKGSIZE']), 0) + self.assertEqual(data['FILELIST'], '/usr/share/pkgconfig/default-icon-theme.pc') + self.assertGreater(int(data['PKGSIZE']), 0) class ArchiverTest(OESelftestTestCase): def test_arch_work_dir_and_export_source(self): diff --git a/meta/lib/oeqa/selftest/cases/cve_check.py b/meta/lib/oeqa/selftest/cases/cve_check.py index 60cecd1328..3dd3e89d3e 100644 --- a/meta/lib/oeqa/selftest/cases/cve_check.py +++ b/meta/lib/oeqa/selftest/cases/cve_check.py @@ -72,6 +72,54 @@ class CVECheck(OESelftestTestCase): self.assertEqual(convert_cve_version("6.2_rc8"), "6.2-rc8") self.assertEqual(convert_cve_version("6.2_rc31"), "6.2-rc31") + def test_product_match(self): + from oe.cve_check import has_cve_product_match + + status = {} + status["detail"] = "ignored" + status["vendor"] = "*" + status["product"] = "*" + status["description"] = "" + status["mapping"] = "" + + self.assertEqual(has_cve_product_match(status, "some_vendor:some_product"), True) + self.assertEqual(has_cve_product_match(status, "*:*"), True) + self.assertEqual(has_cve_product_match(status, "some_product"), True) + self.assertEqual(has_cve_product_match(status, "glibc"), True) + self.assertEqual(has_cve_product_match(status, "glibca"), True) + self.assertEqual(has_cve_product_match(status, "aglibc"), True) + self.assertEqual(has_cve_product_match(status, "*"), True) + self.assertEqual(has_cve_product_match(status, "aglibc glibc test:test"), True) + + status["product"] = "glibc" + self.assertEqual(has_cve_product_match(status, "some_vendor:some_product"), False) + # The CPE in the recipe must be defined, no * accepted + self.assertEqual(has_cve_product_match(status, "*:*"), False) + self.assertEqual(has_cve_product_match(status, "*"), False) + self.assertEqual(has_cve_product_match(status, "some_product"), False) + self.assertEqual(has_cve_product_match(status, "glibc"), True) + self.assertEqual(has_cve_product_match(status, "glibca"), False) + self.assertEqual(has_cve_product_match(status, "aglibc"), False) + self.assertEqual(has_cve_product_match(status, "some_vendor:glibc"), True) + self.assertEqual(has_cve_product_match(status, "some_vendor:glibc test"), True) + self.assertEqual(has_cve_product_match(status, "test some_vendor:glibc"), True) + + status["vendor"] = "glibca" + status["product"] = "glibc" + self.assertEqual(has_cve_product_match(status, "some_vendor:some_product"), False) + # The CPE in the recipe must be defined, no * accepted + self.assertEqual(has_cve_product_match(status, "*:*"), False) + self.assertEqual(has_cve_product_match(status, "*"), False) + self.assertEqual(has_cve_product_match(status, "some_product"), False) + self.assertEqual(has_cve_product_match(status, "glibc"), False) + self.assertEqual(has_cve_product_match(status, "glibca"), False) + self.assertEqual(has_cve_product_match(status, "aglibc"), False) + self.assertEqual(has_cve_product_match(status, "some_vendor:glibc"), False) + self.assertEqual(has_cve_product_match(status, "glibca:glibc"), True) + self.assertEqual(has_cve_product_match(status, "test:test glibca:glibc"), True) + self.assertEqual(has_cve_product_match(status, "test glibca:glibc"), True) + self.assertEqual(has_cve_product_match(status, "glibca:glibc test"), True) + def test_recipe_report_json(self): config = """ @@ -217,9 +265,10 @@ CVE_CHECK_REPORT_PATCHED = "1" # m4 CVE should not be in logrotate self.assertNotIn("CVE-2008-1687", found_cves) # logrotate has both Patched and Ignored CVEs + detail = "version-not-in-range" self.assertIn("CVE-2011-1098", found_cves) self.assertEqual(found_cves["CVE-2011-1098"]["status"], "Patched") - self.assertEqual(len(found_cves["CVE-2011-1098"]["detail"]), 0) + self.assertEqual(found_cves["CVE-2011-1098"]["detail"], detail) self.assertEqual(len(found_cves["CVE-2011-1098"]["description"]), 0) detail = "not-applicable-platform" description = "CVE is debian, gentoo or SUSE specific on the way logrotate was installed/used" diff --git a/meta/lib/oeqa/selftest/cases/debuginfod.py b/meta/lib/oeqa/selftest/cases/debuginfod.py index 505b4be837..46c0cd87bb 100644 --- a/meta/lib/oeqa/selftest/cases/debuginfod.py +++ b/meta/lib/oeqa/selftest/cases/debuginfod.py @@ -62,7 +62,7 @@ class Debuginfod(OESelftestTestCase): raise TimeoutError("Cannot connect debuginfod, still %d scan jobs running" % latest) - def start_debuginfod(self): + def start_debuginfod(self, feed_dir): # We assume that the caller has already bitbake'd elfutils-native:do_addto_recipe_sysroot # Save some useful paths for later @@ -82,7 +82,7 @@ class Debuginfod(OESelftestTestCase): # Disable rescanning, this is a one-shot test "--rescan-time=0", "--groom-time=0", - get_bb_var("DEPLOY_DIR"), + feed_dir, ] format = get_bb_var("PACKAGE_CLASSES").split()[0] @@ -114,11 +114,12 @@ class Debuginfod(OESelftestTestCase): self.write_config(""" TMPDIR = "${TOPDIR}/tmp-debuginfod" DISTRO_FEATURES:append = " debuginfod" +INHERIT += "localpkgfeed" """) - bitbake("elfutils-native:do_addto_recipe_sysroot xz xz:do_package") + bitbake("elfutils-native:do_addto_recipe_sysroot xz xz:do_package xz:do_localpkgfeed") try: - self.start_debuginfod() + self.start_debuginfod(get_bb_var("LOCALPKGFEED_DIR", "xz")) env = os.environ.copy() env["DEBUGINFOD_URLS"] = "http://localhost:%d/" % self.port @@ -141,12 +142,13 @@ DISTRO_FEATURES:append = " debuginfod" self.write_config(""" TMPDIR = "${TOPDIR}/tmp-debuginfod" DISTRO_FEATURES:append = " debuginfod" +INHERIT += "localpkgfeed" CORE_IMAGE_EXTRA_INSTALL += "elfutils xz" """) - bitbake("core-image-minimal elfutils-native:do_addto_recipe_sysroot") + bitbake("core-image-minimal elfutils-native:do_addto_recipe_sysroot xz:do_localpkgfeed") try: - self.start_debuginfod() + self.start_debuginfod(get_bb_var("LOCALPKGFEED_DIR", "xz")) with runqemu("core-image-minimal", runqemuparams="nographic") as qemu: cmd = "DEBUGINFOD_URLS=http://%s:%d/ debuginfod-find debuginfo /usr/bin/xz" % (qemu.server_ip, self.port) diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py index 882225dde3..7d61773980 100644 --- a/meta/lib/oeqa/selftest/cases/devtool.py +++ b/meta/lib/oeqa/selftest/cases/devtool.py @@ -753,6 +753,25 @@ class DevtoolModifyTests(DevtoolBase): result = runCmd('devtool status') self.assertNotIn('mdadm', result.output) + def test_devtool_modify_go(self): + import oe.path + from tempfile import TemporaryDirectory + with TemporaryDirectory(prefix='devtoolqa') as tempdir: + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake -c clean go-helloworld') + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + result = runCmd('devtool modify go-helloworld -x %s' % tempdir) + self.assertExists( + oe.path.join(tempdir, 'src', 'golang.org', 'x', 'example', 'go.mod'), + 'Extracted source could not be found' + ) + self.assertExists( + oe.path.join(self.workspacedir, 'conf', 'layer.conf'), + 'Workspace directory not created' + ) + matches = glob.glob(oe.path.join(self.workspacedir, 'appends', 'go-helloworld_*.bbappend')) + self.assertTrue(matches, 'bbappend not created %s' % result.output) + def test_devtool_buildclean(self): def assertFile(path, *paths): f = os.path.join(path, *paths) @@ -879,13 +898,8 @@ class DevtoolModifyTests(DevtoolBase): self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) - srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc') - srclink = os.path.join(tempdir, 'share/dot.bashrc') + srcfile = os.path.join(tempdir, 'share/dot.bashrc') self.assertExists(srcfile, 'Extracted source could not be found') - if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink): - correct_symlink = True - self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken') - matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) self.assertTrue(matches, 'bbappend not created') # Test devtool status @@ -956,9 +970,9 @@ class DevtoolModifyTests(DevtoolBase): # others git:// in SRC_URI # cointains a patch testrecipe = 'hello-rs' - bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe) + bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'UNPACKDIR', 'CARGO_HOME'], testrecipe) recipefile = bb_vars['FILE'] - workdir = bb_vars['WORKDIR'] + unpackdir = bb_vars['UNPACKDIR'] cargo_home = bb_vars['CARGO_HOME'] src_uri = bb_vars['SRC_URI'].split() self.assertTrue(src_uri[0].startswith('git://'), @@ -1029,7 +1043,7 @@ class DevtoolModifyTests(DevtoolBase): self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"') raw_url = raw_url.replace("git://", '%s://' % parms['protocol']) patch_line = '[patch."%s"]' % raw_url - path_patched = os.path.join(workdir, parms['destsuffix']) + path_patched = os.path.join(unpackdir, parms['destsuffix']) path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched) # Would have been better to use tomllib to read this file :/ self.assertIn(patch_line, cargo_config_contents) @@ -1278,7 +1292,7 @@ class DevtoolUpdateTests(DevtoolBase): with open(bbappendfile, 'r') as f: self.assertEqual(expectedlines, f.readlines()) # Drop new commit and check patch gets deleted - result = runCmd('git reset HEAD^', cwd=tempsrcdir) + result = runCmd('git reset HEAD^ --hard', cwd=tempsrcdir) result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) self.assertNotExists(patchfile, 'Patch file not deleted') expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', @@ -1287,6 +1301,7 @@ class DevtoolUpdateTests(DevtoolBase): self.assertEqual(expectedlines2, f.readlines()) # Put commit back and check we can run it if layer isn't in bblayers.conf os.remove(bbappendfile) + result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir) result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) @@ -1361,7 +1376,7 @@ class DevtoolUpdateTests(DevtoolBase): with open(bbappendfile, 'r') as f: self.assertEqual(expectedlines, set(f.readlines())) # Drop new commit and check SRCREV changes - result = runCmd('git reset HEAD^', cwd=tempsrcdir) + result = runCmd('git reset HEAD^ --hard', cwd=tempsrcdir) result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created') result = runCmd('git rev-parse HEAD', cwd=tempsrcdir) @@ -1373,6 +1388,7 @@ class DevtoolUpdateTests(DevtoolBase): self.assertEqual(expectedlines, set(f.readlines())) # Put commit back and check we can run it if layer isn't in bblayers.conf os.remove(bbappendfile) + result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir) result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) @@ -1404,11 +1420,12 @@ class DevtoolUpdateTests(DevtoolBase): # Try building just to ensure we haven't broken that bitbake("%s" % testrecipe) # Edit / commit local source - runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir) - runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) + runCmd('echo "/* Foobar */" >> makedevs.c', cwd=tempdir) + runCmd('echo "Foo" > new-local', cwd=tempdir) runCmd('echo "Bar" > new-file', cwd=tempdir) runCmd('git add new-file', cwd=tempdir) runCmd('git commit -m "Add new file"', cwd=tempdir) + runCmd('git add new-local', cwd=tempdir) runCmd('devtool update-recipe %s' % testrecipe) expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), (' M', '.*/makedevs/makedevs.c$'), @@ -1434,8 +1451,8 @@ class DevtoolUpdateTests(DevtoolBase): self.assertExists(local_file, 'File makedevs.c not created') self.assertExists(patchfile, 'File new_local not created') - def test_devtool_update_recipe_local_files_2(self): - """Check local source files support when oe-local-files is in Git""" + def _test_devtool_update_recipe_local_files_2(self): + """Check local source files support when editing local files in Git""" testrecipe = 'devtool-test-local' recipefile = get_bb_var('FILE', testrecipe) recipedir = os.path.dirname(recipefile) @@ -1450,17 +1467,13 @@ class DevtoolUpdateTests(DevtoolBase): result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) # Check git repo self._check_src_repo(tempdir) - # Add oe-local-files to Git - runCmd('rm oe-local-files/.gitignore', cwd=tempdir) - runCmd('git add oe-local-files', cwd=tempdir) - runCmd('git commit -m "Add local sources"', cwd=tempdir) # Edit / commit local sources - runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir) + runCmd('echo "# Foobar" >> file1', cwd=tempdir) runCmd('git commit -am "Edit existing file"', cwd=tempdir) - runCmd('git rm oe-local-files/file2', cwd=tempdir) + runCmd('git rm file2', cwd=tempdir) runCmd('git commit -m"Remove file"', cwd=tempdir) - runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) - runCmd('git add oe-local-files/new-local', cwd=tempdir) + runCmd('echo "Foo" > new-local', cwd=tempdir) + runCmd('git add new-local', cwd=tempdir) runCmd('git commit -m "Add new local file"', cwd=tempdir) runCmd('echo "Gar" > new-file', cwd=tempdir) runCmd('git add new-file', cwd=tempdir) @@ -1469,7 +1482,7 @@ class DevtoolUpdateTests(DevtoolBase): os.path.dirname(recipefile)) # Checkout unmodified file to working copy -> devtool should still pick # the modified version from HEAD - runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir) + runCmd('git checkout HEAD^ -- file1', cwd=tempdir) runCmd('devtool update-recipe %s' % testrecipe) expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), (' M', '.*/file1$'), @@ -1544,7 +1557,7 @@ class DevtoolUpdateTests(DevtoolBase): # (don't bother with cleaning the recipe on teardown, we won't be building it) result = runCmd('devtool modify %s' % testrecipe) # Modify one file - runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files')) + runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe)) self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) result = runCmd('devtool update-recipe %s' % testrecipe) expected_status = [(' M', '.*/%s/file2$' % testrecipe)] @@ -2004,6 +2017,52 @@ class DevtoolUpgradeTests(DevtoolBase): newlines = f.readlines() self.assertEqual(desiredlines, newlines) + def test_devtool_upgrade_recipe_upgrade_extra_tasks(self): + # Check preconditions + self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + recipe = 'python3-guessing-game' + version = '0.2.0' + commit = '40cf004c2772ffa20ea803fa3be1528a75be3e98' + oldrecipefile = get_bb_var('FILE', recipe) + oldcratesincfile = os.path.join(os.path.dirname(oldrecipefile), os.path.basename(oldrecipefile).strip('_git.bb') + '-crates.inc') + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + # Check that recipe is not already under devtool control + result = runCmd('devtool status') + self.assertNotIn(recipe, result.output) + # Check upgrade + result = runCmd('devtool upgrade %s %s --version %s --srcrev %s' % (recipe, tempdir, version, commit)) + # Check if srctree at least is populated + self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit)) + # Check new recipe file and new -crates.inc files are present + newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile)) + newcratesincfile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldcratesincfile)) + self.assertExists(newrecipefile, 'Recipe file should exist after upgrade') + self.assertExists(newcratesincfile, 'Recipe crates.inc file should exist after upgrade') + # Check devtool status and make sure recipe is present + result = runCmd('devtool status') + self.assertIn(recipe, result.output) + self.assertIn(tempdir, result.output) + # Check recipe got changed as expected + with open(oldrecipefile + '.upgraded', 'r') as f: + desiredlines = f.readlines() + with open(newrecipefile, 'r') as f: + newlines = f.readlines() + self.assertEqual(desiredlines, newlines) + # Check crates.inc got changed as expected + with open(oldcratesincfile + '.upgraded', 'r') as f: + desiredlines = f.readlines() + with open(newcratesincfile, 'r') as f: + newlines = f.readlines() + self.assertEqual(desiredlines, newlines) + # Check devtool reset recipe + result = runCmd('devtool reset %s -n' % recipe) + result = runCmd('devtool status') + self.assertNotIn(recipe, result.output) + self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting') + def test_devtool_layer_plugins(self): """Test that devtool can use plugins from other layers. diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py index ad952c004b..7771a42e2b 100644 --- a/meta/lib/oeqa/selftest/cases/distrodata.py +++ b/meta/lib/oeqa/selftest/cases/distrodata.py @@ -20,10 +20,10 @@ class Distrodata(OESelftestTestCase): feature = 'LICENSE_FLAGS_ACCEPTED += " commercial"\n' self.write_config(feature) - pkgs = oe.recipeutils.get_recipe_upgrade_status() + pkggroups = oe.recipeutils.get_recipe_upgrade_status() - regressed_failures = [pkg[0] for pkg in pkgs if pkg[1] == 'UNKNOWN_BROKEN'] - regressed_successes = [pkg[0] for pkg in pkgs if pkg[1] == 'KNOWN_BROKEN'] + regressed_failures = [pkg['pn'] for pkgs in pkggroups for pkg in pkgs if pkg['status'] == 'UNKNOWN_BROKEN'] + regressed_successes = [pkg['pn'] for pkgs in pkggroups for pkg in pkgs if pkg['status'] == 'KNOWN_BROKEN'] msg = "" if len(regressed_failures) > 0: msg = msg + """ @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re return False def is_maintainer_exception(entry): - exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data", + exceptions = ["musl", "newlib", "picolibc", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data", "cve-update-nvd2-native",] for i in exceptions: if i in entry: @@ -115,3 +115,15 @@ The list of oe-core recipes with maintainers is empty. This may indicate that th self.fail(""" Unable to find recipes for the following entries in maintainers.inc: """ + "\n".join(['%s' % i for i in missing_recipes])) + + def test_common_include_recipes(self): + """ + Summary: Test that obtaining recipes that share includes between them returns a sane result + Expected: At least cmake and qemu entries are present in the output + Product: oe-core + Author: Alexander Kanavin <alex.kanavin@gmail.com> + """ + recipes = oe.recipeutils.get_common_include_recipes() + + self.assertIn({'qemu-system-native', 'qemu', 'qemu-native'}, recipes) + self.assertIn({'cmake-native', 'cmake'}, recipes) diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py index 347c065377..0b5f4602fb 100644 --- a/meta/lib/oeqa/selftest/cases/fitimage.py +++ b/meta/lib/oeqa/selftest/cases/fitimage.py @@ -11,6 +11,51 @@ import re class FitImageTests(OESelftestTestCase): + def _setup_uboot_tools_native(self): + """build u-boot-tools-native and return RECIPE_SYSROOT_NATIVE""" + bitbake("u-boot-tools-native -c addto_recipe_sysroot") + return get_bb_var('RECIPE_SYSROOT_NATIVE', 'u-boot-tools-native') + + def _verify_fit_image_signature(self, uboot_tools_sysroot_native, fitimage_path, dtb_path, conf_name=None): + """Verify the signature of a fit contfiguration + + The fit_check_sign utility from u-boot-tools-native is called. + uboot-fit_check_sign -f fitImage -k $dtb_name -c conf-$dtb_name + """ + fit_check_sign_path = os.path.join(uboot_tools_sysroot_native, 'usr', 'bin', 'uboot-fit_check_sign') + cmd = '%s -f %s -k %s' % (fit_check_sign_path, fitimage_path, dtb_path) + if conf_name: + cmd += ' -c %s' % conf_name + result = runCmd(cmd) + self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output) + self.assertIn("Signature check OK", result.output) + + @staticmethod + def _find_string_in_bin_file(file_path, search_string): + """find stings in a binary file + + Shell equivalent: strings "$1" | grep "$2" | wc -l + return number of matches + """ + found_positions = 0 + with open(file_path, 'rb') as file: + byte = file.read(1) + current_position = 0 + current_match = 0 + while byte: + char = byte.decode('ascii', errors='ignore') + if char == search_string[current_match]: + current_match += 1 + if current_match == len(search_string): + found_positions += 1 + current_match = 0 + else: + current_match = 0 + current_position += 1 + byte = file.read(1) + return found_positions + + def test_fit_image(self): """ Summary: Check if FIT image and Image Tree Source (its) are built @@ -53,10 +98,8 @@ FIT_DESC = "A model description" fitimage_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], "fitImage-%s-%s" % (bb_vars['INITRAMFS_IMAGE_NAME'], bb_vars['KERNEL_FIT_LINK_NAME'])) - 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)) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(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. @@ -108,19 +151,21 @@ FIT_DESC = "A model description" Author: Paul Eggleton <paul.eggleton@microsoft.com> based upon work by Usama Arif <usama.arif@arm.com> """ + a_comment = "a smart comment" config = """ # Enable creation of fitImage MACHINE = "beaglebone-yocto" KERNEL_IMAGETYPES += " fitImage " -KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " +KERNEL_CLASSES = " kernel-fitimage " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" FIT_SIGN_INDIVIDUAL = "1" -UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" -""" +UBOOT_MKIMAGE_SIGN_ARGS = "-c '%s'" +""" % a_comment + self.write_config(config) # fitImage is created as part of linux recipe @@ -133,10 +178,8 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" fitimage_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], "fitImage-%s.bin" % (bb_vars['KERNEL_FIT_LINK_NAME'])) - 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)) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path)) req_itspaths = [ ['/', 'images', 'kernel-1'], @@ -195,10 +238,8 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" 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') + uboot_tools_sysroot_native = self._setup_uboot_tools_native() + dumpimage_path = os.path.join(uboot_tools_sysroot_native, 'usr', 'bin', 'dumpimage') result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) in_signed = None signed_sections = {} @@ -224,17 +265,15 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" 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') + # Search for the string passed to mkimage: 1 kernel + 3 DTBs + config per DTB = 7 sections + # Looks like mkimage supports to add a comment but does not support to read it back. + found_comments = FitImageTests._find_string_in_bin_file(fitimage_path, a_comment) + self.assertEqual(found_comments, 7, "Expected 7 signed and commented section in the fitImage.") - # 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') + # Verify the signature for all configurations = DTBs + for dtb in ['am335x-bone.dtb', 'am335x-boneblack.dtb', 'am335x-bonegreen.dtb']: + self._verify_fit_image_signature(uboot_tools_sysroot_native, fitimage_path, + os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], dtb), 'conf-' + dtb) def test_uboot_fit_image(self): """ @@ -287,10 +326,8 @@ FIT_SIGN_INDIVIDUAL = "1" 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)) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(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. @@ -351,7 +388,6 @@ UBOOT_ENTRYPOINT = "0x80080000" UBOOT_FIT_DESC = "A model description" KERNEL_IMAGETYPES += " fitImage " KERNEL_CLASSES = " kernel-fitimage " -INHERIT += "test-mkimage-wrapper" UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" @@ -372,10 +408,8 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" 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)) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(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. @@ -425,6 +459,7 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" work by Paul Eggleton <paul.eggleton@microsoft.com> and Usama Arif <usama.arif@arm.com> """ + a_comment = "a smart U-Boot comment" 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 @@ -434,7 +469,6 @@ SPL_BINARY = "MLO" # The kernel-fitimage class is a dependency even if we're only # creating/signing the U-Boot fitImage KERNEL_CLASSES = " kernel-fitimage" -INHERIT += "test-mkimage-wrapper" # Enable creation and signing of the U-Boot fitImage UBOOT_FITIMAGE_ENABLE = "1" SPL_SIGN_ENABLE = "1" @@ -446,17 +480,17 @@ UBOOT_LOADADDRESS = "0x80000000" UBOOT_DTB_LOADADDRESS = "0x82000000" UBOOT_ARCH = "arm" SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" -SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" +SPL_MKIMAGE_SIGN_ARGS = "-c '%s'" UBOOT_EXTLINUX = "0" UBOOT_FIT_GENERATE_KEYS = "1" UBOOT_FIT_HASH_ALG = "sha256" -""" +""" % a_comment + self.write_config(config) # The U-Boot fitImage is created as part of the U-Boot recipe bitbake("virtual/bootloader") - 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, @@ -464,10 +498,8 @@ UBOOT_FIT_HASH_ALG = "sha256" 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)) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path)) req_itspaths = [ ['/', 'images', 'uboot'], @@ -516,10 +548,8 @@ UBOOT_FIT_HASH_ALG = "sha256" 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') + uboot_tools_sysroot_native = self._setup_uboot_tools_native() + dumpimage_path = os.path.join(uboot_tools_sysroot_native, 'usr', 'bin', 'dumpimage') result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) in_signed = None signed_sections = {} @@ -542,16 +572,14 @@ UBOOT_FIT_HASH_ALG = "sha256" 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/bootloader | grep ^T=') - tempdir = result.output.split('=', 1)[1].strip().strip('') - result = runCmd('grep "a smart 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') + # Looks like mkimage supports to add a comment but does not support to read it back. + found_comments = FitImageTests._find_string_in_bin_file(fitimage_path, a_comment) + self.assertEqual(found_comments, 2, "Expected 2 signed and commented section in the fitImage.") + + # Verify the signature + self._verify_fit_image_signature(uboot_tools_sysroot_native, fitimage_path, + os.path.join(deploy_dir_image, 'u-boot-spl.dtb')) - # 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_sign_cascaded_uboot_fit_image(self): """ @@ -573,6 +601,7 @@ UBOOT_FIT_HASH_ALG = "sha256" work by Paul Eggleton <paul.eggleton@microsoft.com> and Usama Arif <usama.arif@arm.com> """ + a_comment = "a smart cascaded U-Boot comment" 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 @@ -588,7 +617,7 @@ 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_MKIMAGE_SIGN_ARGS = "-c '%s'" UBOOT_DTB_LOADADDRESS = "0x82000000" UBOOT_ARCH = "arm" SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" @@ -598,20 +627,18 @@ UBOOT_FIT_GENERATE_KEYS = "1" UBOOT_FIT_HASH_ALG = "sha256" KERNEL_IMAGETYPES += " fitImage " KERNEL_CLASSES = " kernel-fitimage " -INHERIT += "test-mkimage-wrapper" UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" FIT_SIGN_INDIVIDUAL = "1" -""" +""" % a_comment self.write_config(config) # The U-Boot fitImage is created as part of the U-Boot recipe bitbake("virtual/bootloader") - 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, @@ -619,10 +646,8 @@ FIT_SIGN_INDIVIDUAL = "1" 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)) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path)) req_itspaths = [ ['/', 'images', 'uboot'], @@ -671,10 +696,8 @@ FIT_SIGN_INDIVIDUAL = "1" 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') + uboot_tools_sysroot_native = self._setup_uboot_tools_native() + dumpimage_path = os.path.join(uboot_tools_sysroot_native, 'usr', 'bin', 'dumpimage') result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) in_signed = None signed_sections = {} @@ -697,17 +720,13 @@ FIT_SIGN_INDIVIDUAL = "1" 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/bootloader | 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') + # Looks like mkimage supports to add a comment but does not support to read it back. + found_comments = FitImageTests._find_string_in_bin_file(fitimage_path, a_comment) + self.assertEqual(found_comments, 2, "Expected 2 signed and commented section in the fitImage.") + # Verify the signature + self._verify_fit_image_signature(uboot_tools_sysroot_native, fitimage_path, + os.path.join(deploy_dir_image, 'u-boot-spl.dtb')) def test_initramfs_bundle(self): @@ -755,24 +774,24 @@ FIT_HASH_ALG = "sha256" # 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)) + bb_vars = get_bb_vars([ + 'DEPLOY_DIR_IMAGE', + 'FIT_HASH_ALG', + 'FIT_KERNEL_COMP_ALG', + 'INITRAMFS_IMAGE', + 'MACHINE', + 'UBOOT_ARCH', + 'UBOOT_ENTRYPOINT', + 'UBOOT_LOADADDRESS', + 'UBOOT_MKIMAGE_KERNEL_TYPE' + ], + 'virtual/kernel') + fitimage_its_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], + "fitImage-its-%s-%s-%s" % (bb_vars['INITRAMFS_IMAGE'], bb_vars['MACHINE'], bb_vars['MACHINE'])) + fitimage_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'],"fitImage") - kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) - kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) - kernel_type = str(get_bb_var('UBOOT_MKIMAGE_KERNEL_TYPE')) - kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG')) - uboot_arch = str(get_bb_var('UBOOT_ARCH')) - fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) + self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) + self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path)) its_file = open(fitimage_its_path) @@ -782,31 +801,31 @@ FIT_HASH_ALG = "sha256" 'kernel-1 {', 'description = "Linux kernel";', 'data = /incbin/("linux.bin");', - 'type = "' + kernel_type + '";', - 'arch = "' + uboot_arch + '";', + 'type = "' + str(bb_vars['UBOOT_MKIMAGE_KERNEL_TYPE']) + '";', + 'arch = "' + str(bb_vars['UBOOT_ARCH']) + '";', 'os = "linux";', - 'compression = "' + kernel_compression + '";', - 'load = <' + kernel_load + '>;', - 'entry = <' + kernel_entry + '>;', + 'compression = "' + str(bb_vars['FIT_KERNEL_COMP_ALG']) + '";', + 'load = <' + str(bb_vars['UBOOT_LOADADDRESS']) + '>;', + 'entry = <' + str(bb_vars['UBOOT_ENTRYPOINT']) + '>;', 'hash-1 {', - 'algo = "' + fit_hash_alg +'";', + 'algo = "' + str(bb_vars['FIT_HASH_ALG']) +'";', '};', '};' ] node_str = exp_node_lines[0] - test_passed = False - print ("checking kernel node\n") + self.assertIn(node_str, its_lines) - 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") + node_start_idx = its_lines.index(node_str) + node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))] + + # Remove the absolute path. This refers to WORKDIR which is not always predictable. + re_data = re.compile(r'^data = /incbin/\(.*/linux\.bin"\);$') + node = [re.sub(re_data, 'data = /incbin/("linux.bin");', cfg_str) for cfg_str in node] + + self.assertEqual(node, exp_node_lines, "kernel node does not match expectation") rx_configs = re.compile("^conf-.*") its_configs = list(filter(rx_configs.match, its_lines)) @@ -822,25 +841,14 @@ FIT_HASH_ALG = "sha256" 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") + rx_desc_line = re.compile(r'^description = ".*Linux kernel.*') + self.assertEqual(len(list(filter(rx_desc_line.match, node))), 1, "kernel keyword not 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") + self.assertIn('kernel = "kernel-1";', node) - 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") + rx_sign_line = re.compile(r'^sign-images = .*kernel.*') + self.assertEqual(len(list(filter(rx_sign_line.match, node))), 1, "kernel hash not signed") - test_passed = True - self.assertTrue(test_passed == True,"Initramfs bundle test success") + # Verify the signature + uboot_tools_sysroot_native = self._setup_uboot_tools_native() + self._verify_fit_image_signature(uboot_tools_sysroot_native, fitimage_path, os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], 'am335x-bone.dtb')) diff --git a/meta/lib/oeqa/selftest/cases/gcc.py b/meta/lib/oeqa/selftest/cases/gcc.py index 89360178fe..4cc0894d42 100644 --- a/meta/lib/oeqa/selftest/cases/gcc.py +++ b/meta/lib/oeqa/selftest/cases/gcc.py @@ -37,7 +37,7 @@ class GccSelfTestBase(OESelftestTestCase, OEPTestResultTestCase): features = [] features.append('MAKE_CHECK_TARGETS = "{0}"'.format(" ".join(targets))) if ssh is not None: - features.append('TOOLCHAIN_TEST_TARGET = "ssh"') + features.append('TOOLCHAIN_TEST_TARGET = "linux-ssh"') features.append('TOOLCHAIN_TEST_HOST = "{0}"'.format(ssh)) features.append('TOOLCHAIN_TEST_HOST_USER = "root"') features.append('TOOLCHAIN_TEST_HOST_PORT = "22"') diff --git a/meta/lib/oeqa/selftest/cases/imagefeatures.py b/meta/lib/oeqa/selftest/cases/imagefeatures.py index dc88c222bd..94d01ba116 100644 --- a/meta/lib/oeqa/selftest/cases/imagefeatures.py +++ b/meta/lib/oeqa/selftest/cases/imagefeatures.py @@ -250,12 +250,7 @@ USERADD_GID_TABLES += "files/static-group" DISTRO_FEATURES:append = " pam opengl wayland" # Switch to systemd -DISTRO_FEATURES:append = " systemd usrmerge" -VIRTUAL-RUNTIME_init_manager = "systemd" -VIRTUAL-RUNTIME_initscripts = "" -VIRTUAL-RUNTIME_syslog = "" -VIRTUAL-RUNTIME_login_manager = "shadow-base" -DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit" +INIT_MANAGER = "systemd" # Replace busybox PREFERRED_PROVIDER_virtual/base-utils = "packagegroup-core-base-utils" @@ -319,7 +314,7 @@ SKIP_RECIPE[busybox] = "Don't build this" """ config = """ DISTRO_FEATURES:append = " api-documentation" -CORE_IMAGE_EXTRA_INSTALL = "man-pages kmod-doc" +CORE_IMAGE_EXTRA_INSTALL = "man-pages" """ self.write_config(config) bitbake("core-image-minimal") @@ -330,7 +325,7 @@ CORE_IMAGE_EXTRA_INSTALL = "man-pages kmod-doc" self.assertEqual(status, 1, 'Failed to run apropos: %s' % (output)) self.assertIn("iso_8859_15", output) - # This manpage is provided by kmod - status, output = qemu.run_serial("man --pager=cat modprobe") + # This manpage is provided by man-pages + status, output = qemu.run_serial("man --pager=cat intro") self.assertEqual(status, 1, 'Failed to run man: %s' % (output)) - self.assertIn("force-modversion", output) + self.assertIn("introduction to user commands", output) diff --git a/meta/lib/oeqa/selftest/cases/incompatible_lic.py b/meta/lib/oeqa/selftest/cases/incompatible_lic.py index f4af67a239..be5484bca4 100644 --- a/meta/lib/oeqa/selftest/cases/incompatible_lic.py +++ b/meta/lib/oeqa/selftest/cases/incompatible_lic.py @@ -114,7 +114,7 @@ INCOMPATIBLE_LICENSE:pn-core-image-minimal = "GPL-3.0* LGPL-3.0*" def test_bash_and_license(self): self.disable_class("create-spdx") - self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " & SomeLicense"') + self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " & SomeLicense"\nERROR_QA:remove:pn-bash = "license-exists"') error_msg = "ERROR: core-image-minimal-1.0-r0 do_rootfs: Package bash cannot be installed into the image because it has incompatible license(s): GPL-3.0-or-later" result = bitbake('core-image-minimal', ignore_status=True) @@ -123,12 +123,12 @@ INCOMPATIBLE_LICENSE:pn-core-image-minimal = "GPL-3.0* LGPL-3.0*" def test_bash_or_license(self): self.disable_class("create-spdx") - self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " | SomeLicense"') + self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " | SomeLicense"\nERROR_QA:remove:pn-bash = "license-exists"\nERROR_QA:remove:pn-core-image-minimal = "license-file-missing"') bitbake('core-image-minimal') def test_bash_license_exceptions(self): - self.write_config(self.default_config() + '\nINCOMPATIBLE_LICENSE_EXCEPTIONS:pn-core-image-minimal = "bash:GPL-3.0-or-later"') + self.write_config(self.default_config() + '\nINCOMPATIBLE_LICENSE_EXCEPTIONS:pn-core-image-minimal = "bash:GPL-3.0-or-later"\nERROR_QA:remove:pn-core-image-minimal = "license-exception"') bitbake('core-image-minimal') diff --git a/meta/lib/oeqa/selftest/cases/layerappend.py b/meta/lib/oeqa/selftest/cases/layerappend.py index 379ed589ad..64b17117cc 100644 --- a/meta/lib/oeqa/selftest/cases/layerappend.py +++ b/meta/lib/oeqa/selftest/cases/layerappend.py @@ -37,7 +37,7 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" SRC_URI:append = " file://appendtest.txt" sysroot_stage_all:append() { - install -m 644 ${WORKDIR}/appendtest.txt ${SYSROOT_DESTDIR}/ + install -m 644 ${UNPACKDIR}/appendtest.txt ${SYSROOT_DESTDIR}/ } """ diff --git a/meta/lib/oeqa/selftest/cases/locales.py b/meta/lib/oeqa/selftest/cases/locales.py index 4ca8ffb7aa..ac4888ef66 100644 --- a/meta/lib/oeqa/selftest/cases/locales.py +++ b/meta/lib/oeqa/selftest/cases/locales.py @@ -14,7 +14,7 @@ class LocalesTest(OESelftestTestCase): features = [] features.append('EXTRA_IMAGE_FEATURES = "empty-root-password allow-empty-password allow-root-login"') features.append('IMAGE_INSTALL:append = " glibc-utils localedef"') - features.append('GLIBC_GENERATE_LOCALES = "en_US.UTF-8 fr_FR.UTF-8"') + features.append('GLIBC_GENERATE_LOCALES = "en_US.UTF-8 fr_FR.UTF-8 en_US.ISO-8859-1 de_DE.UTF-8 fr_FR.ISO-8859-1 zh_HK.BIG5-HKSCS tr_TR.UTF-8"') features.append('IMAGE_LINGUAS:append = " en-us fr-fr"') if binary_enabled: features.append('ENABLE_BINARY_LOCALE_GENERATION = "1"') diff --git a/meta/lib/oeqa/selftest/cases/meta_ide.py b/meta/lib/oeqa/selftest/cases/meta_ide.py index ffe0d2604d..5a17ca52ea 100644 --- a/meta/lib/oeqa/selftest/cases/meta_ide.py +++ b/meta/lib/oeqa/selftest/cases/meta_ide.py @@ -20,8 +20,8 @@ class MetaIDE(OESelftestTestCase): bitbake('meta-ide-support') bitbake('build-sysroots -c build_native_sysroot') bitbake('build-sysroots -c build_target_sysroot') - bb_vars = get_bb_vars(['MULTIMACH_TARGET_SYS', 'DEPLOY_DIR_IMAGE', 'COREBASE']) - cls.environment_script = 'environment-setup-%s' % bb_vars['MULTIMACH_TARGET_SYS'] + bb_vars = get_bb_vars(['MACHINE_ARCH', 'TARGET_VENDOR', 'TARGET_OS', 'DEPLOY_DIR_IMAGE', 'COREBASE']) + cls.environment_script = 'environment-setup-%s%s-%s' % (bb_vars['MACHINE_ARCH'], bb_vars['TARGET_VENDOR'], bb_vars['TARGET_OS']) cls.deploydir = bb_vars['DEPLOY_DIR_IMAGE'] cls.environment_script_path = '%s/%s' % (cls.deploydir, cls.environment_script) cls.corebasedir = bb_vars['COREBASE'] diff --git a/meta/lib/oeqa/selftest/cases/minidebuginfo.py b/meta/lib/oeqa/selftest/cases/minidebuginfo.py index 2919f07939..a8923460f9 100644 --- a/meta/lib/oeqa/selftest/cases/minidebuginfo.py +++ b/meta/lib/oeqa/selftest/cases/minidebuginfo.py @@ -8,6 +8,7 @@ import subprocess import tempfile import shutil +from oeqa.core.decorator import OETestTag from oeqa.selftest.case import OESelftestTestCase from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars, runCmd @@ -42,3 +43,18 @@ IMAGE_FSTYPES = "tar.bz2" native_sysroot = native_sysroot, target_sys = target_sys) self.assertIn(".gnu_debugdata", r.output) + @OETestTag("runqemu") + def test_minidebuginfo_qemu(self): + """ + Test minidebuginfo inside a qemu. + This runs test_systemd_coredump_minidebuginfo and other minidebuginfo runtime tests which may be added in the future. + """ + + self.write_config(""" +DISTRO_FEATURES:append = " minidebuginfo" +INIT_MANAGER = "systemd" +IMAGE_CLASSES += "testimage" +TEST_SUITES = "ping ssh systemd" + """) + bitbake('core-image-minimal') + bitbake('-c testimage core-image-minimal') diff --git a/meta/lib/oeqa/selftest/cases/oescripts.py b/meta/lib/oeqa/selftest/cases/oescripts.py index f69efccfee..bfbc33b08d 100644 --- a/meta/lib/oeqa/selftest/cases/oescripts.py +++ b/meta/lib/oeqa/selftest/cases/oescripts.py @@ -175,7 +175,7 @@ class OEListPackageconfigTests(OESelftestTestCase): def test_packageconfig_flags_option_all(self): results = runCmd('%s/contrib/list-packageconfig-flags.py -a' % self.scripts_dir) expected_endlines = [] - expected_endlines.append("pinentry-1.2.1") + expected_endlines.append("pinentry-1.3.1") expected_endlines.append("PACKAGECONFIG ncurses") expected_endlines.append("PACKAGECONFIG[qt] --enable-pinentry-qt, --disable-pinentry-qt, qtbase-native qtbase") expected_endlines.append("PACKAGECONFIG[gtk2] --enable-pinentry-gtk2, --disable-pinentry-gtk2, gtk+ glib-2.0") diff --git a/meta/lib/oeqa/selftest/cases/overlayfs.py b/meta/lib/oeqa/selftest/cases/overlayfs.py index e31063567b..580fbdcb9c 100644 --- a/meta/lib/oeqa/selftest/cases/overlayfs.py +++ b/meta/lib/oeqa/selftest/cases/overlayfs.py @@ -5,7 +5,7 @@ # from oeqa.selftest.case import OESelftestTestCase -from oeqa.utils.commands import bitbake, runqemu +from oeqa.utils.commands import bitbake, runqemu, get_bb_vars from oeqa.core.decorator import OETestTag from oeqa.core.decorator.data import skipIfNotMachine @@ -466,6 +466,45 @@ IMAGE_INSTALL:append = " overlayfs-user" line = getline_qemu(output, "Read-only file system") self.assertTrue(line, msg=output) + @skipIfNotMachine("qemux86-64", "tests are qemux86-64 specific currently") + def test_postinst_on_target_for_read_only_rootfs(self): + """ + Summary: The purpose of this test case is to verify that post-installation + on target scripts are executed even if using read-only rootfs when + read-only-rootfs-delayed-postinsts is set + Expected: The test files are created on first boot + """ + + import oe.path + + vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal") + sysconfdir = vars["sysconfdir"] + self.assertIsNotNone(sysconfdir) + # Need to use oe.path here as sysconfdir starts with / + targettestdir = os.path.join(sysconfdir, "postinst-test") + + config = self.get_working_config() + + args = { + 'OVERLAYFS_INIT_OPTION': "", + 'OVERLAYFS_ETC_USE_ORIG_INIT_NAME': 1, + 'OVERLAYFS_ROOTFS_TYPE': "ext4", + 'OVERLAYFS_ETC_CREATE_MOUNT_DIRS': 1 + } + + # read-only-rootfs is already set in get_working_config() + config += 'EXTRA_IMAGE_FEATURES += "read-only-rootfs-delayed-postinsts"\n' + config += 'CORE_IMAGE_EXTRA_INSTALL = "postinst-delayed-b"\n' + + self.write_config(config.format(**args)) + + res = bitbake('core-image-minimal') + + with runqemu('core-image-minimal', image_fstype='wic') as qemu: + for filename in ("rootfs", "delayed-a", "delayed-b"): + status, output = qemu.run_serial("test -f %s && echo found" % os.path.join(targettestdir, filename)) + self.assertIn("found", output, "%s was not present on boot" % filename) + def get_working_config(self): return """ # Use systemd as init manager diff --git a/meta/lib/oeqa/selftest/cases/package.py b/meta/lib/oeqa/selftest/cases/package.py index 1aa6c03f8a..38ed7173fe 100644 --- a/meta/lib/oeqa/selftest/cases/package.py +++ b/meta/lib/oeqa/selftest/cases/package.py @@ -103,11 +103,37 @@ class PackageTests(OESelftestTestCase): dest = get_bb_var('PKGDEST', 'selftest-hardlink') bindir = get_bb_var('bindir', 'selftest-hardlink') + libdir = get_bb_var('libdir', 'selftest-hardlink') + libexecdir = get_bb_var('libexecdir', 'selftest-hardlink') def checkfiles(): # Recipe creates 4 hardlinked files, there is a copy in package/ and a copy in packages-split/ # so expect 8 in total. self.assertEqual(os.stat(dest + "/selftest-hardlink" + bindir + "/hello1").st_nlink, 8) + self.assertEqual(os.stat(dest + "/selftest-hardlink" + libexecdir + "/hello3").st_nlink, 8) + + # Check dbg version + # 2 items, a copy in both package/packages-split so 4 + self.assertEqual(os.stat(dest + "/selftest-hardlink-dbg" + bindir + "/.debug/hello1").st_nlink, 4) + self.assertEqual(os.stat(dest + "/selftest-hardlink-dbg" + libexecdir + "/.debug/hello1").st_nlink, 4) + + # Even though the libexecdir name is 'hello3' or 'hello4', that isn't the debug target name + self.assertEqual(os.path.exists(dest + "/selftest-hardlink-dbg" + libexecdir + "/.debug/hello3"), False) + self.assertEqual(os.path.exists(dest + "/selftest-hardlink-dbg" + libexecdir + "/.debug/hello4"), False) + + # Check the staticdev libraries + # 101 items, a copy in both package/packages-split so 202 + self.assertEqual(os.stat(dest + "/selftest-hardlink-staticdev" + libdir + "/libhello.a").st_nlink, 202) + self.assertEqual(os.stat(dest + "/selftest-hardlink-staticdev" + libdir + "/libhello-25.a").st_nlink, 202) + self.assertEqual(os.stat(dest + "/selftest-hardlink-staticdev" + libdir + "/libhello-50.a").st_nlink, 202) + self.assertEqual(os.stat(dest + "/selftest-hardlink-staticdev" + libdir + "/libhello-75.a").st_nlink, 202) + + # Check static dbg + # 101 items, a copy in both package/packages-split so 202 + self.assertEqual(os.stat(dest + "/selftest-hardlink-dbg" + libdir + "/.debug-static/libhello.a").st_nlink, 202) + self.assertEqual(os.stat(dest + "/selftest-hardlink-dbg" + libdir + "/.debug-static/libhello-25.a").st_nlink, 202) + self.assertEqual(os.stat(dest + "/selftest-hardlink-dbg" + libdir + "/.debug-static/libhello-50.a").st_nlink, 202) + self.assertEqual(os.stat(dest + "/selftest-hardlink-dbg" + libdir + "/.debug-static/libhello-75.a").st_nlink, 202) # Test a sparse file remains sparse sparsestat = os.stat(dest + "/selftest-hardlink" + bindir + "/sparsetest") diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py b/meta/lib/oeqa/selftest/cases/picolibc.py new file mode 100644 index 0000000000..e40b4fc3d3 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/picolibc.py @@ -0,0 +1,18 @@ +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: MIT +# + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake, get_bb_var + +class PicolibcTest(OESelftestTestCase): + + def test_picolibc(self): + compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32', 'qemuriscv64'] + machine = get_bb_var('MACHINE') + if machine not in compatible_machines: + self.skipTest('This test only works with machines : %s' % ' '.join(compatible_machines)) + self.write_config('TCLIBC = "picolibc"') + bitbake("picolibc-helloworld") diff --git a/meta/lib/oeqa/selftest/cases/recipetool.py b/meta/lib/oeqa/selftest/cases/recipetool.py index 126906df50..f742dd4d64 100644 --- a/meta/lib/oeqa/selftest/cases/recipetool.py +++ b/meta/lib/oeqa/selftest/cases/recipetool.py @@ -138,7 +138,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${%s}\n' % dirname, - ' install -m 0755 ${WORKDIR}/%s ${D}${%s}/ls\n' % (testfile2name, dirname), + ' install -m 0755 ${UNPACKDIR}/%s ${D}${%s}/ls\n' % (testfile2name, dirname), '}\n'] self._try_recipetool_appendfile('coreutils', lspath, testfile2, '-r coreutils', expectedlines, [testfile2name]) # Now try bbappending the same file again, contents should not change @@ -164,7 +164,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${datadir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n', + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${datadir}/something\n', '}\n'] self._try_recipetool_appendfile('netbase', '/usr/share/something', self.testfile, '-r netbase', expectedlines, ['testfile']) # Try adding another file, this time where the source file is executable @@ -179,8 +179,8 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${datadir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n', - ' install -m 0755 ${WORKDIR}/%s ${D}${datadir}/scriptname\n' % testfile2name, + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${datadir}/something\n', + ' install -m 0755 ${UNPACKDIR}/%s ${D}${datadir}/scriptname\n' % testfile2name, '}\n'] self._try_recipetool_appendfile('netbase', '/usr/share/scriptname', testfile2, '-r netbase', expectedlines, ['testfile', testfile2name]) @@ -192,7 +192,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${bindir}\n', - ' install -m 0755 ${WORKDIR}/testfile ${D}${bindir}/selftest-recipetool-testbin\n', + ' install -m 0755 ${UNPACKDIR}/testfile ${D}${bindir}/selftest-recipetool-testbin\n', '}\n'] _, output = self._try_recipetool_appendfile('netbase', '/usr/bin/selftest-recipetool-testbin', self.testfile, '-r netbase', expectedlines, ['testfile']) self.assertNotIn('WARNING: ', output) @@ -207,7 +207,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append:mymachine() {\n', ' install -d ${D}${datadir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n', + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${datadir}/something\n', '}\n'] _, output = self._try_recipetool_appendfile('netbase', '/usr/share/something', self.testfile, '-r netbase -m mymachine', expectedlines, ['mymachine/testfile']) self.assertNotIn('WARNING: ', output) @@ -241,7 +241,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${datadir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-subdir\n', + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${datadir}/selftest-replaceme-subdir\n', '}\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-subdir', self.testfile, '', expectedlines, ['testfile']) self.assertNotIn('WARNING: ', output) @@ -268,7 +268,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${sysconfdir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${sysconfdir}/selftest-replaceme-patched\n', + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${sysconfdir}/selftest-replaceme-patched\n', '}\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/etc/selftest-replaceme-patched', self.testfile, '', expectedlines, ['testfile']) for line in output.splitlines(): @@ -286,7 +286,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${datadir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-scripted\n', + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${datadir}/selftest-replaceme-scripted\n', '}\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-scripted', self.testfile, '', expectedlines, ['testfile']) self.assertNotIn('WARNING: ', output) @@ -309,7 +309,7 @@ class RecipetoolAppendTests(RecipetoolBase): '\n', 'do_install:append() {\n', ' install -d ${D}${datadir}\n', - ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-postinst\n', + ' install -m 0644 ${UNPACKDIR}/testfile ${D}${datadir}/selftest-replaceme-postinst\n', '}\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-postinst', self.testfile, '-r selftest-recipetool-appendfile', expectedlines, ['testfile']) @@ -1068,6 +1068,7 @@ class RecipetoolTests(RecipetoolBase): d = DataConnectorCopy d.getVar = Mock(return_value=commonlicdir) + d.expand = Mock(side_effect=lambda x: x) srctree = tempfile.mkdtemp(prefix='recipetoolqa') self.track_for_cleanup(srctree) diff --git a/meta/lib/oeqa/selftest/cases/recipeutils.py b/meta/lib/oeqa/selftest/cases/recipeutils.py index 2cb4445f81..9949737172 100644 --- a/meta/lib/oeqa/selftest/cases/recipeutils.py +++ b/meta/lib/oeqa/selftest/cases/recipeutils.py @@ -72,7 +72,7 @@ class RecipeUtilsTests(OESelftestTestCase): expected_patch = """ --- a/recipes-test/recipeutils/recipeutils-test_1.2.bb +++ b/recipes-test/recipeutils/recipeutils-test_1.2.bb -@@ -8,6 +8,4 @@ +@@ -11,6 +11,4 @@ BBCLASSEXTEND = "native nativesdk" @@ -97,7 +97,7 @@ class RecipeUtilsTests(OESelftestTestCase): expected_patch = """ --- a/recipes-test/recipeutils/recipeutils-test_1.2.bb +++ b/recipes-test/recipeutils/recipeutils-test_1.2.bb -@@ -8,6 +8,3 @@ +@@ -11,6 +11,3 @@ BBCLASSEXTEND = "native nativesdk" diff --git a/meta/lib/oeqa/selftest/cases/reproducible.py b/meta/lib/oeqa/selftest/cases/reproducible.py index 80e830136f..3d3f30eebc 100644 --- a/meta/lib/oeqa/selftest/cases/reproducible.py +++ b/meta/lib/oeqa/selftest/cases/reproducible.py @@ -133,7 +133,8 @@ class ReproducibleTests(OESelftestTestCase): max_report_size = 250 * 1024 * 1024 # targets are the things we want to test the reproducibility of - targets = ['core-image-minimal', 'core-image-sato', 'core-image-full-cmdline', 'core-image-weston', 'world'] + # Have to add the virtual targets manually for now as builds may or may not include them as they're exclude from world + targets = ['core-image-minimal', 'core-image-sato', 'core-image-full-cmdline', 'core-image-weston', 'world', 'virtual/librpc', 'virtual/libsdl2', 'virtual/crypt'] # sstate targets are things to pull from sstate to potentially cut build/debugging time sstate_targets = [] @@ -273,9 +274,13 @@ class ReproducibleTests(OESelftestTestCase): 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) + # The below bug shows that a few reproducible issues are depends on build dir path length. + # https://bugzilla.yoctoproject.org/show_bug.cgi?id=15554 + # So, the reproducibleA & reproducibleB directories are changed to reproducibleA & reproducibleB-extended to have different size. + vars_A = self.do_test_build('reproducibleA', self.build_from_sstate) - vars_B = self.do_test_build('reproducibleB', False) + vars_B = self.do_test_build('reproducibleB-extended', False) # NOTE: The temp directories from the reproducible build are purposely # kept after the build so it can be diffed for debugging. @@ -330,7 +335,7 @@ class ReproducibleTests(OESelftestTestCase): # 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')) - run_diffoscope('reproducibleA', 'reproducibleB', package_html_dir, max_report_size=self.max_report_size, + run_diffoscope('reproducibleA', 'reproducibleB-extended', package_html_dir, max_report_size=self.max_report_size, native_sysroot=diffoscope_sysroot, ignore_status=True, cwd=package_dir) if fails: diff --git a/meta/lib/oeqa/selftest/cases/retain.py b/meta/lib/oeqa/selftest/cases/retain.py new file mode 100644 index 0000000000..892be45857 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/retain.py @@ -0,0 +1,241 @@ +# Tests for retain.bbclass +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: MIT +# + +import os +import glob +import fnmatch +import oe.path +import shutil +import tarfile +from oeqa.utils.commands import bitbake, get_bb_vars +from oeqa.selftest.case import OESelftestTestCase + +class Retain(OESelftestTestCase): + + def test_retain_always(self): + """ + Summary: Test retain class with RETAIN_DIRS_ALWAYS + Expected: Archive written to RETAIN_OUTDIR when build of test recipe completes + Product: oe-core + Author: Paul Eggleton <paul.eggleton@microsoft.com> + """ + + test_recipe = 'quilt-native' + + features = 'INHERIT += "retain"\n' + features += 'RETAIN_DIRS_ALWAYS = "${T}"\n' + self.write_config(features) + + bitbake('-c clean %s' % test_recipe) + + bb_vars = get_bb_vars(['RETAIN_OUTDIR', 'TMPDIR']) + retain_outdir = bb_vars['RETAIN_OUTDIR'] or '' + tmpdir = bb_vars['TMPDIR'] + if len(retain_outdir) < 5: + self.fail('RETAIN_OUTDIR value "%s" is invalid' % retain_outdir) + if not oe.path.is_path_parent(tmpdir, retain_outdir): + self.fail('RETAIN_OUTDIR (%s) is not underneath TMPDIR (%s)' % (retain_outdir, tmpdir)) + try: + shutil.rmtree(retain_outdir) + except FileNotFoundError: + pass + + bitbake(test_recipe) + if not glob.glob(os.path.join(retain_outdir, '%s_temp_*.tar.gz' % test_recipe)): + self.fail('No output archive for %s created' % test_recipe) + + + def test_retain_failure(self): + """ + Summary: Test retain class default behaviour + Expected: Archive written to RETAIN_OUTDIR only when build of test + recipe fails, and archive contents are as expected + Product: oe-core + Author: Paul Eggleton <paul.eggleton@microsoft.com> + """ + + test_recipe_fail = 'error' + + features = 'INHERIT += "retain"\n' + self.write_config(features) + + bb_vars = get_bb_vars(['RETAIN_OUTDIR', 'TMPDIR', 'RETAIN_DIRS_ALWAYS', 'RETAIN_DIRS_GLOBAL_ALWAYS']) + if bb_vars['RETAIN_DIRS_ALWAYS']: + self.fail('RETAIN_DIRS_ALWAYS is set, this interferes with the test') + if bb_vars['RETAIN_DIRS_GLOBAL_ALWAYS']: + self.fail('RETAIN_DIRS_GLOBAL_ALWAYS is set, this interferes with the test') + retain_outdir = bb_vars['RETAIN_OUTDIR'] or '' + tmpdir = bb_vars['TMPDIR'] + if len(retain_outdir) < 5: + self.fail('RETAIN_OUTDIR value "%s" is invalid' % retain_outdir) + if not oe.path.is_path_parent(tmpdir, retain_outdir): + self.fail('RETAIN_OUTDIR (%s) is not underneath TMPDIR (%s)' % (retain_outdir, tmpdir)) + + try: + shutil.rmtree(retain_outdir) + except FileNotFoundError: + pass + + bitbake('-c clean %s' % test_recipe_fail) + + if os.path.exists(retain_outdir): + retain_dirlist = os.listdir(retain_outdir) + if retain_dirlist: + self.fail('RETAIN_OUTDIR should be empty without failure, contents:\n%s' % '\n'.join(retain_dirlist)) + + result = bitbake('-c compile %s' % test_recipe_fail, ignore_status=True) + if result.status == 0: + self.fail('Build of %s did not fail as expected' % test_recipe_fail) + + archives = glob.glob(os.path.join(retain_outdir, '%s_*.tar.gz' % test_recipe_fail)) + if not archives: + self.fail('No output archive for %s created' % test_recipe_fail) + if len(archives) > 1: + self.fail('More than one archive for %s created' % test_recipe_fail) + for archive in archives: + found = False + archive_prefix = os.path.basename(archive).split('.tar')[0] + expected_prefix_start = '%s_workdir' % test_recipe_fail + if not archive_prefix.startswith(expected_prefix_start): + self.fail('Archive %s name does not start with expected prefix "%s"' % (os.path.basename(archive), expected_prefix_start)) + with tarfile.open(archive) as tf: + for ti in tf: + if not fnmatch.fnmatch(ti.name, '%s/*' % archive_prefix): + self.fail('File without tarball-named subdirectory within tarball %s: %s' % (os.path.basename(archive), ti.name)) + if ti.name.endswith('/temp/log.do_compile'): + found = True + if not found: + self.fail('Did not find log.do_compile in output archive %s' % os.path.basename(archive)) + + + def test_retain_global(self): + """ + Summary: Test retain class RETAIN_DIRS_GLOBAL_* behaviour + Expected: Ensure RETAIN_DIRS_GLOBAL_ALWAYS always causes an + archive to be created, and RETAIN_DIRS_GLOBAL_FAILURE + only causes an archive to be created on failure. + Also test archive naming (with : character) as an + added bonus. + Product: oe-core + Author: Paul Eggleton <paul.eggleton@microsoft.com> + """ + + test_recipe = 'quilt-native' + test_recipe_fail = 'error' + + features = 'INHERIT += "retain"\n' + features += 'RETAIN_DIRS_GLOBAL_ALWAYS = "${LOG_DIR};prefix=buildlogs"\n' + features += 'RETAIN_DIRS_GLOBAL_FAILURE = "${STAMPS_DIR}"\n' + self.write_config(features) + + bitbake('-c clean %s' % test_recipe) + + bb_vars = get_bb_vars(['RETAIN_OUTDIR', 'TMPDIR', 'STAMPS_DIR']) + retain_outdir = bb_vars['RETAIN_OUTDIR'] or '' + tmpdir = bb_vars['TMPDIR'] + if len(retain_outdir) < 5: + self.fail('RETAIN_OUTDIR value "%s" is invalid' % retain_outdir) + if not oe.path.is_path_parent(tmpdir, retain_outdir): + self.fail('RETAIN_OUTDIR (%s) is not underneath TMPDIR (%s)' % (retain_outdir, tmpdir)) + try: + shutil.rmtree(retain_outdir) + except FileNotFoundError: + pass + + # Test success case + bitbake(test_recipe) + if not glob.glob(os.path.join(retain_outdir, 'buildlogs_*.tar.gz')): + self.fail('No output archive for LOG_DIR created') + stamps_dir = bb_vars['STAMPS_DIR'] + if glob.glob(os.path.join(retain_outdir, '%s_*.tar.gz' % os.path.basename(stamps_dir))): + self.fail('Output archive for STAMPS_DIR created when it should not have been') + + # Test failure case + result = bitbake('-c compile %s' % test_recipe_fail, ignore_status=True) + if result.status == 0: + self.fail('Build of %s did not fail as expected' % test_recipe_fail) + if not glob.glob(os.path.join(retain_outdir, '%s_*.tar.gz' % os.path.basename(stamps_dir))): + self.fail('Output archive for STAMPS_DIR not created') + if len(glob.glob(os.path.join(retain_outdir, 'buildlogs_*.tar.gz'))) != 2: + self.fail('Should be exactly two buildlogs archives in output dir') + + + def test_retain_misc(self): + """ + Summary: Test retain class with RETAIN_ENABLED and RETAIN_TARBALL_SUFFIX + Expected: Archive written to RETAIN_OUTDIR only when RETAIN_ENABLED is set + and archive contents are as expected. Also test archive naming + (with : character) as an added bonus. + Product: oe-core + Author: Paul Eggleton <paul.eggleton@microsoft.com> + """ + + test_recipe_fail = 'error' + + features = 'INHERIT += "retain"\n' + features += 'RETAIN_DIRS_ALWAYS = "${T}"\n' + features += 'RETAIN_ENABLED = "0"\n' + self.write_config(features) + + bb_vars = get_bb_vars(['RETAIN_OUTDIR', 'TMPDIR']) + retain_outdir = bb_vars['RETAIN_OUTDIR'] or '' + tmpdir = bb_vars['TMPDIR'] + if len(retain_outdir) < 5: + self.fail('RETAIN_OUTDIR value "%s" is invalid' % retain_outdir) + if not oe.path.is_path_parent(tmpdir, retain_outdir): + self.fail('RETAIN_OUTDIR (%s) is not underneath TMPDIR (%s)' % (retain_outdir, tmpdir)) + + try: + shutil.rmtree(retain_outdir) + except FileNotFoundError: + pass + + bitbake('-c clean %s' % test_recipe_fail) + result = bitbake('-c compile %s' % test_recipe_fail, ignore_status=True) + if result.status == 0: + self.fail('Build of %s did not fail as expected' % test_recipe_fail) + + if os.path.exists(retain_outdir) and os.listdir(retain_outdir): + self.fail('RETAIN_OUTDIR should be empty with RETAIN_ENABLED = "0"') + + features = 'INHERIT += "retain"\n' + features += 'RETAIN_DIRS_ALWAYS = "${T};prefix=recipelogs"\n' + features += 'RETAIN_TARBALL_SUFFIX = "${DATETIME}-testsuffix.tar.bz2"\n' + features += 'RETAIN_ENABLED = "1"\n' + self.write_config(features) + + result = bitbake('-c compile %s' % test_recipe_fail, ignore_status=True) + if result.status == 0: + self.fail('Build of %s did not fail as expected' % test_recipe_fail) + + archives = glob.glob(os.path.join(retain_outdir, '%s_*-testsuffix.tar.bz2' % test_recipe_fail)) + if not archives: + self.fail('No output archive for %s created' % test_recipe_fail) + if len(archives) != 2: + self.fail('Two archives for %s expected, but %d exist' % (test_recipe_fail, len(archives))) + recipelogs_found = False + workdir_found = False + for archive in archives: + contents_found = False + archive_prefix = os.path.basename(archive).split('.tar')[0] + if archive_prefix.startswith('%s_recipelogs' % test_recipe_fail): + recipelogs_found = True + if archive_prefix.startswith('%s_workdir' % test_recipe_fail): + workdir_found = True + with tarfile.open(archive, 'r:bz2') as tf: + for ti in tf: + if not fnmatch.fnmatch(ti.name, '%s/*' % (archive_prefix)): + self.fail('File without tarball-named subdirectory within tarball %s: %s' % (os.path.basename(archive), ti.name)) + if ti.name.endswith('/log.do_compile'): + contents_found = True + if not contents_found: + # Both archives should contain this file + self.fail('Did not find log.do_compile in output archive %s' % os.path.basename(archive)) + if not recipelogs_found: + self.fail('No archive with expected "recipelogs" prefix found') + if not workdir_found: + self.fail('No archive with expected "workdir" prefix found') diff --git a/meta/lib/oeqa/selftest/cases/runtime_test.py b/meta/lib/oeqa/selftest/cases/runtime_test.py index 12000aac16..27090ae5cd 100644 --- a/meta/lib/oeqa/selftest/cases/runtime_test.py +++ b/meta/lib/oeqa/selftest/cases/runtime_test.py @@ -273,7 +273,7 @@ TEST_RUNQEMUPARAMS += " slirp" import subprocess, os distro = oe.lsb.distro_identifier() - if distro and (distro in ['debian-9', 'debian-10', 'centos-7', 'centos-8', 'ubuntu-16.04', 'ubuntu-18.04'] or + if distro and (distro in ['debian-9', 'debian-10', 'centos-7', 'centos-8', 'centos-9', 'ubuntu-16.04', 'ubuntu-18.04'] or distro.startswith('almalinux') or distro.startswith('rocky')): self.skipTest('virgl headless cannot be tested with %s' %(distro)) @@ -310,10 +310,7 @@ class Postinst(OESelftestTestCase): features += 'IMAGE_FEATURES += "package-management empty-root-password"\n' features += 'PACKAGE_CLASSES = "%s"\n' % classes if init_manager == "systemd": - features += 'DISTRO_FEATURES:append = " systemd usrmerge"\n' - features += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n' - features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n' - features += 'VIRTUAL-RUNTIME_initscripts = ""\n' + features += 'INIT_MANAGER = "systemd"\n' self.write_config(features) bitbake('core-image-minimal') diff --git a/meta/lib/oeqa/selftest/cases/rust.py b/meta/lib/oeqa/selftest/cases/rust.py index ad14189c6d..cbe6366f75 100644 --- a/meta/lib/oeqa/selftest/cases/rust.py +++ b/meta/lib/oeqa/selftest/cases/rust.py @@ -66,132 +66,45 @@ class RustSelfTestSystemEmulated(OESelftestTestCase, OEPTestResultTestCase): # bless: First runs rustfmt to format the codebase, # then runs tidy checks. exclude_list = [ - 'compiler/rustc', - 'compiler/rustc_interface/src/tests.rs', - 'library/panic_abort', - 'library/panic_unwind', - 'library/test/src/stats/tests.rs', - 'src/bootstrap/builder/tests.rs', + 'src/bootstrap', 'src/doc/rustc', 'src/doc/rustdoc', 'src/doc/unstable-book', 'src/librustdoc', 'src/rustdoc-json-types', 'src/tools/compiletest/src/common.rs', + 'src/tools/jsondoclint', 'src/tools/lint-docs', + 'src/tools/replace-version-placeholder', 'src/tools/rust-analyzer', 'src/tools/rustdoc-themes', - 'src/tools/tidy', + 'src/tools/rust-installer', + 'src/tools/suggest-tests', + 'src/tools/tidy/src/', 'tests/assembly/asm/aarch64-outline-atomics.rs', 'tests/codegen/abi-main-signature-32bit-c-int.rs', - 'tests/codegen/abi-repr-ext.rs', - 'tests/codegen/abi-x86-interrupt.rs', - 'tests/codegen/branch-protection.rs', - 'tests/codegen/catch-unwind.rs', - 'tests/codegen/cf-protection.rs', - 'tests/codegen/enum-bounds-check-derived-idx.rs', - 'tests/codegen/force-unwind-tables.rs', - 'tests/codegen/intrinsic-no-unnamed-attr.rs', - 'tests/codegen/issues/issue-103840.rs', - 'tests/codegen/issues/issue-47278.rs', - 'tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs', - 'tests/codegen/lifetime_start_end.rs', - 'tests/codegen/local-generics-in-exe-internalized.rs', - 'tests/codegen/match-unoptimized.rs', - 'tests/codegen/noalias-rwlockreadguard.rs', - 'tests/codegen/non-terminate/nonempty-infinite-loop.rs', - 'tests/codegen/noreturn-uninhabited.rs', - 'tests/codegen/repr-transparent-aggregates-3.rs', - 'tests/codegen/riscv-abi/call-llvm-intrinsics.rs', - 'tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs', - 'tests/codegen/riscv-abi/riscv64-lp64d-abi.rs', - 'tests/codegen/sse42-implies-crc32.rs', + 'tests/codegen/i128-x86-align.rs', + 'tests/codegen/issues/issue-122805.rs', 'tests/codegen/thread-local.rs', - 'tests/codegen/uninit-consts.rs', - 'tests/pretty/raw-str-nonexpr.rs', + 'tests/mir-opt/', 'tests/run-make', 'tests/run-make-fulldeps', 'tests/rustdoc', 'tests/rustdoc-json', 'tests/rustdoc-js-std', - 'tests/rustdoc-ui/cfg-test.rs', - 'tests/rustdoc-ui/check-cfg-test.rs', - 'tests/rustdoc-ui/display-output.rs', - 'tests/rustdoc-ui/doc-comment-multi-line-attr.rs', - 'tests/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs', - 'tests/rustdoc-ui/doc-test-doctest-feature.rs', - 'tests/rustdoc-ui/doctest-multiline-crate-attribute.rs', - 'tests/rustdoc-ui/doctest-output.rs', - 'tests/rustdoc-ui/doc-test-rustdoc-feature.rs', - 'tests/rustdoc-ui/failed-doctest-compile-fail.rs', - 'tests/rustdoc-ui/issue-80992.rs', - 'tests/rustdoc-ui/issue-91134.rs', - 'tests/rustdoc-ui/nocapture-fail.rs', - 'tests/rustdoc-ui/nocapture.rs', - 'tests/rustdoc-ui/no-run-flag.rs', - 'tests/rustdoc-ui/run-directory.rs', - 'tests/rustdoc-ui/test-no_std.rs', - 'tests/rustdoc-ui/test-type.rs', - 'tests/rustdoc/unit-return.rs', 'tests/ui/abi/stack-probes-lto.rs', 'tests/ui/abi/stack-probes.rs', - 'tests/ui/array-slice-vec/subslice-patterns-const-eval-match.rs', - 'tests/ui/asm/x86_64/sym.rs', - 'tests/ui/associated-type-bounds/fn-apit.rs', - 'tests/ui/associated-type-bounds/fn-dyn-apit.rs', - 'tests/ui/associated-type-bounds/fn-wrap-apit.rs', + 'tests/ui/codegen/mismatched-data-layouts.rs', 'tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs', - 'tests/ui/drop/dynamic-drop.rs', - 'tests/ui/empty_global_asm.rs', - 'tests/ui/functions-closures/fn-help-with-err.rs', - 'tests/ui/linkage-attr/issue-10755.rs', - 'tests/ui/macros/restricted-shadowing-legacy.rs', + 'tests/ui-fulldeps/', 'tests/ui/process/nofile-limit.rs', - 'tests/ui/process/process-panic-after-fork.rs', - 'tests/ui/process/process-sigpipe.rs', - 'tests/ui/simd/target-feature-mixup.rs', 'tests/ui/structs-enums/multiple-reprs.rs', - 'src/tools/jsondoclint', - 'src/tools/replace-version-placeholder', - 'tests/codegen/abi-efiapi.rs', - 'tests/codegen/abi-sysv64.rs', - 'tests/codegen/align-byval.rs', - 'tests/codegen/align-fn.rs', - 'tests/codegen/asm-powerpc-clobbers.rs', - 'tests/codegen/async-fn-debug-awaitee-field.rs', - 'tests/codegen/binary-search-index-no-bound-check.rs', - 'tests/codegen/call-metadata.rs', - 'tests/codegen/debug-column.rs', - 'tests/codegen/debug-limited.rs', - 'tests/codegen/debuginfo-generic-closure-env-names.rs', - 'tests/codegen/drop.rs', - 'tests/codegen/dst-vtable-align-nonzero.rs', - 'tests/codegen/enable-lto-unit-splitting.rs', - 'tests/codegen/enum/enum-u128.rs', - 'tests/codegen/fn-impl-trait-self.rs', - 'tests/codegen/inherit_overflow.rs', - 'tests/codegen/inline-function-args-debug-info.rs', - 'tests/codegen/intrinsics/mask.rs', - 'tests/codegen/intrinsics/transmute-niched.rs', - 'tests/codegen/issues/issue-73258.rs', - 'tests/codegen/issues/issue-75546.rs', - 'tests/codegen/issues/issue-77812.rs', - 'tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs', - 'tests/codegen/llvm-ident.rs', - 'tests/codegen/mainsubprogram.rs', - 'tests/codegen/move-operands.rs', - 'tests/codegen/repr/transparent-mips64.rs', - 'tests/mir-opt/', - 'tests/rustdoc-json', - 'tests/rustdoc-ui/doc-test-rustdoc-feature.rs', - 'tests/rustdoc-ui/no-run-flag.rs', - 'tests/ui-fulldeps/', - 'tests/ui/numbers-arithmetic/u128.rs' + 'tidyselftest' ] exclude_fail_tests = " ".join([" --exclude " + item for item in exclude_list]) # Add exclude_fail_tests with other test arguments - testargs = exclude_fail_tests + " --doc --no-fail-fast --bless" + testargs = exclude_fail_tests + " --no-fail-fast --bless" # wrap the execution with a qemu instance. # Tests are run with 512 tasks in parallel to execute all tests very quickly @@ -210,9 +123,8 @@ class RustSelfTestSystemEmulated(OESelftestTestCase, OEPTestResultTestCase): tmpdir = get_bb_var("TMPDIR", "rust") # Set path for target-poky-linux-gcc, RUST_TARGET_PATH and hosttools. - cmd = " export PATH=%s/recipe-sysroot-native/usr/bin:$PATH;" % rustlibpath - cmd = cmd + " export TARGET_VENDOR=\"-poky\";" - cmd = cmd + " export PATH=%s/recipe-sysroot-native/usr/bin/%s:%s/hosttools:$PATH;" % (rustlibpath, tcpath, tmpdir) + cmd = "export TARGET_VENDOR=\"-poky\";" + cmd = cmd + " export PATH=%s/recipe-sysroot-native/usr/bin/python3-native:%s/recipe-sysroot-native/usr/bin:%s/recipe-sysroot-native/usr/bin/%s:%s/hosttools:$PATH;" % (rustlibpath, rustlibpath, rustlibpath, tcpath, tmpdir) cmd = cmd + " export RUST_TARGET_PATH=%s/rust-targets;" % rustlibpath # Trigger testing. cmd = cmd + " export TEST_DEVICE_ADDR=\"%s:12345\";" % qemu.ip diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py index 05fc4e390b..be595babb3 100644 --- a/meta/lib/oeqa/selftest/cases/spdx.py +++ b/meta/lib/oeqa/selftest/cases/spdx.py @@ -6,29 +6,37 @@ import json import os +import textwrap +from pathlib import Path from oeqa.selftest.case import OESelftestTestCase -from oeqa.utils.commands import bitbake, get_bb_var, runCmd +from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars, runCmd -class SPDXCheck(OESelftestTestCase): +class SPDX22Check(OESelftestTestCase): @classmethod def setUpClass(cls): - super(SPDXCheck, cls).setUpClass() + super().setUpClass() bitbake("python3-spdx-tools-native") bitbake("-c addto_recipe_sysroot python3-spdx-tools-native") def check_recipe_spdx(self, high_level_dir, spdx_file, target_name): - config = """ -INHERIT += "create-spdx" -""" + config = textwrap.dedent( + """\ + INHERIT:remove = "create-spdx" + INHERIT += "create-spdx-2.2" + """ + ) self.write_config(config) deploy_dir = get_bb_var("DEPLOY_DIR") machine_var = get_bb_var("MACHINE") + spdx_version = get_bb_var("SPDX_VERSION") # qemux86-64 creates the directory qemux86_64 machine_dir = machine_var.replace("-", "_") - full_file_path = os.path.join(deploy_dir, "spdx", machine_dir, high_level_dir, spdx_file) + full_file_path = os.path.join( + deploy_dir, "spdx", spdx_version, machine_dir, high_level_dir, spdx_file + ) try: os.remove(full_file_path) @@ -43,8 +51,13 @@ INHERIT += "create-spdx" self.assertNotEqual(report, None) self.assertNotEqual(report["SPDXID"], None) - python = os.path.join(get_bb_var('STAGING_BINDIR', 'python3-spdx-tools-native'), 'nativepython3') - validator = os.path.join(get_bb_var('STAGING_BINDIR', 'python3-spdx-tools-native'), 'pyspdxtools') + python = os.path.join( + get_bb_var("STAGING_BINDIR", "python3-spdx-tools-native"), + "nativepython3", + ) + validator = os.path.join( + get_bb_var("STAGING_BINDIR", "python3-spdx-tools-native"), "pyspdxtools" + ) result = runCmd("{} {} -i {}".format(python, validator, filename)) self.assertExists(full_file_path) @@ -52,3 +65,106 @@ INHERIT += "create-spdx" def test_spdx_base_files(self): self.check_recipe_spdx("packages", "base-files.spdx.json", "base-files") + + +class SPDX3CheckBase(object): + """ + Base class for checking SPDX 3 based tests + """ + + def check_spdx_file(self, filename): + import oe.spdx30 + + self.assertExists(filename) + + # Read the file + objset = oe.spdx30.SHACLObjectSet() + with open(filename, "r") as f: + d = oe.spdx30.JSONLDDeserializer() + d.read(f, objset) + + return objset + + def check_recipe_spdx(self, target_name, spdx_path, *, task=None, extraconf=""): + config = textwrap.dedent( + f"""\ + INHERIT:remove = "create-spdx" + INHERIT += "{self.SPDX_CLASS}" + {extraconf} + """ + ) + self.write_config(config) + + if task: + bitbake(f"-c {task} {target_name}") + else: + bitbake(target_name) + + filename = spdx_path.format( + **get_bb_vars( + [ + "DEPLOY_DIR_IMAGE", + "DEPLOY_DIR_SPDX", + "MACHINE", + "MACHINE_ARCH", + "SDKMACHINE", + "SDK_DEPLOY", + "SPDX_VERSION", + "TOOLCHAIN_OUTPUTNAME", + ], + target_name, + ) + ) + + return self.check_spdx_file(filename) + + def check_objset_missing_ids(self, objset): + if objset.missing_ids: + self.assertTrue( + False, + "The following SPDXIDs are unresolved:\n " + + "\n ".join(objset.missing_ids), + ) + + +class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): + SPDX_CLASS = "create-spdx-3.0" + + def test_base_files(self): + self.check_recipe_spdx( + "base-files", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/base-files.spdx.json", + ) + + def test_core_image_minimal(self): + objset = self.check_recipe_spdx( + "core-image-minimal", + "{DEPLOY_DIR_IMAGE}/core-image-minimal-{MACHINE}.rootfs.spdx.json", + ) + + # Document should be fully linked + self.check_objset_missing_ids(objset) + + def test_core_image_minimal_sdk(self): + objset = self.check_recipe_spdx( + "core-image-minimal", + "{SDK_DEPLOY}/{TOOLCHAIN_OUTPUTNAME}.spdx.json", + task="populate_sdk", + ) + + # Document should be fully linked + self.check_objset_missing_ids(objset) + + def test_baremetal_helloworld(self): + objset = self.check_recipe_spdx( + "baremetal-helloworld", + "{DEPLOY_DIR_IMAGE}/baremetal-helloworld-image-{MACHINE}.spdx.json", + extraconf=textwrap.dedent( + """\ + TCLIBC = "baremetal" + """ + ), + ) + + # Document should be fully linked + self.check_objset_missing_ids(objset) diff --git a/meta/lib/oeqa/selftest/cases/sstatetests.py b/meta/lib/oeqa/selftest/cases/sstatetests.py index 86d6cd7464..ae295bef5f 100644 --- a/meta/lib/oeqa/selftest/cases/sstatetests.py +++ b/meta/lib/oeqa/selftest/cases/sstatetests.py @@ -378,7 +378,6 @@ class SStateHashSameSigs(SStateBase): self.write_config(""" MACHINE = "qemux86" TMPDIR = "${TOPDIR}/tmp-sstatesamehash" -TCLIBCAPPEND = "" BUILD_ARCH = "x86_64" BUILD_OS = "linux" SDKMACHINE = "x86_64" @@ -390,7 +389,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" self.write_config(""" MACHINE = "qemux86" TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" -TCLIBCAPPEND = "" BUILD_ARCH = "i686" BUILD_OS = "linux" SDKMACHINE = "i686" @@ -426,7 +424,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" -TCLIBCAPPEND = \"\" NATIVELSBSTRING = \"DistroA\" BB_SIGNATURE_HANDLER = "OEBasicHash" """) @@ -434,7 +431,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" bitbake("core-image-weston -S none") self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" -TCLIBCAPPEND = \"\" NATIVELSBSTRING = \"DistroB\" BB_SIGNATURE_HANDLER = "OEBasicHash" """) @@ -463,17 +459,17 @@ class SStateHashSameSigs2(SStateBase): configA = """ TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86-64\" BB_SIGNATURE_HANDLER = "OEBasicHash" """ #OLDEST_KERNEL is arch specific so set to a different value here for testing configB = """ TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" -TCLIBCAPPEND = \"\" MACHINE = \"qemuarm\" OLDEST_KERNEL = \"3.3.0\" BB_SIGNATURE_HANDLER = "OEBasicHash" +ERROR_QA:append = " somenewoption" +WARN_QA:append = " someotheroption" """ self.sstate_common_samesigs(configA, configB, allarch=True) @@ -484,7 +480,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" configA = """ TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86-64\" require conf/multilib.conf MULTILIBS = \"multilib:lib32\" @@ -493,7 +488,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" """ configB = """ TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" -TCLIBCAPPEND = \"\" MACHINE = \"qemuarm\" require conf/multilib.conf MULTILIBS = \"\" @@ -511,7 +505,6 @@ class SStateHashSameSigs3(SStateBase): self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86\" require conf/multilib.conf MULTILIBS = "multilib:lib32" @@ -522,7 +515,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" bitbake("world meta-toolchain -S none") self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86copy\" require conf/multilib.conf MULTILIBS = "multilib:lib32" @@ -559,7 +551,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86\" require conf/multilib.conf MULTILIBS = "multilib:lib32" @@ -570,7 +561,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" bitbake("binutils-native -S none") self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86copy\" BB_SIGNATURE_HANDLER = "OEBasicHash" """) @@ -598,7 +588,6 @@ class SStateHashSameSigs4(SStateBase): self.write_config(""" TMPDIR = "${TOPDIR}/tmp-sstatesamehash" -TCLIBCAPPEND = "" BB_NUMBER_THREADS = "${@oe.utils.cpu_count()}" PARALLEL_MAKE = "-j 1" DL_DIR = "${TOPDIR}/download1" @@ -613,7 +602,6 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" bitbake("world meta-toolchain -S none") self.write_config(""" TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" -TCLIBCAPPEND = "" BB_NUMBER_THREADS = "${@oe.utils.cpu_count()+1}" PARALLEL_MAKE = "-j 2" DL_DIR = "${TOPDIR}/download2" @@ -724,7 +712,6 @@ class SStateFindSiginfo(SStateBase): """ self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstates-findsiginfo\" -TCLIBCAPPEND = \"\" MACHINE = \"qemux86-64\" require conf/multilib.conf MULTILIBS = "multilib:lib32" @@ -917,15 +904,24 @@ INHERIT += "base-do-configure-modified" """, expected_sametmp_output, expected_difftmp_output) -@OETestTag("yocto-mirrors") -class SStateMirrors(SStateBase): - def check_bb_output(self, output, exceptions, check_cdn): +class SStateCheckObjectPresence(SStateBase): + def check_bb_output(self, output, targets, exceptions, check_cdn): def is_exception(object, exceptions): for e in exceptions: if re.search(e, object): return True return False + # sstate is checked for existence of these, but they never get written out to begin with + exceptions += ["{}.*image_qa".format(t) for t in targets.split()] + exceptions += ["{}.*deploy_source_date_epoch".format(t) for t in targets.split()] + exceptions += ["{}.*image_complete".format(t) for t in targets.split()] + exceptions += ["linux-yocto.*shared_workdir"] + # these get influnced by IMAGE_FSTYPES tweaks in yocto-autobuilder-helper's config.json (on x86-64) + # additionally, they depend on noexec (thus, absent stamps) package, install, etc. image tasks, + # which makes tracing other changes difficult + exceptions += ["{}.*create_.*spdx".format(t) for t in targets.split()] + output_l = output.splitlines() for l in output_l: if l.startswith("Sstate summary"): @@ -960,18 +956,9 @@ class SStateMirrors(SStateBase): self.assertEqual(len(failed_urls), missing_objects, "Amount of reported missing objects does not match failed URLs: {}\nFailed URLs:\n{}\nFetcher diagnostics:\n{}".format(missing_objects, "\n".join(failed_urls), "\n".join(failed_urls_extrainfo))) self.assertEqual(len(failed_urls), 0, "Missing objects in the cache:\n{}\nFetcher diagnostics:\n{}".format("\n".join(failed_urls), "\n".join(failed_urls_extrainfo))) +@OETestTag("yocto-mirrors") +class SStateMirrors(SStateCheckObjectPresence): def run_test(self, machine, targets, exceptions, check_cdn = True, ignore_errors = False): - # sstate is checked for existence of these, but they never get written out to begin with - exceptions += ["{}.*image_qa".format(t) for t in targets.split()] - exceptions += ["{}.*deploy_source_date_epoch".format(t) for t in targets.split()] - exceptions += ["{}.*image_complete".format(t) for t in targets.split()] - exceptions += ["linux-yocto.*shared_workdir"] - # these get influnced by IMAGE_FSTYPES tweaks in yocto-autobuilder-helper's config.json (on x86-64) - # additionally, they depend on noexec (thus, absent stamps) package, install, etc. image tasks, - # which makes tracing other changes difficult - exceptions += ["{}.*create_spdx".format(t) for t in targets.split()] - exceptions += ["{}.*create_runtime_spdx".format(t) for t in targets.split()] - if check_cdn: self.config_sstate(True) self.append_config(""" @@ -987,7 +974,7 @@ MACHINE = "{}" bitbake("-S none {}".format(targets)) if ignore_errors: return - self.check_bb_output(result.output, exceptions, check_cdn) + self.check_bb_output(result.output, targets, exceptions, check_cdn) def test_cdn_mirror_qemux86_64(self): exceptions = [] |