diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases')
35 files changed, 1379 insertions, 347 deletions
diff --git a/meta/lib/oeqa/selftest/cases/archiver.py b/meta/lib/oeqa/selftest/cases/archiver.py index 0194ae9f69..75195241b7 100644 --- a/meta/lib/oeqa/selftest/cases/archiver.py +++ b/meta/lib/oeqa/selftest/cases/archiver.py @@ -163,21 +163,21 @@ class Archiver(OESelftestTestCase): Test that the archiver works with `ARCHIVER_MODE[src] = "patched"`. """ - self._test_archiver_mode('patched', 'selftest-ed-native-1.14.1-r0-patched.tar.gz') + self._test_archiver_mode('patched', 'selftest-ed-native-1.14.1-r0-patched.tar.xz') def test_archiver_mode_configured(self): """ Test that the archiver works with `ARCHIVER_MODE[src] = "configured"`. """ - self._test_archiver_mode('configured', 'selftest-ed-native-1.14.1-r0-configured.tar.gz') + self._test_archiver_mode('configured', 'selftest-ed-native-1.14.1-r0-configured.tar.xz') def test_archiver_mode_recipe(self): """ Test that the archiver works with `ARCHIVER_MODE[recipe] = "1"`. """ - self._test_archiver_mode('patched', 'selftest-ed-native-1.14.1-r0-recipe.tar.gz', + self._test_archiver_mode('patched', 'selftest-ed-native-1.14.1-r0-recipe.tar.xz', 'ARCHIVER_MODE[recipe] = "1"\n') def test_archiver_mode_diff(self): diff --git a/meta/lib/oeqa/selftest/cases/bblogging.py b/meta/lib/oeqa/selftest/cases/bblogging.py new file mode 100644 index 0000000000..317e68b82f --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/bblogging.py @@ -0,0 +1,186 @@ +# +# SPDX-License-Identifier: MIT +# + + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake + +class BitBakeLogging(OESelftestTestCase): + + def assertCount(self, item, entry, count): + self.assertEqual(item.count(entry), count, msg="Output:\n'''\n%s\n'''\ndoesn't contain %d copies of:\n'''\n%s\n'''\n" % (item, count, entry)) + + def test_shell_loggingA(self): + # no logs, no verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c shelltest -f", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertNotIn("This is shell stdout", result.output) + self.assertNotIn("This is shell stderr", result.output) + + def test_shell_loggingB(self): + # logs, no verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c shelltest -f", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertCount(result.output, "This is shell stdout", 1) + self.assertCount(result.output, "This is shell stderr", 1) + + def test_shell_loggingC(self): + # no logs, verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c shelltest -f -v", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # two copies due to set +x + self.assertCount(result.output, "This is shell stdout", 2) + self.assertCount(result.output, "This is shell stderr", 2) + + def test_shell_loggingD(self): + # logs, verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c shelltest -f -v", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # two copies due to set +x + self.assertCount(result.output, "This is shell stdout", 2) + self.assertCount(result.output, "This is shell stderr", 2) + + def test_python_exec_func_shell_loggingA(self): + # no logs, no verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_exec_func_shell -f", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertNotIn("This is shell stdout", result.output) + self.assertNotIn("This is shell stderr", result.output) + + def test_python_exec_func_shell_loggingB(self): + # logs, no verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_exec_func_shell -f", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertCount(result.output, "This is shell stdout", 1) + self.assertCount(result.output, "This is shell stderr", 1) + + def test_python_exec_func_shell_loggingC(self): + # no logs, verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_exec_func_shell -f -v", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # two copies due to set +x + self.assertCount(result.output, "This is shell stdout", 2) + self.assertCount(result.output, "This is shell stderr", 2) + + def test_python_exec_func_shell_loggingD(self): + # logs, verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_exec_func_shell -f -v", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # two copies due to set +x + self.assertCount(result.output, "This is shell stdout", 2) + self.assertCount(result.output, "This is shell stderr", 2) + + def test_python_exit_loggingA(self): + # no logs, no verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_exit -f", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertNotIn("This is python stdout", result.output) + + def test_python_exit_loggingB(self): + # logs, no verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_exit -f", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # A sys.exit() should include the output + self.assertCount(result.output, "This is python stdout", 1) + + def test_python_exit_loggingC(self): + # no logs, verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_exit -f -v", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # python tasks don't log output with -v currently + #self.assertCount(result.output, "This is python stdout", 1) + + def test_python_exit_loggingD(self): + # logs, verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_exit -f -v", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # python tasks don't log output with -v currently + #self.assertCount(result.output, "This is python stdout", 1) + + def test_python_exec_func_python_loggingA(self): + # no logs, no verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_exec_func_python -f", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertNotIn("This is python stdout", result.output) + + def test_python_exec_func_python_loggingB(self): + # logs, no verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_exec_func_python -f", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # A sys.exit() should include the output + self.assertCount(result.output, "This is python stdout", 1) + + def test_python_exec_func_python_loggingC(self): + # no logs, verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_exec_func_python -f -v", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # python tasks don't log output with -v currently + #self.assertCount(result.output, "This is python stdout", 1) + + def test_python_exec_func_python_loggingD(self): + # logs, verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_exec_func_python -f -v", + ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # python tasks don't log output with -v currently + #self.assertCount(result.output, "This is python stdout", 1) + + def test_python_fatal_loggingA(self): + # no logs, no verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_fatal -f", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + self.assertNotIn("This is python fatal test stdout", result.output) + self.assertCount(result.output, "This is a fatal error", 1) + + def test_python_fatal_loggingB(self): + # logs, no verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_fatal -f", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # A bb.fatal() should not include the output + self.assertNotIn("This is python fatal test stdout", result.output) + self.assertCount(result.output, "This is a fatal error", 1) + + def test_python_fatal_loggingC(self): + # no logs, verbose + self.write_config('BBINCLUDELOGS = ""') + result = bitbake("logging-test -c pythontest_fatal -f -v", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # python tasks don't log output with -v currently + #self.assertCount(result.output, "This is python fatal test stdout", 1) + self.assertCount(result.output, "This is a fatal error", 1) + + def test_python_fatal_loggingD(self): + # logs, verbose + self.write_config('BBINCLUDELOGS = "yes"') + result = bitbake("logging-test -c pythontest_fatal -f -v", ignore_status = True) + self.assertIn("ERROR: Logfile of failure stored in:", result.output) + # python tasks don't log output with -v currently + #self.assertCount(result.output, "This is python fatal test stdout", 1) + self.assertCount(result.output, "This is a fatal error", 1) + diff --git a/meta/lib/oeqa/selftest/cases/bbtests.py b/meta/lib/oeqa/selftest/cases/bbtests.py index 79390acc0d..cfac7afcf4 100644 --- a/meta/lib/oeqa/selftest/cases/bbtests.py +++ b/meta/lib/oeqa/selftest/cases/bbtests.py @@ -63,15 +63,15 @@ class BitbakeTests(OESelftestTestCase): def test_warnings_errors(self): result = bitbake('-b asdf', ignore_status=True) - find_warnings = re.search("Summary: There w.{2,3}? [1-9][0-9]* WARNING messages* shown", result.output) - find_errors = re.search("Summary: There w.{2,3}? [1-9][0-9]* ERROR messages* shown", result.output) + find_warnings = re.search("Summary: There w.{2,3}? [1-9][0-9]* WARNING messages*", result.output) + find_errors = re.search("Summary: There w.{2,3}? [1-9][0-9]* ERROR messages*", result.output) self.assertTrue(find_warnings, msg="Did not find the mumber of warnings at the end of the build:\n" + result.output) self.assertTrue(find_errors, msg="Did not find the mumber of errors at the end of the build:\n" + result.output) def test_invalid_patch(self): # This patch should fail to apply. - self.write_recipeinc('man-db', 'FILESEXTRAPATHS_prepend := "${THISDIR}/files:"\nSRC_URI += "file://0001-Test-patch-here.patch"') - self.write_config("INHERIT_remove = \"report-error\"") + self.write_recipeinc('man-db', 'FILESEXTRAPATHS:prepend := "${THISDIR}/files:"\nSRC_URI += "file://0001-Test-patch-here.patch"') + self.write_config("INHERIT:remove = \"report-error\"") result = bitbake('man-db -c patch', ignore_status=True) self.delete_recipeinc('man-db') bitbake('-cclean man-db') @@ -83,8 +83,10 @@ class BitbakeTests(OESelftestTestCase): def test_force_task_1(self): # test 1 from bug 5875 + import uuid test_recipe = 'zlib' - test_data = "Microsoft Made No Profit From Anyone's Zunes Yo" + # Need to use uuid otherwise hash equivlance would change the workflow + test_data = "Microsoft Made No Profit From Anyone's Zunes Yo %s" % uuid.uuid1() bb_vars = get_bb_vars(['D', 'PKGDEST', 'mandir'], test_recipe) image_dir = bb_vars['D'] pkgsplit_dir = bb_vars['PKGDEST'] @@ -139,7 +141,7 @@ class BitbakeTests(OESelftestTestCase): self.write_recipeinc('man-db', data) self.write_config("""DL_DIR = \"${TOPDIR}/download-selftest\" SSTATE_DIR = \"${TOPDIR}/download-selftest\" -INHERIT_remove = \"report-error\" +INHERIT:remove = \"report-error\" """) self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) @@ -149,9 +151,6 @@ INHERIT_remove = \"report-error\" self.delete_recipeinc('man-db') self.assertEqual(result.status, 1, msg="Command succeded when it should have failed. bitbake output: %s" % result.output) self.assertIn('Fetcher failure: Unable to find file file://invalid anywhere. The paths that were searched were:', result.output) - line = self.getline(result, 'Fetcher failure for URL: \'file://invalid\'. Unable to fetch URL from any source.') - self.assertTrue(line and line.startswith("ERROR:"), msg = "\"invalid\" file \ -doesn't exist, yet fetcher didn't report any error. bitbake output: %s" % result.output) def test_rename_downloaded_file(self): # TODO unique dldir instead of using cleanall @@ -161,7 +160,7 @@ SSTATE_DIR = \"${TOPDIR}/download-selftest\" """) self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) - data = 'SRC_URI = "${GNU_MIRROR}/aspell/aspell-${PV}.tar.gz;downloadfilename=test-aspell.tar.gz"' + data = 'SRC_URI = "https://downloads.yoctoproject.org/mirror/sources/aspell-${PV}.tar.gz;downloadfilename=test-aspell.tar.gz"' self.write_recipeinc('aspell', data) result = bitbake('-f -c fetch aspell', ignore_status=True) self.delete_recipeinc('aspell') @@ -213,7 +212,7 @@ SSTATE_DIR = \"${TOPDIR}/download-selftest\" def test_continue(self): self.write_config("""DL_DIR = \"${TOPDIR}/download-selftest\" SSTATE_DIR = \"${TOPDIR}/download-selftest\" -INHERIT_remove = \"report-error\" +INHERIT:remove = \"report-error\" """) self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) self.write_recipeinc('man-db',"\ndo_fail_task () {\nexit 1 \n}\n\naddtask do_fail_task before do_fetch\n" ) @@ -225,12 +224,12 @@ INHERIT_remove = \"report-error\" self.assertLess(errorpos,continuepos, msg = "bitbake didn't pass do_fail_task. bitbake output: %s" % result.output) def test_non_gplv3(self): - self.write_config('INCOMPATIBLE_LICENSE = "GPLv3"') + self.write_config('INCOMPATIBLE_LICENSE = "GPL-3.0-or-later"') result = bitbake('selftest-ed', ignore_status=True) self.assertEqual(result.status, 0, "Bitbake failed, exit code %s, output %s" % (result.status, result.output)) lic_dir = get_bb_var('LICENSE_DIRECTORY') - self.assertFalse(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPLv3'))) - self.assertTrue(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPLv2'))) + self.assertFalse(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPL-3.0-or-later'))) + self.assertTrue(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPL-2.0-or-later'))) def test_setscene_only(self): """ Bitbake option to restore from sstate only within a build (i.e. execute no real tasks, only setscene)""" @@ -298,3 +297,57 @@ INHERIT_remove = \"report-error\" test_recipe_summary_after = get_bb_var('SUMMARY', test_recipe) self.assertEqual(expected_recipe_summary, test_recipe_summary_after) + + def test_git_patchtool(self): + """ PATCHTOOL=git should work with non-git sources like tarballs + test recipe for the test must NOT containt git:// repository in SRC_URI + """ + test_recipe = "man-db" + self.write_recipeinc(test_recipe, 'PATCHTOOL=\"git\"') + src = get_bb_var("SRC_URI",test_recipe) + gitscm = re.search("git://", src) + self.assertFalse(gitscm, "test_git_patchtool pre-condition failed: {} test recipe contains git repo!".format(test_recipe)) + result = bitbake('{} -c patch'.format(test_recipe), ignore_status=False) + fatal = re.search("fatal: not a git repository (or any of the parent directories)", result.output) + self.assertFalse(fatal, "Failed to patch using PATCHTOOL=\"git\"") + self.delete_recipeinc(test_recipe) + bitbake('-cclean {}'.format(test_recipe)) + + def test_git_patchtool2(self): + """ Test if PATCHTOOL=git works with git repo and doesn't reinitialize it + """ + test_recipe = "gitrepotest" + src = get_bb_var("SRC_URI",test_recipe) + gitscm = re.search("git://", src) + self.assertTrue(gitscm, "test_git_patchtool pre-condition failed: {} test recipe doesn't contains git repo!".format(test_recipe)) + result = bitbake('{} -c patch'.format(test_recipe), ignore_status=False) + srcdir = get_bb_var('S', test_recipe) + result = runCmd("git log", cwd = srcdir) + self.assertFalse("bitbake_patching_started" in result.output, msg = "Repository has been reinitialized. {}".format(srcdir)) + self.delete_recipeinc(test_recipe) + bitbake('-cclean {}'.format(test_recipe)) + + + def test_git_unpack_nonetwork(self): + """ + Test that a recipe with a floating tag that needs to be resolved upstream doesn't + access the network in a patch task run in a separate builld invocation + """ + + # Enable the recipe to float using a distro override + self.write_config("DISTROOVERRIDES .= \":gitunpack-enable-recipe\"") + + bitbake('gitunpackoffline -c fetch') + bitbake('gitunpackoffline -c patch') + + def test_git_unpack_nonetwork_fail(self): + """ + Test that a recipe with a floating tag which doesn't call get_srcrev() in the fetcher + raises an error when the fetcher is called. + """ + + # Enable the recipe to float using a distro override + self.write_config("DISTROOVERRIDES .= \":gitunpack-enable-recipe\"") + + result = bitbake('gitunpackoffline-fail -c fetch', ignore_status=True) + self.assertTrue("Recipe uses a floating tag/branch without a fixed SRCREV" in result.output, msg = "Recipe without PV set to SRCPV should have failed: %s" % result.output) diff --git a/meta/lib/oeqa/selftest/cases/buildoptions.py b/meta/lib/oeqa/selftest/cases/buildoptions.py index 754b77defd..bfe613b847 100644 --- a/meta/lib/oeqa/selftest/cases/buildoptions.py +++ b/meta/lib/oeqa/selftest/cases/buildoptions.py @@ -62,9 +62,9 @@ class DiskMonTest(OESelftestTestCase): res = bitbake("delay -c delay", ignore_status = True) self.assertTrue('ERROR: No new tasks can be executed since the disk space monitor action is "STOPTASKS"!' in res.output, msg = "Tasks should have stopped. Disk monitor is set to STOPTASK: %s" % 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_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"') + self.write_config('BB_DISKMON_DIRS = "HALT,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"') res = bitbake("delay -c delay", ignore_status = True) - self.assertTrue('ERROR: Immediately abort since the disk space monitor action is "ABORT"!' in res.output, "Tasks should have been aborted immediatelly. Disk monitor is set to ABORT: %s" % res.output) + self.assertTrue('ERROR: Immediately halt since the disk space monitor action is "HALT"!' in res.output, "Tasks should have been halted immediately. Disk monitor is set to HALT: %s" % 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_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"') res = bitbake("delay -c delay") @@ -78,9 +78,9 @@ class SanityOptionsTest(OESelftestTestCase): def test_options_warnqa_errorqa_switch(self): - self.write_config("INHERIT_remove = \"report-error\"") + 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 = \" packages-list\"") self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"') self.add_command_to_tearDown('bitbake -c clean xcursor-transparent-theme') @@ -90,8 +90,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 = "packages-list"') + self.append_config('WARN_QA:append = " 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.") @@ -148,6 +148,30 @@ class BuildhistoryTests(BuildhistoryBase): self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True) self.run_buildhistory_operation(target, target_config="PR = \"r0\"", change_bh_location=False, expect_error=True, error_regex=error) + def test_fileinfo(self): + self.config_buildhistory() + bitbake('hicolor-icon-theme') + history_dir = get_bb_var('BUILDHISTORY_DIR_PACKAGE', 'hicolor-icon-theme') + self.assertTrue(os.path.isdir(history_dir), 'buildhistory dir was not created.') + + def load_bh(f): + d = {} + for line in open(f): + split = [s.strip() for s in line.split('=', 1)] + if len(split) > 1: + d[split[0]] = split[1] + return d + + data = load_bh(os.path.join(history_dir, 'hicolor-icon-theme', 'latest')) + self.assertIn('FILELIST', data) + self.assertEqual(data['FILELIST'], '/usr/share/icons/hicolor/index.theme') + self.assertGreater(int(data['PKGSIZE']), 0) + + 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) + class ArchiverTest(OESelftestTestCase): def test_arch_work_dir_and_export_source(self): """ @@ -159,8 +183,8 @@ class ArchiverTest(OESelftestTestCase): deploy_dir_src = get_bb_var('DEPLOY_DIR_SRC') pkgs_path = g.glob(str(deploy_dir_src) + "/allarch*/xcurs*") src_file_glob = str(pkgs_path[0]) + "/xcursor*.src.rpm" - tar_file_glob = str(pkgs_path[0]) + "/xcursor*.tar.gz" - self.assertTrue((g.glob(src_file_glob) and g.glob(tar_file_glob)), "Couldn't find .src.rpm and .tar.gz files under %s/allarch*/xcursor*" % deploy_dir_src) + tar_file_glob = str(pkgs_path[0]) + "/xcursor*.tar.xz" + self.assertTrue((g.glob(src_file_glob) and g.glob(tar_file_glob)), "Couldn't find .src.rpm and .tar.xz files under %s/allarch*/xcursor*" % deploy_dir_src) class ToolchainOptions(OESelftestTestCase): def test_toolchain_fortran(self): @@ -168,7 +192,7 @@ class ToolchainOptions(OESelftestTestCase): Test that Fortran works by building a Hello, World binary. """ - features = 'FORTRAN_forcevariable = ",fortran"\n' + features = 'FORTRAN:forcevariable = ",fortran"\n' self.write_config(features) bitbake('fortran-helloworld') diff --git a/meta/lib/oeqa/selftest/cases/containerimage.py b/meta/lib/oeqa/selftest/cases/containerimage.py index 79cc8a0f2e..e0aea1a1ef 100644 --- a/meta/lib/oeqa/selftest/cases/containerimage.py +++ b/meta/lib/oeqa/selftest/cases/containerimage.py @@ -13,7 +13,7 @@ from oeqa.utils.commands import bitbake, get_bb_vars, runCmd # The only package added to the image is container_image_testpkg, which # contains one file. However, due to some other things not cleaning up during # rootfs creation, there is some cruft. Ideally bugs will be filed and the -# cruft removed, but for now we whitelist some known set. +# cruft removed, but for now we ignore some known set. # # Also for performance reasons we're only checking the cruft when using ipk. # When using deb, and rpm it is a bit different and we could test all @@ -22,7 +22,7 @@ from oeqa.utils.commands import bitbake, get_bb_vars, runCmd # class ContainerImageTests(OESelftestTestCase): - # Verify that when specifying a IMAGE_TYPEDEP_ of the form "foo.bar" that + # Verify that when specifying a IMAGE_TYPEDEP: of the form "foo.bar" that # the conversion type bar gets added as a dep as well def test_expected_files(self): @@ -43,7 +43,7 @@ PACKAGE_CLASSES = "package_ipk" IMAGE_FEATURES = "" IMAGE_BUILDINFO_FILE = "" INIT_MANAGER = "sysvinit" -IMAGE_INSTALL_remove = "ssh-pregen-hostkeys" +IMAGE_INSTALL:remove = "ssh-pregen-hostkeys" """) diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py index 3385546e8e..e910672c31 100644 --- a/meta/lib/oeqa/selftest/cases/devtool.py +++ b/meta/lib/oeqa/selftest/cases/devtool.py @@ -80,32 +80,15 @@ def tearDownModule(): bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb) shutil.rmtree(templayerdir) -class DevtoolBase(OESelftestTestCase): - - @classmethod - def setUpClass(cls): - super(DevtoolBase, cls).setUpClass() - bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR']) - cls.original_sstate = bb_vars['SSTATE_DIR'] - cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool') - cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate - cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n' - % cls.original_sstate) - - @classmethod - def tearDownClass(cls): - cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate) - runCmd('rm -rf %s' % cls.devtool_sstate) - super(DevtoolBase, cls).tearDownClass() +class DevtoolTestCase(OESelftestTestCase): def setUp(self): """Test case setup function""" - super(DevtoolBase, self).setUp() + super(DevtoolTestCase, self).setUp() self.workspacedir = os.path.join(self.builddir, 'workspace') self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory ' 'under the build directory') - self.append_config(self.sstate_conf) def _check_src_repo(self, repo_dir): """Check srctree git repository""" @@ -236,6 +219,30 @@ class DevtoolBase(OESelftestTestCase): return filelist +class DevtoolBase(DevtoolTestCase): + + @classmethod + def setUpClass(cls): + super(DevtoolBase, cls).setUpClass() + bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR']) + cls.original_sstate = bb_vars['SSTATE_DIR'] + cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool') + cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate + cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n' + % cls.original_sstate) + + @classmethod + def tearDownClass(cls): + cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate) + runCmd('rm -rf %s' % cls.devtool_sstate) + super(DevtoolBase, cls).tearDownClass() + + def setUp(self): + """Test case setup function""" + super(DevtoolBase, self).setUp() + self.append_config(self.sstate_conf) + + class DevtoolTests(DevtoolBase): def test_create_workspace(self): @@ -336,11 +343,11 @@ class DevtoolAddTests(DevtoolBase): self.assertIn(srcdir, result.output) self.assertIn(recipefile, result.output) checkvars = {} - checkvars['LICENSE'] = 'GPLv2' + checkvars['LICENSE'] = 'GPL-2.0-only' checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263' checkvars['S'] = '${WORKDIR}/git' checkvars['PV'] = '0.1+git${SRCPV}' - checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https' + checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master' checkvars['SRCREV'] = srcrev checkvars['DEPENDS'] = set(['dbus']) self._test_recipe_contents(recipefile, checkvars, []) @@ -373,7 +380,7 @@ class DevtoolAddTests(DevtoolBase): recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version) result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile) with open(recipefile, 'a') as f: - f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n') + f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n') # We don't have the ability to pick up this dependency automatically yet... f.write('\nDEPENDS += "libusb1"\n') f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n') @@ -442,6 +449,7 @@ class DevtoolAddTests(DevtoolBase): tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) url = 'gitsm://git.yoctoproject.org/mraa' + url_branch = '%s;branch=master' % url checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d' testrecipe = 'mraa' srcdir = os.path.join(tempdir, testrecipe) @@ -462,7 +470,7 @@ class DevtoolAddTests(DevtoolBase): checkvars = {} checkvars['S'] = '${WORKDIR}/git' checkvars['PV'] = '1.0+git${SRCPV}' - checkvars['SRC_URI'] = url + checkvars['SRC_URI'] = url_branch checkvars['SRCREV'] = '${AUTOREV}' self._test_recipe_contents(recipefile, checkvars, []) # Try with revision and version specified @@ -481,7 +489,7 @@ class DevtoolAddTests(DevtoolBase): checkvars = {} checkvars['S'] = '${WORKDIR}/git' checkvars['PV'] = '1.5+git${SRCPV}' - checkvars['SRC_URI'] = url + checkvars['SRC_URI'] = url_branch checkvars['SRCREV'] = checkrev self._test_recipe_contents(recipefile, checkvars, []) @@ -649,7 +657,7 @@ class DevtoolModifyTests(DevtoolBase): self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') - testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split() + testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split() # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose result = runCmd('bitbake-layers show-recipes gcc-source*') for line in result.output.splitlines(): @@ -904,7 +912,7 @@ class DevtoolUpdateTests(DevtoolBase): self._check_repo_status(os.path.dirname(recipefile), expected_status) result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) - addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"'] + addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"'] srcurilines = src_uri.split() srcurilines[0] = 'SRC_URI = "' + srcurilines[0] srcurilines.append('"') @@ -975,7 +983,7 @@ class DevtoolUpdateTests(DevtoolBase): self.assertExists(patchfile, 'Patch file not created') # Check bbappend contents - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n', '\n'] @@ -990,7 +998,7 @@ class DevtoolUpdateTests(DevtoolBase): result = runCmd('git reset HEAD^', 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', + expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] with open(bbappendfile, 'r') as f: self.assertEqual(expectedlines2, f.readlines()) diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py index 0ad6e1ef91..03f31e9fcb 100644 --- a/meta/lib/oeqa/selftest/cases/distrodata.py +++ b/meta/lib/oeqa/selftest/cases/distrodata.py @@ -18,7 +18,7 @@ class Distrodata(OESelftestTestCase): Product: oe-core Author: Alexander Kanavin <alex.kanavin@gmail.com> """ - feature = 'LICENSE_FLAGS_WHITELIST += " commercial"\n' + feature = 'LICENSE_FLAGS_ACCEPTED += " commercial"\n' self.write_config(feature) pkgs = oe.recipeutils.get_recipe_upgrade_status() @@ -93,13 +93,13 @@ The following recipes do not have a DESCRIPTION. Please add an entry for DESCRIP def is_maintainer_exception(entry): exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", - "cve-update-db-native"] + "cve-update-db-native", "rust"] for i in exceptions: if i in entry: return True return False - feature = 'require conf/distro/include/maintainers.inc\nLICENSE_FLAGS_WHITELIST += " commercial"\nPARSE_ALL_RECIPES = "1"\nPACKAGE_CLASSES = "package_ipk package_deb package_rpm"\n' + feature = 'require conf/distro/include/maintainers.inc\nLICENSE_FLAGS_ACCEPTED += " commercial"\nPARSE_ALL_RECIPES = "1"\nPACKAGE_CLASSES = "package_ipk package_deb package_rpm"\n' self.write_config(feature) with bb.tinfoil.Tinfoil() as tinfoil: @@ -110,7 +110,7 @@ The following recipes do not have a DESCRIPTION. Please add an entry for DESCRIP missing_recipes = [] recipes = [] - prefix = "RECIPE_MAINTAINER_pn-" + prefix = "RECIPE_MAINTAINER:pn-" # We could have used all_recipes() here, but this method will find # every recipe if we ever move to setting RECIPE_MAINTAINER in recipe files diff --git a/meta/lib/oeqa/selftest/cases/eSDK.py b/meta/lib/oeqa/selftest/cases/eSDK.py index 862849af35..f7279b3230 100644 --- a/meta/lib/oeqa/selftest/cases/eSDK.py +++ b/meta/lib/oeqa/selftest/cases/eSDK.py @@ -63,7 +63,7 @@ class oeSDKExtSelfTest(OESelftestTestCase): cls.env_eSDK = oeSDKExtSelfTest.get_esdk_environment('', cls.tmpdir_eSDKQA) sstate_config=""" -SDK_LOCAL_CONF_WHITELIST = "SSTATE_MIRRORS" +ESDK_LOCALCONF_ALLOW = "SSTATE_MIRRORS" SSTATE_MIRRORS = "file://.* file://%s/PATH" CORE_IMAGE_EXTRA_INSTALL = "perl" """ % sstate_dir @@ -91,7 +91,7 @@ CORE_IMAGE_EXTRA_INSTALL = "perl" # Configure eSDK to use sstate mirror from poky sstate_config=""" -SDK_LOCAL_CONF_WHITELIST = "SSTATE_MIRRORS" +ESDK_LOCALCONF_ALLOW = "SSTATE_MIRRORS" SSTATE_MIRRORS = "file://.* file://%s/PATH" """ % bb_vars["SSTATE_DIR"] with open(os.path.join(cls.tmpdir_eSDKQA, 'conf', 'local.conf'), 'a+') as f: @@ -100,7 +100,7 @@ SSTATE_MIRRORS = "file://.* file://%s/PATH" @classmethod def tearDownClass(cls): for i in range(0, 10): - if os.path.exists(os.path.join(cls.tmpdir_eSDKQA, 'bitbake.lock')): + if os.path.exists(os.path.join(cls.tmpdir_eSDKQA, 'bitbake.lock')) or os.path.exists(os.path.join(cls.tmpdir_eSDKQA, 'cache/hashserv.db-wal')): time.sleep(1) else: break diff --git a/meta/lib/oeqa/selftest/cases/efibootpartition.py b/meta/lib/oeqa/selftest/cases/efibootpartition.py index a61cf9bcb3..26de3a07c9 100644 --- a/meta/lib/oeqa/selftest/cases/efibootpartition.py +++ b/meta/lib/oeqa/selftest/cases/efibootpartition.py @@ -26,11 +26,11 @@ class GenericEFITest(OESelftestTestCase): self.write_config(self, """ EFI_PROVIDER = "%s" -IMAGE_FSTYPES_pn-%s_append = " wic" +IMAGE_FSTYPES:pn-%s:append = " wic" MACHINE = "%s" -MACHINE_FEATURES_append = " efi" +MACHINE_FEATURES:append = " efi" WKS_FILE = "efi-bootdisk.wks.in" -IMAGE_INSTALL_append = " grub-efi systemd-boot kernel-image-bzimage" +IMAGE_INSTALL:append = " grub-efi systemd-boot kernel-image-bzimage" """ % (self.efi_provider, self.image, self.machine)) if not self.recipes_built: diff --git a/meta/lib/oeqa/selftest/cases/fetch.py b/meta/lib/oeqa/selftest/cases/fetch.py index cd15f65129..be14272e63 100644 --- a/meta/lib/oeqa/selftest/cases/fetch.py +++ b/meta/lib/oeqa/selftest/cases/fetch.py @@ -24,8 +24,8 @@ class Fetch(OESelftestTestCase): # No mirrors, should use git to fetch successfully features = """ DL_DIR = "%s" -MIRRORS_forcevariable = "" -PREMIRRORS_forcevariable = "" +MIRRORS:forcevariable = "" +PREMIRRORS:forcevariable = "" """ % dldir self.write_config(features) oe.path.remove(dldir, recurse=True) @@ -35,8 +35,8 @@ PREMIRRORS_forcevariable = "" features = """ DL_DIR = "%s" GIT_PROXY_COMMAND = "false" -MIRRORS_forcevariable = "" -PREMIRRORS_forcevariable = "" +MIRRORS:forcevariable = "" +PREMIRRORS:forcevariable = "" """ % dldir self.write_config(features) oe.path.remove(dldir, recurse=True) @@ -47,7 +47,7 @@ PREMIRRORS_forcevariable = "" features = """ DL_DIR = "%s" GIT_PROXY_COMMAND = "false" -MIRRORS_forcevariable = "git://.*/.* http://downloads.yoctoproject.org/mirror/sources/" +MIRRORS:forcevariable = "git://.*/.* http://downloads.yoctoproject.org/mirror/sources/" """ % dldir self.write_config(features) oe.path.remove(dldir, recurse=True) @@ -99,7 +99,7 @@ class Dependencies(OESelftestTestCase): r = """ LICENSE="CLOSED" - SRC_URI="git://example.com/repo" + SRC_URI="git://example.com/repo;branch=master" """ f = self.write_recipe(textwrap.dedent(r), tempdir) d = tinfoil.parse_recipe_file(f) diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py index 815ee48c05..f6f6a8e795 100644 --- a/meta/lib/oeqa/selftest/cases/fitimage.py +++ b/meta/lib/oeqa/selftest/cases/fitimage.py @@ -114,7 +114,8 @@ KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" -UBOOT_SIGN_KEYNAME = "oe-selftest" +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'" """ @@ -173,11 +174,11 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" reqsigvalues_image = { 'algo': '"sha256,rsa2048"', - 'key-name-hint': '"oe-selftest"', + 'key-name-hint': '"img-oe-selftest"', } reqsigvalues_config = { 'algo': '"sha256,rsa2048"', - 'key-name-hint': '"oe-selftest"', + 'key-name-hint': '"cfg-oe-selftest"', 'sign-images': '"kernel", "fdt"', } @@ -215,7 +216,10 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" self.assertIn('conf-am335x-boneblack.dtb', signed_sections) for signed_section, values in signed_sections.items(): value = values.get('Sign algo', None) - self.assertEqual(value, 'sha256,rsa2048:oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) + if signed_section.startswith("conf"): + self.assertEqual(value, 'sha256,rsa2048:cfg-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) + else: + self.assertEqual(value, 'sha256,rsa2048:img-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) value = values.get('Sign value', None) self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) @@ -266,7 +270,8 @@ KERNEL_CLASSES = " kernel-fitimage" UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" -UBOOT_SIGN_KEYNAME = "oe-selftest" +UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" +UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" FIT_SIGN_INDIVIDUAL = "1" """ self.write_config(config) @@ -348,7 +353,8 @@ KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" -UBOOT_SIGN_KEYNAME = "oe-selftest" +UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" +UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" FIT_SIGN_INDIVIDUAL = "1" UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" """ @@ -592,7 +598,8 @@ KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " UBOOT_SIGN_ENABLE = "1" FIT_GENERATE_KEYS = "1" UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" -UBOOT_SIGN_KEYNAME = "kernel-oe-selftest" +UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" +UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" FIT_SIGN_INDIVIDUAL = "1" """ self.write_config(config) @@ -735,6 +742,7 @@ UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" UBOOT_EXTLINUX = "0" FIT_GENERATE_KEYS = "1" KERNEL_IMAGETYPE_REPLACEMENT = "zImage" +FIT_KERNEL_COMP_ALG = "none" FIT_HASH_ALG = "sha256" """ self.write_config(config) @@ -756,9 +764,8 @@ FIT_HASH_ALG = "sha256" kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) - initramfs_bundle_format = str(get_bb_var('KERNEL_IMAGETYPE_REPLACEMENT')) + kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG')) uboot_arch = str(get_bb_var('UBOOT_ARCH')) - initramfs_bundle = "arch/" + uboot_arch + "/boot/" + initramfs_bundle_format + ".initramfs" fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) its_file = open(fitimage_its_path) @@ -768,11 +775,11 @@ FIT_HASH_ALG = "sha256" exp_node_lines = [ 'kernel-1 {', 'description = "Linux kernel";', - 'data = /incbin/("' + initramfs_bundle + '");', + 'data = /incbin/("linux.bin");', 'type = "kernel";', 'arch = "' + uboot_arch + '";', 'os = "linux";', - 'compression = "none";', + 'compression = "' + kernel_compression + '";', 'load = <' + kernel_load + '>;', 'entry = <' + kernel_entry + '>;', 'hash-1 {', diff --git a/meta/lib/oeqa/selftest/cases/glibc.py b/meta/lib/oeqa/selftest/cases/glibc.py index c687f6ef93..6f96281ea5 100644 --- a/meta/lib/oeqa/selftest/cases/glibc.py +++ b/meta/lib/oeqa/selftest/cases/glibc.py @@ -24,7 +24,7 @@ class GlibcSelfTestBase(OESelftestTestCase, OEPTestResultTestCase): features.append('TOOLCHAIN_TEST_HOST_USER = "root"') features.append('TOOLCHAIN_TEST_HOST_PORT = "22"') # force single threaded test execution - features.append('EGLIBCPARALLELISM_task-check_pn-glibc-testsuite = "PARALLELMFLAGS="-j1""') + features.append('EGLIBCPARALLELISM_task-check:pn-glibc-testsuite = "PARALLELMFLAGS="-j1""') self.write_config("\n".join(features)) bitbake("glibc-testsuite -c check") @@ -33,7 +33,7 @@ class GlibcSelfTestBase(OESelftestTestCase, OEPTestResultTestCase): ptestsuite = "glibc-user" if ssh is None else "glibc" self.ptest_section(ptestsuite) - with open(os.path.join(builddir, "tests.sum"), "r") as f: + with open(os.path.join(builddir, "tests.sum"), "r", errors='replace') as f: for test, result in parse_values(f): self.ptest_result(ptestsuite, test, result) diff --git a/meta/lib/oeqa/selftest/cases/gotoolchain.py b/meta/lib/oeqa/selftest/cases/gotoolchain.py index 4fc3605f42..c809d7c9b1 100644 --- a/meta/lib/oeqa/selftest/cases/gotoolchain.py +++ b/meta/lib/oeqa/selftest/cases/gotoolchain.py @@ -43,6 +43,12 @@ class oeGoToolchainSelfTest(OESelftestTestCase): @classmethod def tearDownClass(cls): + # Go creates file which are readonly + for dirpath, dirnames, filenames in os.walk(cls.tmpdir_SDKQA): + for filename in filenames + dirnames: + f = os.path.join(dirpath, filename) + if not os.path.islink(f): + os.chmod(f, 0o775) shutil.rmtree(cls.tmpdir_SDKQA, ignore_errors=True) super(oeGoToolchainSelfTest, cls).tearDownClass() diff --git a/meta/lib/oeqa/selftest/cases/image_typedep.py b/meta/lib/oeqa/selftest/cases/image_typedep.py index 52e1080f13..5b182a8f94 100644 --- a/meta/lib/oeqa/selftest/cases/image_typedep.py +++ b/meta/lib/oeqa/selftest/cases/image_typedep.py @@ -9,7 +9,7 @@ from oeqa.utils.commands import bitbake class ImageTypeDepTests(OESelftestTestCase): - # Verify that when specifying a IMAGE_TYPEDEP_ of the form "foo.bar" that + # Verify that when specifying a IMAGE_TYPEDEP: of the form "foo.bar" that # the conversion type bar gets added as a dep as well def test_conversion_typedep_added(self): @@ -22,7 +22,7 @@ LICENSE = "MIT" IMAGE_FSTYPES = "testfstype" IMAGE_TYPES_MASKED += "testfstype" -IMAGE_TYPEDEP_testfstype = "tar.bz2" +IMAGE_TYPEDEP:testfstype = "tar.bz2" inherit image diff --git a/meta/lib/oeqa/selftest/cases/imagefeatures.py b/meta/lib/oeqa/selftest/cases/imagefeatures.py index 2de22d3404..d36d45c551 100644 --- a/meta/lib/oeqa/selftest/cases/imagefeatures.py +++ b/meta/lib/oeqa/selftest/cases/imagefeatures.py @@ -198,8 +198,8 @@ class ImageFeatures(OESelftestTestCase): image_name = 'core-image-minimal' all_image_types = set(get_bb_var("IMAGE_TYPES", image_name).split()) - blacklist = set(('container', 'elf', 'f2fs', 'multiubi', 'tar.zst', 'wic.zst')) - img_types = all_image_types - blacklist + skip_image_types = set(('container', 'elf', 'f2fs', 'multiubi', 'tar.zst', 'wic.zst')) + img_types = all_image_types - skip_image_types config = 'IMAGE_FSTYPES += "%s"\n'\ 'MKUBIFS_ARGS ?= "-m 2048 -e 129024 -c 2047"\n'\ @@ -229,7 +229,7 @@ USERADD_GID_TABLES += "files/static-group" def test_no_busybox_base_utils(self): config = """ # Enable wayland -DISTRO_FEATURES_append += "pam opengl wayland" +DISTRO_FEATURES:append = " pam opengl wayland" # Switch to systemd DISTRO_FEATURES += "systemd" @@ -245,8 +245,8 @@ VIRTUAL-RUNTIME_base-utils = "packagegroup-core-base-utils" VIRTUAL-RUNTIME_base-utils-hwclock = "util-linux-hwclock" VIRTUAL-RUNTIME_base-utils-syslog = "" -# Blacklist busybox -PNBLACKLIST[busybox] = "Don't build this" +# Skip busybox +SKIP_RECIPE[busybox] = "Don't build this" """ self.write_config(config) diff --git a/meta/lib/oeqa/selftest/cases/incompatible_lic.py b/meta/lib/oeqa/selftest/cases/incompatible_lic.py index 152da6332a..0794d46e6d 100644 --- a/meta/lib/oeqa/selftest/cases/incompatible_lic.py +++ b/meta/lib/oeqa/selftest/cases/incompatible_lic.py @@ -1,10 +1,11 @@ from oeqa.selftest.case import OESelftestTestCase from oeqa.utils.commands import bitbake -class IncompatibleLicenseTests(OESelftestTestCase): +class IncompatibleLicenseTestObsolete(OESelftestTestCase): - def lic_test(self, pn, pn_lic, lic): - error_msg = 'ERROR: Nothing PROVIDES \'%s\'\n%s was skipped: it has incompatible license(s): %s' % (pn, pn, pn_lic) + def lic_test(self, pn, pn_lic, lic, error_msg=None): + if not error_msg: + error_msg = 'ERROR: Nothing PROVIDES \'%s\'\n%s was skipped: it has incompatible license(s): %s' % (pn, pn, pn_lic) self.write_config("INCOMPATIBLE_LICENSE += \"%s\"" % (lic)) @@ -13,68 +14,81 @@ class IncompatibleLicenseTests(OESelftestTestCase): raise AssertionError(result.output) # Verify that a package with an SPDX license (from AVAILABLE_LICENSES) - # cannot be built when INCOMPATIBLE_LICENSE contains this SPDX license - def test_incompatible_spdx_license(self): - self.lic_test('incompatible-license', 'GPL-3.0-only', 'GPL-3.0-only') - - # Verify that a package with an SPDX license (from AVAILABLE_LICENSES) # cannot be built when INCOMPATIBLE_LICENSE contains an alias (in # SPDXLICENSEMAP) of this SPDX license def test_incompatible_alias_spdx_license(self): - self.lic_test('incompatible-license', 'GPL-3.0-only', 'GPLv3') - - # Verify that a package with an SPDX license (from AVAILABLE_LICENSES) - # cannot be built when INCOMPATIBLE_LICENSE contains a wildcarded license - # matching this SPDX license - def test_incompatible_spdx_license_wildcard(self): - self.lic_test('incompatible-license', 'GPL-3.0-only', '*GPL-3.0-only') + self.lic_test('incompatible-license', 'GPL-3.0-only', 'GPLv3', "is an obsolete license, please use an SPDX reference in INCOMPATIBLE_LICENSE") # Verify that a package with an SPDX license (from AVAILABLE_LICENSES) # cannot be built when INCOMPATIBLE_LICENSE contains a wildcarded alias # license matching this SPDX license def test_incompatible_alias_spdx_license_wildcard(self): - self.lic_test('incompatible-license', 'GPL-3.0-only', '*GPLv3') - - # Verify that a package with an alias (from SPDXLICENSEMAP) to an SPDX - # license cannot be built when INCOMPATIBLE_LICENSE contains this SPDX - # license - def test_incompatible_spdx_license_alias(self): - self.lic_test('incompatible-license-alias', 'GPL-3.0-only', 'GPL-3.0-only') + self.lic_test('incompatible-license', 'GPL-3.0-only', '*GPLv3', "*GPLv3 is an invalid license wildcard entry") # Verify that a package with an alias (from SPDXLICENSEMAP) to an SPDX # license cannot be built when INCOMPATIBLE_LICENSE contains this alias def test_incompatible_alias_spdx_license_alias(self): - self.lic_test('incompatible-license-alias', 'GPL-3.0-only', 'GPLv3') + self.lic_test('incompatible-license-alias', 'GPL-3.0-only', 'GPLv3', "is an obsolete license, please use an SPDX reference in INCOMPATIBLE_LICENSE") # Verify that a package with an alias (from SPDXLICENSEMAP) to an SPDX # license cannot be built when INCOMPATIBLE_LICENSE contains a wildcarded # license matching this SPDX license def test_incompatible_spdx_license_alias_wildcard(self): - self.lic_test('incompatible-license-alias', 'GPL-3.0-only', '*GPL-3.0') + self.lic_test('incompatible-license-alias', 'GPL-3.0-only', '*GPL-3.0', "*GPL-3.0 is an invalid license wildcard entry") # Verify that a package with an alias (from SPDXLICENSEMAP) to an SPDX # license cannot be built when INCOMPATIBLE_LICENSE contains a wildcarded # alias license matching the SPDX license def test_incompatible_alias_spdx_license_alias_wildcard(self): - self.lic_test('incompatible-license-alias', 'GPL-3.0-only', '*GPLv3') + self.lic_test('incompatible-license-alias', 'GPL-3.0-only', '*GPLv3', "*GPLv3 is an invalid license wildcard entry") - # Verify that a package with multiple SPDX licenses (from - # AVAILABLE_LICENSES) cannot be built when INCOMPATIBLE_LICENSE contains - # some of them - def test_incompatible_spdx_licenses(self): - self.lic_test('incompatible-licenses', 'GPL-3.0-only LGPL-3.0-only', 'GPL-3.0-only LGPL-3.0-only') # Verify that a package with multiple SPDX licenses (from # AVAILABLE_LICENSES) cannot be built when INCOMPATIBLE_LICENSE contains a # wildcard to some of them def test_incompatible_spdx_licenses_wildcard(self): - self.lic_test('incompatible-licenses', 'GPL-3.0-only LGPL-3.0-only', '*GPL-3.0-only') + self.lic_test('incompatible-licenses', 'GPL-3.0-only LGPL-3.0-only', '*GPL-3.0-only', "*GPL-3.0-only is an invalid license wildcard entry") + # Verify that a package with multiple SPDX licenses (from # AVAILABLE_LICENSES) cannot be built when INCOMPATIBLE_LICENSE contains a # wildcard matching all licenses def test_incompatible_all_licenses_wildcard(self): - self.lic_test('incompatible-licenses', 'GPL-2.0-only GPL-3.0-only LGPL-3.0-only', '*') + self.lic_test('incompatible-licenses', 'GPL-2.0-only GPL-3.0-only LGPL-3.0-only', '*', "* is an invalid license wildcard entry") + +class IncompatibleLicenseTests(OESelftestTestCase): + + def lic_test(self, pn, pn_lic, lic): + error_msg = 'ERROR: Nothing PROVIDES \'%s\'\n%s was skipped: it has incompatible license(s): %s' % (pn, pn, pn_lic) + + self.write_config("INCOMPATIBLE_LICENSE += \"%s\"" % (lic)) + + result = bitbake('%s --dry-run' % (pn), ignore_status=True) + if error_msg not in result.output: + raise AssertionError(result.output) + + # Verify that a package with an SPDX license (from AVAILABLE_LICENSES) + # cannot be built when INCOMPATIBLE_LICENSE contains this SPDX license + def test_incompatible_spdx_license(self): + self.lic_test('incompatible-license', 'GPL-3.0-only', 'GPL-3.0-only') + + # Verify that a package with an SPDX license (from AVAILABLE_LICENSES) + # cannot be built when INCOMPATIBLE_LICENSE contains a wildcarded license + # matching this SPDX license + def test_incompatible_spdx_license_wildcard(self): + self.lic_test('incompatible-license', 'GPL-3.0-only', 'GPL-3.0*') + + # Verify that a package with an alias (from SPDXLICENSEMAP) to an SPDX + # license cannot be built when INCOMPATIBLE_LICENSE contains this SPDX + # license + def test_incompatible_spdx_license_alias(self): + self.lic_test('incompatible-license-alias', 'GPL-3.0-only', 'GPL-3.0-only') + + # Verify that a package with multiple SPDX licenses (from + # AVAILABLE_LICENSES) cannot be built when INCOMPATIBLE_LICENSE contains + # some of them + def test_incompatible_spdx_licenses(self): + self.lic_test('incompatible-licenses', 'GPL-3.0-only LGPL-3.0-only', 'GPL-3.0-only LGPL-3.0-only') # Verify that a package with a non-SPDX license (neither in # AVAILABLE_LICENSES nor in SPDXLICENSEMAP) cannot be built when @@ -85,8 +99,8 @@ class IncompatibleLicenseTests(OESelftestTestCase): class IncompatibleLicensePerImageTests(OESelftestTestCase): def default_config(self): return """ -IMAGE_INSTALL_append = " bash" -INCOMPATIBLE_LICENSE_pn-core-image-minimal = "GPL-3.0 LGPL-3.0" +IMAGE_INSTALL:append = " bash" +INCOMPATIBLE_LICENSE:pn-core-image-minimal = "GPL-3.0* LGPL-3.0*" """ def test_bash_default(self): @@ -98,7 +112,7 @@ INCOMPATIBLE_LICENSE_pn-core-image-minimal = "GPL-3.0 LGPL-3.0" raise AssertionError(result.output) def test_bash_and_license(self): - self.write_config(self.default_config() + '\nLICENSE_append_pn-bash = " & SomeLicense"') + self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " & SomeLicense"') 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) @@ -106,30 +120,42 @@ INCOMPATIBLE_LICENSE_pn-core-image-minimal = "GPL-3.0 LGPL-3.0" raise AssertionError(result.output) def test_bash_or_license(self): - self.write_config(self.default_config() + '\nLICENSE_append_pn-bash = " | SomeLicense"') + self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " | SomeLicense"') bitbake('core-image-minimal') - def test_bash_whitelist(self): - self.write_config(self.default_config() + '\nWHITELIST_GPL-3.0_pn-core-image-minimal = "bash"') + 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"') bitbake('core-image-minimal') class NoGPL3InImagesTests(OESelftestTestCase): def test_core_image_minimal(self): self.write_config(""" -INCOMPATIBLE_LICENSE_pn-core-image-minimal = "GPL-3.0 LGPL-3.0" +INCOMPATIBLE_LICENSE:pn-core-image-minimal = "GPL-3.0* LGPL-3.0*" """) bitbake('core-image-minimal') - def test_core_image_full_cmdline(self): + def test_core_image_full_cmdline_weston(self): self.write_config(""" -INHERIT += "testimage"\n -INCOMPATIBLE_LICENSE_pn-core-image-full-cmdline = "GPL-3.0 LGPL-3.0"\n -RDEPENDS_packagegroup-core-full-cmdline-utils_remove = "bash bc coreutils cpio ed findutils gawk grep mc mc-fish mc-helpers mc-helpers-perl sed tar time"\n -RDEPENDS_packagegroup-core-full-cmdline-dev-utils_remove = "diffutils m4 make patch"\n -RDEPENDS_packagegroup-core-full-cmdline-multiuser_remove = "gzip"\n +INHERIT += "testimage" +INCOMPATIBLE_LICENSE:pn-core-image-full-cmdline = "GPL-3.0* LGPL-3.0*" +INCOMPATIBLE_LICENSE:pn-core-image-weston = "GPL-3.0* LGPL-3.0*" +# Settings for full-cmdline +RDEPENDS:packagegroup-core-full-cmdline-utils:remove = "bash bc coreutils cpio ed findutils gawk grep mc mc-fish mc-helpers mc-helpers-perl sed tar time" +RDEPENDS:packagegroup-core-full-cmdline-dev-utils:remove = "diffutils m4 make patch" +RDEPENDS:packagegroup-core-full-cmdline-multiuser:remove = "gzip" +# Settings for weston +# direct gpl3 dependencies +RRECOMMENDS:packagegroup-base-vfat:remove = "dosfstools" +PACKAGECONFIG:remove:pn-bluez5 = "readline" +# dnf pulls in gpg which is gpl3; it also pulls in python3-rpm which pulls in rpm-build which pulls in bash +# so install rpm but not dnf +IMAGE_FEATURES:remove:pn-core-image-weston = "package-management" +CORE_IMAGE_EXTRA_INSTALL:pn-core-image-weston += "rpm" +# matchbox-terminal depends on vte, which is gpl3 +CORE_IMAGE_BASE_INSTALL:remove:pn-core-image-weston = "matchbox-terminal" """) - bitbake('core-image-full-cmdline') - bitbake('-c testimage core-image-full-cmdline') + bitbake('core-image-full-cmdline core-image-weston') + bitbake('-c testimage core-image-full-cmdline core-image-weston') diff --git a/meta/lib/oeqa/selftest/cases/kerneldevelopment.py b/meta/lib/oeqa/selftest/cases/kerneldevelopment.py index a61876ee61..b1623a1885 100644 --- a/meta/lib/oeqa/selftest/cases/kerneldevelopment.py +++ b/meta/lib/oeqa/selftest/cases/kerneldevelopment.py @@ -58,7 +58,7 @@ class KernelDev(OESelftestTestCase): recipe_append = os.path.join(self.recipeskernel_dir, 'linux-yocto_%.bbappend') with open(recipe_append, 'w+') as fh: fh.write('SRC_URI += "file://%s"\n' % patch_name) - fh.write('FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"') + fh.write('FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"') runCmd('bitbake virtual/kernel -c clean') runCmd('bitbake virtual/kernel -c patch') diff --git a/meta/lib/oeqa/selftest/cases/layerappend.py b/meta/lib/oeqa/selftest/cases/layerappend.py index 05e9426fc6..dadc7c5d28 100644 --- a/meta/lib/oeqa/selftest/cases/layerappend.py +++ b/meta/lib/oeqa/selftest/cases/layerappend.py @@ -30,20 +30,20 @@ python do_build() { addtask build """ append = """ -FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" -SRC_URI_append = " file://appendtest.txt" +SRC_URI:append = " file://appendtest.txt" -sysroot_stage_all_append() { +sysroot_stage_all:append() { install -m 644 ${WORKDIR}/appendtest.txt ${SYSROOT_DESTDIR}/ } """ append2 = """ -FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" -SRC_URI_append = " file://appendtest.txt" +SRC_URI:append = " file://appendtest.txt" """ layerappend = '' diff --git a/meta/lib/oeqa/selftest/cases/lic_checksum.py b/meta/lib/oeqa/selftest/cases/lic_checksum.py index bae935d697..91021ac335 100644 --- a/meta/lib/oeqa/selftest/cases/lic_checksum.py +++ b/meta/lib/oeqa/selftest/cases/lic_checksum.py @@ -21,7 +21,7 @@ class LicenseTests(OESelftestTestCase): os.close(lic_file) self.track_for_cleanup(lic_path) - self.write_config("INHERIT_remove = \"report-error\"") + self.write_config("INHERIT:remove = \"report-error\"") self.write_recipeinc('emptytest', """ INHIBIT_DEFAULT_DEPS = "1" diff --git a/meta/lib/oeqa/selftest/cases/multiconfig.py b/meta/lib/oeqa/selftest/cases/multiconfig.py index 39b92f2439..baae9b456f 100644 --- a/meta/lib/oeqa/selftest/cases/multiconfig.py +++ b/meta/lib/oeqa/selftest/cases/multiconfig.py @@ -17,7 +17,7 @@ class MultiConfig(OESelftestTestCase): """ config = """ -IMAGE_INSTALL_append_pn-core-image-full-cmdline = " multiconfig-image-packager-tiny multiconfig-image-packager-musl" +IMAGE_INSTALL:append:pn-core-image-full-cmdline = " multiconfig-image-packager-tiny multiconfig-image-packager-musl" BBMULTICONFIG = "tiny musl" """ self.write_config(config) @@ -52,7 +52,7 @@ TMPDIR = "${TOPDIR}/tmp-mc-tiny" self.write_config(config) testconfig = textwrap.dedent('''\ - MCTESTVAR_append = "1" + MCTESTVAR:append = "1" ''') self.write_config(testconfig, 'test') @@ -64,7 +64,7 @@ TMPDIR = "${TOPDIR}/tmp-mc-tiny" self.assertIn('MCTESTVAR=test1', result.output.splitlines()) testconfig = textwrap.dedent('''\ - MCTESTVAR_append = "2" + MCTESTVAR:append = "2" ''') self.write_config(testconfig, 'test') diff --git a/meta/lib/oeqa/selftest/cases/newlib.py b/meta/lib/oeqa/selftest/cases/newlib.py new file mode 100644 index 0000000000..999e3e78b0 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/newlib.py @@ -0,0 +1,11 @@ +# +# SPDX-License-Identifier: MIT +# + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake + +class NewlibTest(OESelftestTestCase): + def test_newlib(self): + self.write_config('TCLIBC = "newlib"') + bitbake("newlib libgloss") diff --git a/meta/lib/oeqa/selftest/cases/oelib/license.py b/meta/lib/oeqa/selftest/cases/oelib/license.py index 6ebbee589f..3b359396b6 100644 --- a/meta/lib/oeqa/selftest/cases/oelib/license.py +++ b/meta/lib/oeqa/selftest/cases/oelib/license.py @@ -15,11 +15,11 @@ class SeenVisitor(oe.license.LicenseVisitor): class TestSingleLicense(TestCase): licenses = [ - "GPLv2", - "LGPL-2.0", - "Artistic", + "GPL-2.0-only", + "LGPL-2.0-only", + "Artistic-1.0", "MIT", - "GPLv3+", + "GPL-3.0-or-later", "FOO_BAR", ] invalid_licenses = ["GPL/BSD"] @@ -67,9 +67,9 @@ class TestComplexCombinations(TestSimpleCombinations): "FOO & (BAR | BAZ)&MOO": ["FOO", "BAR", "MOO"], "(ALPHA|(BETA&THETA)|OMEGA)&DELTA": ["OMEGA", "DELTA"], "((ALPHA|BETA)&FOO)|BAZ": ["BETA", "FOO"], - "(GPL-2.0|Proprietary)&BSD-4-clause&MIT": ["GPL-2.0", "BSD-4-clause", "MIT"], + "(GPL-2.0-only|Proprietary)&BSD-4-clause&MIT": ["GPL-2.0-only", "BSD-4-clause", "MIT"], } - preferred = ["BAR", "OMEGA", "BETA", "GPL-2.0"] + preferred = ["BAR", "OMEGA", "BETA", "GPL-2.0-only"] class TestIsIncluded(TestCase): tests = { @@ -87,12 +87,12 @@ class TestIsIncluded(TestCase): [True, ["BAR", "FOOBAR"]], ("(FOO | BAR) & FOOBAR | BAZ & MOO & BARFOO", None, "FOO"): [True, ["BAZ", "MOO", "BARFOO"]], - ("GPL-3.0 & GPL-2.0 & LGPL-2.1 | Proprietary", None, None): - [True, ["GPL-3.0", "GPL-2.0", "LGPL-2.1"]], - ("GPL-3.0 & GPL-2.0 & LGPL-2.1 | Proprietary", None, "GPL-3.0"): + ("GPL-3.0-or-later & GPL-2.0-only & LGPL-2.1-only | Proprietary", None, None): + [True, ["GPL-3.0-or-later", "GPL-2.0-only", "LGPL-2.1-only"]], + ("GPL-3.0-or-later & GPL-2.0-only & LGPL-2.1-only | Proprietary", None, "GPL-3.0-or-later"): [True, ["Proprietary"]], - ("GPL-3.0 & GPL-2.0 & LGPL-2.1 | Proprietary", None, "GPL-3.0 Proprietary"): - [False, ["GPL-3.0"]] + ("GPL-3.0-or-later & GPL-2.0-only & LGPL-2.1-only | Proprietary", None, "GPL-3.0-or-later Proprietary"): + [False, ["GPL-3.0-or-later"]] } def test_tests(self): diff --git a/meta/lib/oeqa/selftest/cases/oescripts.py b/meta/lib/oeqa/selftest/cases/oescripts.py index 8a10ff357b..91abf9654a 100644 --- a/meta/lib/oeqa/selftest/cases/oescripts.py +++ b/meta/lib/oeqa/selftest/cases/oescripts.py @@ -150,7 +150,7 @@ class OEListPackageconfigTests(OEScriptTests): expected_endlines = [] expected_endlines.append("RECIPE NAME PACKAGECONFIG FLAGS") expected_endlines.append("pinentry gtk2 libcap ncurses qt secret") - expected_endlines.append("tar acl") + expected_endlines.append("tar acl selinux") self.check_endlines(results, expected_endlines) @@ -167,7 +167,7 @@ class OEListPackageconfigTests(OEScriptTests): 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.1.1") + expected_endlines.append("pinentry-1.2.0") expected_endlines.append("PACKAGECONFIG ncurses libcap") 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 new file mode 100644 index 0000000000..56ae48ce64 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/overlayfs.py @@ -0,0 +1,423 @@ +# +# SPDX-License-Identifier: MIT +# + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu + +def getline_qemu(out, line): + for l in out.split('\n'): + if line in l: + return l + +def getline(res, line): + return getline_qemu(res.output, line) + +class OverlayFSTests(OESelftestTestCase): + """Overlayfs class usage tests""" + + def add_overlay_conf_to_machine(self): + machine_inc = """ +OVERLAYFS_MOUNT_POINT[mnt-overlay] = "/mnt/overlay" +""" + self.set_machine_config(machine_inc) + + def test_distro_features_missing(self): + """ + Summary: Check that required DISTRO_FEATURES are set + Expected: Fail when either systemd or overlayfs are not in DISTRO_FEATURES + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +IMAGE_INSTALL:append = " overlayfs-user" +""" + overlayfs_recipe_append = """ +inherit overlayfs +""" + self.write_config(config) + self.add_overlay_conf_to_machine() + self.write_recipeinc('overlayfs-user', overlayfs_recipe_append) + + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "overlayfs-user was skipped: missing required distro features") + self.assertTrue("overlayfs" in res.output, msg=res.output) + self.assertTrue("systemd" in res.output, msg=res.output) + self.assertTrue("ERROR: Required build target 'core-image-minimal' has no buildable providers." in res.output, msg=res.output) + + def test_not_all_units_installed(self): + """ + Summary: Test QA check that we have required mount units in the image + Expected: Fail because mount unit for overlay partition is not installed + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +IMAGE_INSTALL:append = " overlayfs-user" +DISTRO_FEATURES += "systemd overlayfs" +""" + + self.write_config(config) + self.add_overlay_conf_to_machine() + + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, " Mount path /mnt/overlay not found in fstat and unit mnt-overlay.mount not found in systemd unit directories") + self.assertTrue(line and line.startswith("WARNING:"), msg=res.output) + line = getline(res, "Not all mount paths and units are installed in the image") + self.assertTrue(line and line.startswith("ERROR:"), msg=res.output) + + def test_mount_unit_not_set(self): + """ + Summary: Test whether mount unit was set properly + Expected: Fail because mount unit was not set + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +IMAGE_INSTALL:append = " overlayfs-user" +DISTRO_FEATURES += "systemd overlayfs" +""" + + self.write_config(config) + + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "A recipe uses overlayfs class but there is no OVERLAYFS_MOUNT_POINT set in your MACHINE configuration") + self.assertTrue(line and line.startswith("Parsing recipes...ERROR:"), msg=res.output) + + def test_wrong_mount_unit_set(self): + """ + Summary: Test whether mount unit was set properly + Expected: Fail because not the correct flag used for mount unit + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +IMAGE_INSTALL:append = " overlayfs-user" +DISTRO_FEATURES += "systemd overlayfs" +""" + + wrong_machine_config = """ +OVERLAYFS_MOUNT_POINT[usr-share-overlay] = "/usr/share/overlay" +""" + + self.write_config(config) + self.set_machine_config(wrong_machine_config) + + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "Missing required mount point for OVERLAYFS_MOUNT_POINT[mnt-overlay] in your MACHINE configuration") + self.assertTrue(line and line.startswith("Parsing recipes...ERROR:"), msg=res.output) + + def _test_correct_image(self, recipe, data): + """ + Summary: Check that we can create an image when all parameters are + set correctly + Expected: Image is created successfully + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +IMAGE_INSTALL:append = " overlayfs-user systemd-machine-units" +DISTRO_FEATURES += "systemd overlayfs" + +# Use systemd as init manager +VIRTUAL-RUNTIME_init_manager = "systemd" + +# enable overlayfs in the kernel +KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc" +""" + + overlayfs_recipe_append = """ +OVERLAYFS_WRITABLE_PATHS[mnt-overlay] += "/usr/share/another-overlay-mount" + +SYSTEMD_SERVICE:${PN} += " \ + my-application.service \ +" + +do_install:append() { + install -d ${D}${systemd_system_unitdir} + cat <<EOT > ${D}${systemd_system_unitdir}/my-application.service +[Unit] +Description=Sample application start-up unit +After=overlayfs-user-overlays.service +Requires=overlayfs-user-overlays.service + +[Service] +Type=oneshot +ExecStart=/bin/true +RemainAfterExit=true + +[Install] +WantedBy=multi-user.target +EOT +} +""" + + self.write_config(config) + self.add_overlay_conf_to_machine() + self.write_recipeinc(recipe, data) + self.write_recipeinc('overlayfs-user', overlayfs_recipe_append) + + bitbake('core-image-minimal') + + with runqemu('core-image-minimal') as qemu: + # Check that application service started + status, output = qemu.run_serial("systemctl status my-application") + self.assertTrue("active (exited)" in output, msg=output) + + # Check that overlay mounts are dependencies of our application unit + status, output = qemu.run_serial("systemctl list-dependencies my-application") + self.assertTrue("overlayfs-user-overlays.service" in output, msg=output) + + status, output = qemu.run_serial("systemctl list-dependencies overlayfs-user-overlays") + self.assertTrue("usr-share-another\\x2doverlay\\x2dmount.mount" in output, msg=output) + self.assertTrue("usr-share-my\\x2dapplication.mount" in output, msg=output) + + # Check that we have /mnt/overlay fs mounted as tmpfs and + # /usr/share/my-application as an overlay (see overlayfs-user recipe) + status, output = qemu.run_serial("/bin/mount -t tmpfs,overlay") + + line = getline_qemu(output, "on /mnt/overlay") + self.assertTrue(line and line.startswith("tmpfs"), msg=output) + + line = getline_qemu(output, "upperdir=/mnt/overlay/upper/usr/share/my-application") + self.assertTrue(line and line.startswith("overlay"), msg=output) + + line = getline_qemu(output, "upperdir=/mnt/overlay/upper/usr/share/another-overlay-mount") + self.assertTrue(line and line.startswith("overlay"), msg=output) + + def test_correct_image_fstab(self): + """ + Summary: Check that we can create an image when all parameters are + set correctly via fstab + Expected: Image is created successfully + Author: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> + """ + + base_files_append = """ +do_install:append() { + cat <<EOT >> ${D}${sysconfdir}/fstab +tmpfs /mnt/overlay tmpfs mode=1777,strictatime,nosuid,nodev 0 0 +EOT +} +""" + + self._test_correct_image('base-files', base_files_append) + + def test_correct_image_unit(self): + """ + Summary: Check that we can create an image when all parameters are + set correctly via mount unit + Expected: Image is created successfully + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + systemd_machine_unit_append = """ +SYSTEMD_SERVICE:${PN} += " \ + mnt-overlay.mount \ +" + +do_install:append() { + install -d ${D}${systemd_system_unitdir} + cat <<EOT > ${D}${systemd_system_unitdir}/mnt-overlay.mount +[Unit] +Description=Tmpfs directory +DefaultDependencies=no + +[Mount] +What=tmpfs +Where=/mnt/overlay +Type=tmpfs +Options=mode=1777,strictatime,nosuid,nodev + +[Install] +WantedBy=multi-user.target +EOT +} + +""" + + self._test_correct_image('systemd-machine-units', systemd_machine_unit_append) + +class OverlayFSEtcRunTimeTests(OESelftestTestCase): + """overlayfs-etc class tests""" + + def test_all_required_variables_set(self): + """ + Summary: Check that required variables are set + Expected: Fail when any of required variables is missing + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + configBase = """ +DISTRO_FEATURES += "systemd" + +# Use systemd as init manager +VIRTUAL-RUNTIME_init_manager = "systemd" + +# enable overlayfs in the kernel +KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc" + +# Image configuration for overlayfs-etc +EXTRA_IMAGE_FEATURES += "overlayfs-etc" +IMAGE_FEATURES:remove = "package-management" +""" + configMountPoint = """ +OVERLAYFS_ETC_MOUNT_POINT = "/data" +""" + configDevice = """ +OVERLAYFS_ETC_DEVICE = "/dev/mmcblk0p1" +""" + + self.write_config(configBase) + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "OVERLAYFS_ETC_MOUNT_POINT must be set in your MACHINE configuration") + self.assertTrue(line, msg=res.output) + + self.append_config(configMountPoint) + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "OVERLAYFS_ETC_DEVICE must be set in your MACHINE configuration") + self.assertTrue(line, msg=res.output) + + self.append_config(configDevice) + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "OVERLAYFS_ETC_FSTYPE should contain a valid file system type on /dev/mmcblk0p1") + self.assertTrue(line, msg=res.output) + + def test_image_feature_conflict(self): + """ + Summary: Overlayfs-etc is not allowed to be used with package-management + Expected: Feature conflict + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +DISTRO_FEATURES += "systemd" + +# Use systemd as init manager +VIRTUAL-RUNTIME_init_manager = "systemd" + +# enable overlayfs in the kernel +KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc" +EXTRA_IMAGE_FEATURES += "overlayfs-etc" +EXTRA_IMAGE_FEATURES += "package-management" +""" + + self.write_config(config) + + res = bitbake('core-image-minimal', ignore_status=True) + line = getline(res, "contains conflicting IMAGE_FEATURES") + self.assertTrue("overlayfs-etc" in res.output, msg=res.output) + self.assertTrue("package-management" in res.output, msg=res.output) + + def test_image_feature_is_missing_class_included(self): + configAppend = """ +INHERIT += "overlayfs-etc" +""" + self.run_check_image_feature(configAppend) + + def test_image_feature_is_missing(self): + self.run_check_image_feature() + + def run_check_image_feature(self, appendToConfig=""): + """ + Summary: Overlayfs-etc class is not applied when image feature is not set + even if we inherit it directly, + Expected: Image is created successfully but /etc is not an overlay + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = f""" +DISTRO_FEATURES += "systemd" + +# Use systemd as init manager +VIRTUAL-RUNTIME_init_manager = "systemd" + +# enable overlayfs in the kernel +KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc" + +IMAGE_FSTYPES += "wic" +WKS_FILE = "overlayfs_etc.wks.in" + +EXTRA_IMAGE_FEATURES += "read-only-rootfs" +# Image configuration for overlayfs-etc +OVERLAYFS_ETC_MOUNT_POINT = "/data" +OVERLAYFS_ETC_DEVICE = "/dev/sda3" +{appendToConfig} +""" + + self.write_config(config) + + bitbake('core-image-minimal') + + with runqemu('core-image-minimal', image_fstype='wic') as qemu: + status, output = qemu.run_serial("/bin/mount") + + line = getline_qemu(output, "upperdir=/data/overlay-etc/upper") + self.assertFalse(line, msg=output) + + def test_sbin_init_preinit(self): + self.run_sbin_init(False) + + def test_sbin_init_original(self): + self.run_sbin_init(True) + + def run_sbin_init(self, origInit): + """ + Summary: Confirm we can replace original init and mount overlay on top of /etc + Expected: Image is created successfully and /etc is mounted as an overlay + Author: Vyacheslav Yurkov <uvv.mail@gmail.com> + """ + + config = """ +DISTRO_FEATURES += "systemd" + +# Use systemd as init manager +VIRTUAL-RUNTIME_init_manager = "systemd" + +# enable overlayfs in the kernel +KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc" + +IMAGE_FSTYPES += "wic" +OVERLAYFS_INIT_OPTION = "{OVERLAYFS_INIT_OPTION}" +WKS_FILE = "overlayfs_etc.wks.in" + +EXTRA_IMAGE_FEATURES += "read-only-rootfs" +# Image configuration for overlayfs-etc +EXTRA_IMAGE_FEATURES += "overlayfs-etc" +IMAGE_FEATURES:remove = "package-management" +OVERLAYFS_ETC_MOUNT_POINT = "/data" +OVERLAYFS_ETC_FSTYPE = "ext4" +OVERLAYFS_ETC_DEVICE = "/dev/sda3" +OVERLAYFS_ETC_USE_ORIG_INIT_NAME = "{OVERLAYFS_ETC_USE_ORIG_INIT_NAME}" +""" + + args = { + 'OVERLAYFS_INIT_OPTION': "" if origInit else "init=/sbin/preinit", + 'OVERLAYFS_ETC_USE_ORIG_INIT_NAME': int(origInit == True) + } + + self.write_config(config.format(**args)) + + bitbake('core-image-minimal') + testFile = "/etc/my-test-data" + + with runqemu('core-image-minimal', image_fstype='wic', discard_writes=False) as qemu: + status, output = qemu.run_serial("/bin/mount") + + line = getline_qemu(output, "/dev/sda3") + self.assertTrue("/data" in output, msg=output) + + line = getline_qemu(output, "upperdir=/data/overlay-etc/upper") + self.assertTrue(line and line.startswith("/data/overlay-etc/upper on /etc type overlay"), msg=output) + + status, output = qemu.run_serial("touch " + testFile) + status, output = qemu.run_serial("sync") + status, output = qemu.run_serial("ls -1 " + testFile) + line = getline_qemu(output, testFile) + self.assertTrue(line and line.startswith(testFile), msg=output) + + # Check that file exists in /etc after reboot + with runqemu('core-image-minimal', image_fstype='wic') as qemu: + status, output = qemu.run_serial("ls -1 " + testFile) + line = getline_qemu(output, testFile) + self.assertTrue(line and line.startswith(testFile), msg=output) diff --git a/meta/lib/oeqa/selftest/cases/package.py b/meta/lib/oeqa/selftest/cases/package.py index 7166c3991f..cebbb4f3f4 100644 --- a/meta/lib/oeqa/selftest/cases/package.py +++ b/meta/lib/oeqa/selftest/cases/package.py @@ -116,9 +116,9 @@ class PackageTests(OESelftestTestCase): # Verify gdb to read symbols from separated debug hardlink file correctly def test_gdb_hardlink_debug(self): - features = 'IMAGE_INSTALL_append = " selftest-hardlink"\n' - features += 'IMAGE_INSTALL_append = " selftest-hardlink-dbg"\n' - features += 'IMAGE_INSTALL_append = " selftest-hardlink-gdb"\n' + features = 'IMAGE_INSTALL:append = " selftest-hardlink"\n' + features += 'IMAGE_INSTALL:append = " selftest-hardlink-dbg"\n' + features += 'IMAGE_INSTALL:append = " selftest-hardlink-gdb"\n' self.write_config(features) bitbake("core-image-minimal") @@ -151,7 +151,7 @@ class PackageTests(OESelftestTestCase): def test_preserve_ownership(self): import os, stat, oe.cachedpath - features = 'IMAGE_INSTALL_append = " selftest-chown"\n' + features = 'IMAGE_INSTALL:append = " selftest-chown"\n' self.write_config(features) bitbake("core-image-minimal") diff --git a/meta/lib/oeqa/selftest/cases/prservice.py b/meta/lib/oeqa/selftest/cases/prservice.py index 578b2b4dd9..10158ca7c2 100644 --- a/meta/lib/oeqa/selftest/cases/prservice.py +++ b/meta/lib/oeqa/selftest/cases/prservice.py @@ -40,7 +40,7 @@ class BitbakePrTests(OESelftestTestCase): return str(stamps[0]) def increment_package_pr(self, package_name): - inc_data = "do_package_append() {\n bb.build.exec_func('do_test_prserv', d)\n}\ndo_test_prserv() {\necho \"The current date is: %s\" > ${PKGDESTWORK}/${PN}.datestamp\n}" % datetime.datetime.now() + inc_data = "do_package:append() {\n bb.build.exec_func('do_test_prserv', d)\n}\ndo_test_prserv() {\necho \"The current date is: %s\" > ${PKGDESTWORK}/${PN}.datestamp\n}" % datetime.datetime.now() self.write_recipeinc(package_name, inc_data) res = bitbake(package_name, ignore_status=True) self.delete_recipeinc(package_name) diff --git a/meta/lib/oeqa/selftest/cases/recipetool.py b/meta/lib/oeqa/selftest/cases/recipetool.py index f0685d3718..510dae6bad 100644 --- a/meta/lib/oeqa/selftest/cases/recipetool.py +++ b/meta/lib/oeqa/selftest/cases/recipetool.py @@ -25,7 +25,7 @@ def tearDownModule(): runCmd('rm -rf %s' % templayerdir) -class RecipetoolBase(devtool.DevtoolBase): +class RecipetoolBase(devtool.DevtoolTestCase): def setUpLocal(self): super(RecipetoolBase, self).setUpLocal() @@ -68,17 +68,16 @@ class RecipetoolBase(devtool.DevtoolBase): return bbappendfile, result.output -class RecipetoolTests(RecipetoolBase): +class RecipetoolAppendTests(RecipetoolBase): @classmethod def setUpClass(cls): - super(RecipetoolTests, cls).setUpClass() + super(RecipetoolAppendTests, cls).setUpClass() # Ensure we have the right data in shlibs/pkgdata cls.logger.info('Running bitbake to generate pkgdata') bitbake('-c packagedata base-files coreutils busybox selftest-recipetool-appendfile') - bb_vars = get_bb_vars(['COREBASE', 'BBPATH']) + bb_vars = get_bb_vars(['COREBASE']) cls.corebase = bb_vars['COREBASE'] - cls.bbpath = bb_vars['BBPATH'] def _try_recipetool_appendfile(self, testrecipe, destfile, newfile, options, expectedlines, expectedfiles): cmd = 'recipetool appendfile %s %s %s %s' % (self.templayerdir, destfile, newfile, options) @@ -94,7 +93,7 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_basic(self): # Basic test - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('base-files', '/etc/motd', self.testfile, '', expectedlines, ['motd']) self.assertNotIn('WARNING: ', output) @@ -112,11 +111,11 @@ class RecipetoolTests(RecipetoolBase): # Need a test file - should be executable testfile2 = os.path.join(self.corebase, 'oe-init-build-env') testfile2name = os.path.basename(testfile2) - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://%s"\n' % testfile2name, '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${base_bindir}\n', ' install -m 0755 ${WORKDIR}/%s ${D}${base_bindir}/ls\n' % testfile2name, '}\n'] @@ -138,11 +137,11 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_add(self): # Try arbitrary file add to a recipe - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile"\n', '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${datadir}\n', ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n', '}\n'] @@ -151,13 +150,13 @@ class RecipetoolTests(RecipetoolBase): # (so we're testing that, plus modifying an existing bbappend) testfile2 = os.path.join(self.corebase, 'oe-init-build-env') testfile2name = os.path.basename(testfile2) - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile \\\n', ' file://%s \\\n' % testfile2name, ' "\n', '\n', - 'do_install_append() {\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, @@ -166,11 +165,11 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_add_bindir(self): # Try arbitrary file add to a recipe, this time to a location such that should be installed as executable - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile"\n', '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${bindir}\n', ' install -m 0755 ${WORKDIR}/testfile ${D}${bindir}/selftest-recipetool-testbin\n', '}\n'] @@ -179,13 +178,13 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_add_machine(self): # Try arbitrary file add to a recipe, this time to a location such that should be installed as executable - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'PACKAGE_ARCH = "${MACHINE_ARCH}"\n', '\n', - 'SRC_URI_append_mymachine = " file://testfile"\n', + 'SRC_URI:append:mymachine = " file://testfile"\n', '\n', - 'do_install_append_mymachine() {\n', + 'do_install:append:mymachine() {\n', ' install -d ${D}${datadir}\n', ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n', '}\n'] @@ -194,32 +193,32 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_orig(self): # A file that's in SRC_URI and in do_install with the same name - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-orig', self.testfile, '', expectedlines, ['selftest-replaceme-orig']) self.assertNotIn('WARNING: ', output) def test_recipetool_appendfile_todir(self): # A file that's in SRC_URI and in do_install with destination directory rather than file - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-todir', self.testfile, '', expectedlines, ['selftest-replaceme-todir']) self.assertNotIn('WARNING: ', output) def test_recipetool_appendfile_renamed(self): # A file that's in SRC_URI with a different name to the destination file - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-renamed', self.testfile, '', expectedlines, ['file1']) self.assertNotIn('WARNING: ', output) def test_recipetool_appendfile_subdir(self): # A file that's in SRC_URI in a subdir - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile"\n', '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${datadir}\n', ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-subdir\n', '}\n'] @@ -228,25 +227,25 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_inst_glob(self): # A file that's in do_install as a glob - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-inst-globfile', self.testfile, '', expectedlines, ['selftest-replaceme-inst-globfile']) self.assertNotIn('WARNING: ', output) def test_recipetool_appendfile_inst_todir_glob(self): # A file that's in do_install as a glob with destination as a directory - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-inst-todir-globfile', self.testfile, '', expectedlines, ['selftest-replaceme-inst-todir-globfile']) self.assertNotIn('WARNING: ', output) def test_recipetool_appendfile_patch(self): # A file that's added by a patch in SRC_URI - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile"\n', '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${sysconfdir}\n', ' install -m 0644 ${WORKDIR}/testfile ${D}${sysconfdir}/selftest-replaceme-patched\n', '}\n'] @@ -260,11 +259,11 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_script(self): # Now, a file that's in SRC_URI but installed by a script (so no mention in do_install) - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile"\n', '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${datadir}\n', ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-scripted\n', '}\n'] @@ -273,7 +272,7 @@ class RecipetoolTests(RecipetoolBase): def test_recipetool_appendfile_inst_func(self): # A file that's installed from a function called by do_install - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-inst-func', self.testfile, '', expectedlines, ['selftest-replaceme-inst-func']) self.assertNotIn('WARNING: ', output) @@ -283,11 +282,11 @@ class RecipetoolTests(RecipetoolBase): # First try without specifying recipe self._try_recipetool_appendfile_fail('/usr/share/selftest-replaceme-postinst', self.testfile, ['File /usr/share/selftest-replaceme-postinst may be written out in a pre/postinstall script of the following recipes:', 'selftest-recipetool-appendfile']) # Now specify recipe - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n', 'SRC_URI += "file://testfile"\n', '\n', - 'do_install_append() {\n', + 'do_install:append() {\n', ' install -d ${D}${datadir}\n', ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-postinst\n', '}\n'] @@ -332,6 +331,9 @@ class RecipetoolTests(RecipetoolBase): filename = try_appendfile_wc('-w') self.assertEqual(filename, recipefn.split('_')[0] + '_%.bbappend') + +class RecipetoolCreateTests(RecipetoolBase): + def test_recipetool_create(self): # Try adding a recipe tempsrc = os.path.join(self.tempdir, 'srctree') @@ -341,14 +343,14 @@ class RecipetoolTests(RecipetoolBase): result = runCmd('recipetool create -o %s %s -x %s' % (recipefile, srcuri, tempsrc)) self.assertTrue(os.path.isfile(recipefile)) checkvars = {} - checkvars['LICENSE'] = 'GPLv2' + checkvars['LICENSE'] = 'GPL-2.0-only' checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263' checkvars['SRC_URI'] = 'https://github.com/logrotate/logrotate/releases/download/${PV}/logrotate-${PV}.tar.xz' checkvars['SRC_URI[md5sum]'] = 'a560c57fac87c45b2fc17406cdf79288' checkvars['SRC_URI[sha256sum]'] = '2e6a401cac9024db2288297e3be1a8ab60e7401ba8e91225218aaf4a27e82a07' self._test_recipe_contents(recipefile, checkvars, []) - def test_recipetool_create_git(self): + def test_recipetool_create_autotools(self): if 'x11' not in get_bb_var('DISTRO_FEATURES'): self.skipTest('Test requires x11 as distro feature') # Ensure we have the right data in shlibs/pkgdata @@ -361,11 +363,11 @@ class RecipetoolTests(RecipetoolBase): result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri + ";rev=9f7cf8895ae2d39c465c04cc78e918c157420269", '-x', tempsrc]) self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output) checkvars = {} - checkvars['LICENSE'] = 'LGPLv2.1' + checkvars['LICENSE'] = 'LGPL-2.1-only' checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=7fbc338309ac38fefcd64b04bb903e34' checkvars['S'] = '${WORKDIR}/git' checkvars['PV'] = '1.11+git${SRCPV}' - checkvars['SRC_URI'] = srcuri + checkvars['SRC_URI'] = srcuri + ';branch=master' checkvars['DEPENDS'] = set(['libcheck', 'libjpeg-turbo', 'libpng', 'libx11', 'libxext', 'pango']) inherits = ['autotools', 'pkgconfig'] self._test_recipe_contents(recipefile, checkvars, inherits) @@ -375,7 +377,7 @@ class RecipetoolTests(RecipetoolBase): temprecipe = os.path.join(self.tempdir, 'recipe') os.makedirs(temprecipe) pv = '1.7.4.1' - srcuri = 'http://www.dest-unreach.org/socat/download/socat-%s.tar.bz2' % pv + srcuri = 'http://www.dest-unreach.org/socat/download/Archive/socat-%s.tar.bz2' % pv result = runCmd('recipetool create %s -o %s' % (srcuri, temprecipe)) dirlist = os.listdir(temprecipe) if len(dirlist) > 1: @@ -384,7 +386,7 @@ class RecipetoolTests(RecipetoolBase): self.fail('recipetool did not create recipe file; output:\n%s\ndirlist:\n%s' % (result.output, str(dirlist))) self.assertEqual(dirlist[0], 'socat_%s.bb' % pv, 'Recipe file incorrectly named') checkvars = {} - checkvars['LICENSE'] = set(['Unknown', 'GPLv2']) + checkvars['LICENSE'] = set(['Unknown', 'GPL-2.0-only']) checkvars['LIC_FILES_CHKSUM'] = set(['file://COPYING.OpenSSL;md5=5c9bccc77f67a8328ef4ebaf468116f4', 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263']) # We don't check DEPENDS since they are variable for this recipe depending on what's in the sysroot checkvars['S'] = None @@ -400,7 +402,7 @@ class RecipetoolTests(RecipetoolBase): result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri)) self.assertTrue(os.path.isfile(recipefile)) checkvars = {} - checkvars['LICENSE'] = set(['LGPLv2.1', 'MPL-1.1']) + checkvars['LICENSE'] = set(['LGPL-2.1-only', 'MPL-1.1-only']) checkvars['SRC_URI'] = 'http://taglib.github.io/releases/taglib-${PV}.tar.gz' checkvars['SRC_URI[md5sum]'] = 'cee7be0ccfc892fa433d6c837df9522a' checkvars['SRC_URI[sha256sum]'] = 'b6d1a5a610aae6ff39d93de5efd0fdc787aa9e9dc1e7026fa4c961b26563526b' @@ -424,16 +426,16 @@ class RecipetoolTests(RecipetoolBase): checkvars = {} checkvars['SUMMARY'] = 'Node Server Example' checkvars['HOMEPAGE'] = 'https://github.com/savoirfairelinux/node-server-example#readme' - checkvars['LICENSE'] = set(['MIT', 'ISC', 'Unknown']) + checkvars['LICENSE'] = 'BSD-3-Clause & ISC & MIT & Unknown' urls = [] urls.append('npm://registry.npmjs.org/;package=@savoirfairelinux/node-server-example;version=${PV}') urls.append('npmsw://${THISDIR}/${BPN}/npm-shrinkwrap.json') checkvars['SRC_URI'] = set(urls) checkvars['S'] = '${WORKDIR}/npm' - checkvars['LICENSE_${PN}'] = 'MIT' - checkvars['LICENSE_${PN}-base64'] = 'Unknown' - checkvars['LICENSE_${PN}-accepts'] = 'MIT' - checkvars['LICENSE_${PN}-inherits'] = 'ISC' + checkvars['LICENSE:${PN}'] = 'MIT' + checkvars['LICENSE:${PN}-base64'] = 'Unknown' + checkvars['LICENSE:${PN}-accepts'] = 'MIT' + checkvars['LICENSE:${PN}-inherits'] = 'ISC' inherits = ['npm'] self._test_recipe_contents(recipefile, checkvars, inherits) @@ -447,7 +449,7 @@ class RecipetoolTests(RecipetoolBase): self.assertTrue(os.path.isfile(recipefile)) checkvars = {} checkvars['LICENSE'] = set(['Apache-2.0']) - checkvars['SRC_URI'] = 'git://github.com/mesonbuild/meson;protocol=https' + checkvars['SRC_URI'] = 'git://github.com/mesonbuild/meson;protocol=https;branch=master' inherits = ['setuptools3'] self._test_recipe_contents(recipefile, checkvars, inherits) @@ -470,25 +472,6 @@ class RecipetoolTests(RecipetoolBase): inherits = ['setuptools3'] self._test_recipe_contents(recipefile, checkvars, inherits) - def test_recipetool_create_python3_distutils(self): - # Test creating python3 package from tarball (using distutils3 class) - temprecipe = os.path.join(self.tempdir, 'recipe') - os.makedirs(temprecipe) - pn = 'docutils' - pv = '0.14' - recipefile = os.path.join(temprecipe, '%s_%s.bb' % (pn, pv)) - srcuri = 'https://files.pythonhosted.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-%s.tar.gz' % pv - result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri)) - self.assertTrue(os.path.isfile(recipefile)) - checkvars = {} - checkvars['LICENSE'] = set(['PSF', '&', 'BSD', 'GPL']) - checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING.txt;md5=35a23d42b615470583563132872c97d6' - checkvars['SRC_URI'] = 'https://files.pythonhosted.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-${PV}.tar.gz' - checkvars['SRC_URI[md5sum]'] = 'c53768d63db3873b7d452833553469de' - checkvars['SRC_URI[sha256sum]'] = '51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274' - inherits = ['distutils3'] - self._test_recipe_contents(recipefile, checkvars, inherits) - def test_recipetool_create_github_tarball(self): # Basic test to ensure github URL mangling doesn't apply to release tarballs temprecipe = os.path.join(self.tempdir, 'recipe') @@ -504,19 +487,48 @@ class RecipetoolTests(RecipetoolBase): inherits = ['setuptools3'] self._test_recipe_contents(recipefile, checkvars, inherits) - def test_recipetool_create_git_http(self): + def _test_recipetool_create_git(self, srcuri, branch=None): # Basic test to check http git URL mangling works temprecipe = os.path.join(self.tempdir, 'recipe') os.makedirs(temprecipe) - recipefile = os.path.join(temprecipe, 'matchbox-terminal_git.bb') - srcuri = 'http://git.yoctoproject.org/git/matchbox-terminal' - result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri)) + name = srcuri.split(';')[0].split('/')[-1] + recipefile = os.path.join(temprecipe, name + '_git.bb') + options = ' -B %s' % branch if branch else '' + result = runCmd('recipetool create -o %s%s "%s"' % (temprecipe, options, srcuri)) self.assertTrue(os.path.isfile(recipefile)) checkvars = {} - checkvars['LICENSE'] = set(['GPLv2']) - checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/matchbox-terminal;protocol=http' - inherits = ['pkgconfig', 'autotools'] - self._test_recipe_contents(recipefile, checkvars, inherits) + checkvars['SRC_URI'] = srcuri + for scheme in ['http', 'https']: + if srcuri.startswith(scheme + ":"): + checkvars['SRC_URI'] = 'git%s;protocol=%s' % (srcuri[len(scheme):], scheme) + if ';branch=' not in srcuri: + checkvars['SRC_URI'] += ';branch=' + (branch or 'master') + self._test_recipe_contents(recipefile, checkvars, []) + + def test_recipetool_create_git_http(self): + self._test_recipetool_create_git('http://git.yoctoproject.org/git/matchbox-keyboard') + + def test_recipetool_create_git_srcuri_master(self): + self._test_recipetool_create_git('git://git.yoctoproject.org/matchbox-keyboard;branch=master') + + def test_recipetool_create_git_srcuri_branch(self): + self._test_recipetool_create_git('git://git.yoctoproject.org/matchbox-keyboard;branch=matchbox-keyboard-0-1') + + def test_recipetool_create_git_srcbranch(self): + self._test_recipetool_create_git('git://git.yoctoproject.org/matchbox-keyboard', 'matchbox-keyboard-0-1') + + +class RecipetoolTests(RecipetoolBase): + + @classmethod + def setUpClass(cls): + import sys + + super(RecipetoolTests, cls).setUpClass() + bb_vars = get_bb_vars(['BBPATH']) + cls.bbpath = bb_vars['BBPATH'] + libpath = os.path.join(get_bb_var('COREBASE'), 'scripts', 'lib', 'recipetool') + sys.path.insert(0, libpath) def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths): dstdir = basedstdir @@ -561,6 +573,128 @@ class RecipetoolTests(RecipetoolBase): with open(srcfile, 'w') as fh: fh.writelines(plugincontent) + def test_recipetool_handle_license_vars(self): + from create import handle_license_vars + from unittest.mock import Mock + + commonlicdir = get_bb_var('COMMON_LICENSE_DIR') + + d = bb.tinfoil.TinfoilDataStoreConnector + d.getVar = Mock(return_value=commonlicdir) + + srctree = tempfile.mkdtemp(prefix='recipetoolqa') + self.track_for_cleanup(srctree) + + # Multiple licenses + licenses = ['MIT', 'ISC', 'BSD-3-Clause', 'Apache-2.0'] + for licence in licenses: + shutil.copy(os.path.join(commonlicdir, licence), os.path.join(srctree, 'LICENSE.' + licence)) + # Duplicate license + shutil.copy(os.path.join(commonlicdir, 'MIT'), os.path.join(srctree, 'LICENSE')) + + extravalues = { + # Duplicate and missing licenses + 'LICENSE': 'Zlib & BSD-2-Clause & Zlib', + 'LIC_FILES_CHKSUM': [ + 'file://README.md;md5=0123456789abcdef0123456789abcd' + ] + } + lines_before = [] + handled = [] + licvalues = handle_license_vars(srctree, lines_before, handled, extravalues, d) + expected_lines_before = [ + '# WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is', + '# your responsibility to verify that the values are complete and correct.', + '# NOTE: Original package / source metadata indicates license is: BSD-2-Clause & Zlib', + '#', + '# NOTE: multiple licenses have been detected; they have been separated with &', + '# in the LICENSE value for now since it is a reasonable assumption that all', + '# of the licenses apply. If instead there is a choice between the multiple', + '# licenses then you should change the value to separate the licenses with |', + '# instead of &. If there is any doubt, check the accompanying documentation', + '# to determine which situation is applicable.', + 'LICENSE = "Apache-2.0 & BSD-2-Clause & BSD-3-Clause & ISC & MIT & Zlib"', + 'LIC_FILES_CHKSUM = "file://LICENSE;md5=0835ade698e0bcf8506ecda2f7b4f302 \\\n' + ' file://LICENSE.Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10 \\\n' + ' file://LICENSE.BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9 \\\n' + ' file://LICENSE.ISC;md5=f3b90e78ea0cffb20bf5cca7947a896d \\\n' + ' file://LICENSE.MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \\\n' + ' file://README.md;md5=0123456789abcdef0123456789abcd"', + '' + ] + self.assertEqual(lines_before, expected_lines_before) + expected_licvalues = [ + ('MIT', 'LICENSE', '0835ade698e0bcf8506ecda2f7b4f302'), + ('Apache-2.0', 'LICENSE.Apache-2.0', '89aea4e17d99a7cacdbeed46a0096b10'), + ('BSD-3-Clause', 'LICENSE.BSD-3-Clause', '550794465ba0ec5312d6919e203a55f9'), + ('ISC', 'LICENSE.ISC', 'f3b90e78ea0cffb20bf5cca7947a896d'), + ('MIT', 'LICENSE.MIT', '0835ade698e0bcf8506ecda2f7b4f302') + ] + self.assertEqual(handled, [('license', expected_licvalues)]) + self.assertEqual(extravalues, {}) + self.assertEqual(licvalues, expected_licvalues) + + + def test_recipetool_split_pkg_licenses(self): + from create import split_pkg_licenses + licvalues = [ + # Duplicate licenses + ('BSD-2-Clause', 'x/COPYING', None), + ('BSD-2-Clause', 'x/LICENSE', None), + # Multiple licenses + ('MIT', 'x/a/LICENSE.MIT', None), + ('ISC', 'x/a/LICENSE.ISC', None), + # Alternative licenses + ('(MIT | ISC)', 'x/b/LICENSE', None), + # Alternative licenses without brackets + ('MIT | BSD-2-Clause', 'x/c/LICENSE', None), + # Multi licenses with alternatives + ('MIT', 'x/d/COPYING', None), + ('MIT | BSD-2-Clause', 'x/d/LICENSE', None), + # Multi licenses with alternatives and brackets + ('Apache-2.0 & ((MIT | ISC) & BSD-3-Clause)', 'x/e/LICENSE', None) + ] + packages = { + '${PN}': '', + 'a': 'x/a', + 'b': 'x/b', + 'c': 'x/c', + 'd': 'x/d', + 'e': 'x/e', + 'f': 'x/f', + 'g': 'x/g', + } + fallback_licenses = { + # Ignored + 'a': 'BSD-3-Clause', + # Used + 'f': 'BSD-3-Clause' + } + outlines = [] + outlicenses = split_pkg_licenses(licvalues, packages, outlines, fallback_licenses) + expected_outlicenses = { + '${PN}': ['BSD-2-Clause'], + 'a': ['ISC', 'MIT'], + 'b': ['(ISC | MIT)'], + 'c': ['(BSD-2-Clause | MIT)'], + 'd': ['(BSD-2-Clause | MIT)', 'MIT'], + 'e': ['(ISC | MIT)', 'Apache-2.0', 'BSD-3-Clause'], + 'f': ['BSD-3-Clause'], + 'g': ['Unknown'] + } + self.assertEqual(outlicenses, expected_outlicenses) + expected_outlines = [ + 'LICENSE:${PN} = "BSD-2-Clause"', + 'LICENSE:a = "ISC & MIT"', + 'LICENSE:b = "(ISC | MIT)"', + 'LICENSE:c = "(BSD-2-Clause | MIT)"', + 'LICENSE:d = "(BSD-2-Clause | MIT) & MIT"', + 'LICENSE:e = "(ISC | MIT) & Apache-2.0 & BSD-3-Clause"', + 'LICENSE:f = "BSD-3-Clause"', + 'LICENSE:g = "Unknown"' + ] + self.assertEqual(outlines, expected_outlines) + class RecipetoolAppendsrcBase(RecipetoolBase): def _try_recipetool_appendsrcfile(self, testrecipe, newfile, destfile, options, expectedlines, expectedfiles): @@ -620,7 +754,7 @@ class RecipetoolAppendsrcBase(RecipetoolBase): else: destpath = '.' + os.sep - expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', + expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', '\n'] if has_src_uri: uri = 'file://%s' % filename diff --git a/meta/lib/oeqa/selftest/cases/recipeutils.py b/meta/lib/oeqa/selftest/cases/recipeutils.py index 747870383b..f1dd63f65b 100644 --- a/meta/lib/oeqa/selftest/cases/recipeutils.py +++ b/meta/lib/oeqa/selftest/cases/recipeutils.py @@ -40,7 +40,7 @@ class RecipeUtilsTests(OESelftestTestCase): SUMMARY = "Python framework to process interdependent tasks in a pool of workers" HOMEPAGE = "http://github.com/gitpython-developers/async" SECTION = "devel/python" --LICENSE = "BSD" +-LICENSE = "BSD-3-Clause" +LICENSE = "something" LIC_FILES_CHKSUM = "file://PKG-INFO;beginline=8;endline=8;md5=88df8e78b9edfd744953862179f2d14e" @@ -52,7 +52,7 @@ class RecipeUtilsTests(OESelftestTestCase): +SRC_URI[md5sum] = "aaaaaa" SRC_URI[sha256sum] = "ac6894d876e45878faae493b0cf61d0e28ec417334448ac0a6ea2229d8343051" - RDEPENDS_${PN} += "${PYTHON_PN}-threading" + RDEPENDS:${PN} += "${PYTHON_PN}-threading" """ patchlines = [] for f in patches: @@ -80,7 +80,7 @@ class RecipeUtilsTests(OESelftestTestCase): -SRC_URI += "file://somefile" - - SRC_URI_append = " file://anotherfile" + SRC_URI:append = " file://anotherfile" """ patchlines = [] for f in patches: @@ -105,7 +105,7 @@ class RecipeUtilsTests(OESelftestTestCase): -SRC_URI += "file://somefile" - --SRC_URI_append = " file://anotherfile" +-SRC_URI:append = " file://anotherfile" """ patchlines = [] for f in patches: diff --git a/meta/lib/oeqa/selftest/cases/reproducible.py b/meta/lib/oeqa/selftest/cases/reproducible.py index a62757399b..7caf8c3e7d 100644 --- a/meta/lib/oeqa/selftest/cases/reproducible.py +++ b/meta/lib/oeqa/selftest/cases/reproducible.py @@ -17,23 +17,7 @@ import stat import os import datetime -# For sample packages, see: -# https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-0t7wr_oo/ -# https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-4s9ejwyp/ -# https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-haiwdlbr/ -# https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-hwds3mcl/ -# https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201203-sua0pzvc/ -# (both packages/ and packages-excluded/) - -# ruby-ri-docs, meson: -#https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20210215-0_td9la2/packages/diff-html/ exclude_packages = [ - 'glide', - 'go-helloworld', - 'go-runtime', - 'go_', - 'go-', - 'ruby-ri-docs' ] def is_excluded(package): @@ -114,8 +98,9 @@ def compare_file(reference, test, diffutils_sysroot): result.status = SAME return result -def run_diffoscope(a_dir, b_dir, html_dir, **kwargs): - return runCmd(['diffoscope', '--no-default-limits', '--exclude-directory-metadata', 'yes', '--html-dir', html_dir, a_dir, b_dir], +def run_diffoscope(a_dir, b_dir, html_dir, max_report_size=0, **kwargs): + return runCmd(['diffoscope', '--no-default-limits', '--max-report-size', str(max_report_size), + '--exclude-directory-metadata', 'yes', '--html-dir', html_dir, a_dir, b_dir], **kwargs) class DiffoscopeTests(OESelftestTestCase): @@ -145,6 +130,9 @@ class ReproducibleTests(OESelftestTestCase): package_classes = ['deb', 'ipk', 'rpm'] + # Maximum report size, in bytes + 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'] # sstate targets are things to pull from sstate to potentially cut build/debugging time @@ -215,12 +203,11 @@ class ReproducibleTests(OESelftestTestCase): bb.utils.remove(tmpdir, recurse=True) config = textwrap.dedent('''\ - INHERIT += "reproducible_build" PACKAGE_CLASSES = "{package_classes}" INHIBIT_PACKAGE_STRIP = "1" TMPDIR = "{tmpdir}" - LICENSE_FLAGS_WHITELIST = "commercial" - DISTRO_FEATURES_append = ' systemd pam' + LICENSE_FLAGS_ACCEPTED = "commercial" + DISTRO_FEATURES:append = ' systemd pam' USERADDEXTENSION = "useradd-staticids" USERADD_ERROR_DYNAMIC = "skip" USERADD_UID_TABLES += "files/static-passwd" @@ -321,7 +308,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, + run_diffoscope('reproducibleA', 'reproducibleB', 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/runtime_test.py b/meta/lib/oeqa/selftest/cases/runtime_test.py index d0c2440722..642f0eb637 100644 --- a/meta/lib/oeqa/selftest/cases/runtime_test.py +++ b/meta/lib/oeqa/selftest/cases/runtime_test.py @@ -120,7 +120,7 @@ class TestImage(OESelftestTestCase): self.skipTest('core-image-full-cmdline not buildable for poky-tiny') features = 'INHERIT += "testimage"\n' - features += 'IMAGE_INSTALL_append = " libssl"\n' + features += 'IMAGE_INSTALL:append = " libssl"\n' features += 'TEST_SUITES = "ping ssh selftest"\n' self.write_config(features) @@ -186,14 +186,14 @@ class TestImage(OESelftestTestCase): qemu_distrofeatures = get_bb_var('DISTRO_FEATURES', 'qemu-system-native') features = 'INHERIT += "testimage"\n' if 'gtk+' not in qemu_packageconfig: - features += 'PACKAGECONFIG_append_pn-qemu-system-native = " gtk+"\n' + features += 'PACKAGECONFIG:append:pn-qemu-system-native = " gtk+"\n' if 'sdl' not in qemu_packageconfig: - features += 'PACKAGECONFIG_append_pn-qemu-system-native = " sdl"\n' + features += 'PACKAGECONFIG:append:pn-qemu-system-native = " sdl"\n' if 'opengl' not in qemu_distrofeatures: - features += 'DISTRO_FEATURES_append = " opengl"\n' + features += 'DISTRO_FEATURES:append = " opengl"\n' features += 'TEST_SUITES = "ping ssh virgl"\n' - features += 'IMAGE_FEATURES_append = " ssh-server-dropbear"\n' - features += 'IMAGE_INSTALL_append = " kmscube"\n' + features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n' + features += 'IMAGE_INSTALL:append = " kmscube"\n' features_gtk = features + 'TEST_RUNQEMUPARAMS = "gtk gl"\n' self.write_config(features_gtk) bitbake('core-image-minimal') @@ -212,23 +212,29 @@ class TestImage(OESelftestTestCase): Author: Alexander Kanavin <alex.kanavin@gmail.com> """ 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', 'almalinux-8.5']: + self.skipTest('virgl headless cannot be tested with %s' %(distro)) + + render_hint = """If /dev/dri/renderD* is absent due to lack of suitable GPU, 'modprobe vgem' will create one suitable for mesa llvmpipe software renderer.""" try: content = os.listdir("/dev/dri") if len([i for i in content if i.startswith('render')]) == 0: - self.skipTest("No render nodes found in /dev/dri: %s" %(content)) + self.fail("No render nodes found in /dev/dri: %s. %s" %(content, render_hint)) except FileNotFoundError: - self.skipTest("/dev/dri directory does not exist; no render nodes available on this machine.") + self.fail("/dev/dri directory does not exist; no render nodes available on this machine. %s" %(render_hint)) try: dripath = subprocess.check_output("pkg-config --variable=dridriverdir dri", shell=True) except subprocess.CalledProcessError as e: - self.skipTest("Could not determine the path to dri drivers on the host via pkg-config.\nPlease install Mesa development files (particularly, dri.pc) on the host machine.") + self.fail("Could not determine the path to dri drivers on the host via pkg-config.\nPlease install Mesa development files (particularly, dri.pc) on the host machine.") qemu_distrofeatures = get_bb_var('DISTRO_FEATURES', 'qemu-system-native') features = 'INHERIT += "testimage"\n' if 'opengl' not in qemu_distrofeatures: - features += 'DISTRO_FEATURES_append = " opengl"\n' + features += 'DISTRO_FEATURES:append = " opengl"\n' features += 'TEST_SUITES = "ping ssh virgl"\n' - features += 'IMAGE_FEATURES_append = " ssh-server-dropbear"\n' - features += 'IMAGE_INSTALL_append = " kmscube"\n' + features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n' + features += 'IMAGE_INSTALL:append = " kmscube"\n' features += 'TEST_RUNQEMUPARAMS = "egl-headless"\n' self.write_config(features) bitbake('core-image-minimal') @@ -254,7 +260,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"\n' + features += 'DISTRO_FEATURES:append = " systemd"\n' features += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n' features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n' features += 'VIRTUAL-RUNTIME_initscripts = ""\n' @@ -371,14 +377,14 @@ TEST_SERVER_IP = "192.168.7.1" TEST_TARGET_IP = "192.168.7.2" EXTRA_IMAGE_FEATURES += "tools-profile dbg-pkgs" -IMAGE_FEATURES_append = " ssh-server-dropbear" +IMAGE_FEATURES:append = " ssh-server-dropbear" # enables kernel debug symbols -KERNEL_EXTRA_FEATURES_append = " features/debug/debug-kernel.scc" -KERNEL_EXTRA_FEATURES_append = " features/systemtap/systemtap.scc" +KERNEL_EXTRA_FEATURES:append = " features/debug/debug-kernel.scc" +KERNEL_EXTRA_FEATURES:append = " features/systemtap/systemtap.scc" # add systemtap run-time into target image if it is not there yet -IMAGE_INSTALL_append = " systemtap-runtime" +IMAGE_INSTALL:append = " systemtap-runtime" """ def test_crosstap_helloworld(self): diff --git a/meta/lib/oeqa/selftest/cases/signing.py b/meta/lib/oeqa/selftest/cases/signing.py index a28c7eb19a..6f3d4aeae9 100644 --- a/meta/lib/oeqa/selftest/cases/signing.py +++ b/meta/lib/oeqa/selftest/cases/signing.py @@ -145,7 +145,7 @@ class Signing(OESelftestTestCase): feature += 'GPG_PATH = "%s"\n' % self.gpg_dir feature += 'SSTATE_DIR = "%s"\n' % sstatedir # Any mirror might have partial sstate without .sig files, triggering failures - feature += 'SSTATE_MIRRORS_forcevariable = ""\n' + feature += 'SSTATE_MIRRORS:forcevariable = ""\n' self.write_config(feature) @@ -159,13 +159,13 @@ class Signing(OESelftestTestCase): bitbake('-c clean %s' % test_recipe) bitbake('-c populate_lic %s' % test_recipe) - recipe_sig = glob.glob(sstatedir + '/*/*/*:ed:*_populate_lic.tgz.sig') - recipe_tgz = glob.glob(sstatedir + '/*/*/*:ed:*_populate_lic.tgz') + recipe_sig = glob.glob(sstatedir + '/*/*/*:ed:*_populate_lic.tar.zst.sig') + recipe_archive = glob.glob(sstatedir + '/*/*/*:ed:*_populate_lic.tar.zst') self.assertEqual(len(recipe_sig), 1, 'Failed to find .sig file.') - self.assertEqual(len(recipe_tgz), 1, 'Failed to find .tgz file.') + self.assertEqual(len(recipe_archive), 1, 'Failed to find .tar.zst file.') - ret = runCmd('gpg --homedir %s --verify %s %s' % (self.gpg_dir, recipe_sig[0], recipe_tgz[0])) + ret = runCmd('gpg --homedir %s --verify %s %s' % (self.gpg_dir, recipe_sig[0], recipe_archive[0])) # gpg: Signature made Thu 22 Oct 2015 01:45:09 PM EEST using RSA key ID 61EEFB30 # gpg: Good signature from "testuser (nocomment) <testuser@email.com>" self.assertIn('gpg: Good signature from', ret.output, 'Package signed incorrectly.') @@ -206,7 +206,7 @@ class LockedSignatures(OESelftestTestCase): # Use uuid so hash equivalance server isn't triggered recipe_append_file = test_recipe + '_' + get_bb_var('PV', test_recipe) + '.bbappend' recipe_append_path = os.path.join(templayerdir, 'recipes-test', test_recipe, recipe_append_file) - feature = 'SUMMARY_${PN} = "test locked signature%s"\n' % uuid.uuid4() + feature = 'SUMMARY:${PN} = "test locked signature%s"\n' % uuid.uuid4() os.mkdir(os.path.join(templayerdir, 'recipes-test')) os.mkdir(os.path.join(templayerdir, 'recipes-test', test_recipe)) diff --git a/meta/lib/oeqa/selftest/cases/sstatetests.py b/meta/lib/oeqa/selftest/cases/sstatetests.py index 9db2a0bb44..3038b40021 100644 --- a/meta/lib/oeqa/selftest/cases/sstatetests.py +++ b/meta/lib/oeqa/selftest/cases/sstatetests.py @@ -11,6 +11,7 @@ import tempfile from oeqa.selftest.case import OESelftestTestCase from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer, create_temp_layer from oeqa.selftest.cases.sstate import SStateBase +import oe import bb.siggen @@ -39,7 +40,7 @@ class SStateTests(SStateBase): recipefile = os.path.join(tempdir, "recipes-test", "dbus-wait-test", 'dbus-wait-test_git.bb') os.makedirs(os.path.dirname(recipefile)) - srcuri = 'git://' + srcdir + ';protocol=file' + srcuri = 'git://' + srcdir + ';protocol=file;branch=master' result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri]) self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output) @@ -68,7 +69,7 @@ class SStateTests(SStateBase): results = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific) if distro_nonspecific: for r in results: - if r.endswith(("_populate_lic.tgz", "_populate_lic.tgz.siginfo", "_fetch.tgz.siginfo", "_unpack.tgz.siginfo", "_patch.tgz.siginfo")): + if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo", "_fetch.tar.zst.siginfo", "_unpack.tar.zst.siginfo", "_patch.tar.zst.siginfo")): continue file_tracker.append(r) else: @@ -98,15 +99,15 @@ class SStateTests(SStateBase): bitbake(['-ccleansstate'] + targets) bitbake(targets) - tgz_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific) - self.assertTrue(tgz_created, msg="Could not find sstate .tgz files for: %s (%s)" % (', '.join(map(str, targets)), str(tgz_created))) + archives_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific) + self.assertTrue(archives_created, msg="Could not find sstate .tar.zst files for: %s (%s)" % (', '.join(map(str, targets)), str(archives_created))) siginfo_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific) self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s (%s)" % (', '.join(map(str, targets)), str(siginfo_created))) bitbake(['-ccleansstate'] + targets) - tgz_removed = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific) - self.assertTrue(not tgz_removed, msg="do_cleansstate didn't remove .tgz sstate files for: %s (%s)" % (', '.join(map(str, targets)), str(tgz_removed))) + archives_removed = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific) + self.assertTrue(not archives_removed, msg="do_cleansstate didn't remove .tar.zst sstate files for: %s (%s)" % (', '.join(map(str, targets)), str(archives_removed))) def test_cleansstate_task_distro_specific_nonspecific(self): targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native'] @@ -129,15 +130,15 @@ class SStateTests(SStateBase): bitbake(['-ccleansstate'] + targets) bitbake(targets) - results = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific=False, distro_nonspecific=True) + results = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=False, distro_nonspecific=True) filtered_results = [] for r in results: - if r.endswith(("_populate_lic.tgz", "_populate_lic.tgz.siginfo")): + if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo")): continue filtered_results.append(r) self.assertTrue(filtered_results == [], msg="Found distro non-specific sstate for: %s (%s)" % (', '.join(map(str, targets)), str(filtered_results))) - file_tracker_1 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False) - self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets))) + file_tracker_1 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False) + self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets))) self.track_for_cleanup(self.distro_specific_sstate + "_old") shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old") @@ -145,14 +146,14 @@ class SStateTests(SStateBase): bitbake(['-cclean'] + targets) bitbake(targets) - file_tracker_2 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False) - self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets))) + file_tracker_2 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False) + self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets))) not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2] - self.assertTrue(not_recreated == [], msg="The following sstate files ware not recreated: %s" % ', '.join(map(str, not_recreated))) + self.assertTrue(not_recreated == [], msg="The following sstate files were not recreated: %s" % ', '.join(map(str, not_recreated))) created_once = [x for x in file_tracker_2 if x not in file_tracker_1] - self.assertTrue(created_once == [], msg="The following sstate files ware created only in the second run: %s" % ', '.join(map(str, created_once))) + self.assertTrue(created_once == [], msg="The following sstate files were created only in the second run: %s" % ', '.join(map(str, created_once))) def test_rebuild_distro_specific_sstate_cross_native_targets(self): self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch, 'binutils-native'], temp_sstate_location=True) @@ -174,9 +175,9 @@ class SStateTests(SStateBase): # If buildhistory is enabled, we need to disable version-going-backwards # QA checks for this test. It may report errors otherwise. - self.append_config('ERROR_QA_remove = "version-going-backwards"') + self.append_config('ERROR_QA:remove = "version-going-backwards"') - # For not this only checks if random sstate tasks are handled correctly as a group. + # For now this only checks if random sstate tasks are handled correctly as a group. # In the future we should add control over what tasks we check for. sstate_archs_list = [] @@ -188,23 +189,23 @@ class SStateTests(SStateBase): if not sstate_arch in sstate_archs_list: sstate_archs_list.append(sstate_arch) if target_config[idx] == target_config[-1]: - target_sstate_before_build = self.search_sstate(target + r'.*?\.tgz$') + target_sstate_before_build = self.search_sstate(target + r'.*?\.tar.zst$') bitbake("-cclean %s" % target) result = bitbake(target, ignore_status=True) if target_config[idx] == target_config[-1]: - target_sstate_after_build = self.search_sstate(target + r'.*?\.tgz$') + target_sstate_after_build = self.search_sstate(target + r'.*?\.tar.zst$') expected_remaining_sstate += [x for x in target_sstate_after_build if x not in target_sstate_before_build if not any(pattern in x for pattern in ignore_patterns)] self.remove_config(global_config[idx]) self.remove_recipeinc(target, target_config[idx]) self.assertEqual(result.status, 0, msg = "build of %s failed with %s" % (target, result.output)) runCmd("sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ','.join(map(str, sstate_archs_list)))) - actual_remaining_sstate = [x for x in self.search_sstate(target + r'.*?\.tgz$') if not any(pattern in x for pattern in ignore_patterns)] + actual_remaining_sstate = [x for x in self.search_sstate(target + r'.*?\.tar.zst$') if not any(pattern in x for pattern in ignore_patterns)] actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate] - self.assertFalse(actual_not_expected, msg="Files should have been removed but ware not: %s" % ', '.join(map(str, actual_not_expected))) + self.assertFalse(actual_not_expected, msg="Files should have been removed but were not: %s" % ', '.join(map(str, actual_not_expected))) expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate] - self.assertFalse(expected_not_actual, msg="Extra files ware removed: %s" ', '.join(map(str, expected_not_actual))) + self.assertFalse(expected_not_actual, msg="Extra files were removed: %s" ', '.join(map(str, expected_not_actual))) def test_sstate_cache_management_script_using_pr_1(self): global_config = [] @@ -341,13 +342,15 @@ 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" """ - self.sstate_allarch_samesigs(configA, configB) + self.sstate_common_samesigs(configA, configB, allarch=True) def test_sstate_nativesdk_samesigs_multilib(self): """ @@ -360,7 +363,7 @@ TCLIBCAPPEND = \"\" MACHINE = \"qemux86-64\" require conf/multilib.conf MULTILIBS = \"multilib:lib32\" -DEFAULTTUNE_virtclass-multilib-lib32 = \"x86\" +DEFAULTTUNE:virtclass-multilib-lib32 = \"x86\" BB_SIGNATURE_HANDLER = "OEBasicHash" """ configB = """ @@ -371,9 +374,9 @@ require conf/multilib.conf MULTILIBS = \"\" BB_SIGNATURE_HANDLER = "OEBasicHash" """ - self.sstate_allarch_samesigs(configA, configB) + self.sstate_common_samesigs(configA, configB) - def sstate_allarch_samesigs(self, configA, configB): + def sstate_common_samesigs(self, configA, configB, allarch=False): self.write_config(configA) self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") @@ -401,6 +404,13 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" self.maxDiff = None self.assertEqual(files1, files2) + if allarch: + allarchdir = os.path.basename(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/all-*-linux")[0]) + + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/" + allarchdir) + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/" + allarchdir) + self.assertEqual(files1, files2) + def test_sstate_sametune_samesigs(self): """ The sstate checksums of two identical machines (using the same tune) should be the @@ -414,7 +424,7 @@ TCLIBCAPPEND = \"\" MACHINE = \"qemux86\" require conf/multilib.conf MULTILIBS = "multilib:lib32" -DEFAULTTUNE_virtclass-multilib-lib32 = "x86" +DEFAULTTUNE:virtclass-multilib-lib32 = "x86" BB_SIGNATURE_HANDLER = "OEBasicHash" """) self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") @@ -425,7 +435,7 @@ TCLIBCAPPEND = \"\" MACHINE = \"qemux86copy\" require conf/multilib.conf MULTILIBS = "multilib:lib32" -DEFAULTTUNE_virtclass-multilib-lib32 = "x86" +DEFAULTTUNE:virtclass-multilib-lib32 = "x86" BB_SIGNATURE_HANDLER = "OEBasicHash" """) self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") @@ -462,7 +472,7 @@ TCLIBCAPPEND = \"\" MACHINE = \"qemux86\" require conf/multilib.conf MULTILIBS = "multilib:lib32" -DEFAULTTUNE_virtclass-multilib-lib32 = "x86" +DEFAULTTUNE:virtclass-multilib-lib32 = "x86" BB_SIGNATURE_HANDLER = "OEBasicHash" """) self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") @@ -503,7 +513,7 @@ PARALLEL_MAKE = "-j 1" DL_DIR = "${TOPDIR}/download1" TIME = "111111" DATE = "20161111" -INHERIT_remove = "buildstats-summary buildhistory uninative" +INHERIT:remove = "buildstats-summary buildhistory uninative" http_proxy = "" BB_SIGNATURE_HANDLER = "OEBasicHash" """) @@ -519,7 +529,7 @@ DL_DIR = "${TOPDIR}/download2" TIME = "222222" DATE = "20161212" # Always remove uninative as we're changing proxies -INHERIT_remove = "uninative" +INHERIT:remove = "uninative" INHERIT += "buildstats-summary buildhistory" http_proxy = "http://example.com/" BB_SIGNATURE_HANDLER = "OEBasicHash" @@ -573,3 +583,44 @@ BB_SIGNATURE_HANDLER = "OEBasicHash" compare_sigfiles(rest, files1, files2, compare=False) self.fail("sstate hashes not identical.") + + def test_sstate_movelayer_samesigs(self): + """ + The sstate checksums of two builds with the same oe-core layer in two + different locations should be the same. + """ + core_layer = os.path.join( + self.tc.td["COREBASE"], 'meta') + copy_layer_1 = self.topdir + "/meta-copy1/meta" + copy_layer_2 = self.topdir + "/meta-copy2/meta" + + oe.path.copytree(core_layer, copy_layer_1) + self.write_config(""" +TMPDIR = "${TOPDIR}/tmp-sstatesamehash" +""") + bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_1, core_layer) + self.write_bblayers_config(bblayers_conf) + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") + bitbake("bash -S none") + + oe.path.copytree(core_layer, copy_layer_2) + self.write_config(""" +TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" +""") + bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_2, core_layer) + self.write_bblayers_config(bblayers_conf) + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") + bitbake("bash -S none") + + def get_files(d): + f = [] + for root, dirs, files in os.walk(d): + for name in files: + f.append(os.path.join(root, name)) + return f + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps") + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps") + files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] + self.maxDiff = None + self.assertCountEqual(files1, files2) + diff --git a/meta/lib/oeqa/selftest/cases/sysroot.py b/meta/lib/oeqa/selftest/cases/sysroot.py index 6e34927c90..79ab45235d 100644 --- a/meta/lib/oeqa/selftest/cases/sysroot.py +++ b/meta/lib/oeqa/selftest/cases/sysroot.py @@ -24,14 +24,14 @@ class SysrootTests(OESelftestTestCase): self.write_config(""" PREFERRED_PROVIDER_virtual/sysroot-test = "sysroot-test-arch1" MACHINE = "qemux86" -TESTSTRING_pn-sysroot-test-arch1 = "%s" -TESTSTRING_pn-sysroot-test-arch2 = "%s" +TESTSTRING:pn-sysroot-test-arch1 = "%s" +TESTSTRING:pn-sysroot-test-arch2 = "%s" """ % (uuid1, uuid2)) bitbake("sysroot-test") self.write_config(""" PREFERRED_PROVIDER_virtual/sysroot-test = "sysroot-test-arch2" MACHINE = "qemux86copy" -TESTSTRING_pn-sysroot-test-arch1 = "%s" -TESTSTRING_pn-sysroot-test-arch2 = "%s" +TESTSTRING:pn-sysroot-test-arch1 = "%s" +TESTSTRING:pn-sysroot-test-arch2 = "%s" """ % (uuid1, uuid2)) bitbake("sysroot-test") diff --git a/meta/lib/oeqa/selftest/cases/tinfoil.py b/meta/lib/oeqa/selftest/cases/tinfoil.py index a51c6048d3..8fd48bb054 100644 --- a/meta/lib/oeqa/selftest/cases/tinfoil.py +++ b/meta/lib/oeqa/selftest/cases/tinfoil.py @@ -94,14 +94,13 @@ class TinfoilTests(OESelftestTestCase): pass pattern = 'conf' - res = tinfoil.run_command('findFilesMatchingInDir', pattern, 'conf/machine') + res = tinfoil.run_command('testCookerCommandEvent', pattern) self.assertTrue(res) eventreceived = False commandcomplete = False start = time.time() # Wait for maximum 60s in total so we'd detect spurious heartbeat events for example - # The test is IO load sensitive too while (not (eventreceived == True and commandcomplete == True) and (time.time() - start < 60)): # if we received both events (on let's say a good day), we are done @@ -111,7 +110,8 @@ class TinfoilTests(OESelftestTestCase): commandcomplete = True elif isinstance(event, bb.event.FilesMatchingFound): self.assertEqual(pattern, event._pattern) - self.assertIn('qemuarm.conf', event._matches) + self.assertIn('A', event._matches) + self.assertIn('B', event._matches) eventreceived = True elif isinstance(event, logging.LogRecord): continue @@ -173,8 +173,8 @@ class TinfoilTests(OESelftestTestCase): self.assertEqual(value, 'origvalue', 'Variable renamed using config_data.renameVar() does not appear with new name') # Test overrides tinfoil.config_data.setVar('TESTVAR', 'original') - tinfoil.config_data.setVar('TESTVAR_overrideone', 'one') - tinfoil.config_data.setVar('TESTVAR_overridetwo', 'two') + tinfoil.config_data.setVar('TESTVAR:overrideone', 'one') + tinfoil.config_data.setVar('TESTVAR:overridetwo', 'two') tinfoil.config_data.appendVar('OVERRIDES', ':overrideone') value = tinfoil.config_data.getVar('TESTVAR') self.assertEqual(value, 'one', 'Variable overrides not functioning correctly') diff --git a/meta/lib/oeqa/selftest/cases/wic.py b/meta/lib/oeqa/selftest/cases/wic.py index a11e2d0781..6f3dc27743 100644 --- a/meta/lib/oeqa/selftest/cases/wic.py +++ b/meta/lib/oeqa/selftest/cases/wic.py @@ -11,6 +11,7 @@ import os import sys import unittest +import hashlib from glob import glob from shutil import rmtree, copy @@ -189,8 +190,8 @@ class Wic(WicTestCase): def test_iso_image(self): """Test creation of hybrid iso image with legacy and EFI boot""" config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\ - 'MACHINE_FEATURES_append = " efi"\n'\ - 'DEPENDS_pn-core-image-minimal += "syslinux"\n' + 'MACHINE_FEATURES:append = " efi"\n'\ + 'DEPENDS:pn-core-image-minimal += "syslinux"\n' self.append_config(config) bitbake('core-image-minimal core-image-minimal-initramfs') self.remove_config(config) @@ -216,7 +217,7 @@ class Wic(WicTestCase): @only_for_arch(['i586', 'i686', 'x86_64']) def test_bootloader_config(self): """Test creation of directdisk-bootloader-config image""" - config = 'DEPENDS_pn-core-image-minimal += "syslinux"\n' + config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n' self.append_config(config) bitbake('core-image-minimal') self.remove_config(config) @@ -227,7 +228,7 @@ class Wic(WicTestCase): @only_for_arch(['i586', 'i686', 'x86_64']) def test_systemd_bootdisk(self): """Test creation of systemd-bootdisk image""" - config = 'MACHINE_FEATURES_append = " efi"\n' + config = 'MACHINE_FEATURES:append = " efi"\n' self.append_config(config) bitbake('core-image-minimal') self.remove_config(config) @@ -259,7 +260,7 @@ class Wic(WicTestCase): """Test default output location""" for fname in glob("directdisk-*.direct"): os.remove(fname) - config = 'DEPENDS_pn-core-image-minimal += "syslinux"\n' + config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n' self.append_config(config) bitbake('core-image-minimal') self.remove_config(config) @@ -686,6 +687,74 @@ part /etc --source rootfs --fstype=ext4 --change-directory=etc % (wks_file, self.resultdir), ignore_status=True).status) os.remove(wks_file) + def test_no_fstab_update(self): + """Test --no-fstab-update wks option.""" + + oldpath = os.environ['PATH'] + os.environ['PATH'] = get_bb_var("PATH", "wic-tools") + + # Get stock fstab from base-files recipe + self.assertEqual(0, bitbake('base-files -c do_install').status) + bf_fstab = os.path.join(get_bb_var('D', 'base-files'), 'etc/fstab') + self.assertEqual(True, os.path.exists(bf_fstab)) + bf_fstab_md5sum = runCmd('md5sum %s 2>/dev/null' % bf_fstab).output.split(" ")[0] + + try: + no_fstab_update_path = os.path.join(self.resultdir, 'test-no-fstab-update') + os.makedirs(no_fstab_update_path) + wks_file = os.path.join(no_fstab_update_path, 'temp.wks') + with open(wks_file, 'w') as wks: + wks.writelines(['part / --source rootfs --fstype=ext4 --label rootfs\n', + 'part /mnt/p2 --source rootfs --rootfs-dir=core-image-minimal ', + '--fstype=ext4 --label p2 --no-fstab-update\n']) + runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wks_file, self.resultdir)) + + part_fstab_md5sum = [] + for i in range(1, 3): + part = glob(os.path.join(self.resultdir, 'temp-*.direct.p') + str(i))[0] + part_fstab = runCmd("debugfs -R 'cat etc/fstab' %s 2>/dev/null" % (part)) + part_fstab_md5sum.append(hashlib.md5((part_fstab.output + "\n\n").encode('utf-8')).hexdigest()) + + # '/etc/fstab' in partition 2 should contain the same stock fstab file + # as the one installed by the base-file recipe. + self.assertEqual(bf_fstab_md5sum, part_fstab_md5sum[1]) + + # '/etc/fstab' in partition 1 should contain an updated fstab file. + self.assertNotEqual(bf_fstab_md5sum, part_fstab_md5sum[0]) + + finally: + os.environ['PATH'] = oldpath + + def test_no_fstab_update_errors(self): + """Test --no-fstab-update wks option error handling.""" + wks_file = 'temp.wks' + + # Absolute argument. + with open(wks_file, 'w') as wks: + wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update /etc") + self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wks_file, self.resultdir), ignore_status=True).status) + os.remove(wks_file) + + # Argument pointing to parent directory. + with open(wks_file, 'w') as wks: + wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update ././..") + self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wks_file, self.resultdir), ignore_status=True).status) + os.remove(wks_file) + + def test_extra_space(self): + """Test --extra-space wks option.""" + extraspace = 1024**3 + runCmd("wic create wictestdisk " + "--image-name core-image-minimal " + "--extra-space %i -o %s" % (extraspace ,self.resultdir)) + wicout = glob(self.resultdir + "wictestdisk-*.direct") + self.assertEqual(1, len(wicout)) + size = os.path.getsize(wicout[0]) + self.assertTrue(size > extraspace) + class Wic2(WicTestCase): def test_bmap_short(self): @@ -757,7 +826,7 @@ class Wic2(WicTestCase): def test_wic_image_type(self): """Test building wic images by bitbake""" config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ - 'MACHINE_FEATURES_append = " efi"\n' + 'MACHINE_FEATURES:append = " efi"\n' self.append_config(config) self.assertEqual(0, bitbake('wic-image-minimal').status) self.remove_config(config) @@ -777,12 +846,12 @@ class Wic2(WicTestCase): def test_qemu(self): """Test wic-image-minimal under qemu""" config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ - 'MACHINE_FEATURES_append = " efi"\n' + 'MACHINE_FEATURES:append = " efi"\n' self.append_config(config) self.assertEqual(0, bitbake('wic-image-minimal').status) self.remove_config(config) - with runqemu('wic-image-minimal', ssh=False) as qemu: + with runqemu('wic-image-minimal', ssh=False, runqemuparams='nographic') as qemu: cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' " \ "-e '/dev/root /|/dev/sda2 /' -e '/dev/sda3 /media' -e '/dev/sda4 /mnt'" status, output = qemu.run_serial(cmd) @@ -802,7 +871,7 @@ class Wic2(WicTestCase): self.remove_config(config) with runqemu('core-image-minimal', ssh=False, - runqemuparams='ovmf', image_fstype='wic') as qemu: + runqemuparams='nographic ovmf', image_fstype='wic') as qemu: cmd = "grep sda. /proc/partitions |wc -l" status, output = qemu.run_serial(cmd) self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) @@ -990,21 +1059,21 @@ class Wic2(WicTestCase): self.assertEqual(0, bitbake('core-image-minimal-mtdutils').status) self.remove_config(config) - with runqemu('core-image-minimal-mtdutils', ssh=False, image_fstype='wic') as qemu: + with runqemu('core-image-minimal-mtdutils', ssh=False, + runqemuparams='nographic', image_fstype='wic') as qemu: cmd = "grep sda. /proc/partitions |wc -l" status, output = qemu.run_serial(cmd) self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) self.assertEqual(output, '2') - def test_rawcopy_plugin(self): + def _rawcopy_plugin(self, fstype): """Test rawcopy plugin""" img = 'core-image-minimal' machine = get_bb_var('MACHINE', img) + params = ',unpack' if fstype.endswith('.gz') else '' with NamedTemporaryFile("w", suffix=".wks") as wks: - wks.writelines(['part /boot --active --source bootimg-pcbios\n', - 'part / --source rawcopy --sourceparams="file=%s-%s.ext4" --use-uuid\n'\ - % (img, machine), - 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n']) + wks.write('part / --source rawcopy --sourceparams="file=%s-%s.%s%s"\n'\ + % (img, machine, fstype, params)) wks.flush() cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) runCmd(cmd) @@ -1012,6 +1081,17 @@ class Wic2(WicTestCase): out = glob(self.resultdir + "%s-*direct" % wksname) self.assertEqual(1, len(out)) + def test_rawcopy_plugin(self): + self._rawcopy_plugin('ext4') + + def test_rawcopy_plugin_unpack(self): + fstype = 'ext4.gz' + config = 'IMAGE_FSTYPES = "%s"\n' % fstype + self.append_config(config) + self.assertEqual(0, bitbake('core-image-minimal').status) + self.remove_config(config) + self._rawcopy_plugin(fstype) + def test_empty_plugin(self): """Test empty plugin""" config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_empty_plugin.wks"\n' @@ -1035,12 +1115,13 @@ class Wic2(WicTestCase): @only_for_arch(['i586', 'i686', 'x86_64']) def test_biosplusefi_plugin_qemu(self): """Test biosplusefi plugin in qemu""" - config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES_append = " efi"\n' + config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n' self.append_config(config) self.assertEqual(0, bitbake('core-image-minimal').status) self.remove_config(config) - with runqemu('core-image-minimal', ssh=False, image_fstype='wic') as qemu: + with runqemu('core-image-minimal', ssh=False, + runqemuparams='nographic', image_fstype='wic') as qemu: # Check that we have ONLY two /dev/sda* partitions (/boot and /) cmd = "grep sda. /proc/partitions | wc -l" status, output = qemu.run_serial(cmd) @@ -1072,7 +1153,7 @@ class Wic2(WicTestCase): # If an image hasn't been built yet, directory ${STAGING_DATADIR}/syslinux won't exists and _get_bootimg_dir() # will raise with "Couldn't find correct bootimg_dir" # The easiest way to work-around this issue is to make sure we already built an image here, hence the bitbake call - config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES_append = " efi"\n' + config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n' self.append_config(config) self.assertEqual(0, bitbake('core-image-minimal').status) self.remove_config(config) @@ -1089,6 +1170,35 @@ class Wic2(WicTestCase): out = glob(self.resultdir + "%s-*.direct" % wksname) self.assertEqual(1, len(out)) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_efi_plugin_unified_kernel_image_qemu(self): + """Test efi plugin's Unified Kernel Image feature in qemu""" + config = 'IMAGE_FSTYPES = "wic"\n'\ + 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\ + 'WKS_FILE = "test_efi_plugin.wks"\n'\ + 'MACHINE_FEATURES:append = " efi"\n' + self.append_config(config) + self.assertEqual(0, bitbake('core-image-minimal core-image-minimal-initramfs ovmf').status) + self.remove_config(config) + + with runqemu('core-image-minimal', ssh=False, + runqemuparams='nographic ovmf', image_fstype='wic') as qemu: + # Check that /boot has EFI bootx64.efi (required for EFI) + cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l" + status, output = qemu.run_serial(cmd) + self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) + self.assertEqual(output, '1') + # Check that /boot has EFI/Linux/linux.efi (required for Unified Kernel Images auto detection) + cmd = "ls /boot/EFI/Linux/linux.efi | wc -l" + status, output = qemu.run_serial(cmd) + self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) + self.assertEqual(output, '1') + # Check that /boot doesn't have loader/entries/boot.conf (Unified Kernel Images are auto detected by the bootloader) + cmd = "ls /boot/loader/entries/boot.conf 2&>/dev/null | wc -l" + status, output = qemu.run_serial(cmd) + self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) + self.assertEqual(output, '0') + def test_fs_types(self): """Test filesystem types for empty and not empty partitions""" img = 'core-image-minimal' @@ -1310,7 +1420,7 @@ class Wic2(WicTestCase): bb.utils.rename(new_image_path, image_path) # Check if it boots in qemu - with runqemu('core-image-minimal', ssh=False) as qemu: + with runqemu('core-image-minimal', ssh=False, runqemuparams='nographic') as qemu: cmd = "ls /etc/" status, output = qemu.run_serial('true') self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) |