diff options
Diffstat (limited to 'poky/meta/lib/oeqa/selftest')
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/archiver.py | 6 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/bbtests.py | 17 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/buildoptions.py | 4 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/devtool.py | 54 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/fetch.py | 2 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/imagefeatures.py | 2 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/overlayfs.py | 254 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/recipetool.py | 189 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/reproducible.py | 30 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/runtime_test.py | 2 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/sstatetests.py | 59 |
11 files changed, 527 insertions, 92 deletions
diff --git a/poky/meta/lib/oeqa/selftest/cases/archiver.py b/poky/meta/lib/oeqa/selftest/cases/archiver.py index 0194ae9f69..75195241b7 100644 --- a/poky/meta/lib/oeqa/selftest/cases/archiver.py +++ b/poky/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/poky/meta/lib/oeqa/selftest/cases/bbtests.py b/poky/meta/lib/oeqa/selftest/cases/bbtests.py index 6779e62103..246cb032bf 100644 --- a/poky/meta/lib/oeqa/selftest/cases/bbtests.py +++ b/poky/meta/lib/oeqa/selftest/cases/bbtests.py @@ -160,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') @@ -297,3 +297,18 @@ 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('man-db -c patch', 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 man-db') diff --git a/poky/meta/lib/oeqa/selftest/cases/buildoptions.py b/poky/meta/lib/oeqa/selftest/cases/buildoptions.py index f99881758e..651bb03c7e 100644 --- a/poky/meta/lib/oeqa/selftest/cases/buildoptions.py +++ b/poky/meta/lib/oeqa/selftest/cases/buildoptions.py @@ -183,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): diff --git a/poky/meta/lib/oeqa/selftest/cases/devtool.py b/poky/meta/lib/oeqa/selftest/cases/devtool.py index f495e84c79..23d55903fb 100644 --- a/poky/meta/lib/oeqa/selftest/cases/devtool.py +++ b/poky/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): @@ -340,7 +347,7 @@ class DevtoolAddTests(DevtoolBase): 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, []) @@ -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, []) @@ -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('"') diff --git a/poky/meta/lib/oeqa/selftest/cases/fetch.py b/poky/meta/lib/oeqa/selftest/cases/fetch.py index 9aa91e59c1..be14272e63 100644 --- a/poky/meta/lib/oeqa/selftest/cases/fetch.py +++ b/poky/meta/lib/oeqa/selftest/cases/fetch.py @@ -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/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py b/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py index 12902add94..18f37c6d7d 100644 --- a/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py +++ b/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py @@ -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" diff --git a/poky/meta/lib/oeqa/selftest/cases/overlayfs.py b/poky/meta/lib/oeqa/selftest/cases/overlayfs.py index 0184d52494..82007fade7 100644 --- a/poky/meta/lib/oeqa/selftest/cases/overlayfs.py +++ b/poky/meta/lib/oeqa/selftest/cases/overlayfs.py @@ -5,14 +5,17 @@ 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 getline(self, res, line): - for l in res.output.split('\n'): - if line in l: - return l - def add_overlay_conf_to_machine(self): machine_inc = """ OVERLAYFS_MOUNT_POINT[mnt-overlay] = "/mnt/overlay" @@ -37,7 +40,7 @@ inherit overlayfs self.write_recipeinc('overlayfs-user', overlayfs_recipe_append) res = bitbake('core-image-minimal', ignore_status=True) - line = self.getline(res, "overlayfs-user was skipped: missing required distro features") + 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) @@ -58,9 +61,9 @@ DISTRO_FEATURES += "systemd overlayfs" self.add_overlay_conf_to_machine() res = bitbake('core-image-minimal', ignore_status=True) - line = self.getline(res, "Unit name mnt-overlay.mount not found in systemd unit directories") + line = getline(res, "Unit name mnt-overlay.mount not found in systemd unit directories") self.assertTrue(line and line.startswith("WARNING:"), msg=res.output) - line = self.getline(res, "Not all mount units are installed by the BSP") + line = getline(res, "Not all mount units are installed by the BSP") self.assertTrue(line and line.startswith("ERROR:"), msg=res.output) def test_mount_unit_not_set(self): @@ -78,7 +81,7 @@ DISTRO_FEATURES += "systemd overlayfs" self.write_config(config) res = bitbake('core-image-minimal', ignore_status=True) - line = self.getline(res, "A recipe uses overlayfs class but there is no OVERLAYFS_MOUNT_POINT set in your MACHINE configuration") + 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): @@ -101,7 +104,7 @@ OVERLAYFS_MOUNT_POINT[usr-share-overlay] = "/usr/share/overlay" self.set_machine_config(wrong_machine_config) res = bitbake('core-image-minimal', ignore_status=True) - line = self.getline(res, "Missing required mount point for OVERLAYFS_MOUNT_POINT[mnt-overlay] in your MACHINE configuration") + 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): @@ -148,18 +151,52 @@ EOT """ + 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('systemd-machine-units', systemd_machine_unit_append) + self.write_recipeinc('overlayfs-user', overlayfs_recipe_append) bitbake('core-image-minimal') - def getline_qemu(out, line): - for l in out.split('\n'): - if line in l: - return l - 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") @@ -169,3 +206,190 @@ EOT 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) + +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/poky/meta/lib/oeqa/selftest/cases/recipetool.py b/poky/meta/lib/oeqa/selftest/cases/recipetool.py index c2a53815d0..9db1ddb532 100644 --- a/poky/meta/lib/oeqa/selftest/cases/recipetool.py +++ b/poky/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) @@ -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') @@ -348,7 +350,7 @@ class RecipetoolTests(RecipetoolBase): 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 @@ -365,7 +367,7 @@ class RecipetoolTests(RecipetoolBase): 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) @@ -424,7 +426,7 @@ 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') @@ -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) @@ -481,7 +483,7 @@ class RecipetoolTests(RecipetoolBase): result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri)) self.assertTrue(os.path.isfile(recipefile)) checkvars = {} - checkvars['LICENSE'] = set(['PSF', '&', 'BSD-3-Clause', 'GPL']) + checkvars['LICENSE'] = 'BSD-3-Clause & GPL & PSF' 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' @@ -504,19 +506,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 +592,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): diff --git a/poky/meta/lib/oeqa/selftest/cases/reproducible.py b/poky/meta/lib/oeqa/selftest/cases/reproducible.py index 2e983d2f17..e539365031 100644 --- a/poky/meta/lib/oeqa/selftest/cases/reproducible.py +++ b/poky/meta/lib/oeqa/selftest/cases/reproducible.py @@ -17,27 +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/ -# rust-llvm: -#https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20210825-kaihham6/ exclude_packages = [ - 'glide', - 'go-helloworld', - 'go-runtime', - 'go_', - 'go-', - 'ruby-ri-docs', - 'rust-llvm-liblto', - 'rust-llvm-staticdev' ] def is_excluded(package): @@ -118,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): @@ -149,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 @@ -324,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/poky/meta/lib/oeqa/selftest/cases/runtime_test.py b/poky/meta/lib/oeqa/selftest/cases/runtime_test.py index a90f62bfe1..5637a02451 100644 --- a/poky/meta/lib/oeqa/selftest/cases/runtime_test.py +++ b/poky/meta/lib/oeqa/selftest/cases/runtime_test.py @@ -214,7 +214,7 @@ class TestImage(OESelftestTestCase): 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']: + 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 sutable for mesa llvmpipe sofware renderer.""" diff --git a/poky/meta/lib/oeqa/selftest/cases/sstatetests.py b/poky/meta/lib/oeqa/selftest/cases/sstatetests.py index 3dab607eeb..96b2d115ed 100644 --- a/poky/meta/lib/oeqa/selftest/cases/sstatetests.py +++ b/poky/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) @@ -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): """ @@ -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 @@ -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) + |