summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/selftest
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oeqa/selftest')
-rw-r--r--meta/lib/oeqa/selftest/case.py52
-rw-r--r--meta/lib/oeqa/selftest/cases/_sstatetests_noauto.py8
-rw-r--r--meta/lib/oeqa/selftest/cases/archiver.py218
-rw-r--r--meta/lib/oeqa/selftest/cases/bblayers.py25
-rw-r--r--meta/lib/oeqa/selftest/cases/bblogging.py186
-rw-r--r--meta/lib/oeqa/selftest/cases/bbtests.py177
-rw-r--r--meta/lib/oeqa/selftest/cases/binutils.py50
-rw-r--r--meta/lib/oeqa/selftest/cases/buildhistory.py4
-rw-r--r--meta/lib/oeqa/selftest/cases/buildoptions.py90
-rw-r--r--meta/lib/oeqa/selftest/cases/containerimage.py19
-rw-r--r--meta/lib/oeqa/selftest/cases/cve_check.py44
-rw-r--r--meta/lib/oeqa/selftest/cases/devtool.py306
-rw-r--r--meta/lib/oeqa/selftest/cases/diffoscope/A/file.txt1
-rw-r--r--meta/lib/oeqa/selftest/cases/diffoscope/B/file.txt1
-rw-r--r--meta/lib/oeqa/selftest/cases/distrodata.py77
-rw-r--r--meta/lib/oeqa/selftest/cases/eSDK.py13
-rw-r--r--meta/lib/oeqa/selftest/cases/efibootpartition.py8
-rw-r--r--meta/lib/oeqa/selftest/cases/fetch.py71
-rw-r--r--meta/lib/oeqa/selftest/cases/fitimage.py840
-rw-r--r--meta/lib/oeqa/selftest/cases/gcc.py152
-rw-r--r--meta/lib/oeqa/selftest/cases/glibc.py89
-rw-r--r--meta/lib/oeqa/selftest/cases/gotoolchain.py25
-rw-r--r--meta/lib/oeqa/selftest/cases/image_typedep.py10
-rw-r--r--meta/lib/oeqa/selftest/cases/imagefeatures.py108
-rw-r--r--meta/lib/oeqa/selftest/cases/incompatible_lic.py161
-rw-r--r--meta/lib/oeqa/selftest/cases/kerneldevelopment.py67
-rw-r--r--meta/lib/oeqa/selftest/cases/layerappend.py16
-rw-r--r--meta/lib/oeqa/selftest/cases/liboe.py8
-rw-r--r--meta/lib/oeqa/selftest/cases/lic_checksum.py8
-rw-r--r--meta/lib/oeqa/selftest/cases/manifest.py14
-rw-r--r--meta/lib/oeqa/selftest/cases/meta_ide.py14
-rw-r--r--meta/lib/oeqa/selftest/cases/multiconfig.py72
-rw-r--r--meta/lib/oeqa/selftest/cases/newlib.py11
-rw-r--r--meta/lib/oeqa/selftest/cases/oelib/buildhistory.py56
-rw-r--r--meta/lib/oeqa/selftest/cases/oelib/elf.py6
-rw-r--r--meta/lib/oeqa/selftest/cases/oelib/license.py26
-rw-r--r--meta/lib/oeqa/selftest/cases/oelib/path.py4
-rw-r--r--meta/lib/oeqa/selftest/cases/oelib/types.py4
-rw-r--r--meta/lib/oeqa/selftest/cases/oelib/utils.py7
-rw-r--r--meta/lib/oeqa/selftest/cases/oescripts.py163
-rw-r--r--meta/lib/oeqa/selftest/cases/overlayfs.py423
-rw-r--r--meta/lib/oeqa/selftest/cases/package.py41
-rw-r--r--meta/lib/oeqa/selftest/cases/pkgdata.py19
-rw-r--r--meta/lib/oeqa/selftest/cases/prservice.py26
-rw-r--r--meta/lib/oeqa/selftest/cases/pseudo.py27
-rw-r--r--meta/lib/oeqa/selftest/cases/recipetool.py386
-rw-r--r--meta/lib/oeqa/selftest/cases/recipeutils.py13
-rw-r--r--meta/lib/oeqa/selftest/cases/reproducible.py316
-rw-r--r--meta/lib/oeqa/selftest/cases/resulttooltests.py98
-rw-r--r--meta/lib/oeqa/selftest/cases/runcmd.py50
-rw-r--r--meta/lib/oeqa/selftest/cases/runqemu.py26
-rw-r--r--meta/lib/oeqa/selftest/cases/runtime_test.py301
-rw-r--r--meta/lib/oeqa/selftest/cases/selftest.py6
-rw-r--r--meta/lib/oeqa/selftest/cases/signing.py49
-rw-r--r--meta/lib/oeqa/selftest/cases/sstate.py8
-rw-r--r--meta/lib/oeqa/selftest/cases/sstatetests.py203
-rw-r--r--meta/lib/oeqa/selftest/cases/sysroot.py37
-rw-r--r--meta/lib/oeqa/selftest/cases/tinfoil.py43
-rw-r--r--meta/lib/oeqa/selftest/cases/wic.py755
-rw-r--r--meta/lib/oeqa/selftest/context.py179
60 files changed, 5295 insertions, 922 deletions
diff --git a/meta/lib/oeqa/selftest/case.py b/meta/lib/oeqa/selftest/case.py
index 9c08d595ef..dcad4f76ec 100644
--- a/meta/lib/oeqa/selftest/case.py
+++ b/meta/lib/oeqa/selftest/case.py
@@ -1,9 +1,11 @@
+#
# Copyright (C) 2013-2017 Intel Corporation
-# Released under the MIT license (see COPYING.MIT)
+#
+# SPDX-License-Identifier: MIT
+#
import sys
import os
-import shutil
import glob
import errno
from unittest.util import safe_repr
@@ -27,9 +29,7 @@ class OESelftestTestCase(OETestCase):
cls.builddir = cls.tc.config_paths['builddir']
cls.localconf_path = cls.tc.config_paths['localconf']
- cls.localconf_backup = cls.tc.config_paths['localconf_class_backup']
cls.local_bblayers_path = cls.tc.config_paths['bblayers']
- cls.local_bblayers_backup = cls.tc.config_paths['bblayers_class_backup']
cls.testinc_path = os.path.join(cls.tc.config_paths['builddir'],
"conf/selftest.inc")
@@ -40,8 +40,7 @@ class OESelftestTestCase(OETestCase):
cls._track_for_cleanup = [
cls.testinc_path, cls.testinc_bblayers_path,
- cls.machineinc_path, cls.localconf_backup,
- cls.local_bblayers_backup]
+ cls.machineinc_path]
cls.add_include()
@@ -99,30 +98,6 @@ class OESelftestTestCase(OETestCase):
def setUp(self):
super(OESelftestTestCase, self).setUp()
os.chdir(self.builddir)
- # Check if local.conf or bblayers.conf files backup exists
- # from a previous failed test and restore them
- if os.path.isfile(self.localconf_backup) or os.path.isfile(
- self.local_bblayers_backup):
- self.logger.debug("\
-Found a local.conf and/or bblayers.conf backup from a previously aborted test.\
-Restoring these files now, but tests should be re-executed from a clean environment\
-to ensure accurate results.")
- try:
- shutil.copyfile(self.localconf_backup, self.localconf_path)
- except OSError as e:
- if e.errno != errno.ENOENT:
- raise
- try:
- shutil.copyfile(self.local_bblayers_backup,
- self.local_bblayers_path)
- except OSError as e:
- if e.errno != errno.ENOENT:
- raise
- else:
- # backup local.conf and bblayers.conf
- shutil.copyfile(self.localconf_path, self.localconf_backup)
- shutil.copyfile(self.local_bblayers_path, self.local_bblayers_backup)
- self.logger.debug("Creating local.conf and bblayers.conf backups.")
# we don't know what the previous test left around in config or inc files
# if it failed so we need a fresh start
try:
@@ -190,13 +165,20 @@ to ensure accurate results.")
self.logger.debug("Adding path '%s' to be cleaned up when test is over" % path)
self._track_for_cleanup.append(path)
- def write_config(self, data):
- """Write to <builddir>/conf/selftest.inc"""
+ def write_config(self, data, multiconfig=None):
+ """Write to config file"""
+ if multiconfig:
+ multiconfigdir = "%s/conf/multiconfig" % self.builddir
+ os.makedirs(multiconfigdir, exist_ok=True)
+ dest_path = '%s/%s.conf' % (multiconfigdir, multiconfig)
+ self.track_for_cleanup(dest_path)
+ else:
+ dest_path = self.testinc_path
- self.logger.debug("Writing to: %s\n%s\n" % (self.testinc_path, data))
- ftools.write_file(self.testinc_path, data)
+ self.logger.debug("Writing to: %s\n%s\n" % (dest_path, data))
+ ftools.write_file(dest_path, data)
- if self.tc.custommachine and 'MACHINE' in data:
+ if not multiconfig and self.tc.custommachine and 'MACHINE' in data:
machine = get_bb_var('MACHINE')
self.logger.warning('MACHINE overridden: %s' % machine)
diff --git a/meta/lib/oeqa/selftest/cases/_sstatetests_noauto.py b/meta/lib/oeqa/selftest/cases/_sstatetests_noauto.py
index 0e5896234c..7ac03f0cec 100644
--- a/meta/lib/oeqa/selftest/cases/_sstatetests_noauto.py
+++ b/meta/lib/oeqa/selftest/cases/_sstatetests_noauto.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import shutil
@@ -86,7 +90,7 @@ class RebuildFromSState(SStateBase):
self.assertFalse(failed_cleansstate, msg="The following recipes have failed cleansstate(all others have passed both cleansstate and rebuild from sstate tests): %s" % ' '.join(map(str, failed_cleansstate)))
def test_sstate_relocation(self):
- self.run_test_sstate_rebuild(['core-image-sato-sdk'], relocate=True, rebuild_dependencies=True)
+ self.run_test_sstate_rebuild(['core-image-weston-sdk'], relocate=True, rebuild_dependencies=True)
def test_sstate_rebuild(self):
- self.run_test_sstate_rebuild(['core-image-sato-sdk'], relocate=False, rebuild_dependencies=True)
+ self.run_test_sstate_rebuild(['core-image-weston-sdk'], relocate=False, rebuild_dependencies=True)
diff --git a/meta/lib/oeqa/selftest/cases/archiver.py b/meta/lib/oeqa/selftest/cases/archiver.py
index 0a6d4e325f..75195241b7 100644
--- a/meta/lib/oeqa/selftest/cases/archiver.py
+++ b/meta/lib/oeqa/selftest/cases/archiver.py
@@ -1,12 +1,14 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import glob
from oeqa.utils.commands import bitbake, get_bb_vars
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.core.decorator.oeid import OETestID
class Archiver(OESelftestTestCase):
- @OETestID(1345)
def test_archiver_allows_to_filter_on_recipe_name(self):
"""
Summary: The archiver should offer the possibility to filter on the recipe. (#6929)
@@ -17,8 +19,8 @@ class Archiver(OESelftestTestCase):
AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com>
"""
- include_recipe = 'busybox'
- exclude_recipe = 'zlib'
+ include_recipe = 'selftest-ed'
+ exclude_recipe = 'initscripts'
features = 'INHERIT += "archiver"\n'
features += 'ARCHIVER_MODE[src] = "original"\n'
@@ -33,14 +35,13 @@ class Archiver(OESelftestTestCase):
src_path = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['TARGET_SYS'])
# Check that include_recipe was included
- included_present = len(glob.glob(src_path + '/%s-*' % include_recipe))
+ included_present = len(glob.glob(src_path + '/%s-*/*' % include_recipe))
self.assertTrue(included_present, 'Recipe %s was not included.' % include_recipe)
# Check that exclude_recipe was excluded
- excluded_present = len(glob.glob(src_path + '/%s-*' % exclude_recipe))
+ excluded_present = len(glob.glob(src_path + '/%s-*/*' % exclude_recipe))
self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % exclude_recipe)
- @OETestID(1900)
def test_archiver_filters_by_type(self):
"""
Summary: The archiver is documented to filter on the recipe type.
@@ -50,8 +51,8 @@ class Archiver(OESelftestTestCase):
Author: André Draszik <adraszik@tycoint.com>
"""
- target_recipe = 'initscripts'
- native_recipe = 'zlib-native'
+ target_recipe = 'selftest-ed'
+ native_recipe = 'selftest-ed-native'
features = 'INHERIT += "archiver"\n'
features += 'ARCHIVER_MODE[src] = "original"\n'
@@ -66,14 +67,13 @@ class Archiver(OESelftestTestCase):
src_path_native = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['BUILD_SYS'])
# Check that target_recipe was included
- included_present = len(glob.glob(src_path_target + '/%s-*' % target_recipe))
+ included_present = len(glob.glob(src_path_target + '/%s-*/*' % target_recipe))
self.assertTrue(included_present, 'Recipe %s was not included.' % target_recipe)
# Check that native_recipe was excluded
- excluded_present = len(glob.glob(src_path_native + '/%s-*' % native_recipe))
+ excluded_present = len(glob.glob(src_path_native + '/%s-*/*' % native_recipe))
self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % native_recipe)
- @OETestID(1901)
def test_archiver_filters_by_type_and_name(self):
"""
Summary: Test that the archiver archives by recipe type, taking the
@@ -86,8 +86,8 @@ class Archiver(OESelftestTestCase):
Author: André Draszik <adraszik@tycoint.com>
"""
- target_recipes = [ 'initscripts', 'zlib' ]
- native_recipes = [ 'update-rc.d-native', 'zlib-native' ]
+ target_recipes = [ 'initscripts', 'selftest-ed' ]
+ native_recipes = [ 'update-rc.d-native', 'selftest-ed-native' ]
features = 'INHERIT += "archiver"\n'
features += 'ARCHIVER_MODE[src] = "original"\n'
@@ -104,17 +104,17 @@ class Archiver(OESelftestTestCase):
src_path_native = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['BUILD_SYS'])
# Check that target_recipe[0] and native_recipes[1] were included
- included_present = len(glob.glob(src_path_target + '/%s-*' % target_recipes[0]))
+ included_present = len(glob.glob(src_path_target + '/%s-*/*' % target_recipes[0]))
self.assertTrue(included_present, 'Recipe %s was not included.' % target_recipes[0])
- included_present = len(glob.glob(src_path_native + '/%s-*' % native_recipes[1]))
+ included_present = len(glob.glob(src_path_native + '/%s-*/*' % native_recipes[1]))
self.assertTrue(included_present, 'Recipe %s was not included.' % native_recipes[1])
# Check that native_recipes[0] and target_recipes[1] were excluded
- excluded_present = len(glob.glob(src_path_native + '/%s-*' % native_recipes[0]))
+ excluded_present = len(glob.glob(src_path_native + '/%s-*/*' % native_recipes[0]))
self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % native_recipes[0])
- excluded_present = len(glob.glob(src_path_target + '/%s-*' % target_recipes[1]))
+ excluded_present = len(glob.glob(src_path_target + '/%s-*/*' % target_recipes[1]))
self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % target_recipes[1])
@@ -126,6 +126,186 @@ class Archiver(OESelftestTestCase):
features = 'INHERIT += "archiver"\n'
features += 'ARCHIVER_MODE[srpm] = "1"\n'
+ features += 'PACKAGE_CLASSES = "package_rpm"\n'
self.write_config(features)
- bitbake('-n core-image-sato')
+ bitbake('-n selftest-nopackages selftest-ed')
+
+ def _test_archiver_mode(self, mode, target_file_name, extra_config=None):
+ target = 'selftest-ed-native'
+
+ features = 'INHERIT += "archiver"\n'
+ features += 'ARCHIVER_MODE[src] = "%s"\n' % (mode)
+ if extra_config:
+ features += extra_config
+ self.write_config(features)
+
+ bitbake('-c clean %s' % (target))
+ bitbake('-c deploy_archives %s' % (target))
+
+ bb_vars = get_bb_vars(['DEPLOY_DIR_SRC', 'BUILD_SYS'])
+ glob_str = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['BUILD_SYS'], '%s-*' % (target))
+ glob_result = glob.glob(glob_str)
+ self.assertTrue(glob_result, 'Missing archiver directory for %s' % (target))
+
+ archive_path = os.path.join(glob_result[0], target_file_name)
+ self.assertTrue(os.path.exists(archive_path), 'Missing archive file %s' % (target_file_name))
+
+ def test_archiver_mode_original(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[src] = "original"`.
+ """
+
+ self._test_archiver_mode('original', 'ed-1.14.1.tar.lz')
+
+ def test_archiver_mode_patched(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[src] = "patched"`.
+ """
+
+ 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.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.xz',
+ 'ARCHIVER_MODE[recipe] = "1"\n')
+
+ def test_archiver_mode_diff(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[diff] = "1"`.
+ Exclusions controlled by `ARCHIVER_MODE[diff-exclude]` are not yet tested.
+ """
+
+ self._test_archiver_mode('patched', 'selftest-ed-native-1.14.1-r0-diff.gz',
+ 'ARCHIVER_MODE[diff] = "1"\n')
+
+ def test_archiver_mode_dumpdata(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[dumpdata] = "1"`.
+ """
+
+ self._test_archiver_mode('patched', 'selftest-ed-native-1.14.1-r0-showdata.dump',
+ 'ARCHIVER_MODE[dumpdata] = "1"\n')
+
+ def test_archiver_mode_mirror(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[src] = "mirror"`.
+ """
+
+ self._test_archiver_mode('mirror', 'ed-1.14.1.tar.lz',
+ 'BB_GENERATE_MIRROR_TARBALLS = "1"\n')
+
+ def test_archiver_mode_mirror_excludes(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[src] = "mirror"` and
+ correctly excludes an archive when its URL matches
+ `ARCHIVER_MIRROR_EXCLUDE`.
+ """
+
+ target='selftest-ed'
+ target_file_name = 'ed-1.14.1.tar.lz'
+
+ features = 'INHERIT += "archiver"\n'
+ features += 'ARCHIVER_MODE[src] = "mirror"\n'
+ features += 'BB_GENERATE_MIRROR_TARBALLS = "1"\n'
+ features += 'ARCHIVER_MIRROR_EXCLUDE = "${GNU_MIRROR}"\n'
+ self.write_config(features)
+
+ bitbake('-c clean %s' % (target))
+ bitbake('-c deploy_archives %s' % (target))
+
+ bb_vars = get_bb_vars(['DEPLOY_DIR_SRC', 'TARGET_SYS'])
+ glob_str = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['TARGET_SYS'], '%s-*' % (target))
+ glob_result = glob.glob(glob_str)
+ self.assertTrue(glob_result, 'Missing archiver directory for %s' % (target))
+
+ archive_path = os.path.join(glob_result[0], target_file_name)
+ self.assertFalse(os.path.exists(archive_path), 'Failed to exclude archive file %s' % (target_file_name))
+
+ def test_archiver_mode_mirror_combined(self):
+ """
+ Test that the archiver works with `ARCHIVER_MODE[src] = "mirror"`
+ and `ARCHIVER_MODE[mirror] = "combined"`. Archives for multiple recipes
+ should all end up in the 'mirror' directory.
+ """
+
+ features = 'INHERIT += "archiver"\n'
+ features += 'ARCHIVER_MODE[src] = "mirror"\n'
+ features += 'ARCHIVER_MODE[mirror] = "combined"\n'
+ features += 'BB_GENERATE_MIRROR_TARBALLS = "1"\n'
+ features += 'COPYLEFT_LICENSE_INCLUDE = "*"\n'
+ self.write_config(features)
+
+ for target in ['selftest-ed', 'selftest-hardlink']:
+ bitbake('-c clean %s' % (target))
+ bitbake('-c deploy_archives %s' % (target))
+
+ bb_vars = get_bb_vars(['DEPLOY_DIR_SRC'])
+ for target_file_name in ['ed-1.14.1.tar.lz', 'hello.c']:
+ glob_str = os.path.join(bb_vars['DEPLOY_DIR_SRC'], 'mirror', target_file_name)
+ glob_result = glob.glob(glob_str)
+ self.assertTrue(glob_result, 'Missing archive file %s' % (target_file_name))
+
+ def test_archiver_mode_mirror_gitsm(self):
+ """
+ Test that the archiver correctly handles git submodules with
+ `ARCHIVER_MODE[src] = "mirror"`.
+ """
+ features = 'INHERIT += "archiver"\n'
+ features += 'ARCHIVER_MODE[src] = "mirror"\n'
+ features += 'ARCHIVER_MODE[mirror] = "combined"\n'
+ features += 'BB_GENERATE_MIRROR_TARBALLS = "1"\n'
+ features += 'COPYLEFT_LICENSE_INCLUDE = "*"\n'
+ self.write_config(features)
+
+ bitbake('-c clean git-submodule-test')
+ bitbake('-c deploy_archives -f git-submodule-test')
+
+ bb_vars = get_bb_vars(['DEPLOY_DIR_SRC'])
+ for target_file_name in [
+ 'git2_git.yoctoproject.org.git-submodule-test.tar.gz',
+ 'git2_git.yoctoproject.org.bitbake-gitsm-test1.tar.gz',
+ 'git2_git.yoctoproject.org.bitbake-gitsm-test2.tar.gz',
+ 'git2_git.openembedded.org.bitbake.tar.gz'
+ ]:
+ target_path = os.path.join(bb_vars['DEPLOY_DIR_SRC'], 'mirror', target_file_name)
+ self.assertTrue(os.path.exists(target_path))
+
+ def test_archiver_mode_mirror_gitsm_shallow(self):
+ """
+ Test that the archiver correctly handles git submodules with
+ `ARCHIVER_MODE[src] = "mirror"`.
+ """
+ features = 'INHERIT += "archiver"\n'
+ features += 'ARCHIVER_MODE[src] = "mirror"\n'
+ features += 'ARCHIVER_MODE[mirror] = "combined"\n'
+ features += 'BB_GENERATE_MIRROR_TARBALLS = "1"\n'
+ features += 'COPYLEFT_LICENSE_INCLUDE = "*"\n'
+ features += 'BB_GIT_SHALLOW = "1"\n'
+ features += 'BB_GENERATE_SHALLOW_TARBALLS = "1"\n'
+ features += 'DL_DIR = "${TOPDIR}/downloads-shallow"\n'
+ self.write_config(features)
+
+ bitbake('-c clean git-submodule-test')
+ bitbake('-c deploy_archives -f git-submodule-test')
+
+ bb_vars = get_bb_vars(['DEPLOY_DIR_SRC'])
+ for target_file_name in [
+ 'gitsmshallow_git.yoctoproject.org.git-submodule-test_a2885dd-1_master.tar.gz',
+ 'gitsmshallow_git.yoctoproject.org.bitbake-gitsm-test1_bare_120f4c7-1.tar.gz',
+ 'gitsmshallow_git.yoctoproject.org.bitbake-gitsm-test2_bare_f66699e-1.tar.gz',
+ 'gitsmshallow_git.openembedded.org.bitbake_bare_52a144a-1.tar.gz',
+ 'gitsmshallow_git.openembedded.org.bitbake_bare_c39b997-1.tar.gz'
+ ]:
+ target_path = os.path.join(bb_vars['DEPLOY_DIR_SRC'], 'mirror', target_file_name)
+ self.assertTrue(os.path.exists(target_path))
diff --git a/meta/lib/oeqa/selftest/cases/bblayers.py b/meta/lib/oeqa/selftest/cases/bblayers.py
index 447c54b7e6..7d74833f61 100644
--- a/meta/lib/oeqa/selftest/cases/bblayers.py
+++ b/meta/lib/oeqa/selftest/cases/bblayers.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
@@ -5,33 +9,32 @@ import oeqa.utils.ftools as ftools
from oeqa.utils.commands import runCmd, get_bb_var, get_bb_vars
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.core.decorator.oeid import OETestID
class BitbakeLayers(OESelftestTestCase):
- @OETestID(756)
+ def test_bitbakelayers_layerindexshowdepends(self):
+ result = runCmd('bitbake-layers layerindex-show-depends meta-poky')
+ find_in_contents = re.search("openembedded-core", result.output)
+ self.assertTrue(find_in_contents, msg = "openembedded-core should have been listed at this step. bitbake-layers layerindex-show-depends meta-poky output: %s" % result.output)
+
def test_bitbakelayers_showcrossdepends(self):
result = runCmd('bitbake-layers show-cross-depends')
- self.assertTrue('aspell' in result.output, msg = "No dependencies were shown. bitbake-layers show-cross-depends output: %s" % result.output)
+ self.assertIn('aspell', result.output)
- @OETestID(83)
def test_bitbakelayers_showlayers(self):
result = runCmd('bitbake-layers show-layers')
- self.assertTrue('meta-selftest' in result.output, msg = "No layers were shown. bitbake-layers show-layers output: %s" % result.output)
+ self.assertIn('meta-selftest', result.output)
- @OETestID(93)
def test_bitbakelayers_showappends(self):
recipe = "xcursor-transparent-theme"
bb_file = self.get_recipe_basename(recipe)
result = runCmd('bitbake-layers show-appends')
- self.assertTrue(bb_file in result.output, msg="%s file was not recognised. bitbake-layers show-appends output: %s" % (bb_file, result.output))
+ self.assertIn(bb_file, result.output)
- @OETestID(90)
def test_bitbakelayers_showoverlayed(self):
result = runCmd('bitbake-layers show-overlayed')
- self.assertTrue('aspell' in result.output, msg="aspell overlayed recipe was not recognised bitbake-layers show-overlayed %s" % result.output)
+ self.assertIn('aspell', result.output)
- @OETestID(95)
def test_bitbakelayers_flatten(self):
recipe = "xcursor-transparent-theme"
recipe_path = "recipes-graphics/xcursor-transparent-theme"
@@ -46,7 +49,6 @@ class BitbakeLayers(OESelftestTestCase):
find_in_contents = re.search("##### bbappended from meta-selftest #####\n(.*\n)*include test_recipe.inc", contents)
self.assertTrue(find_in_contents, msg = "Flattening layers did not work. bitbake-layers flatten output: %s" % result.output)
- @OETestID(1195)
def test_bitbakelayers_add_remove(self):
test_layer = os.path.join(get_bb_var('COREBASE'), 'meta-skeleton')
result = runCmd('bitbake-layers show-layers')
@@ -64,7 +66,6 @@ class BitbakeLayers(OESelftestTestCase):
result = runCmd('bitbake-layers show-layers')
self.assertNotIn('meta-skeleton', result.output, msg = "meta-skeleton should have been removed at this step. bitbake-layers show-layers output: %s" % result.output)
- @OETestID(1384)
def test_bitbakelayers_showrecipes(self):
result = runCmd('bitbake-layers show-recipes')
self.assertIn('aspell:', result.output)
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 005fdd0964..cfac7afcf4 100644
--- a/meta/lib/oeqa/selftest/cases/bbtests.py
+++ b/meta/lib/oeqa/selftest/cases/bbtests.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
@@ -5,7 +9,6 @@ import oeqa.utils.ftools as ftools
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.core.decorator.oeid import OETestID
class BitbakeTests(OESelftestTestCase):
@@ -14,13 +17,11 @@ class BitbakeTests(OESelftestTestCase):
if line in l:
return l
- @OETestID(789)
# Test bitbake can run from the <builddir>/conf directory
def test_run_bitbake_from_dir_1(self):
os.chdir(os.path.join(self.builddir, 'conf'))
self.assertEqual(bitbake('-e').status, 0, msg = "bitbake couldn't run from \"conf\" dir")
- @OETestID(790)
# Test bitbake can run from the <builddir>'s parent directory
def test_run_bitbake_from_dir_2(self):
my_env = os.environ.copy()
@@ -36,17 +37,15 @@ class BitbakeTests(OESelftestTestCase):
self.assertEqual(bitbake('-e', env=my_env).status, 0, msg = "bitbake couldn't run from /tmp/")
- @OETestID(806)
def test_event_handler(self):
self.write_config("INHERIT += \"test_events\"")
result = bitbake('m4-native')
- find_build_started = re.search("NOTE: Test for bb\.event\.BuildStarted(\n.*)*NOTE: Executing RunQueue Tasks", result.output)
- find_build_completed = re.search("Tasks Summary:.*(\n.*)*NOTE: Test for bb\.event\.BuildCompleted", result.output)
+ find_build_started = re.search(r"NOTE: Test for bb\.event\.BuildStarted(\n.*)*NOTE: Executing.*Tasks", result.output)
+ find_build_completed = re.search(r"Tasks Summary:.*(\n.*)*NOTE: Test for bb\.event\.BuildCompleted", result.output)
self.assertTrue(find_build_started, msg = "Match failed in:\n%s" % result.output)
self.assertTrue(find_build_completed, msg = "Match failed in:\n%s" % result.output)
- self.assertFalse('Test for bb.event.InvalidEvent' in result.output, msg = "\"Test for bb.event.InvalidEvent\" message found during bitbake process. bitbake output: %s" % result.output)
+ self.assertNotIn('Test for bb.event.InvalidEvent', result.output)
- @OETestID(103)
def test_local_sstate(self):
bitbake('m4-native')
bitbake('m4-native -cclean')
@@ -54,44 +53,45 @@ class BitbakeTests(OESelftestTestCase):
find_setscene = re.search("m4-native.*do_.*_setscene", result.output)
self.assertTrue(find_setscene, msg = "No \"m4-native.*do_.*_setscene\" message found during bitbake m4-native. bitbake output: %s" % result.output )
- @OETestID(105)
def test_bitbake_invalid_recipe(self):
result = bitbake('-b asdf', ignore_status=True)
self.assertTrue("ERROR: Unable to find any recipe file matching 'asdf'" in result.output, msg = "Though asdf recipe doesn't exist, bitbake didn't output any err. message. bitbake output: %s" % result.output)
- @OETestID(107)
def test_bitbake_invalid_target(self):
result = bitbake('asdf', ignore_status=True)
- self.assertTrue("ERROR: Nothing PROVIDES 'asdf'" in result.output, msg = "Though no 'asdf' target exists, bitbake didn't output any err. message. bitbake output: %s" % result.output)
+ self.assertIn("ERROR: Nothing PROVIDES 'asdf'", result.output)
- @OETestID(106)
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)
- @OETestID(108)
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')
- line = self.getline(result, "Function failed: patch_do_patch")
- self.assertTrue(line and line.startswith("ERROR:"), msg = "Incorrectly formed patch application didn't fail. bitbake output: %s" % result.output)
+ found = False
+ for l in result.output.split('\n'):
+ if l.startswith("ERROR:") and "failed" in l and "do_patch" in l:
+ found = l
+ self.assertTrue(found and found.startswith("ERROR:"), msg = "Incorrectly formed patch application didn't fail. bitbake output: %s" % result.output)
- @OETestID(1354)
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']
man_dir = bb_vars['mandir']
+ self.write_config("PACKAGE_CLASSES = \"package_rpm\"")
bitbake('-c clean %s' % test_recipe)
bitbake('-c package -f %s' % test_recipe)
@@ -108,7 +108,6 @@ class BitbakeTests(OESelftestTestCase):
ret = bitbake(test_recipe)
self.assertIn('task do_package_write_rpm:', ret.output, 'Task do_package_write_rpm did not re-executed.')
- @OETestID(163)
def test_force_task_2(self):
# test 2 from bug 5875
test_recipe = 'zlib'
@@ -121,15 +120,14 @@ class BitbakeTests(OESelftestTestCase):
for task in look_for_tasks:
self.assertIn(task, result.output, msg="Couldn't find %s task.")
- @OETestID(167)
def test_bitbake_g(self):
- result = bitbake('-g core-image-minimal')
- for f in ['pn-buildlist', 'recipe-depends.dot', 'task-depends.dot']:
+ recipe = 'base-files'
+ result = bitbake('-g %s' % recipe)
+ for f in ['pn-buildlist', 'task-depends.dot']:
self.addCleanup(os.remove, f)
self.assertTrue('Task dependencies saved to \'task-depends.dot\'' in result.output, msg = "No task dependency \"task-depends.dot\" file was generated for the given task target. bitbake output: %s" % result.output)
- self.assertTrue('busybox' in ftools.read_file(os.path.join(self.builddir, 'task-depends.dot')), msg = "No \"busybox\" dependency found in task-depends.dot file.")
+ self.assertIn(recipe, ftools.read_file(os.path.join(self.builddir, 'task-depends.dot')))
- @OETestID(899)
def test_image_manifest(self):
bitbake('core-image-minimal')
bb_vars = get_bb_vars(["DEPLOY_DIR_IMAGE", "IMAGE_LINK_NAME"], "core-image-minimal")
@@ -138,13 +136,12 @@ class BitbakeTests(OESelftestTestCase):
manifest = os.path.join(deploydir, imagename + ".manifest")
self.assertTrue(os.path.islink(manifest), msg="No manifest file created for image. It should have been created in %s" % manifest)
- @OETestID(168)
def test_invalid_recipe_src_uri(self):
data = 'SRC_URI = "file://invalid"'
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"))
@@ -153,13 +150,8 @@ INHERIT_remove = \"report-error\"
bitbake('-ccleanall man-db')
self.delete_recipeinc('man-db')
self.assertEqual(result.status, 1, msg="Command succeded when it should have failed. bitbake output: %s" % result.output)
- self.assertTrue('Fetcher failure: Unable to find file file://invalid anywhere. The paths that were searched were:' in result.output, msg = "\"invalid\" file \
-doesn't exist, yet no error message encountered. bitbake output: %s" % 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)
+ self.assertIn('Fetcher failure: Unable to find file file://invalid anywhere. The paths that were searched were:', result.output)
- @OETestID(171)
def test_rename_downloaded_file(self):
# TODO unique dldir instead of using cleanall
# TODO: need to set sstatedir?
@@ -168,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')
@@ -177,58 +169,50 @@ SSTATE_DIR = \"${TOPDIR}/download-selftest\"
self.assertTrue(os.path.isfile(os.path.join(dl_dir, 'test-aspell.tar.gz')), msg = "File rename failed. No corresponding test-aspell.tar.gz file found under %s" % dl_dir)
self.assertTrue(os.path.isfile(os.path.join(dl_dir, 'test-aspell.tar.gz.done')), "File rename failed. No corresponding test-aspell.tar.gz.done file found under %s" % dl_dir)
- @OETestID(1028)
def test_environment(self):
self.write_config("TEST_ENV=\"localconf\"")
result = runCmd('bitbake -e | grep TEST_ENV=')
- self.assertTrue('localconf' in result.output, msg = "bitbake didn't report any value for TEST_ENV variable. To test, run 'bitbake -e | grep TEST_ENV='")
+ self.assertIn('localconf', result.output)
- @OETestID(1029)
def test_dry_run(self):
result = runCmd('bitbake -n m4-native')
self.assertEqual(0, result.status, "bitbake dry run didn't run as expected. %s" % result.output)
- @OETestID(1030)
def test_just_parse(self):
result = runCmd('bitbake -p')
self.assertEqual(0, result.status, "errors encountered when parsing recipes. %s" % result.output)
- @OETestID(1031)
def test_version(self):
result = runCmd('bitbake -s | grep wget')
- find = re.search("wget *:([0-9a-zA-Z\.\-]+)", result.output)
+ find = re.search(r"wget *:([0-9a-zA-Z\.\-]+)", result.output)
self.assertTrue(find, "No version returned for searched recipe. bitbake output: %s" % result.output)
- @OETestID(1032)
def test_prefile(self):
preconf = os.path.join(self.builddir, 'conf/prefile.conf')
self.track_for_cleanup(preconf)
ftools.write_file(preconf ,"TEST_PREFILE=\"prefile\"")
result = runCmd('bitbake -r conf/prefile.conf -e | grep TEST_PREFILE=')
- self.assertTrue('prefile' in result.output, "Preconfigure file \"prefile.conf\"was not taken into consideration. ")
+ self.assertIn('prefile', result.output)
self.write_config("TEST_PREFILE=\"localconf\"")
result = runCmd('bitbake -r conf/prefile.conf -e | grep TEST_PREFILE=')
- self.assertTrue('localconf' in result.output, "Preconfigure file \"prefile.conf\"was not taken into consideration.")
+ self.assertIn('localconf', result.output)
- @OETestID(1033)
def test_postfile(self):
postconf = os.path.join(self.builddir, 'conf/postfile.conf')
self.track_for_cleanup(postconf)
ftools.write_file(postconf , "TEST_POSTFILE=\"postfile\"")
self.write_config("TEST_POSTFILE=\"localconf\"")
result = runCmd('bitbake -R conf/postfile.conf -e | grep TEST_POSTFILE=')
- self.assertTrue('postfile' in result.output, "Postconfigure file \"postfile.conf\"was not taken into consideration.")
+ self.assertIn('postfile', result.output)
- @OETestID(1034)
def test_checkuri(self):
result = runCmd('bitbake -c checkuri m4')
self.assertEqual(0, result.status, msg = "\"checkuri\" task was not executed. bitbake output: %s" % result.output)
- @OETestID(1035)
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" )
@@ -239,16 +223,14 @@ INHERIT_remove = \"report-error\"
continuepos = result.output.find('NOTE: recipe xcursor-transparent-theme-%s: task do_unpack: Started' % manver.group(1))
self.assertLess(errorpos,continuepos, msg = "bitbake didn't pass do_fail_task. bitbake output: %s" % result.output)
- @OETestID(1119)
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')))
- @OETestID(1422)
def test_setscene_only(self):
""" Bitbake option to restore from sstate only within a build (i.e. execute no real tasks, only setscene)"""
test_recipe = 'ed'
@@ -263,7 +245,36 @@ INHERIT_remove = \"report-error\"
self.assertIn('_setscene', task, 'A task different from _setscene ran: %s.\n'
'Executed tasks were: %s' % (task, str(tasks)))
- @OETestID(1425)
+ def test_skip_setscene(self):
+ test_recipe = 'ed'
+
+ bitbake(test_recipe)
+ bitbake('-c clean %s' % test_recipe)
+
+ ret = bitbake('--setscene-only %s' % test_recipe)
+ tasks = re.findall(r'task\s+(do_\S+):', ret.output)
+
+ for task in tasks:
+ self.assertIn('_setscene', task, 'A task different from _setscene ran: %s.\n'
+ 'Executed tasks were: %s' % (task, str(tasks)))
+
+ # Run without setscene. Should do nothing
+ ret = bitbake('--skip-setscene %s' % test_recipe)
+ tasks = re.findall(r'task\s+(do_\S+):', ret.output)
+
+ self.assertFalse(tasks, 'Tasks %s ran when they should not have' % (str(tasks)))
+
+ # Clean (leave sstate cache) and run with --skip-setscene. No setscene
+ # tasks should run
+ bitbake('-c clean %s' % test_recipe)
+
+ ret = bitbake('--skip-setscene %s' % test_recipe)
+ tasks = re.findall(r'task\s+(do_\S+):', ret.output)
+
+ for task in tasks:
+ self.assertNotIn('_setscene', task, 'A _setscene task ran: %s.\n'
+ 'Executed tasks were: %s' % (task, str(tasks)))
+
def test_bbappend_order(self):
""" Bitbake should bbappend to recipe in a predictable order """
test_recipe = 'ed'
@@ -286,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/binutils.py b/meta/lib/oeqa/selftest/cases/binutils.py
new file mode 100644
index 0000000000..821f52f5a8
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/binutils.py
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: MIT
+import os
+import sys
+import re
+import logging
+from oeqa.core.decorator import OETestTag
+from oeqa.core.case import OEPTestResultTestCase
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars
+
+def parse_values(content):
+ for i in content:
+ for v in ["PASS", "FAIL", "XPASS", "XFAIL", "UNRESOLVED", "UNSUPPORTED", "UNTESTED", "ERROR", "WARNING"]:
+ if i.startswith(v + ": "):
+ yield i[len(v) + 2:].strip(), v
+ break
+
+@OETestTag("toolchain-user", "toolchain-system")
+class BinutilsCrossSelfTest(OESelftestTestCase, OEPTestResultTestCase):
+ def test_binutils(self):
+ self.run_binutils("binutils")
+
+ def test_gas(self):
+ self.run_binutils("gas")
+
+ def test_ld(self):
+ self.run_binutils("ld")
+
+ def run_binutils(self, suite):
+ features = []
+ features.append('CHECK_TARGETS = "{0}"'.format(suite))
+ self.write_config("\n".join(features))
+
+ recipe = "binutils-cross-testsuite"
+ bb_vars = get_bb_vars(["B", "TARGET_SYS", "T"], recipe)
+ builddir, target_sys, tdir = bb_vars["B"], bb_vars["TARGET_SYS"], bb_vars["T"]
+
+ bitbake("{0} -c check".format(recipe))
+
+ sumspath = os.path.join(builddir, suite, "{0}.sum".format(suite))
+ if not os.path.exists(sumspath):
+ sumspath = os.path.join(builddir, suite, "testsuite", "{0}.sum".format(suite))
+ logpath = os.path.splitext(sumspath)[0] + ".log"
+
+ ptestsuite = "binutils-{}".format(suite) if suite != "binutils" else suite
+ self.ptest_section(ptestsuite, logfile = logpath)
+ with open(sumspath, "r") as f:
+ for test, result in parse_values(f):
+ self.ptest_result(ptestsuite, test, result)
+
diff --git a/meta/lib/oeqa/selftest/cases/buildhistory.py b/meta/lib/oeqa/selftest/cases/buildhistory.py
index 06792d9146..d865da6252 100644
--- a/meta/lib/oeqa/selftest/cases/buildhistory.py
+++ b/meta/lib/oeqa/selftest/cases/buildhistory.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
import datetime
diff --git a/meta/lib/oeqa/selftest/cases/buildoptions.py b/meta/lib/oeqa/selftest/cases/buildoptions.py
index 6a18eb8366..bfe613b847 100644
--- a/meta/lib/oeqa/selftest/cases/buildoptions.py
+++ b/meta/lib/oeqa/selftest/cases/buildoptions.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
import glob as g
@@ -7,11 +11,9 @@ from oeqa.selftest.case import OESelftestTestCase
from oeqa.selftest.cases.buildhistory import BuildhistoryBase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
import oeqa.utils.ftools as ftools
-from oeqa.core.decorator.oeid import OETestID
class ImageOptionsTests(OESelftestTestCase):
- @OETestID(761)
def test_incremental_image_generation(self):
image_pkgtype = get_bb_var("IMAGE_PKGTYPE")
if image_pkgtype != 'rpm':
@@ -30,43 +32,41 @@ class ImageOptionsTests(OESelftestTestCase):
incremental_removed = re.search(r"Erasing\s*:\s*packagegroup-core-ssh-openssh", log_data_removed)
self.assertTrue(incremental_removed, msg = "Match failed in:\n%s" % log_data_removed)
- @OETestID(286)
def test_ccache_tool(self):
bitbake("ccache-native")
bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'ccache-native')
p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "ccache"
self.assertTrue(os.path.isfile(p), msg = "No ccache found (%s)" % p)
self.write_config('INHERIT += "ccache"')
- self.add_command_to_tearDown('bitbake -c clean m4-native')
- bitbake("m4-native -c clean")
- bitbake("m4-native -f -c compile")
- log_compile = os.path.join(get_bb_var("WORKDIR","m4-native"), "temp/log.do_compile")
+ recipe = "libgcc-initial"
+ self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
+ bitbake("%s -c clean" % recipe)
+ bitbake("%s -f -c compile" % recipe)
+ log_compile = os.path.join(get_bb_var("WORKDIR", recipe), "temp/log.do_compile")
with open(log_compile, "r") as f:
loglines = "".join(f.readlines())
- self.assertIn("ccache", loglines, msg="No match for ccache in m4-native log.do_compile. For further details: %s" % log_compile)
+ self.assertIn("ccache", loglines, msg="No match for ccache in %s log.do_compile. For further details: %s" % (recipe , log_compile))
- @OETestID(1435)
def test_read_only_image(self):
distro_features = get_bb_var('DISTRO_FEATURES')
if not ('x11' in distro_features and 'opengl' in distro_features):
- self.skipTest('core-image-sato requires x11 and opengl in distro features')
+ self.skipTest('core-image-sato/weston requires x11 and opengl in distro features')
self.write_config('IMAGE_FEATURES += "read-only-rootfs"')
- bitbake("core-image-sato")
+ bitbake("core-image-sato core-image-weston")
# do_image will fail if there are any pending postinsts
class DiskMonTest(OESelftestTestCase):
- @OETestID(277)
def test_stoptask_behavior(self):
- self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"')
+ self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
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"')
+ 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"')
+ self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
res = bitbake("delay -c delay")
self.assertTrue('WARNING: The free space' in res.output, msg = "A warning should have been displayed for disk monitor is set to WARN: %s" %res.output)
@@ -76,12 +76,11 @@ class SanityOptionsTest(OESelftestTestCase):
if line in l:
return l
- @OETestID(927)
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')
@@ -91,14 +90,13 @@ 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.")
self.assertTrue(line and line.startswith("WARNING:"), msg=res.output)
- @OETestID(1421)
def test_layer_without_git_dir(self):
"""
Summary: Test that layer git revisions are displayed and do not fail without git repository
@@ -140,20 +138,41 @@ class SanityOptionsTest(OESelftestTestCase):
class BuildhistoryTests(BuildhistoryBase):
- @OETestID(293)
def test_buildhistory_basic(self):
self.run_buildhistory_operation('xcursor-transparent-theme')
self.assertTrue(os.path.isdir(get_bb_var('BUILDHISTORY_DIR')), "buildhistory dir was not created.")
- @OETestID(294)
def test_buildhistory_buildtime_pr_backwards(self):
target = 'xcursor-transparent-theme'
- error = "ERROR:.*QA Issue: Package version for package %s went backwards which would break package feeds from (.*-r1.* to .*-r0.*)" % target
+ error = "ERROR:.*QA Issue: Package version for package %s went backwards which would break package feeds \(from .*-r1.* to .*-r0.*\)" % target
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):
- @OETestID(926)
def test_arch_work_dir_and_export_source(self):
"""
Test for archiving the work directory and exporting the source files.
@@ -164,21 +183,18 @@ 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):
"""
- Test whether we can enable and build fortran and its supporting libraries
+ Test that Fortran works by building a Hello, World binary.
"""
- features = 'FORTRAN_forcevariable = ",fortran"\n'
- features += 'RUNTIMETARGET_append_pn-gcc-runtime = " libquadmath"\n'
+ features = 'FORTRAN:forcevariable = ",fortran"\n'
self.write_config(features)
-
- bitbake('gcc-runtime libgfortran')
+ bitbake('fortran-helloworld')
class SourceMirroring(OESelftestTestCase):
# Can we download everything from the Yocto Sources Mirror over http only
@@ -205,3 +221,9 @@ PREMIRRORS = "\\
bitbake("world --runall fetch")
+
+class Poisoning(OESelftestTestCase):
+ def test_poisoning(self):
+ res = bitbake("poison", ignore_status=True)
+ self.assertNotEqual(res.status, 0)
+ self.assertTrue("is unsafe for cross-compilation" in res.output)
diff --git a/meta/lib/oeqa/selftest/cases/containerimage.py b/meta/lib/oeqa/selftest/cases/containerimage.py
index 8deaae75d8..e0aea1a1ef 100644
--- a/meta/lib/oeqa/selftest/cases/containerimage.py
+++ b/meta/lib/oeqa/selftest/cases/containerimage.py
@@ -1,8 +1,11 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import bitbake, get_bb_vars, runCmd
-from oeqa.core.decorator.oeid import OETestID
# This test builds an image with using the "container" IMAGE_FSTYPE, and
# ensures that then files in the image are only the ones expected.
@@ -10,7 +13,7 @@ from oeqa.core.decorator.oeid import OETestID
# 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
@@ -19,9 +22,8 @@ from oeqa.core.decorator.oeid import OETestID
#
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
- @OETestID(1619)
def test_expected_files(self):
def get_each_path_part(path):
@@ -40,6 +42,9 @@ IMAGE_FSTYPES = "container"
PACKAGE_CLASSES = "package_ipk"
IMAGE_FEATURES = ""
IMAGE_BUILDINFO_FILE = ""
+INIT_MANAGER = "sysvinit"
+IMAGE_INSTALL:remove = "ssh-pregen-hostkeys"
+
""")
bbvars = get_bb_vars(['bindir', 'sysconfdir', 'localstatedir',
@@ -55,11 +60,7 @@ IMAGE_BUILDINFO_FILE = ""
'.{sysconfdir}/version',
'./run/',
'.{localstatedir}/cache/',
- '.{localstatedir}/cache/ldconfig/',
- '.{localstatedir}/cache/ldconfig/aux-cache',
- '.{localstatedir}/cache/opkg/',
- '.{localstatedir}/lib/',
- '.{localstatedir}/lib/opkg/'
+ '.{localstatedir}/lib/'
]
expected_files = [ x.format(bindir=bbvars['bindir'],
diff --git a/meta/lib/oeqa/selftest/cases/cve_check.py b/meta/lib/oeqa/selftest/cases/cve_check.py
new file mode 100644
index 0000000000..d1947baffc
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/cve_check.py
@@ -0,0 +1,44 @@
+from oe.cve_check import Version
+from oeqa.selftest.case import OESelftestTestCase
+
+class CVECheck(OESelftestTestCase):
+
+ def test_version_compare(self):
+ result = Version("100") > Version("99")
+ self.assertTrue( result, msg="Failed to compare version '100' > '99'")
+ result = Version("2.3.1") > Version("2.2.3")
+ self.assertTrue( result, msg="Failed to compare version '2.3.1' > '2.2.3'")
+ result = Version("2021-01-21") > Version("2020-12-25")
+ self.assertTrue( result, msg="Failed to compare version '2021-01-21' > '2020-12-25'")
+ result = Version("1.2-20200910") < Version("1.2-20200920")
+ self.assertTrue( result, msg="Failed to compare version '1.2-20200910' < '1.2-20200920'")
+
+ result = Version("1.0") >= Version("1.0beta")
+ self.assertTrue( result, msg="Failed to compare version '1.0' >= '1.0beta'")
+ result = Version("1.0-rc2") > Version("1.0-rc1")
+ self.assertTrue( result, msg="Failed to compare version '1.0-rc2' > '1.0-rc1'")
+ result = Version("1.0.alpha1") < Version("1.0")
+ self.assertTrue( result, msg="Failed to compare version '1.0.alpha1' < '1.0'")
+ result = Version("1.0_dev") <= Version("1.0")
+ self.assertTrue( result, msg="Failed to compare version '1.0_dev' <= '1.0'")
+
+ # ignore "p1" and "p2", so these should be equal
+ result = Version("1.0p2") == Version("1.0p1")
+ self.assertTrue( result ,msg="Failed to compare version '1.0p2' to '1.0p1'")
+ # ignore the "b" and "r"
+ result = Version("1.0b") == Version("1.0r")
+ self.assertTrue( result ,msg="Failed to compare version '1.0b' to '1.0r'")
+
+ # consider the trailing alphabet as patched level when comparing
+ result = Version("1.0b","alphabetical") < Version("1.0r","alphabetical")
+ self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'")
+ result = Version("1.0b","alphabetical") > Version("1.0","alphabetical")
+ self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'")
+
+ # consider the trailing "p" and "patch" as patched released when comparing
+ result = Version("1.0","patch") < Version("1.0p1","patch")
+ self.assertTrue( result ,msg="Failed to compare version with suffix '1.0' < '1.0p1'")
+ result = Version("1.0p2","patch") > Version("1.0p1","patch")
+ self.assertTrue( result ,msg="Failed to compare version with suffix '1.0p2' > '1.0p1'")
+ result = Version("1.0_patch2","patch") < Version("1.0_patch3","patch")
+ self.assertTrue( result ,msg="Failed to compare version with suffix '1.0_patch2' < '1.0_patch3'")
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index 9eb9badf84..e910672c31 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
import shutil
@@ -9,7 +13,6 @@ import oeqa.utils.ftools as ftools
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
-from oeqa.core.decorator.oeid import OETestID
oldmetapath = None
@@ -53,7 +56,8 @@ def setUpModule():
if pth.startswith(canonical_layerpath):
if relpth.endswith('/'):
destdir = os.path.join(corecopydir, relpth)
- shutil.copytree(pth, destdir)
+ # avoid race condition by not copying .pyc files YPBZ#13421,13803
+ shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
else:
destdir = os.path.join(corecopydir, os.path.dirname(relpth))
bb.utils.mkdirhier(destdir)
@@ -76,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"""
@@ -134,6 +121,7 @@ class DevtoolBase(OESelftestTestCase):
with open(recipefile, 'r') as f:
invar = None
invalue = None
+ inherits = set()
for line in f:
var = None
if invar:
@@ -155,7 +143,7 @@ class DevtoolBase(OESelftestTestCase):
invar = var
continue
elif line.startswith('inherit '):
- inherits = line.split()[1:]
+ inherits.update(line.split()[1:])
if var and var in checkvars:
needvalue = checkvars.pop(var)
@@ -231,13 +219,39 @@ 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):
- @OETestID(1158)
def test_create_workspace(self):
# Check preconditions
result = runCmd('bitbake-layers show-layers')
self.assertTrue('\nworkspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf')
+ # remove conf/devtool.conf to avoid it corrupting tests
+ devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
+ self.track_for_cleanup(devtoolconf)
# Try creating a workspace layer with a specific path
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
@@ -256,14 +270,13 @@ class DevtoolTests(DevtoolBase):
class DevtoolAddTests(DevtoolBase):
- @OETestID(1159)
def test_devtool_add(self):
# Fetch source
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
pn = 'pv'
pv = '1.5.3'
- url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2'
+ url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
result = runCmd('wget %s' % url, cwd=tempdir)
result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
@@ -298,7 +311,6 @@ class DevtoolAddTests(DevtoolBase):
bindir = bindir[1:]
self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
- @OETestID(1423)
def test_devtool_add_git_local(self):
# We need dbus built so that DEPENDS recognition works
bitbake('dbus')
@@ -331,16 +343,15 @@ 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, [])
- @OETestID(1162)
def test_devtool_add_library(self):
# Fetch source
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
@@ -369,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')
@@ -389,13 +400,12 @@ class DevtoolAddTests(DevtoolBase):
self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
- @OETestID(1160)
def test_devtool_add_fetch(self):
# Fetch source
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
testver = '0.23'
- url = 'https://pypi.python.org/packages/source/M/MarkupSafe/MarkupSafe-%s.tar.gz' % testver
+ url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
testrecipe = 'python-markupsafe'
srcdir = os.path.join(tempdir, testrecipe)
# Test devtool add
@@ -435,11 +445,11 @@ class DevtoolAddTests(DevtoolBase):
checkvars['SRC_URI'] = url
self._test_recipe_contents(recipefile, checkvars, [])
- @OETestID(1161)
def test_devtool_add_fetch_git(self):
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)
@@ -460,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
@@ -479,11 +489,10 @@ 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, [])
- @OETestID(1391)
def test_devtool_add_fetch_simple(self):
# Fetch source from a remote URL, auto-detecting name
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
@@ -511,17 +520,40 @@ class DevtoolAddTests(DevtoolBase):
checkvars['SRC_URI'] = url.replace(testver, '${PV}')
self._test_recipe_contents(recipefile, checkvars, [])
+ def test_devtool_add_npm(self):
+ collections = get_bb_var('BBFILE_COLLECTIONS').split()
+ if "openembedded-layer" not in collections:
+ self.skipTest("Test needs meta-oe for nodejs")
+
+ pn = 'savoirfairelinux-node-server-example'
+ pv = '1.0.0'
+ url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
+ # Test devtool add
+ self.track_for_cleanup(self.workspacedir)
+ self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
+ result = runCmd('devtool add \'%s\'' % url)
+ self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
+ self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
+ self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
+ # Test devtool status
+ result = runCmd('devtool status')
+ self.assertIn(pn, result.output)
+ # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
+ bitbake('%s -c cleansstate' % pn)
+ # Test devtool build
+ result = runCmd('devtool build %s' % pn)
+
class DevtoolModifyTests(DevtoolBase):
- @OETestID(1164)
def test_devtool_modify(self):
import oe.path
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean mdadm')
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
result = runCmd('devtool modify mdadm -x %s' % tempdir)
self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
@@ -571,7 +603,6 @@ class DevtoolModifyTests(DevtoolBase):
result = runCmd('devtool status')
self.assertNotIn('mdadm', result.output)
- @OETestID(1620)
def test_devtool_buildclean(self):
def assertFile(path, *paths):
f = os.path.join(path, *paths)
@@ -590,8 +621,8 @@ class DevtoolModifyTests(DevtoolBase):
self.track_for_cleanup(tempdir_m4)
self.track_for_cleanup(builddir_m4)
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean mdadm m4')
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
try:
runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
@@ -607,6 +638,7 @@ class DevtoolModifyTests(DevtoolBase):
bitbake('mdadm m4 -c buildclean')
assertNoFile(tempdir_mdadm, 'mdadm')
assertNoFile(builddir_m4, 'src/m4')
+ runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
bitbake('mdadm m4 -c compile')
assertFile(tempdir_mdadm, 'mdadm')
assertFile(builddir_m4, 'src/m4')
@@ -618,7 +650,6 @@ class DevtoolModifyTests(DevtoolBase):
finally:
self.delete_recipeinc('m4')
- @OETestID(1166)
def test_devtool_modify_invalid(self):
# Try modifying some recipes
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
@@ -626,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():
@@ -647,7 +678,6 @@ class DevtoolModifyTests(DevtoolBase):
self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
- @OETestID(1365)
def test_devtool_modify_native(self):
# Check preconditions
self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
@@ -659,7 +689,7 @@ class DevtoolModifyTests(DevtoolBase):
bbclassextended = False
inheritnative = False
- testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split()
+ testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
for testrecipe in testrecipes:
checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
if not bbclassextended:
@@ -675,9 +705,45 @@ class DevtoolModifyTests(DevtoolBase):
self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
+ def test_devtool_modify_localfiles_only(self):
+ # Check preconditions
+ testrecipe = 'base-files'
+ src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
+ foundlocalonly = False
+ correct_symlink = False
+ for item in src_uri:
+ if item.startswith('file://'):
+ if '.patch' not in item:
+ foundlocalonly = True
+ else:
+ foundlocalonly = False
+ break
+ self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
+ # Clean up anything in the workdir/sysroot/sstate cache
+ bitbake('%s -c cleansstate' % testrecipe)
+ # Try modifying a recipe
+ tempdir = tempfile.mkdtemp(prefix='devtoolqa')
+ self.track_for_cleanup(tempdir)
+ self.track_for_cleanup(self.workspacedir)
+ self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
+ result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
+ srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
+ srclink = os.path.join(tempdir, 'share/dot.bashrc')
+ self.assertExists(srcfile, 'Extracted source could not be found')
+ if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
+ correct_symlink = True
+ self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
+ matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
+ self.assertTrue(matches, 'bbappend not created')
+ # Test devtool status
+ result = runCmd('devtool status')
+ self.assertIn(testrecipe, result.output)
+ self.assertIn(tempdir, result.output)
+ # Try building
+ bitbake(testrecipe)
- @OETestID(1165)
def test_devtool_modify_git(self):
# Check preconditions
testrecipe = 'psplash'
@@ -689,8 +755,8 @@ class DevtoolModifyTests(DevtoolBase):
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
@@ -705,7 +771,6 @@ class DevtoolModifyTests(DevtoolBase):
# Try building
bitbake(testrecipe)
- @OETestID(1167)
def test_devtool_modify_localfiles(self):
# Check preconditions
testrecipe = 'lighttpd'
@@ -722,8 +787,8 @@ class DevtoolModifyTests(DevtoolBase):
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
@@ -736,7 +801,6 @@ class DevtoolModifyTests(DevtoolBase):
# Try building
bitbake(testrecipe)
- @OETestID(1378)
def test_devtool_modify_virtual(self):
# Try modifying a virtual recipe
virtrecipe = 'virtual/make'
@@ -758,9 +822,28 @@ class DevtoolModifyTests(DevtoolBase):
self._check_src_repo(tempdir)
# This is probably sufficient
+ def test_devtool_modify_overrides(self):
+ # Try modifying a recipe with patches in overrides
+ tempdir = tempfile.mkdtemp(prefix='devtoolqa')
+ self.track_for_cleanup(tempdir)
+ self.track_for_cleanup(self.workspacedir)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
+ result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
+
+ self._check_src_repo(tempdir)
+ source = os.path.join(tempdir, "source")
+ def check(branch, expected):
+ runCmd('git -C %s checkout %s' % (tempdir, branch))
+ with open(source, "rt") as f:
+ content = f.read()
+ self.assertEquals(content, expected)
+ check('devtool', 'This is a test for something\n')
+ check('devtool-no-overrides', 'This is a test for something\n')
+ check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
+ check('devtool-override-qemux86', 'This is a test for qemux86\n')
+
class DevtoolUpdateTests(DevtoolBase):
- @OETestID(1169)
def test_devtool_update_recipe(self):
# Check preconditions
testrecipe = 'minicom'
@@ -793,7 +876,6 @@ class DevtoolUpdateTests(DevtoolBase):
('??', '.*/0002-Add-a-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
- @OETestID(1172)
def test_devtool_update_recipe_git(self):
# Check preconditions
testrecipe = 'mtd-utils'
@@ -830,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('"')
@@ -863,7 +945,6 @@ class DevtoolUpdateTests(DevtoolBase):
('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
- @OETestID(1170)
def test_devtool_update_recipe_append(self):
# Check preconditions
testrecipe = 'mdadm'
@@ -902,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']
@@ -917,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())
@@ -932,7 +1013,6 @@ class DevtoolUpdateTests(DevtoolBase):
self.assertEqual(expectedlines, f.readlines())
# Deleting isn't expected to work under these circumstances
- @OETestID(1171)
def test_devtool_update_recipe_append_git(self):
# Check preconditions
testrecipe = 'mtd-utils'
@@ -1023,7 +1103,6 @@ class DevtoolUpdateTests(DevtoolBase):
self.assertEqual(expectedlines, set(f.readlines()))
# Deleting isn't expected to work under these circumstances
- @OETestID(1370)
def test_devtool_update_recipe_local_files(self):
"""Check that local source files are copied over instead of patched"""
testrecipe = 'makedevs'
@@ -1055,7 +1134,6 @@ class DevtoolUpdateTests(DevtoolBase):
('??', '.*/makedevs/0001-Add-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
- @OETestID(1371)
def test_devtool_update_recipe_local_files_2(self):
"""Check local source files support when oe-local-files is in Git"""
testrecipe = 'devtool-test-local'
@@ -1100,7 +1178,59 @@ class DevtoolUpdateTests(DevtoolBase):
('??', '.*/0001-Add-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
- @OETestID(1627)
+ def test_devtool_update_recipe_with_gitignore(self):
+ # First, modify the recipe
+ testrecipe = 'devtool-test-ignored'
+ bb_vars = get_bb_vars(['FILE'], testrecipe)
+ recipefile = bb_vars['FILE']
+ patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
+ newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
+ tempdir = tempfile.mkdtemp(prefix='devtoolqa')
+ self.track_for_cleanup(tempdir)
+ self.track_for_cleanup(self.workspacedir)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
+ # (don't bother with cleaning the recipe on teardown, we won't be building it)
+ result = runCmd('devtool modify %s' % testrecipe)
+ self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
+ # Check recipe got changed as expected
+ with open(newpatchfile, 'r') as f:
+ desiredlines = f.readlines()
+ with open(patchfile, 'r') as f:
+ newlines = f.readlines()
+ # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
+ # which changes the metadata subject which is added into the patch, but keep
+ # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
+ # devtool-test-ignored manually, then it should generate exactly the same .patch file
+ self.assertEqual(desiredlines[5:], newlines[5:])
+
+ def test_devtool_update_recipe_long_filename(self):
+ # First, modify the recipe
+ testrecipe = 'devtool-test-long-filename'
+ bb_vars = get_bb_vars(['FILE'], testrecipe)
+ recipefile = bb_vars['FILE']
+ patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
+ patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
+ newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
+ tempdir = tempfile.mkdtemp(prefix='devtoolqa')
+ self.track_for_cleanup(tempdir)
+ self.track_for_cleanup(self.workspacedir)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
+ # (don't bother with cleaning the recipe on teardown, we won't be building it)
+ result = runCmd('devtool modify %s' % testrecipe)
+ self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
+ # Check recipe got changed as expected
+ with open(newpatchfile, 'r') as f:
+ desiredlines = f.readlines()
+ with open(patchfile, 'r') as f:
+ newlines = f.readlines()
+ # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
+ # which changes the metadata subject which is added into the patch, but keep
+ # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
+ # devtool-test-ignored manually, then it should generate exactly the same .patch file
+ self.assertEqual(desiredlines[5:], newlines[5:])
+
def test_devtool_update_recipe_local_files_3(self):
# First, modify the recipe
testrecipe = 'devtool-test-localonly'
@@ -1120,7 +1250,6 @@ class DevtoolUpdateTests(DevtoolBase):
expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
- @OETestID(1629)
def test_devtool_update_recipe_local_patch_gz(self):
# First, modify the recipe
testrecipe = 'devtool-test-patch-gz'
@@ -1148,7 +1277,6 @@ class DevtoolUpdateTests(DevtoolBase):
if 'gzip compressed data' not in result.output:
self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
- @OETestID(1628)
def test_devtool_update_recipe_local_files_subdir(self):
# Try devtool update-recipe on a recipe that has a file with subdir= set in
# SRC_URI such that it overwrites a file that was in an archive that
@@ -1177,7 +1305,6 @@ class DevtoolUpdateTests(DevtoolBase):
class DevtoolExtractTests(DevtoolBase):
- @OETestID(1163)
def test_devtool_extract(self):
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
# Try devtool extract
@@ -1188,7 +1315,6 @@ class DevtoolExtractTests(DevtoolBase):
self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
self._check_src_repo(tempdir)
- @OETestID(1379)
def test_devtool_extract_virtual(self):
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
# Try devtool extract
@@ -1199,7 +1325,6 @@ class DevtoolExtractTests(DevtoolBase):
self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
self._check_src_repo(tempdir)
- @OETestID(1168)
def test_devtool_reset_all(self):
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
@@ -1226,7 +1351,6 @@ class DevtoolExtractTests(DevtoolBase):
matches2 = glob.glob(stampprefix2 + '*')
self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
- @OETestID(1272)
def test_devtool_deploy_target(self):
# NOTE: Whilst this test would seemingly be better placed as a runtime test,
# unfortunately the runtime tests run under bitbake and you can't run
@@ -1267,8 +1391,8 @@ class DevtoolExtractTests(DevtoolBase):
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
self.track_for_cleanup(tempdir)
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
# Test that deploy-target at this point fails (properly)
result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
@@ -1291,7 +1415,7 @@ class DevtoolExtractTests(DevtoolBase):
installdir = bb_vars['D']
fakerootenv = bb_vars['FAKEROOTENV']
fakerootcmd = bb_vars['FAKEROOTCMD']
- result = runCmd('%s %s find . -type f -exec ls -l {} \;' % (fakerootenv, fakerootcmd), cwd=installdir)
+ result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
filelist1 = self._process_ls_output(result.output)
# Now look on the target
@@ -1312,15 +1436,14 @@ class DevtoolExtractTests(DevtoolBase):
result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
- @OETestID(1366)
def test_devtool_build_image(self):
"""Test devtool build-image plugin"""
# Check preconditions
self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
image = 'core-image-minimal'
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean %s' % image)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
bitbake('%s -c clean' % image)
# Add target and native recipes to workspace
recipes = ['mdadm', 'parted-native']
@@ -1348,7 +1471,6 @@ class DevtoolExtractTests(DevtoolBase):
class DevtoolUpgradeTests(DevtoolBase):
- @OETestID(1367)
def test_devtool_upgrade(self):
# Check preconditions
self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
@@ -1393,7 +1515,6 @@ class DevtoolUpgradeTests(DevtoolBase):
self.assertNotIn(recipe, result.output)
self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
- @OETestID(1433)
def test_devtool_upgrade_git(self):
# Check preconditions
self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
@@ -1430,7 +1551,6 @@ class DevtoolUpgradeTests(DevtoolBase):
self.assertNotIn(recipe, result.output)
self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
- @OETestID(1352)
def test_devtool_layer_plugins(self):
"""Test that devtool can use plugins from other layers.
@@ -1450,13 +1570,16 @@ class DevtoolUpgradeTests(DevtoolBase):
dstdir = os.path.join(dstdir, p)
if not os.path.exists(dstdir):
os.makedirs(dstdir)
- self.track_for_cleanup(dstdir)
+ if p == "lib":
+ # Can race with other tests
+ self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
+ else:
+ self.track_for_cleanup(dstdir)
dstfile = os.path.join(dstdir, os.path.basename(srcfile))
if srcfile != dstfile:
shutil.copy(srcfile, dstfile)
self.track_for_cleanup(dstfile)
- @OETestID(1625)
def test_devtool_load_plugin(self):
"""Test that devtool loads only the first found plugin in BBPATH."""
@@ -1521,12 +1644,13 @@ class DevtoolUpgradeTests(DevtoolBase):
recipedir = os.path.dirname(oldrecipefile)
olddir = os.path.join(recipedir, recipe + '-' + oldversion)
patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
+ backportedpatchfn = 'backported.patch'
self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
- return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn
+ self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
+ return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
- @OETestID(1623)
def test_devtool_finish_upgrade_origlayer(self):
- recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
+ recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
# Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
self.assertIn('/meta-selftest/', recipedir)
# Try finish to the original layer
@@ -1537,15 +1661,23 @@ class DevtoolUpgradeTests(DevtoolBase):
self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
+ self.assertNotExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should have been deleted but wasn\'t')
newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
newdir = os.path.join(recipedir, recipe + '-' + newversion)
self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
+ self.assertNotExists(os.path.join(newdir, backportedpatchfn), 'Backported patch file should not have been copied into new directory but was')
self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
+ with open(newrecipefile, 'r') as f:
+ newcontent = f.read()
+ self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
+ self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
+ self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
+ self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
+
- @OETestID(1624)
def test_devtool_finish_upgrade_otherlayer(self):
- recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
+ recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
# Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
self.assertIn('/meta-selftest/', recipedir)
# Try finish to a different layer - should create a bbappend
@@ -1561,10 +1693,18 @@ class DevtoolUpgradeTests(DevtoolBase):
self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
+ self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
+ self.assertNotExists(os.path.join(newdir, backportedpatchfn), 'Backported patch file should not have been copied into new directory but was')
self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
+ with open(newrecipefile, 'r') as f:
+ newcontent = f.read()
+ self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
+ self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
+ self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
+ self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
def _setup_test_devtool_finish_modify(self):
# Check preconditions
@@ -1599,7 +1739,6 @@ class DevtoolUpgradeTests(DevtoolBase):
self.fail('Unable to find recipe files directory for %s' % recipe)
return recipe, oldrecipefile, recipedir, filesdir
- @OETestID(1621)
def test_devtool_finish_modify_origlayer(self):
recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
# Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
@@ -1614,7 +1753,6 @@ class DevtoolUpgradeTests(DevtoolBase):
('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
self._check_repo_status(recipedir, expected_status)
- @OETestID(1622)
def test_devtool_finish_modify_otherlayer(self):
recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
# Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
@@ -1647,7 +1785,6 @@ class DevtoolUpgradeTests(DevtoolBase):
if files:
self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
- @OETestID(1626)
def test_devtool_rename(self):
# Check preconditions
self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
@@ -1708,7 +1845,6 @@ class DevtoolUpgradeTests(DevtoolBase):
checkvars['SRC_URI'] = url
self._test_recipe_contents(newrecipefile, checkvars, [])
- @OETestID(1577)
def test_devtool_virtual_kernel_modify(self):
"""
Summary: The purpose of this test case is to verify that
@@ -1732,15 +1868,15 @@ class DevtoolUpgradeTests(DevtoolBase):
when building the kernel.
"""
kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
- # Clean up the enviroment
+ # Clean up the environment
bitbake('%s -c clean' % kernel_provider)
tempdir = tempfile.mkdtemp(prefix='devtoolqa')
tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
self.track_for_cleanup(tempdir)
self.track_for_cleanup(tempdir_cfg)
self.track_for_cleanup(self.workspacedir)
- self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
+ self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
#Step 1
#Here is just generated the config file instead of all the kernel to optimize the
#time of executing this test case.
diff --git a/meta/lib/oeqa/selftest/cases/diffoscope/A/file.txt b/meta/lib/oeqa/selftest/cases/diffoscope/A/file.txt
new file mode 100644
index 0000000000..f70f10e4db
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/diffoscope/A/file.txt
@@ -0,0 +1 @@
+A
diff --git a/meta/lib/oeqa/selftest/cases/diffoscope/B/file.txt b/meta/lib/oeqa/selftest/cases/diffoscope/B/file.txt
new file mode 100644
index 0000000000..223b7836fb
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/diffoscope/B/file.txt
@@ -0,0 +1 @@
+B
diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py
index 0b454714e9..03f31e9fcb 100644
--- a/meta/lib/oeqa/selftest/cases/distrodata.py
+++ b/meta/lib/oeqa/selftest/cases/distrodata.py
@@ -1,14 +1,16 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
from oeqa.utils.decorators import testcase
from oeqa.utils.ftools import write_file
-from oeqa.core.decorator.oeid import OETestID
import oe.recipeutils
class Distrodata(OESelftestTestCase):
- @OETestID(1902)
def test_checkpkg(self):
"""
Summary: Test that upstream version checks do not regress
@@ -16,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()
@@ -38,10 +40,47 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
""" + "\n".join(regressed_successes)
self.assertTrue(len(regressed_failures) == 0 and len(regressed_successes) == 0, msg)
+ def test_missing_homepg(self):
+ """
+ Summary: Test for oe-core recipes that don't have a HOMEPAGE or DESCRIPTION
+ Expected: All oe-core recipes should have a DESCRIPTION entry
+ Expected: All oe-core recipes should have a HOMEPAGE entry except for recipes that are not fetched from external sources.
+ Product: oe-core
+ """
+ with bb.tinfoil.Tinfoil() as tinfoil:
+ tinfoil.prepare(config_only=False)
+ no_description = []
+ no_homepage = []
+ for fn in tinfoil.all_recipe_files(variants=False):
+ if not '/meta/recipes-' in fn:
+ # We are only interested in OE-Core
+ continue
+ rd = tinfoil.parse_recipe_file(fn, appends=False)
+ pn = rd.getVar('BPN')
+ srcfile = rd.getVar('SRC_URI').split()
+ #Since DESCRIPTION defaults to SUMMARY if not set, we are only interested in recipes without DESCRIPTION or SUMMARY
+ if not (rd.getVar('SUMMARY') or rd.getVar('DESCRIPTION')):
+ no_description.append((pn, fn))
+ if not rd.getVar('HOMEPAGE'):
+ if srcfile and srcfile[0].startswith('file') or not rd.getVar('SRC_URI'):
+ # We are only interested in recipes SRC_URI fetched from external sources
+ continue
+ no_homepage.append((pn, fn))
+ if no_homepage:
+ self.fail("""
+The following recipes do not have a HOMEPAGE. Please add an entry for HOMEPAGE in the recipe.
+""" + "\n".join(['%s (%s)' % i for i in no_homepage]))
+
+ if no_description:
+ self.fail("""
+The following recipes do not have a DESCRIPTION. Please add an entry for DESCRIPTION in the recipe.
+""" + "\n".join(['%s (%s)' % i for i in no_description]))
+
def test_maintainers(self):
"""
- Summary: Test that oe-core recipes have a maintainer
+ Summary: Test that oe-core recipes have a maintainer and entries in maintainers list have a recipe
Expected: All oe-core recipes (except a few special static/testing ones) should have a maintainer listed in maintainers.inc file.
+ Expected: All entries in maintainers list should have a recipe file that matches them
Product: oe-core
Author: Alexander Kanavin <alex.kanavin@gmail.com>
"""
@@ -52,7 +91,15 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
return True
return False
- feature = 'require conf/distro/include/maintainers.inc\n'
+ def is_maintainer_exception(entry):
+ exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran",
+ "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_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:
@@ -60,6 +107,11 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
with_maintainer_list = []
no_maintainer_list = []
+
+ missing_recipes = []
+ recipes = []
+ 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
# instead of maintainers.inc
@@ -69,6 +121,7 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
continue
rd = tinfoil.parse_recipe_file(fn, appends=False)
pn = rd.getVar('PN')
+ recipes.append(pn)
if is_exception(pn):
continue
if rd.getVar('RECIPE_MAINTAINER'):
@@ -76,6 +129,15 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
else:
no_maintainer_list.append((pn, fn))
+ maintainers = tinfoil.config_data.keys()
+ for key in maintainers:
+ if key.startswith(prefix):
+ recipe = tinfoil.config_data.expand(key[len(prefix):])
+ if is_maintainer_exception(recipe):
+ continue
+ if recipe not in recipes:
+ missing_recipes.append(recipe)
+
if no_maintainer_list:
self.fail("""
The following recipes do not have a maintainer assigned to them. Please add an entry to meta/conf/distro/include/maintainers.inc file.
@@ -85,3 +147,8 @@ The following recipes do not have a maintainer assigned to them. Please add an e
self.fail("""
The list of oe-core recipes with maintainers is empty. This may indicate that the test has regressed and needs fixing.
""")
+
+ if missing_recipes:
+ self.fail("""
+Unable to find recipes for the following entries in maintainers.inc:
+""" + "\n".join(['%s' % i for i in missing_recipes]))
diff --git a/meta/lib/oeqa/selftest/cases/eSDK.py b/meta/lib/oeqa/selftest/cases/eSDK.py
index 8eb6ec660c..f7279b3230 100644
--- a/meta/lib/oeqa/selftest/cases/eSDK.py
+++ b/meta/lib/oeqa/selftest/cases/eSDK.py
@@ -1,9 +1,12 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import tempfile
import shutil
import os
import glob
import time
-from oeqa.core.decorator.oeid import OETestID
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
@@ -60,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
@@ -88,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:
@@ -97,21 +100,19 @@ 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
cls.tmpdirobj.cleanup()
super().tearDownClass()
- @OETestID(1602)
def test_install_libraries_headers(self):
pn_sstate = 'bc'
bitbake(pn_sstate)
cmd = "devtool sdk-install %s " % pn_sstate
oeSDKExtSelfTest.run_esdk_cmd(self.env_eSDK, self.tmpdir_eSDKQA, cmd)
- @OETestID(1603)
def test_image_generation_binary_feeds(self):
image = 'core-image-minimal'
cmd = "devtool build-image %s" % image
diff --git a/meta/lib/oeqa/selftest/cases/efibootpartition.py b/meta/lib/oeqa/selftest/cases/efibootpartition.py
index c6f39d5b16..26de3a07c9 100644
--- a/meta/lib/oeqa/selftest/cases/efibootpartition.py
+++ b/meta/lib/oeqa/selftest/cases/efibootpartition.py
@@ -2,6 +2,8 @@
#
# Copyright (c) 2017 Wind River Systems, Inc.
#
+# SPDX-License-Identifier: MIT
+#
import re
@@ -24,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 4acc8cdcc8..be14272e63 100644
--- a/meta/lib/oeqa/selftest/cases/fetch.py
+++ b/meta/lib/oeqa/selftest/cases/fetch.py
@@ -1,10 +1,15 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+import tempfile
+import textwrap
+import bb.tinfoil
import oe.path
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import bitbake
-from oeqa.core.decorator.oeid import OETestID
class Fetch(OESelftestTestCase):
- @OETestID(1058)
def test_git_mirrors(self):
"""
Verify that the git fetcher will fall back to the HTTP mirrors. The
@@ -19,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)
@@ -30,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)
@@ -42,8 +47,60 @@ 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)
bitbake("dbus-wait -c fetch -f")
+
+
+class Dependencies(OESelftestTestCase):
+ def write_recipe(self, content, tempdir):
+ f = os.path.join(tempdir, "test.bb")
+ with open(f, "w") as fd:
+ fd.write(content)
+ return f
+
+ def test_dependencies(self):
+ """
+ Verify that the correct dependencies are generated for specific SRC_URI entries.
+ """
+
+ with bb.tinfoil.Tinfoil() as tinfoil, tempfile.TemporaryDirectory(prefix="selftest-fetch") as tempdir:
+ tinfoil.prepare(config_only=False, quiet=2)
+
+ r = """
+ LICENSE="CLOSED"
+ SRC_URI="http://example.com/tarball.zip"
+ """
+ f = self.write_recipe(textwrap.dedent(r), tempdir)
+ d = tinfoil.parse_recipe_file(f)
+ self.assertIn("wget-native", d.getVarFlag("do_fetch", "depends"))
+ self.assertIn("unzip-native", d.getVarFlag("do_unpack", "depends"))
+
+ # Verify that the downloadfilename overrides the URI
+ r = """
+ LICENSE="CLOSED"
+ SRC_URI="https://example.com/tarball;downloadfilename=something.zip"
+ """
+ f = self.write_recipe(textwrap.dedent(r), tempdir)
+ d = tinfoil.parse_recipe_file(f)
+ self.assertIn("wget-native", d.getVarFlag("do_fetch", "depends"))
+ self.assertIn("unzip-native", d.getVarFlag("do_unpack", "depends") or "")
+
+ r = """
+ LICENSE="CLOSED"
+ SRC_URI="ftp://example.com/tarball.lz"
+ """
+ f = self.write_recipe(textwrap.dedent(r), tempdir)
+ d = tinfoil.parse_recipe_file(f)
+ self.assertIn("wget-native", d.getVarFlag("do_fetch", "depends"))
+ self.assertIn("lzip-native", d.getVarFlag("do_unpack", "depends"))
+
+ r = """
+ LICENSE="CLOSED"
+ SRC_URI="git://example.com/repo;branch=master"
+ """
+ f = self.write_recipe(textwrap.dedent(r), tempdir)
+ d = tinfoil.parse_recipe_file(f)
+ self.assertIn("git-native", d.getVarFlag("do_fetch", "depends"))
diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
new file mode 100644
index 0000000000..f6f6a8e795
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/fitimage.py
@@ -0,0 +1,840 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu
+import os
+import json
+import re
+
+class FitImageTests(OESelftestTestCase):
+
+ def test_fit_image(self):
+ """
+ Summary: Check if FIT image and Image Tree Source (its) are built
+ and the Image Tree Source has the correct fields.
+ Expected: 1. fitImage and fitImage-its can be built
+ 2. The type, load address, entrypoint address and
+ default values of kernel and ramdisk are as expected
+ in the Image Tree Source. Not all the fields are tested,
+ only the key fields that wont vary between different
+ architectures.
+ Product: oe-core
+ Author: Usama Arif <usama.arif@arm.com>
+ """
+ config = """
+# Enable creation of fitImage
+KERNEL_IMAGETYPE = "Image"
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage "
+
+# RAM disk variables including load address and entrypoint for kernel and RAM disk
+IMAGE_FSTYPES += "cpio.gz"
+INITRAMFS_IMAGE = "core-image-minimal"
+UBOOT_RD_LOADADDRESS = "0x88000000"
+UBOOT_RD_ENTRYPOINT = "0x88000000"
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+FIT_DESC = "A model description"
+"""
+ self.write_config(config)
+
+ # fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ image_type = "core-image-minimal"
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "fitImage-its-%s-%s-%s" % (image_type, machine, machine))
+ fitimage_path = os.path.join(deploy_dir_image,
+ "fitImage-%s-%s-%s" % (image_type, machine, machine))
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ # Check that the type, load address, entrypoint address and default
+ # values for kernel and ramdisk in Image Tree Source are as expected.
+ # The order of fields in the below array is important. Not all the
+ # fields are tested, only the key fields that wont vary between
+ # different architectures.
+ its_field_check = [
+ 'description = "A model description";',
+ 'type = "kernel";',
+ 'load = <0x80080000>;',
+ 'entry = <0x80080000>;',
+ 'type = "ramdisk";',
+ 'load = <0x88000000>;',
+ 'entry = <0x88000000>;',
+ 'default = "conf-1";',
+ 'kernel = "kernel-1";',
+ 'ramdisk = "ramdisk-1";'
+ ]
+
+ with open(fitimage_its_path) as its_file:
+ field_index = 0
+ for line in its_file:
+ if field_index == len(its_field_check):
+ break
+ if its_field_check[field_index] in line:
+ field_index +=1
+
+ if field_index != len(its_field_check): # if its equal, the test passed
+ self.assertTrue(field_index == len(its_field_check),
+ "Fields in Image Tree Source File %s did not match, error in finding %s"
+ % (fitimage_its_path, its_field_check[field_index]))
+
+
+ def test_sign_fit_image(self):
+ """
+ Summary: Check if FIT image and Image Tree Source (its) are created
+ and signed correctly.
+ Expected: 1) its and FIT image are built successfully
+ 2) Scanning the its file indicates signing is enabled
+ as requested by UBOOT_SIGN_ENABLE (using keys generated
+ via FIT_GENERATE_KEYS)
+ 3) Dumping the FIT image indicates signature values
+ are present (including for images as enabled via
+ FIT_SIGN_INDIVIDUAL)
+ 4) Examination of the do_assemble_fitimage runfile/logfile
+ indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and
+ UBOOT_MKIMAGE_SIGN_ARGS are working as expected.
+ Product: oe-core
+ Author: Paul Eggleton <paul.eggleton@microsoft.com> based upon
+ work by Usama Arif <usama.arif@arm.com>
+ """
+ config = """
+# Enable creation of fitImage
+MACHINE = "beaglebone-yocto"
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
+UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
+FIT_SIGN_INDIVIDUAL = "1"
+UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'"
+"""
+ self.write_config(config)
+
+ # fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ image_type = "core-image-minimal"
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "fitImage-its-%s" % (machine,))
+ fitimage_path = os.path.join(deploy_dir_image,
+ "fitImage-%s.bin" % (machine,))
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ req_itspaths = [
+ ['/', 'images', 'kernel-1'],
+ ['/', 'images', 'kernel-1', 'signature-1'],
+ ['/', 'images', 'fdt-am335x-boneblack.dtb'],
+ ['/', 'images', 'fdt-am335x-boneblack.dtb', 'signature-1'],
+ ['/', 'configurations', 'conf-am335x-boneblack.dtb'],
+ ['/', 'configurations', 'conf-am335x-boneblack.dtb', 'signature-1'],
+ ]
+
+ itspath = []
+ itspaths = []
+ linect = 0
+ sigs = {}
+ with open(fitimage_its_path) as its_file:
+ linect += 1
+ for line in its_file:
+ line = line.strip()
+ if line.endswith('};'):
+ itspath.pop()
+ elif line.endswith('{'):
+ itspath.append(line[:-1].strip())
+ itspaths.append(itspath[:])
+ elif itspath and itspath[-1] == 'signature-1':
+ itsdotpath = '.'.join(itspath)
+ if not itsdotpath in sigs:
+ sigs[itsdotpath] = {}
+ if not '=' in line or not line.endswith(';'):
+ self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
+ key, value = line.split('=', 1)
+ sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
+
+ for reqpath in req_itspaths:
+ if not reqpath in itspaths:
+ self.fail('Missing section in its file: %s' % reqpath)
+
+ reqsigvalues_image = {
+ 'algo': '"sha256,rsa2048"',
+ 'key-name-hint': '"img-oe-selftest"',
+ }
+ reqsigvalues_config = {
+ 'algo': '"sha256,rsa2048"',
+ 'key-name-hint': '"cfg-oe-selftest"',
+ 'sign-images': '"kernel", "fdt"',
+ }
+
+ for itspath, values in sigs.items():
+ if 'conf-' in itspath:
+ reqsigvalues = reqsigvalues_config
+ else:
+ reqsigvalues = reqsigvalues_image
+ for reqkey, reqvalue in reqsigvalues.items():
+ value = values.get(reqkey, None)
+ if value is None:
+ self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
+ self.assertEqual(value, reqvalue)
+
+ # Dump the image to see if it really got signed
+ bitbake("u-boot-tools-native -c addto_recipe_sysroot")
+ result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
+ recipe_sysroot_native = result.output.split('=')[1].strip('"')
+ dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
+ result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
+ in_signed = None
+ signed_sections = {}
+ for line in result.output.splitlines():
+ if line.startswith((' Configuration', ' Image')):
+ in_signed = re.search('\((.*)\)', line).groups()[0]
+ elif re.match('^ *', line) in (' ', ''):
+ in_signed = None
+ elif in_signed:
+ if not in_signed in signed_sections:
+ signed_sections[in_signed] = {}
+ key, value = line.split(':', 1)
+ signed_sections[in_signed][key.strip()] = value.strip()
+ self.assertIn('kernel-1', signed_sections)
+ self.assertIn('fdt-am335x-boneblack.dtb', signed_sections)
+ self.assertIn('conf-am335x-boneblack.dtb', signed_sections)
+ for signed_section, values in signed_sections.items():
+ value = values.get('Sign algo', None)
+ 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)
+
+ # Check for UBOOT_MKIMAGE_SIGN_ARGS
+ result = runCmd('bitbake -e virtual/kernel | grep ^T=')
+ tempdir = result.output.split('=', 1)[1].strip().strip('')
+ result = runCmd('grep "a smart comment" %s/run.do_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN_ARGS value did not get used')
+
+ # Check for evidence of test-mkimage-wrapper class
+ result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
+ result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
+
+ def test_uboot_fit_image(self):
+ """
+ Summary: Check if Uboot FIT image and Image Tree Source
+ (its) are built and the Image Tree Source has the
+ correct fields.
+ Expected: 1. u-boot-fitImage and u-boot-its can be built
+ 2. The type, load address, entrypoint address and
+ default values of U-boot image are correct in the
+ Image Tree Source. Not all the fields are tested,
+ only the key fields that wont vary between
+ different architectures.
+ Product: oe-core
+ Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+ based on work by Usama Arif <usama.arif@arm.com>
+ """
+ config = """
+# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+
+# Enable creation of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+
+# (U-boot) fitImage properties
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+UBOOT_FIT_DESC = "A model description"
+
+# Enable creation of Kernel fitImage
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage"
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
+UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
+FIT_SIGN_INDIVIDUAL = "1"
+"""
+ self.write_config(config)
+
+ # The U-Boot fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "u-boot-its-%s" % (machine,))
+ fitimage_path = os.path.join(deploy_dir_image,
+ "u-boot-fitImage-%s" % (machine,))
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ # Check that the type, load address, entrypoint address and default
+ # values for kernel and ramdisk in Image Tree Source are as expected.
+ # The order of fields in the below array is important. Not all the
+ # fields are tested, only the key fields that wont vary between
+ # different architectures.
+ its_field_check = [
+ 'description = "A model description";',
+ 'type = "standalone";',
+ 'load = <0x80080000>;',
+ 'entry = <0x80080000>;',
+ 'default = "conf";',
+ 'loadables = "uboot";',
+ 'fdt = "fdt";'
+ ]
+
+ with open(fitimage_its_path) as its_file:
+ field_index = 0
+ for line in its_file:
+ if field_index == len(its_field_check):
+ break
+ if its_field_check[field_index] in line:
+ field_index +=1
+
+ if field_index != len(its_field_check): # if its equal, the test passed
+ self.assertTrue(field_index == len(its_field_check),
+ "Fields in Image Tree Source File %s did not match, error in finding %s"
+ % (fitimage_its_path, its_field_check[field_index]))
+
+ def test_uboot_sign_fit_image(self):
+ """
+ Summary: Check if Uboot FIT image and Image Tree Source
+ (its) are built and the Image Tree Source has the
+ correct fields, in the scenario where the Kernel
+ is also creating/signing it's fitImage.
+ Expected: 1. u-boot-fitImage and u-boot-its can be built
+ 2. The type, load address, entrypoint address and
+ default values of U-boot image are correct in the
+ Image Tree Source. Not all the fields are tested,
+ only the key fields that wont vary between
+ different architectures.
+ Product: oe-core
+ Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+ based on work by Usama Arif <usama.arif@arm.com>
+ """
+ config = """
+# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+
+# Enable creation of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+
+# (U-boot) fitImage properties
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+UBOOT_FIT_DESC = "A model description"
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_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'"
+"""
+ self.write_config(config)
+
+ # The U-Boot fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "u-boot-its-%s" % (machine,))
+ fitimage_path = os.path.join(deploy_dir_image,
+ "u-boot-fitImage-%s" % (machine,))
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ # Check that the type, load address, entrypoint address and default
+ # values for kernel and ramdisk in Image Tree Source are as expected.
+ # The order of fields in the below array is important. Not all the
+ # fields are tested, only the key fields that wont vary between
+ # different architectures.
+ its_field_check = [
+ 'description = "A model description";',
+ 'type = "standalone";',
+ 'load = <0x80080000>;',
+ 'entry = <0x80080000>;',
+ 'default = "conf";',
+ 'loadables = "uboot";',
+ 'fdt = "fdt";'
+ ]
+
+ with open(fitimage_its_path) as its_file:
+ field_index = 0
+ for line in its_file:
+ if field_index == len(its_field_check):
+ break
+ if its_field_check[field_index] in line:
+ field_index +=1
+
+ if field_index != len(its_field_check): # if its equal, the test passed
+ self.assertTrue(field_index == len(its_field_check),
+ "Fields in Image Tree Source File %s did not match, error in finding %s"
+ % (fitimage_its_path, its_field_check[field_index]))
+
+
+ def test_sign_standalone_uboot_fit_image(self):
+ """
+ Summary: Check if U-Boot FIT image and Image Tree Source (its) are
+ created and signed correctly for the scenario where only
+ the U-Boot proper fitImage is being created and signed.
+ Expected: 1) U-Boot its and FIT image are built successfully
+ 2) Scanning the its file indicates signing is enabled
+ as requested by SPL_SIGN_ENABLE (using keys generated
+ via UBOOT_FIT_GENERATE_KEYS)
+ 3) Dumping the FIT image indicates signature values
+ are present
+ 4) Examination of the do_uboot_assemble_fitimage
+ runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN
+ and SPL_MKIMAGE_SIGN_ARGS are working as expected.
+ Product: oe-core
+ Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon
+ work by Paul Eggleton <paul.eggleton@microsoft.com> and
+ Usama Arif <usama.arif@arm.com>
+ """
+ config = """
+# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at
+# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+# The kernel-fitimage class is a dependency even if we're only
+# creating/signing the U-Boot fitImage
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+# Enable creation and signing of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+SPL_SIGN_ENABLE = "1"
+SPL_SIGN_KEYNAME = "spl-oe-selftest"
+SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_DTB_BINARY = "u-boot.dtb"
+UBOOT_ENTRYPOINT = "0x80000000"
+UBOOT_LOADADDRESS = "0x80000000"
+UBOOT_DTB_LOADADDRESS = "0x82000000"
+UBOOT_ARCH = "arm"
+SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'"
+UBOOT_EXTLINUX = "0"
+UBOOT_FIT_GENERATE_KEYS = "1"
+UBOOT_FIT_HASH_ALG = "sha256"
+"""
+ self.write_config(config)
+
+ # The U-Boot fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ image_type = "core-image-minimal"
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "u-boot-its-%s" % (machine,))
+ fitimage_path = os.path.join(deploy_dir_image,
+ "u-boot-fitImage-%s" % (machine,))
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ req_itspaths = [
+ ['/', 'images', 'uboot'],
+ ['/', 'images', 'uboot', 'signature'],
+ ['/', 'images', 'fdt'],
+ ['/', 'images', 'fdt', 'signature'],
+ ]
+
+ itspath = []
+ itspaths = []
+ linect = 0
+ sigs = {}
+ with open(fitimage_its_path) as its_file:
+ linect += 1
+ for line in its_file:
+ line = line.strip()
+ if line.endswith('};'):
+ itspath.pop()
+ elif line.endswith('{'):
+ itspath.append(line[:-1].strip())
+ itspaths.append(itspath[:])
+ elif itspath and itspath[-1] == 'signature':
+ itsdotpath = '.'.join(itspath)
+ if not itsdotpath in sigs:
+ sigs[itsdotpath] = {}
+ if not '=' in line or not line.endswith(';'):
+ self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
+ key, value = line.split('=', 1)
+ sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
+
+ for reqpath in req_itspaths:
+ if not reqpath in itspaths:
+ self.fail('Missing section in its file: %s' % reqpath)
+
+ reqsigvalues_image = {
+ 'algo': '"sha256,rsa2048"',
+ 'key-name-hint': '"spl-oe-selftest"',
+ }
+
+ for itspath, values in sigs.items():
+ reqsigvalues = reqsigvalues_image
+ for reqkey, reqvalue in reqsigvalues.items():
+ value = values.get(reqkey, None)
+ if value is None:
+ self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
+ self.assertEqual(value, reqvalue)
+
+ # Dump the image to see if it really got signed
+ bitbake("u-boot-tools-native -c addto_recipe_sysroot")
+ result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
+ recipe_sysroot_native = result.output.split('=')[1].strip('"')
+ dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
+ result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
+ in_signed = None
+ signed_sections = {}
+ for line in result.output.splitlines():
+ if line.startswith((' Image')):
+ in_signed = re.search('\((.*)\)', line).groups()[0]
+ elif re.match(' \w', line):
+ in_signed = None
+ elif in_signed:
+ if not in_signed in signed_sections:
+ signed_sections[in_signed] = {}
+ key, value = line.split(':', 1)
+ signed_sections[in_signed][key.strip()] = value.strip()
+ self.assertIn('uboot', signed_sections)
+ self.assertIn('fdt', signed_sections)
+ for signed_section, values in signed_sections.items():
+ value = values.get('Sign algo', None)
+ self.assertEqual(value, 'sha256,rsa2048:spl-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section)
+ value = values.get('Sign value', None)
+ self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section)
+
+ # Check for SPL_MKIMAGE_SIGN_ARGS
+ result = runCmd('bitbake -e virtual/kernel | grep ^T=')
+ tempdir = result.output.split('=', 1)[1].strip().strip('')
+ result = runCmd('grep "a smart U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used')
+
+ # Check for evidence of test-mkimage-wrapper class
+ result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
+ result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
+
+ def test_sign_cascaded_uboot_fit_image(self):
+ """
+ Summary: Check if U-Boot FIT image and Image Tree Source (its) are
+ created and signed correctly for the scenario where both
+ U-Boot proper and Kernel fitImages are being created and
+ signed.
+ Expected: 1) U-Boot its and FIT image are built successfully
+ 2) Scanning the its file indicates signing is enabled
+ as requested by SPL_SIGN_ENABLE (using keys generated
+ via UBOOT_FIT_GENERATE_KEYS)
+ 3) Dumping the FIT image indicates signature values
+ are present
+ 4) Examination of the do_uboot_assemble_fitimage
+ runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN
+ and SPL_MKIMAGE_SIGN_ARGS are working as expected.
+ Product: oe-core
+ Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon
+ work by Paul Eggleton <paul.eggleton@microsoft.com> and
+ Usama Arif <usama.arif@arm.com>
+ """
+ config = """
+# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at
+# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+# Enable creation and signing of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+SPL_SIGN_ENABLE = "1"
+SPL_SIGN_KEYNAME = "spl-cascaded-oe-selftest"
+SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_DTB_BINARY = "u-boot.dtb"
+UBOOT_ENTRYPOINT = "0x80000000"
+UBOOT_LOADADDRESS = "0x80000000"
+UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded Kernel comment'"
+UBOOT_DTB_LOADADDRESS = "0x82000000"
+UBOOT_ARCH = "arm"
+SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded U-Boot comment'"
+UBOOT_EXTLINUX = "0"
+UBOOT_FIT_GENERATE_KEYS = "1"
+UBOOT_FIT_HASH_ALG = "sha256"
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
+UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
+FIT_SIGN_INDIVIDUAL = "1"
+"""
+ self.write_config(config)
+
+ # The U-Boot fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ image_type = "core-image-minimal"
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "u-boot-its-%s" % (machine,))
+ fitimage_path = os.path.join(deploy_dir_image,
+ "u-boot-fitImage-%s" % (machine,))
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ req_itspaths = [
+ ['/', 'images', 'uboot'],
+ ['/', 'images', 'uboot', 'signature'],
+ ['/', 'images', 'fdt'],
+ ['/', 'images', 'fdt', 'signature'],
+ ]
+
+ itspath = []
+ itspaths = []
+ linect = 0
+ sigs = {}
+ with open(fitimage_its_path) as its_file:
+ linect += 1
+ for line in its_file:
+ line = line.strip()
+ if line.endswith('};'):
+ itspath.pop()
+ elif line.endswith('{'):
+ itspath.append(line[:-1].strip())
+ itspaths.append(itspath[:])
+ elif itspath and itspath[-1] == 'signature':
+ itsdotpath = '.'.join(itspath)
+ if not itsdotpath in sigs:
+ sigs[itsdotpath] = {}
+ if not '=' in line or not line.endswith(';'):
+ self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
+ key, value = line.split('=', 1)
+ sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
+
+ for reqpath in req_itspaths:
+ if not reqpath in itspaths:
+ self.fail('Missing section in its file: %s' % reqpath)
+
+ reqsigvalues_image = {
+ 'algo': '"sha256,rsa2048"',
+ 'key-name-hint': '"spl-cascaded-oe-selftest"',
+ }
+
+ for itspath, values in sigs.items():
+ reqsigvalues = reqsigvalues_image
+ for reqkey, reqvalue in reqsigvalues.items():
+ value = values.get(reqkey, None)
+ if value is None:
+ self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
+ self.assertEqual(value, reqvalue)
+
+ # Dump the image to see if it really got signed
+ bitbake("u-boot-tools-native -c addto_recipe_sysroot")
+ result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
+ recipe_sysroot_native = result.output.split('=')[1].strip('"')
+ dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
+ result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
+ in_signed = None
+ signed_sections = {}
+ for line in result.output.splitlines():
+ if line.startswith((' Image')):
+ in_signed = re.search('\((.*)\)', line).groups()[0]
+ elif re.match(' \w', line):
+ in_signed = None
+ elif in_signed:
+ if not in_signed in signed_sections:
+ signed_sections[in_signed] = {}
+ key, value = line.split(':', 1)
+ signed_sections[in_signed][key.strip()] = value.strip()
+ self.assertIn('uboot', signed_sections)
+ self.assertIn('fdt', signed_sections)
+ for signed_section, values in signed_sections.items():
+ value = values.get('Sign algo', None)
+ self.assertEqual(value, 'sha256,rsa2048:spl-cascaded-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section)
+ value = values.get('Sign value', None)
+ self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section)
+
+ # Check for SPL_MKIMAGE_SIGN_ARGS
+ result = runCmd('bitbake -e virtual/kernel | grep ^T=')
+ tempdir = result.output.split('=', 1)[1].strip().strip('')
+ result = runCmd('grep "a smart cascaded U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used')
+
+ # Check for evidence of test-mkimage-wrapper class
+ result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
+ result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
+
+
+
+ def test_initramfs_bundle(self):
+ """
+ Summary: Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its)
+ The FIT settings are set by the test case.
+ The machine used is beaglebone-yocto.
+ Expected: 1. The ITS is generated with initramfs bundle support
+ 2. All the fields in the kernel node are as expected (matching the
+ conf settings)
+ 3. The kernel is included in all the available configurations and
+ its hash is included in the configuration signature
+
+ Product: oe-core
+ Author: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ """
+
+ config = """
+DISTRO="poky"
+MACHINE = "beaglebone-yocto"
+INITRAMFS_IMAGE_BUNDLE = "1"
+INITRAMFS_IMAGE = "core-image-minimal-initramfs"
+INITRAMFS_SCRIPTS = ""
+UBOOT_MACHINE = "am335x_evm_defconfig"
+KERNEL_CLASSES = " kernel-fitimage "
+KERNEL_IMAGETYPES = "fitImage"
+UBOOT_SIGN_ENABLE = "1"
+UBOOT_SIGN_KEYNAME = "beaglebonekey"
+UBOOT_SIGN_KEYDIR ?= "${DEPLOY_DIR_IMAGE}"
+UBOOT_DTB_BINARY = "u-boot.dtb"
+UBOOT_ENTRYPOINT = "0x80000000"
+UBOOT_LOADADDRESS = "0x80000000"
+UBOOT_DTB_LOADADDRESS = "0x82000000"
+UBOOT_ARCH = "arm"
+UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+UBOOT_EXTLINUX = "0"
+FIT_GENERATE_KEYS = "1"
+KERNEL_IMAGETYPE_REPLACEMENT = "zImage"
+FIT_KERNEL_COMP_ALG = "none"
+FIT_HASH_ALG = "sha256"
+"""
+ self.write_config(config)
+
+ # fitImage is created as part of linux recipe
+ bitbake("virtual/kernel")
+
+ image_type = get_bb_var('INITRAMFS_IMAGE')
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ machine = get_bb_var('MACHINE')
+ fitimage_its_path = os.path.join(deploy_dir_image,
+ "fitImage-its-%s-%s-%s" % (image_type, machine, machine))
+ fitimage_path = os.path.join(deploy_dir_image,"fitImage")
+
+ self.assertTrue(os.path.exists(fitimage_its_path),
+ "%s image tree source doesn't exist" % (fitimage_its_path))
+ self.assertTrue(os.path.exists(fitimage_path),
+ "%s FIT image doesn't exist" % (fitimage_path))
+
+ kernel_load = str(get_bb_var('UBOOT_LOADADDRESS'))
+ kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT'))
+ kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG'))
+ uboot_arch = str(get_bb_var('UBOOT_ARCH'))
+ fit_hash_alg = str(get_bb_var('FIT_HASH_ALG'))
+
+ its_file = open(fitimage_its_path)
+
+ its_lines = [line.strip() for line in its_file.readlines()]
+
+ exp_node_lines = [
+ 'kernel-1 {',
+ 'description = "Linux kernel";',
+ 'data = /incbin/("linux.bin");',
+ 'type = "kernel";',
+ 'arch = "' + uboot_arch + '";',
+ 'os = "linux";',
+ 'compression = "' + kernel_compression + '";',
+ 'load = <' + kernel_load + '>;',
+ 'entry = <' + kernel_entry + '>;',
+ 'hash-1 {',
+ 'algo = "' + fit_hash_alg +'";',
+ '};',
+ '};'
+ ]
+
+ node_str = exp_node_lines[0]
+
+ test_passed = False
+
+ print ("checking kernel node\n")
+
+ if node_str in its_lines:
+ node_start_idx = its_lines.index(node_str)
+ node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))]
+ if node == exp_node_lines:
+ print("kernel node verified")
+ else:
+ self.assertTrue(test_passed == True,"kernel node does not match expectation")
+
+ rx_configs = re.compile("^conf-.*")
+ its_configs = list(filter(rx_configs.match, its_lines))
+
+ for cfg_str in its_configs:
+ cfg_start_idx = its_lines.index(cfg_str)
+ line_idx = cfg_start_idx + 2
+ node_end = False
+ while node_end == False:
+ if its_lines[line_idx] == "};" and its_lines[line_idx-1] == "};" :
+ node_end = True
+ line_idx = line_idx + 1
+
+ node = its_lines[cfg_start_idx:line_idx]
+ print("checking configuration " + cfg_str.rstrip(" {"))
+ rx_desc_line = re.compile("^description.*1 Linux kernel.*")
+ if len(list(filter(rx_desc_line.match, node))) != 1:
+ self.assertTrue(test_passed == True,"kernel keyword not found in the description line")
+ break
+ else:
+ print("kernel keyword found in the description line")
+
+ if 'kernel = "kernel-1";' not in node:
+ self.assertTrue(test_passed == True,"kernel line not found")
+ break
+ else:
+ print("kernel line found")
+
+ rx_sign_line = re.compile("^sign-images.*kernel.*")
+ if len(list(filter(rx_sign_line.match, node))) != 1:
+ self.assertTrue(test_passed == True,"kernel hash not signed")
+ break
+ else:
+ print("kernel hash signed")
+
+ test_passed = True
+ self.assertTrue(test_passed == True,"Initramfs bundle test success")
diff --git a/meta/lib/oeqa/selftest/cases/gcc.py b/meta/lib/oeqa/selftest/cases/gcc.py
new file mode 100644
index 0000000000..3efe15228f
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/gcc.py
@@ -0,0 +1,152 @@
+# SPDX-License-Identifier: MIT
+import os
+from oeqa.core.decorator import OETestTag
+from oeqa.core.case import OEPTestResultTestCase
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars, runqemu, Command
+
+def parse_values(content):
+ for i in content:
+ for v in ["PASS", "FAIL", "XPASS", "XFAIL", "UNRESOLVED", "UNSUPPORTED", "UNTESTED", "ERROR", "WARNING"]:
+ if i.startswith(v + ": "):
+ yield i[len(v) + 2:].strip(), v
+ break
+
+class GccSelfTestBase(OESelftestTestCase, OEPTestResultTestCase):
+ def check_skip(self, suite):
+ targets = get_bb_var("RUNTIMETARGET", "gcc-runtime").split()
+ if suite not in targets:
+ self.skipTest("Target does not use {0}".format(suite))
+
+ def run_check(self, *suites, ssh = None):
+ targets = set()
+ for s in suites:
+ if s == "gcc":
+ targets.add("check-gcc-c")
+ elif s == "g++":
+ targets.add("check-gcc-c++")
+ else:
+ targets.add("check-target-{}".format(s))
+
+ # configure ssh target
+ features = []
+ features.append('MAKE_CHECK_TARGETS = "{0}"'.format(" ".join(targets)))
+ if ssh is not None:
+ features.append('TOOLCHAIN_TEST_TARGET = "ssh"')
+ features.append('TOOLCHAIN_TEST_HOST = "{0}"'.format(ssh))
+ features.append('TOOLCHAIN_TEST_HOST_USER = "root"')
+ features.append('TOOLCHAIN_TEST_HOST_PORT = "22"')
+ self.write_config("\n".join(features))
+
+ recipe = "gcc-runtime"
+ bitbake("{} -c check".format(recipe))
+
+ bb_vars = get_bb_vars(["B", "TARGET_SYS"], recipe)
+ builddir, target_sys = bb_vars["B"], bb_vars["TARGET_SYS"]
+
+ for suite in suites:
+ sumspath = os.path.join(builddir, "gcc", "testsuite", suite, "{0}.sum".format(suite))
+ if not os.path.exists(sumspath): # check in target dirs
+ sumspath = os.path.join(builddir, target_sys, suite, "testsuite", "{0}.sum".format(suite))
+ if not os.path.exists(sumspath): # handle libstdc++-v3 -> libstdc++
+ sumspath = os.path.join(builddir, target_sys, suite, "testsuite", "{0}.sum".format(suite.split("-")[0]))
+ logpath = os.path.splitext(sumspath)[0] + ".log"
+
+ ptestsuite = "gcc-{}".format(suite) if suite != "gcc" else suite
+ ptestsuite = ptestsuite + "-user" if ssh is None else ptestsuite
+ self.ptest_section(ptestsuite, logfile = logpath)
+ with open(sumspath, "r") as f:
+ for test, result in parse_values(f):
+ self.ptest_result(ptestsuite, test, result)
+
+ def run_check_emulated(self, *args, **kwargs):
+ # build core-image-minimal with required packages
+ default_installed_packages = ["libgcc", "libstdc++", "libatomic", "libgomp"]
+ features = []
+ features.append('IMAGE_FEATURES += "ssh-server-openssh"')
+ features.append('CORE_IMAGE_EXTRA_INSTALL += "{0}"'.format(" ".join(default_installed_packages)))
+ self.write_config("\n".join(features))
+ bitbake("core-image-minimal")
+
+ # wrap the execution with a qemu instance
+ with runqemu("core-image-minimal", runqemuparams = "nographic") as qemu:
+ # validate that SSH is working
+ status, _ = qemu.run("uname")
+ self.assertEqual(status, 0)
+
+ return self.run_check(*args, ssh=qemu.ip, **kwargs)
+
+@OETestTag("toolchain-user")
+class GccCrossSelfTest(GccSelfTestBase):
+ def test_cross_gcc(self):
+ self.run_check("gcc")
+
+@OETestTag("toolchain-user")
+class GxxCrossSelfTest(GccSelfTestBase):
+ def test_cross_gxx(self):
+ self.run_check("g++")
+
+@OETestTag("toolchain-user")
+class GccLibAtomicSelfTest(GccSelfTestBase):
+ def test_libatomic(self):
+ self.run_check("libatomic")
+
+@OETestTag("toolchain-user")
+class GccLibGompSelfTest(GccSelfTestBase):
+ def test_libgomp(self):
+ self.run_check("libgomp")
+
+@OETestTag("toolchain-user")
+class GccLibStdCxxSelfTest(GccSelfTestBase):
+ def test_libstdcxx(self):
+ self.run_check("libstdc++-v3")
+
+@OETestTag("toolchain-user")
+class GccLibSspSelfTest(GccSelfTestBase):
+ def test_libssp(self):
+ self.check_skip("libssp")
+ self.run_check("libssp")
+
+@OETestTag("toolchain-user")
+class GccLibItmSelfTest(GccSelfTestBase):
+ def test_libitm(self):
+ self.check_skip("libitm")
+ self.run_check("libitm")
+
+@OETestTag("toolchain-system")
+class GccCrossSelfTestSystemEmulated(GccSelfTestBase):
+ def test_cross_gcc(self):
+ self.run_check_emulated("gcc")
+
+@OETestTag("toolchain-system")
+class GxxCrossSelfTestSystemEmulated(GccSelfTestBase):
+ def test_cross_gxx(self):
+ self.run_check_emulated("g++")
+
+@OETestTag("toolchain-system")
+class GccLibAtomicSelfTestSystemEmulated(GccSelfTestBase):
+ def test_libatomic(self):
+ self.run_check_emulated("libatomic")
+
+@OETestTag("toolchain-system")
+class GccLibGompSelfTestSystemEmulated(GccSelfTestBase):
+ def test_libgomp(self):
+ self.run_check_emulated("libgomp")
+
+@OETestTag("toolchain-system")
+class GccLibStdCxxSelfTestSystemEmulated(GccSelfTestBase):
+ def test_libstdcxx(self):
+ self.run_check_emulated("libstdc++-v3")
+
+@OETestTag("toolchain-system")
+class GccLibSspSelfTestSystemEmulated(GccSelfTestBase):
+ def test_libssp(self):
+ self.check_skip("libssp")
+ self.run_check_emulated("libssp")
+
+@OETestTag("toolchain-system")
+class GccLibItmSelfTestSystemEmulated(GccSelfTestBase):
+ def test_libitm(self):
+ self.check_skip("libitm")
+ self.run_check_emulated("libitm")
+
diff --git a/meta/lib/oeqa/selftest/cases/glibc.py b/meta/lib/oeqa/selftest/cases/glibc.py
new file mode 100644
index 0000000000..6f96281ea5
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/glibc.py
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: MIT
+import os
+import contextlib
+from oeqa.core.decorator import OETestTag
+from oeqa.core.case import OEPTestResultTestCase
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars, runqemu, Command
+from oeqa.utils.nfs import unfs_server
+
+def parse_values(content):
+ for i in content:
+ for v in ["PASS", "FAIL", "XPASS", "XFAIL", "UNRESOLVED", "UNSUPPORTED", "UNTESTED", "ERROR", "WARNING"]:
+ if i.startswith(v + ": "):
+ yield i[len(v) + 2:].strip(), v
+ break
+
+class GlibcSelfTestBase(OESelftestTestCase, OEPTestResultTestCase):
+ def run_check(self, ssh = None):
+ # configure ssh target
+ features = []
+ if ssh is not None:
+ features.append('TOOLCHAIN_TEST_TARGET = "ssh"')
+ features.append('TOOLCHAIN_TEST_HOST = "{0}"'.format(ssh))
+ 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""')
+ self.write_config("\n".join(features))
+
+ bitbake("glibc-testsuite -c check")
+
+ builddir = get_bb_var("B", "glibc-testsuite")
+
+ ptestsuite = "glibc-user" if ssh is None else "glibc"
+ self.ptest_section(ptestsuite)
+ 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)
+
+ def run_check_emulated(self):
+ with contextlib.ExitStack() as s:
+ # use the base work dir, as the nfs mount, since the recipe directory may not exist
+ tmpdir = get_bb_var("BASE_WORKDIR")
+ nfsport, mountport = s.enter_context(unfs_server(tmpdir))
+
+ # build core-image-minimal with required packages
+ default_installed_packages = [
+ "glibc-charmaps",
+ "libgcc",
+ "libstdc++",
+ "libatomic",
+ "libgomp",
+ # "python3",
+ # "python3-pexpect",
+ "nfs-utils",
+ ]
+ features = []
+ features.append('IMAGE_FEATURES += "ssh-server-openssh"')
+ features.append('CORE_IMAGE_EXTRA_INSTALL += "{0}"'.format(" ".join(default_installed_packages)))
+ self.write_config("\n".join(features))
+ bitbake("core-image-minimal")
+
+ # start runqemu
+ qemu = s.enter_context(runqemu("core-image-minimal", runqemuparams = "nographic"))
+
+ # validate that SSH is working
+ status, _ = qemu.run("uname")
+ self.assertEqual(status, 0)
+
+ # setup nfs mount
+ if qemu.run("mkdir -p \"{0}\"".format(tmpdir))[0] != 0:
+ raise Exception("Failed to setup NFS mount directory on target")
+ mountcmd = "mount -o noac,nfsvers=3,port={0},udp,mountport={1} \"{2}:{3}\" \"{3}\"".format(nfsport, mountport, qemu.server_ip, tmpdir)
+ status, output = qemu.run(mountcmd)
+ if status != 0:
+ raise Exception("Failed to setup NFS mount on target ({})".format(repr(output)))
+
+ self.run_check(ssh = qemu.ip)
+
+@OETestTag("toolchain-user")
+class GlibcSelfTest(GlibcSelfTestBase):
+ def test_glibc(self):
+ self.run_check()
+
+@OETestTag("toolchain-system")
+class GlibcSelfTestSystemEmulated(GlibcSelfTestBase):
+ def test_glibc(self):
+ self.run_check_emulated()
+
diff --git a/meta/lib/oeqa/selftest/cases/gotoolchain.py b/meta/lib/oeqa/selftest/cases/gotoolchain.py
index 1e23257f4d..c809d7c9b1 100644
--- a/meta/lib/oeqa/selftest/cases/gotoolchain.py
+++ b/meta/lib/oeqa/selftest/cases/gotoolchain.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import glob
import os
import shutil
@@ -39,29 +43,34 @@ 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()
- def run_sdk_go_command(self, gocmd):
- cmd = "cd %s; " % self.tmpdir_SDKQA
+ def run_sdk_go_command(self, gocmd, proj, name):
+ cmd = "cd %s/src/%s/%s; " % (self.go_path, proj, name)
cmd = cmd + ". %s; " % self.env_SDK
cmd = cmd + "export GOPATH=%s; " % self.go_path
cmd = cmd + "${CROSS_COMPILE}go %s" % gocmd
return runCmd(cmd).status
def test_go_dep_build(self):
- proj = "github.com/golang"
- name = "dep"
- ver = "v0.3.1"
+ proj = "github.com/direnv"
+ name = "direnv"
+ ver = "v2.27.0"
archive = ".tar.gz"
url = "https://%s/%s/archive/%s%s" % (proj, name, ver, archive)
runCmd("cd %s; wget %s" % (self.tmpdir_SDKQA, url))
runCmd("cd %s; tar -xf %s" % (self.tmpdir_SDKQA, ver+archive))
runCmd("mkdir -p %s/src/%s" % (self.go_path, proj))
- runCmd("mv %s/dep-0.3.1 %s/src/%s/%s"
+ runCmd("mv %s/direnv-2.27.0 %s/src/%s/%s"
% (self.tmpdir_SDKQA, self.go_path, proj, name))
- retv = self.run_sdk_go_command('build %s/%s/cmd/dep'
- % (proj, name))
+ retv = self.run_sdk_go_command('build', proj, name)
self.assertEqual(retv, 0,
msg="Running go build failed for %s" % name)
diff --git a/meta/lib/oeqa/selftest/cases/image_typedep.py b/meta/lib/oeqa/selftest/cases/image_typedep.py
index 932c7f883d..5b182a8f94 100644
--- a/meta/lib/oeqa/selftest/cases/image_typedep.py
+++ b/meta/lib/oeqa/selftest/cases/image_typedep.py
@@ -1,14 +1,16 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import bitbake
-from oeqa.core.decorator.oeid import OETestID
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
- @OETestID(1633)
def test_conversion_typedep_added(self):
self.write_recipeinc('emptytest', """
@@ -20,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 8c95432e00..d36d45c551 100644
--- a/meta/lib/oeqa/selftest/cases/imagefeatures.py
+++ b/meta/lib/oeqa/selftest/cases/imagefeatures.py
@@ -1,7 +1,11 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu
-from oeqa.core.decorator.oeid import OETestID
from oeqa.utils.sshcontrol import SSHControl
+import glob
import os
import json
@@ -10,7 +14,6 @@ class ImageFeatures(OESelftestTestCase):
test_user = 'tester'
root_user = 'root'
- @OETestID(1107)
def test_non_root_user_can_connect_via_ssh_without_password(self):
"""
Summary: Check if non root user can connect via ssh without password
@@ -36,7 +39,6 @@ class ImageFeatures(OESelftestTestCase):
status, output = ssh.run("true")
self.assertEqual(status, 0, 'ssh to user %s failed with %s' % (user, output))
- @OETestID(1115)
def test_all_users_can_connect_via_ssh_without_password(self):
"""
Summary: Check if all users can connect via ssh without password
@@ -66,20 +68,6 @@ class ImageFeatures(OESelftestTestCase):
self.assertEqual(status, 0, 'ssh to user tester failed with %s' % output)
- @OETestID(1116)
- def test_clutter_image_can_be_built(self):
- """
- Summary: Check if clutter image can be built
- Expected: 1. core-image-clutter can be built
- Product: oe-core
- Author: Ionut Chisanovici <ionutx.chisanovici@intel.com>
- AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com>
- """
-
- # Build a core-image-clutter
- bitbake('core-image-clutter')
-
- @OETestID(1117)
def test_wayland_support_in_image(self):
"""
Summary: Check Wayland support in image
@@ -97,7 +85,6 @@ class ImageFeatures(OESelftestTestCase):
# Build a core-image-weston
bitbake('core-image-weston')
- @OETestID(1497)
def test_bmap(self):
"""
Summary: Check bmap support
@@ -126,12 +113,11 @@ class ImageFeatures(OESelftestTestCase):
# check if result image is sparse
image_stat = os.stat(image_path)
- self.assertTrue(image_stat.st_size > image_stat.st_blocks * 512)
+ self.assertGreater(image_stat.st_size, image_stat.st_blocks * 512)
# check if the resulting gzip is valid
self.assertTrue(runCmd('gzip -t %s' % gzip_path))
- @OETestID(1903)
def test_hypervisor_fmts(self):
"""
Summary: Check various hypervisor formats
@@ -164,9 +150,13 @@ class ImageFeatures(OESelftestTestCase):
sysroot = get_bb_var('STAGING_DIR_NATIVE', 'core-image-minimal')
result = runCmd('qemu-img info --output json %s' % image_path,
native_sysroot=sysroot)
- self.assertTrue(json.loads(result.output).get('format') == itype)
+ try:
+ data = json.loads(result.output)
+ self.assertEqual(data.get('format'), itype,
+ msg="Unexpected format in '%s'" % (result.output))
+ except json.decoder.JSONDecodeError:
+ self.fail("Could not parse '%ss'" % result.output)
- @OETestID(1905)
def test_long_chain_conversion(self):
"""
Summary: Check for chaining many CONVERSION_CMDs together
@@ -198,7 +188,6 @@ class ImageFeatures(OESelftestTestCase):
self.assertTrue(runCmd('cd %s;sha256sum -c %s.%s.sha256sum' %
(deploy_dir_image, link_name, conv)))
- @OETestID(1904)
def test_image_fstypes(self):
"""
Summary: Check if image of supported image fstypes can be built
@@ -208,13 +197,13 @@ class ImageFeatures(OESelftestTestCase):
"""
image_name = 'core-image-minimal'
- img_types = [itype for itype in get_bb_var("IMAGE_TYPES", image_name).split() \
- if itype not in ('container', 'elf', 'f2fs', 'multiubi')]
+ all_image_types = set(get_bb_var("IMAGE_TYPES", image_name).split())
+ 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'\
'UBINIZE_ARGS ?= "-m 2048 -p 128KiB -s 512"' % ' '.join(img_types)
-
self.write_config(config)
bitbake(image_name)
@@ -236,3 +225,70 @@ USERADD_GID_TABLES += "files/static-group"
"""
self.write_config(config)
bitbake("core-image-base")
+
+ def test_no_busybox_base_utils(self):
+ config = """
+# Enable wayland
+DISTRO_FEATURES:append = " pam opengl wayland"
+
+# Switch to systemd
+DISTRO_FEATURES += "systemd"
+VIRTUAL-RUNTIME_init_manager = "systemd"
+VIRTUAL-RUNTIME_initscripts = ""
+VIRTUAL-RUNTIME_syslog = ""
+VIRTUAL-RUNTIME_login_manager = "shadow-base"
+DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
+
+# Replace busybox
+PREFERRED_PROVIDER_virtual/base-utils = "packagegroup-core-base-utils"
+VIRTUAL-RUNTIME_base-utils = "packagegroup-core-base-utils"
+VIRTUAL-RUNTIME_base-utils-hwclock = "util-linux-hwclock"
+VIRTUAL-RUNTIME_base-utils-syslog = ""
+
+# Skip busybox
+SKIP_RECIPE[busybox] = "Don't build this"
+"""
+ self.write_config(config)
+
+ bitbake("--graphviz core-image-weston")
+
+ def test_image_gen_debugfs(self):
+ """
+ Summary: Check debugfs generation
+ Expected: 1. core-image-minimal can be build with IMAGE_GEN_DEBUGFS variable set
+ 2. debug filesystem is created when variable set
+ 3. debug symbols available
+ Product: oe-core
+ Author: Humberto Ibarra <humberto.ibarra.lopez@intel.com>
+ Yeoh Ee Peng <ee.peng.yeoh@intel.com>
+ """
+
+ image_name = 'core-image-minimal'
+ features = 'IMAGE_GEN_DEBUGFS = "1"\n'
+ features += 'IMAGE_FSTYPES_DEBUGFS = "tar.bz2"\n'
+ features += 'MACHINE = "genericx86-64"\n'
+ self.write_config(features)
+
+ bitbake(image_name)
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+ dbg_tar_file = os.path.join(deploy_dir_image, "*-dbg.rootfs.tar.bz2")
+ debug_files = glob.glob(dbg_tar_file)
+ self.assertNotEqual(len(debug_files), 0, 'debug filesystem not generated at %s' % dbg_tar_file)
+ result = runCmd('cd %s; tar xvf %s' % (deploy_dir_image, dbg_tar_file))
+ self.assertEqual(result.status, 0, msg='Failed to extract %s: %s' % (dbg_tar_file, result.output))
+ result = runCmd('find %s -name %s' % (deploy_dir_image, "udevadm"))
+ self.assertTrue("udevadm" in result.output, msg='Failed to find udevadm: %s' % result.output)
+ dbg_symbols_targets = result.output.splitlines()
+ self.assertTrue(dbg_symbols_targets, msg='Failed to split udevadm: %s' % dbg_symbols_targets)
+ for t in dbg_symbols_targets:
+ result = runCmd('objdump --syms %s | grep debug' % t)
+ self.assertTrue("debug" in result.output, msg='Failed to find debug symbol: %s' % result.output)
+
+ def test_empty_image(self):
+ """Test creation of image with no packages"""
+ bitbake('test-empty-image')
+ res_dir = get_bb_var('DEPLOY_DIR_IMAGE')
+ images = os.path.join(res_dir, "test-empty-image-*.manifest")
+ result = glob.glob(images)
+ with open(result[1],"r") as f:
+ self.assertEqual(len(f.read().strip()),0)
diff --git a/meta/lib/oeqa/selftest/cases/incompatible_lic.py b/meta/lib/oeqa/selftest/cases/incompatible_lic.py
new file mode 100644
index 0000000000..0794d46e6d
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/incompatible_lic.py
@@ -0,0 +1,161 @@
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake
+
+class IncompatibleLicenseTestObsolete(OESelftestTestCase):
+
+ 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))
+
+ 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 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', "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', "*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', "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', "*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', "*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 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', "*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', '*', "* 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
+ # INCOMPATIBLE_LICENSE contains this license
+ def test_incompatible_nonspdx_license(self):
+ self.lic_test('incompatible-nonspdx-license', 'FooLicense', 'FooLicense')
+
+class IncompatibleLicensePerImageTests(OESelftestTestCase):
+ def default_config(self):
+ return """
+IMAGE_INSTALL:append = " bash"
+INCOMPATIBLE_LICENSE:pn-core-image-minimal = "GPL-3.0* LGPL-3.0*"
+"""
+
+ def test_bash_default(self):
+ self.write_config(self.default_config())
+ 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)
+ if error_msg not in result.output:
+ raise AssertionError(result.output)
+
+ def test_bash_and_license(self):
+ 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)
+ if error_msg not in result.output:
+ raise AssertionError(result.output)
+
+ def test_bash_or_license(self):
+ self.write_config(self.default_config() + '\nLICENSE:append:pn-bash = " | SomeLicense"')
+
+ bitbake('core-image-minimal')
+
+ def test_bash_license_exceptions(self):
+ self.write_config(self.default_config() + '\nINCOMPATIBLE_LICENSE_EXCEPTIONS:pn-core-image-minimal = "bash:GPL-3.0-or-later"')
+
+ 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*"
+""")
+ bitbake('core-image-minimal')
+
+ def test_core_image_full_cmdline_weston(self):
+ self.write_config("""
+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 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
new file mode 100644
index 0000000000..b1623a1885
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/kerneldevelopment.py
@@ -0,0 +1,67 @@
+import os
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import runCmd, get_bb_var
+from oeqa.utils.git import GitRepo
+
+class KernelDev(OESelftestTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(KernelDev, cls).setUpClass()
+ # Create the recipe directory structure inside the created layer
+ cls.layername = 'meta-kerneltest'
+ runCmd('bitbake-layers create-layer %s' % cls.layername)
+ runCmd('mkdir -p %s/recipes-kernel/linux/linux-yocto' % cls.layername)
+ cls.recipes_linuxyocto_dir = os.path.join \
+ (cls.builddir, cls.layername, 'recipes-kernel', 'linux', 'linux-yocto')
+ cls.recipeskernel_dir = os.path.dirname(cls.recipes_linuxyocto_dir)
+ runCmd('bitbake-layers add-layer %s' % cls.layername)
+
+ @classmethod
+ def tearDownClass(cls):
+ runCmd('bitbake-layers remove-layer %s' % cls.layername, ignore_status=True)
+ runCmd('rm -rf %s' % cls.layername)
+ super(KernelDev, cls).tearDownClass()
+
+ def setUp(self):
+ super(KernelDev, self).setUp()
+ self.set_machine_config('MACHINE = "qemux86-64"\n')
+
+ def test_apply_patches(self):
+ """
+ Summary: Able to apply a single patch to the Linux kernel source
+ Expected: The README file should exist and the patch changes should be
+ displayed at the end of the file.
+ Product: Kernel Development
+ Author: Yeoh Ee Peng <ee.peng.yeoh@intel.com>
+ AutomatedBy: Mazliana Mohamad <mazliana.mohamad@intel.com>
+ """
+ runCmd('bitbake virtual/kernel -c patch')
+ kernel_source = get_bb_var('STAGING_KERNEL_DIR')
+ readme = os.path.join(kernel_source, 'README')
+
+ # This test step adds modified file 'README' to git and creates a
+ # patch file '0001-KERNEL_DEV_TEST_CASE.patch' at the same location as file
+ patch_content = 'This is a test to apply a patch to the kernel'
+ with open(readme, 'a+') as f:
+ f.write(patch_content)
+ repo = GitRepo('%s' % kernel_source, is_topdir=True)
+ repo.run_cmd('add %s' % readme)
+ repo.run_cmd(['commit', '-m', 'KERNEL_DEV_TEST_CASE'])
+ repo.run_cmd(['format-patch', '-1'])
+ patch_name = '0001-KERNEL_DEV_TEST_CASE.patch'
+ patchpath = os.path.join(kernel_source, patch_name)
+ runCmd('mv %s %s' % (patchpath, self.recipes_linuxyocto_dir))
+ runCmd('rm %s ' % readme)
+ self.assertFalse(os.path.exists(readme))
+
+ 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}:"')
+
+ runCmd('bitbake virtual/kernel -c clean')
+ runCmd('bitbake virtual/kernel -c patch')
+ self.assertTrue(os.path.exists(readme))
+ result = runCmd('tail -n 1 %s' % readme)
+ self.assertEqual(result.output, patch_content)
diff --git a/meta/lib/oeqa/selftest/cases/layerappend.py b/meta/lib/oeqa/selftest/cases/layerappend.py
index 2fd5cdb0c6..dadc7c5d28 100644
--- a/meta/lib/oeqa/selftest/cases/layerappend.py
+++ b/meta/lib/oeqa/selftest/cases/layerappend.py
@@ -1,9 +1,12 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var
import oeqa.utils.ftools as ftools
-from oeqa.core.decorator.oeid import OETestID
class LayerAppendTests(OESelftestTestCase):
layerconf = """
@@ -27,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 = ''
@@ -49,7 +52,6 @@ SRC_URI_append = " file://appendtest.txt"
ftools.remove_from_file(self.builddir + "/conf/bblayers.conf", self.layerappend)
super(LayerAppendTests, self).tearDownLocal()
- @OETestID(1196)
def test_layer_appends(self):
corebase = get_bb_var("COREBASE")
diff --git a/meta/lib/oeqa/selftest/cases/liboe.py b/meta/lib/oeqa/selftest/cases/liboe.py
index e84609246a..afe8f8809f 100644
--- a/meta/lib/oeqa/selftest/cases/liboe.py
+++ b/meta/lib/oeqa/selftest/cases/liboe.py
@@ -1,5 +1,8 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.core.decorator.oeid import OETestID
from oeqa.utils.commands import get_bb_var, get_bb_vars, bitbake, runCmd
import oe.path
import os
@@ -11,7 +14,6 @@ class LibOE(OESelftestTestCase):
super(LibOE, cls).setUpClass()
cls.tmp_dir = get_bb_var('TMPDIR')
- @OETestID(1635)
def test_copy_tree_special(self):
"""
Summary: oe.path.copytree() should copy files with special character
@@ -37,7 +39,6 @@ class LibOE(OESelftestTestCase):
oe.path.remove(testloc)
- @OETestID(1636)
def test_copy_tree_xattr(self):
"""
Summary: oe.path.copytree() should preserve xattr on copied files
@@ -72,7 +73,6 @@ class LibOE(OESelftestTestCase):
oe.path.remove(testloc)
- @OETestID(1634)
def test_copy_hardlink_tree_count(self):
"""
Summary: oe.path.copyhardlinktree() shouldn't miss out files
diff --git a/meta/lib/oeqa/selftest/cases/lic_checksum.py b/meta/lib/oeqa/selftest/cases/lic_checksum.py
index f992b3736e..91021ac335 100644
--- a/meta/lib/oeqa/selftest/cases/lic_checksum.py
+++ b/meta/lib/oeqa/selftest/cases/lic_checksum.py
@@ -1,16 +1,18 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import tempfile
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import bitbake
from oeqa.utils import CommandError
-from oeqa.core.decorator.oeid import OETestID
class LicenseTests(OESelftestTestCase):
# Verify that changing a license file that has an absolute path causes
# the license qa to fail due to a mismatched md5sum.
- @OETestID(1197)
def test_nonmatching_checksum(self):
bitbake_cmd = '-c populate_lic emptytest'
error_msg = 'emptytest: The new md5 checksum is 8d777f385d3dfec8815d20f7496026dc'
@@ -19,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/manifest.py b/meta/lib/oeqa/selftest/cases/manifest.py
index 146071934d..5d13f35468 100644
--- a/meta/lib/oeqa/selftest/cases/manifest.py
+++ b/meta/lib/oeqa/selftest/cases/manifest.py
@@ -1,8 +1,11 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import get_bb_var, get_bb_vars, bitbake
-from oeqa.core.decorator.oeid import OETestID
class ManifestEntry:
'''A manifest item of a collection able to list missing packages'''
@@ -59,7 +62,6 @@ class VerifyManifest(OESelftestTestCase):
self.skipTest("{}: Cannot setup testing scenario"\
.format(self.classname))
- @OETestID(1380)
def test_SDK_manifest_entries(self):
'''Verifying the SDK manifest entries exist, this may take a build'''
@@ -84,11 +86,8 @@ class VerifyManifest(OESelftestTestCase):
try:
mdir = self.get_dir_from_bb_var('SDK_DEPLOY', self.buildtarget)
for k in d_target.keys():
- bb_vars = get_bb_vars(['SDK_NAME', 'SDK_VERSION'], self.buildtarget)
- mfilename[k] = "{}-toolchain-{}.{}.manifest".format(
- bb_vars['SDK_NAME'],
- bb_vars['SDK_VERSION'],
- k)
+ toolchain_outputname = get_bb_var('TOOLCHAIN_OUTPUTNAME', self.buildtarget)
+ mfilename[k] = "{}.{}.manifest".format(toolchain_outputname, k)
mpath[k] = os.path.join(mdir, mfilename[k])
if not os.path.isfile(mpath[k]):
self.logger.debug("{}: {} does not exist".format(
@@ -126,7 +125,6 @@ class VerifyManifest(OESelftestTestCase):
self.logger.info(msg)
self.fail(logmsg)
- @OETestID(1381)
def test_image_manifest_entries(self):
'''Verifying the image manifest entries exist'''
diff --git a/meta/lib/oeqa/selftest/cases/meta_ide.py b/meta/lib/oeqa/selftest/cases/meta_ide.py
index 5df9d3ed93..6f10d30dc9 100644
--- a/meta/lib/oeqa/selftest/cases/meta_ide.py
+++ b/meta/lib/oeqa/selftest/cases/meta_ide.py
@@ -1,10 +1,15 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
from oeqa.sdk.utils.sdkbuildproject import SDKBuildProject
from oeqa.utils.commands import bitbake, get_bb_vars, runCmd
-from oeqa.core.decorator.oeid import OETestID
+from oeqa.core.decorator import OETestTag
import tempfile
import shutil
+@OETestTag("machine")
class MetaIDE(OESelftestTestCase):
@classmethod
@@ -23,25 +28,22 @@ class MetaIDE(OESelftestTestCase):
shutil.rmtree(cls.tmpdir_metaideQA, ignore_errors=True)
super(MetaIDE, cls).tearDownClass()
- @OETestID(1982)
def test_meta_ide_had_installed_meta_ide_support(self):
self.assertExists(self.environment_script_path)
- @OETestID(1983)
def test_meta_ide_can_compile_c_program(self):
runCmd('cp %s/test.c %s' % (self.tc.files_dir, self.tmpdir_metaideQA))
runCmd("cd %s; . %s; $CC test.c -lm" % (self.tmpdir_metaideQA, self.environment_script_path))
compiled_file = '%s/a.out' % self.tmpdir_metaideQA
self.assertExists(compiled_file)
- @OETestID(1984)
def test_meta_ide_can_build_cpio_project(self):
dl_dir = self.td.get('DL_DIR', None)
self.project = SDKBuildProject(self.tmpdir_metaideQA + "/cpio/", self.environment_script_path,
- "https://ftp.gnu.org/gnu/cpio/cpio-2.12.tar.gz",
+ "https://ftp.gnu.org/gnu/cpio/cpio-2.13.tar.gz",
self.tmpdir_metaideQA, self.td['DATETIME'], dl_dir=dl_dir)
self.project.download_archive()
- self.assertEqual(self.project.run_configure(), 0,
+ self.assertEqual(self.project.run_configure('$CONFIGURE_FLAGS --disable-maintainer-mode','sed -i -e "/char \*program_name/d" src/global.c;'), 0,
msg="Running configure failed")
self.assertEqual(self.project.run_make(), 0,
msg="Running make failed")
diff --git a/meta/lib/oeqa/selftest/cases/multiconfig.py b/meta/lib/oeqa/selftest/cases/multiconfig.py
new file mode 100644
index 0000000000..baae9b456f
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/multiconfig.py
@@ -0,0 +1,72 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+import os
+import textwrap
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake
+
+class MultiConfig(OESelftestTestCase):
+
+ def test_multiconfig(self):
+ """
+ Test that a simple multiconfig build works. This uses the mcextend class and the
+ multiconfig-image-packager test recipe to build a core-image-full-cmdline image which
+ contains a tiny core-image-minimal and a musl core-image-minimal, installed as packages.
+ """
+
+ config = """
+IMAGE_INSTALL:append:pn-core-image-full-cmdline = " multiconfig-image-packager-tiny multiconfig-image-packager-musl"
+BBMULTICONFIG = "tiny musl"
+"""
+ self.write_config(config)
+
+ muslconfig = """
+MACHINE = "qemux86-64"
+DISTRO = "poky"
+TCLIBC = "musl"
+TMPDIR = "${TOPDIR}/tmp-mc-musl"
+"""
+ self.write_config(muslconfig, 'musl')
+
+ tinyconfig = """
+MACHINE = "qemux86"
+DISTRO = "poky-tiny"
+TMPDIR = "${TOPDIR}/tmp-mc-tiny"
+"""
+ self.write_config(tinyconfig, 'tiny')
+
+ # Build a core-image-minimal
+ bitbake('core-image-full-cmdline')
+
+ def test_multiconfig_reparse(self):
+ """
+ Test that changes to a multiconfig conf file are correctly detected and
+ cause a reparse/rebuild of a recipe.
+ """
+ config = textwrap.dedent('''\
+ MCTESTVAR = "test"
+ BBMULTICONFIG = "test"
+ ''')
+ self.write_config(config)
+
+ testconfig = textwrap.dedent('''\
+ MCTESTVAR:append = "1"
+ ''')
+ self.write_config(testconfig, 'test')
+
+ # Check that the 1) the task executed and 2) that it output the correct
+ # value. Note "bitbake -e" is not used because it always reparses the
+ # recipe and we want to ensure that the automatic reparsing and parse
+ # caching is detected.
+ result = bitbake('mc:test:multiconfig-test-parse -c showvar')
+ self.assertIn('MCTESTVAR=test1', result.output.splitlines())
+
+ testconfig = textwrap.dedent('''\
+ MCTESTVAR:append = "2"
+ ''')
+ self.write_config(testconfig, 'test')
+
+ result = bitbake('mc:test:multiconfig-test-parse -c showvar')
+ self.assertIn('MCTESTVAR=test2', result.output.splitlines())
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/buildhistory.py b/meta/lib/oeqa/selftest/cases/oelib/buildhistory.py
index 08675fd820..802a91a488 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/buildhistory.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/buildhistory.py
@@ -1,8 +1,12 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
from oeqa.selftest.case import OESelftestTestCase
import tempfile
+import operator
from oeqa.utils.commands import get_bb_var
-from oeqa.core.decorator.oeid import OETestID
class TestBlobParsing(OESelftestTestCase):
@@ -40,10 +44,9 @@ class TestBlobParsing(OESelftestTestCase):
self.repo.git.add("--all")
self.repo.git.commit(message=msg)
- @OETestID(1859)
def test_blob_to_dict(self):
"""
- Test convertion of git blobs to dictionary
+ Test conversion of git blobs to dictionary
"""
from oe.buildhistory_analysis import blob_to_dict
valuesmap = { "foo" : "1", "bar" : "2" }
@@ -53,7 +56,6 @@ class TestBlobParsing(OESelftestTestCase):
self.assertEqual(valuesmap, blob_to_dict(blob),
"commit was not translated correctly to dictionary")
- @OETestID(1860)
def test_compare_dict_blobs(self):
"""
Test comparisson of dictionaries extracted from git blobs
@@ -74,7 +76,6 @@ class TestBlobParsing(OESelftestTestCase):
var_changes = { x.fieldname : (x.oldvalue, x.newvalue) for x in change_records}
self.assertEqual(changesmap, var_changes, "Changes not reported correctly")
- @OETestID(1861)
def test_compare_dict_blobs_default(self):
"""
Test default values for comparisson of git blob dictionaries
@@ -97,3 +98,48 @@ class TestBlobParsing(OESelftestTestCase):
var_changes[x.fieldname] = (oldvalue, x.newvalue)
self.assertEqual(defaultmap, var_changes, "Defaults not set properly")
+
+class TestFileListCompare(OESelftestTestCase):
+
+ def test_compare_file_lists(self):
+ # Test that a directory tree that moves location such as /lib/modules/5.4.40-yocto-standard -> /lib/modules/5.4.43-yocto-standard
+ # is correctly identified as a move
+ from oe.buildhistory_analysis import compare_file_lists, FileChange
+
+ with open(self.tc.files_dir + "/buildhistory_filelist1.txt", "r") as f:
+ filelist1 = f.readlines()
+ with open(self.tc.files_dir + "/buildhistory_filelist2.txt", "r") as f:
+ filelist2 = f.readlines()
+
+ expectedResult = [
+ '/lib/libcap.so.2 changed symlink target from libcap.so.2.33 to libcap.so.2.34',
+ '/lib/libcap.so.2.33 moved to /lib/libcap.so.2.34',
+ '/lib/modules/5.4.40-yocto-standard moved to /lib/modules/5.4.43-yocto-standard',
+ '/lib/modules/5.4.43-yocto-standard/modules.builtin.alias.bin was added',
+ '/usr/bin/gawk-5.0.1 moved to /usr/bin/gawk-5.1.0',
+ '/usr/lib/libbtrfsutil.so changed symlink target from libbtrfsutil.so.1.1.1 to libbtrfsutil.so.1.2.0',
+ '/usr/lib/libbtrfsutil.so.1 changed symlink target from libbtrfsutil.so.1.1.1 to libbtrfsutil.so.1.2.0',
+ '/usr/lib/libbtrfsutil.so.1.1.1 moved to /usr/lib/libbtrfsutil.so.1.2.0',
+ '/usr/lib/libkmod.so changed symlink target from libkmod.so.2.3.4 to libkmod.so.2.3.5',
+ '/usr/lib/libkmod.so.2 changed symlink target from libkmod.so.2.3.4 to libkmod.so.2.3.5',
+ '/usr/lib/libkmod.so.2.3.4 moved to /usr/lib/libkmod.so.2.3.5',
+ '/usr/lib/libpixman-1.so.0 changed symlink target from libpixman-1.so.0.38.4 to libpixman-1.so.0.40.0',
+ '/usr/lib/libpixman-1.so.0.38.4 moved to /usr/lib/libpixman-1.so.0.40.0',
+ '/usr/lib/opkg/alternatives/rtcwake was added',
+ '/usr/lib/python3.8/site-packages/PyGObject-3.34.0.egg-info moved to /usr/lib/python3.8/site-packages/PyGObject-3.36.1.egg-info',
+ '/usr/lib/python3.8/site-packages/btrfsutil-1.1.1-py3.8.egg-info moved to /usr/lib/python3.8/site-packages/btrfsutil-1.2.0-py3.8.egg-info',
+ '/usr/lib/python3.8/site-packages/pycairo-1.19.0.egg-info moved to /usr/lib/python3.8/site-packages/pycairo-1.19.1.egg-info',
+ '/usr/sbin/rtcwake changed type from file to symlink',
+ '/usr/sbin/rtcwake changed permissions from rwxr-xr-x to rwxrwxrwx',
+ '/usr/sbin/rtcwake changed symlink target from None to /usr/sbin/rtcwake.util-linux',
+ '/usr/sbin/rtcwake.util-linux was added'
+ ]
+
+ result = compare_file_lists(filelist1, filelist2)
+ rendered = []
+ for entry in sorted(result, key=operator.attrgetter("path")):
+ rendered.append(str(entry))
+
+ self.maxDiff = None
+ self.assertCountEqual(rendered, expectedResult)
+
diff --git a/meta/lib/oeqa/selftest/cases/oelib/elf.py b/meta/lib/oeqa/selftest/cases/oelib/elf.py
index 15c03f4609..5a5f9b4fdf 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/elf.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/elf.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from unittest.case import TestCase
import oe.qa
@@ -17,6 +21,6 @@ class TestElf(TestCase):
self.assertEqual(oe.qa.elf_machine_to_string(0xB7), "AArch64")
self.assertEqual(oe.qa.elf_machine_to_string(0xF7), "BPF")
- self.assertEqual(oe.qa.elf_machine_to_string(0x00), "Unknown (0)")
+ self.assertEqual(oe.qa.elf_machine_to_string(0x00), "Unset")
self.assertEqual(oe.qa.elf_machine_to_string(0xDEADBEEF), "Unknown (3735928559)")
self.assertEqual(oe.qa.elf_machine_to_string("foobar"), "Unknown ('foobar')")
diff --git a/meta/lib/oeqa/selftest/cases/oelib/license.py b/meta/lib/oeqa/selftest/cases/oelib/license.py
index d7f91fb2f4..3b359396b6 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/license.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/license.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from unittest.case import TestCase
import oe.license
@@ -11,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"]
@@ -63,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 = {
@@ -83,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/oelib/path.py b/meta/lib/oeqa/selftest/cases/oelib/path.py
index e0eb8134a9..a1cfa08c09 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/path.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/path.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from unittest.case import TestCase
import oe, oe.path
import tempfile
diff --git a/meta/lib/oeqa/selftest/cases/oelib/types.py b/meta/lib/oeqa/selftest/cases/oelib/types.py
index 6b53aa64e5..7eb49e6f95 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/types.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/types.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from unittest.case import TestCase
from oe.maketype import create
diff --git a/meta/lib/oeqa/selftest/cases/oelib/utils.py b/meta/lib/oeqa/selftest/cases/oelib/utils.py
index 789c6f78d2..bbf67bf9c9 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/utils.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/utils.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import sys
from unittest.case import TestCase
from contextlib import contextmanager
@@ -60,7 +64,7 @@ class TestMultiprocessLaunch(TestCase):
import bb
def testfunction(item, d):
- if item == "2" or item == "1":
+ if item == "2":
raise KeyError("Invalid number %s" % item)
return "Found %s" % item
@@ -95,5 +99,4 @@ class TestMultiprocessLaunch(TestCase):
# Assert the function prints exceptions
with captured_output() as (out, err):
self.assertRaises(bb.BBHandledException, multiprocess_launch, testfunction, ["1", "2", "3", "4", "5", "6"], d, extraargs=(d,))
- self.assertIn("KeyError: 'Invalid number 1'", out.getvalue())
self.assertIn("KeyError: 'Invalid number 2'", out.getvalue())
diff --git a/meta/lib/oeqa/selftest/cases/oescripts.py b/meta/lib/oeqa/selftest/cases/oescripts.py
index bcdc2d5ac0..91abf9654a 100644
--- a/meta/lib/oeqa/selftest/cases/oescripts.py
+++ b/meta/lib/oeqa/selftest/cases/oescripts.py
@@ -1,11 +1,18 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+import os
+import shutil
+import importlib
+import unittest
from oeqa.selftest.case import OESelftestTestCase
from oeqa.selftest.cases.buildhistory import BuildhistoryBase
from oeqa.utils.commands import Command, runCmd, bitbake, get_bb_var, get_test_layer
-from oeqa.core.decorator.oeid import OETestID
+from oeqa.utils import CommandError
class BuildhistoryDiffTests(BuildhistoryBase):
- @OETestID(295)
def test_buildhistory_diff(self):
target = 'xcursor-transparent-theme'
self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True)
@@ -26,3 +33,155 @@ class BuildhistoryDiffTests(BuildhistoryBase):
self.fail('Unexpected line:\n%s\nExpected line endings:\n %s' % (line, '\n '.join(expected_endlines)))
if expected_endlines:
self.fail('Missing expected line endings:\n %s' % '\n '.join(expected_endlines))
+
+@unittest.skipUnless(importlib.util.find_spec("cairo"), "Python cairo module is not present")
+class OEScriptTests(OESelftestTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(OEScriptTests, cls).setUpClass()
+ import cairo
+ bitbake("core-image-minimal -c rootfs -f")
+ cls.tmpdir = get_bb_var('TMPDIR')
+ cls.buildstats = cls.tmpdir + "/buildstats/" + sorted(os.listdir(cls.tmpdir + "/buildstats"))[-1]
+
+ scripts_dir = os.path.join(get_bb_var('COREBASE'), 'scripts')
+
+class OEPybootchartguyTests(OEScriptTests):
+
+ def test_pybootchartguy_help(self):
+ runCmd('%s/pybootchartgui/pybootchartgui.py --help' % self.scripts_dir)
+
+ def test_pybootchartguy_to_generate_build_png_output(self):
+ runCmd('%s/pybootchartgui/pybootchartgui.py %s -o %s/charts -f png' % (self.scripts_dir, self.buildstats, self.tmpdir))
+ self.assertTrue(os.path.exists(self.tmpdir + "/charts.png"))
+
+ def test_pybootchartguy_to_generate_build_svg_output(self):
+ runCmd('%s/pybootchartgui/pybootchartgui.py %s -o %s/charts -f svg' % (self.scripts_dir, self.buildstats, self.tmpdir))
+ self.assertTrue(os.path.exists(self.tmpdir + "/charts.svg"))
+
+ def test_pybootchartguy_to_generate_build_pdf_output(self):
+ runCmd('%s/pybootchartgui/pybootchartgui.py %s -o %s/charts -f pdf' % (self.scripts_dir, self.buildstats, self.tmpdir))
+ self.assertTrue(os.path.exists(self.tmpdir + "/charts.pdf"))
+
+
+class OEGitproxyTests(OESelftestTestCase):
+
+ scripts_dir = os.path.join(get_bb_var('COREBASE'), 'scripts')
+
+ def test_oegitproxy_help(self):
+ try:
+ res = runCmd('%s/oe-git-proxy --help' % self.scripts_dir, assert_error=False)
+ self.assertTrue(False)
+ except CommandError as e:
+ self.assertEqual(2, e.retcode)
+
+ def run_oegitproxy(self, custom_shell=None):
+ os.environ['SOCAT'] = shutil.which("echo")
+ os.environ['ALL_PROXY'] = "https://proxy.example.com:3128"
+ os.environ['NO_PROXY'] = "*.example.com,.no-proxy.org,192.168.42.0/24,127.*.*.*"
+
+ if custom_shell is None:
+ prefix = ''
+ else:
+ prefix = custom_shell + ' '
+
+ # outside, use the proxy
+ res = runCmd('%s%s/oe-git-proxy host.outside-example.com 9418' %
+ (prefix,self.scripts_dir))
+ self.assertIn('PROXY:', res.output)
+ # match with wildcard suffix
+ res = runCmd('%s%s/oe-git-proxy host.example.com 9418' %
+ (prefix, self.scripts_dir))
+ self.assertIn('TCP:', res.output)
+ # match just suffix
+ res = runCmd('%s%s/oe-git-proxy host.no-proxy.org 9418' %
+ (prefix, self.scripts_dir))
+ self.assertIn('TCP:', res.output)
+ # match IP subnet
+ res = runCmd('%s%s/oe-git-proxy 192.168.42.42 9418' %
+ (prefix, self.scripts_dir))
+ self.assertIn('TCP:', res.output)
+ # match IP wildcard
+ res = runCmd('%s%s/oe-git-proxy 127.1.2.3 9418' %
+ (prefix, self.scripts_dir))
+ self.assertIn('TCP:', res.output)
+
+ # test that * globbering is off
+ os.environ['NO_PROXY'] = "*"
+ res = runCmd('%s%s/oe-git-proxy host.example.com 9418' %
+ (prefix, self.scripts_dir))
+ self.assertIn('TCP:', res.output)
+
+ def test_oegitproxy_proxy(self):
+ self.run_oegitproxy()
+
+ def test_oegitproxy_proxy_dash(self):
+ dash = shutil.which("dash")
+ if dash is None:
+ self.skipTest("No \"dash\" found on test system.")
+ self.run_oegitproxy(custom_shell=dash)
+
+class OeRunNativeTest(OESelftestTestCase):
+ def test_oe_run_native(self):
+ bitbake("qemu-helper-native -c addto_recipe_sysroot")
+ result = runCmd("oe-run-native qemu-helper-native tunctl -h")
+ self.assertIn("Delete: tunctl -d device-name [-f tun-clone-device]", result.output)
+
+class OEListPackageconfigTests(OEScriptTests):
+ #oe-core.scripts.List_all_the_PACKAGECONFIG's_flags
+ def check_endlines(self, results, expected_endlines):
+ for line in results.output.splitlines():
+ for el in expected_endlines:
+ if line.split() == el.split():
+ expected_endlines.remove(el)
+ break
+
+ if expected_endlines:
+ self.fail('Missing expected listings:\n %s' % '\n '.join(expected_endlines))
+
+
+ #oe-core.scripts.List_all_the_PACKAGECONFIG's_flags
+ def test_packageconfig_flags_help(self):
+ runCmd('%s/contrib/list-packageconfig-flags.py -h' % self.scripts_dir)
+
+ def test_packageconfig_flags_default(self):
+ results = runCmd('%s/contrib/list-packageconfig-flags.py' % self.scripts_dir)
+ expected_endlines = []
+ expected_endlines.append("RECIPE NAME PACKAGECONFIG FLAGS")
+ expected_endlines.append("pinentry gtk2 libcap ncurses qt secret")
+ expected_endlines.append("tar acl selinux")
+
+ self.check_endlines(results, expected_endlines)
+
+
+ def test_packageconfig_flags_option_flags(self):
+ results = runCmd('%s/contrib/list-packageconfig-flags.py -f' % self.scripts_dir)
+ expected_endlines = []
+ expected_endlines.append("PACKAGECONFIG FLAG RECIPE NAMES")
+ expected_endlines.append("qt nativesdk-pinentry pinentry pinentry-native")
+ expected_endlines.append("secret nativesdk-pinentry pinentry pinentry-native")
+
+ self.check_endlines(results, expected_endlines)
+
+ def test_packageconfig_flags_option_all(self):
+ results = runCmd('%s/contrib/list-packageconfig-flags.py -a' % self.scripts_dir)
+ expected_endlines = []
+ expected_endlines.append("pinentry-1.2.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")
+ expected_endlines.append("PACKAGECONFIG[libcap] --with-libcap, --without-libcap, libcap")
+ expected_endlines.append("PACKAGECONFIG[ncurses] --enable-ncurses --with-ncurses-include-dir=${STAGING_INCDIR}, --disable-ncurses, ncurses")
+ expected_endlines.append("PACKAGECONFIG[secret] --enable-libsecret, --disable-libsecret, libsecret")
+
+ self.check_endlines(results, expected_endlines)
+
+ def test_packageconfig_flags_options_preferred_only(self):
+ results = runCmd('%s/contrib/list-packageconfig-flags.py -p' % self.scripts_dir)
+ expected_endlines = []
+ expected_endlines.append("RECIPE NAME PACKAGECONFIG FLAGS")
+ expected_endlines.append("pinentry gtk2 libcap ncurses qt secret")
+
+ self.check_endlines(results, expected_endlines)
+
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 6596dabc32..cebbb4f3f4 100644
--- a/meta/lib/oeqa/selftest/cases/package.py
+++ b/meta/lib/oeqa/selftest/cases/package.py
@@ -1,9 +1,13 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.core.decorator.oeid import OETestID
from oeqa.utils.commands import bitbake, get_bb_vars, get_bb_var, runqemu
import stat
import subprocess, os
import oe.path
+import re
class VersionOrdering(OESelftestTestCase):
# version1, version2, sort order
@@ -36,7 +40,6 @@ class VersionOrdering(OESelftestTestCase):
self.bindir = type(self).bindir
self.libdir = type(self).libdir
- @OETestID(1880)
def test_dpkg(self):
for ver1, ver2, sort in self.tests:
op = { -1: "<<", 0: "=", 1: ">>" }[sort]
@@ -53,7 +56,6 @@ class VersionOrdering(OESelftestTestCase):
status = subprocess.call((oe.path.join(self.bindir, "dpkg"), "--compare-versions", ver1, op, ver2))
self.assertNotEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2))
- @OETestID(1881)
def test_opkg(self):
for ver1, ver2, sort in self.tests:
op = { -1: "<<", 0: "=", 1: ">>" }[sort]
@@ -70,7 +72,6 @@ class VersionOrdering(OESelftestTestCase):
status = subprocess.call((oe.path.join(self.bindir, "opkg"), "compare-versions", ver1, op, ver2))
self.assertNotEqual(status, 0, "%s %s %s failed" % (ver1, op, ver2))
- @OETestID(1882)
def test_rpm(self):
# Need to tell the Python bindings where to find its configuration
env = os.environ.copy()
@@ -115,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")
@@ -134,7 +135,7 @@ class PackageTests(OESelftestTestCase):
return False
# Check debugging symbols works correctly
- elif "Breakpoint 1, main () at hello.c:4" in l:
+ elif re.match(r"Breakpoint 1.*hello\.c.*4", l):
return True
self.logger.error("GDB result:\n%d: %s", status, output)
@@ -147,3 +148,27 @@ class PackageTests(OESelftestTestCase):
'/usr/libexec/hello4']:
if not gdbtest(qemu, binary):
self.fail('GDB %s failed' % binary)
+
+ def test_preserve_ownership(self):
+ import os, stat, oe.cachedpath
+ features = 'IMAGE_INSTALL:append = " selftest-chown"\n'
+ self.write_config(features)
+ bitbake("core-image-minimal")
+
+ sysconfdir = get_bb_var('sysconfdir', 'selftest-chown')
+ def check_ownership(qemu, gid, uid, path):
+ self.logger.info("Check ownership of %s", path)
+ status, output = qemu.run_serial(r'/bin/stat -c "%U %G" ' + path, timeout=60)
+ output = output.split(" ")
+ if output[0] != uid or output[1] != gid :
+ self.logger.error("Incrrect ownership %s [%s:%s]", path, output[0], output[1])
+ return False
+ return True
+
+ with runqemu('core-image-minimal') as qemu:
+ for path in [ sysconfdir + "/selftest-chown/file",
+ sysconfdir + "/selftest-chown/dir",
+ sysconfdir + "/selftest-chown/symlink",
+ sysconfdir + "/selftest-chown/fifotest/fifo"]:
+ if not check_ownership(qemu, "test", "test", path):
+ self.fail('Test ownership %s failed' % path)
diff --git a/meta/lib/oeqa/selftest/cases/pkgdata.py b/meta/lib/oeqa/selftest/cases/pkgdata.py
index aa05f40d6a..254abc40c6 100644
--- a/meta/lib/oeqa/selftest/cases/pkgdata.py
+++ b/meta/lib/oeqa/selftest/cases/pkgdata.py
@@ -1,10 +1,13 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import tempfile
import fnmatch
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
-from oeqa.core.decorator.oeid import OETestID
class OePkgdataUtilTests(OESelftestTestCase):
@@ -16,7 +19,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
bitbake('target-sdk-provides-dummy -c clean')
bitbake('busybox zlib m4')
- @OETestID(1203)
def test_lookup_pkg(self):
# Forward tests
result = runCmd('oe-pkgdata-util lookup-pkg "zlib busybox"')
@@ -35,7 +37,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output)
self.assertEqual(result.output, 'ERROR: The following packages could not be found: nonexistentpkg')
- @OETestID(1205)
def test_read_value(self):
result = runCmd('oe-pkgdata-util read-value PN libz1')
self.assertEqual(result.output, 'zlib')
@@ -45,7 +46,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
pkgsize = int(result.output.strip())
self.assertGreater(pkgsize, 1, "Size should be greater than 1. %s" % result.output)
- @OETestID(1198)
def test_find_path(self):
result = runCmd('oe-pkgdata-util find-path /lib/libz.so.1')
self.assertEqual(result.output, 'zlib: /lib/libz.so.1')
@@ -55,7 +55,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output)
self.assertEqual(result.output, 'ERROR: Unable to find any package producing path /not/exist')
- @OETestID(1204)
def test_lookup_recipe(self):
result = runCmd('oe-pkgdata-util lookup-recipe "libz-staticdev busybox"')
self.assertEqual(result.output, 'zlib\nbusybox')
@@ -65,7 +64,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output)
self.assertEqual(result.output, 'ERROR: The following packages could not be found: nonexistentpkg')
- @OETestID(1202)
def test_list_pkgs(self):
# No arguments
result = runCmd('oe-pkgdata-util list-pkgs')
@@ -109,7 +107,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
pkglist = sorted(result.output.split())
self.assertEqual(pkglist, ['libz-dbg', 'libz-dev', 'libz-doc'], "Packages listed: %s" % result.output)
- @OETestID(1201)
def test_list_pkg_files(self):
def splitoutput(output):
files = {}
@@ -199,7 +196,6 @@ class OePkgdataUtilTests(OESelftestTestCase):
self.assertIn(os.path.join(mandir, 'man3/zlib.3'), files['libz-doc'])
self.assertIn(os.path.join(libdir, 'libz.a'), files['libz-staticdev'])
- @OETestID(1200)
def test_glob(self):
tempdir = tempfile.mkdtemp(prefix='pkgdataqa')
self.track_for_cleanup(tempdir)
@@ -219,7 +215,12 @@ class OePkgdataUtilTests(OESelftestTestCase):
self.assertNotIn('libz-dev', resultlist)
self.assertNotIn('libz-dbg', resultlist)
- @OETestID(1206)
def test_specify_pkgdatadir(self):
result = runCmd('oe-pkgdata-util -p %s lookup-pkg zlib' % get_bb_var('PKGDATA_DIR'))
self.assertEqual(result.output, 'libz1')
+
+ def test_no_param(self):
+ result = runCmd('oe-pkgdata-util', ignore_status=True)
+ self.assertEqual(result.status, 2, "Status different than 2. output: %s" % result.output)
+ currpos = result.output.find('usage: oe-pkgdata-util')
+ self.assertTrue(currpos != -1, msg = "Test is Failed. Help is not Displayed in %s" % result.output)
diff --git a/meta/lib/oeqa/selftest/cases/prservice.py b/meta/lib/oeqa/selftest/cases/prservice.py
index 479e520618..10158ca7c2 100644
--- a/meta/lib/oeqa/selftest/cases/prservice.py
+++ b/meta/lib/oeqa/selftest/cases/prservice.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
import shutil
@@ -6,7 +10,6 @@ import datetime
import oeqa.utils.ftools as ftools
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var
-from oeqa.core.decorator.oeid import OETestID
from oeqa.utils.network import get_free_port
class BitbakePrTests(OESelftestTestCase):
@@ -19,8 +22,8 @@ class BitbakePrTests(OESelftestTestCase):
def get_pr_version(self, package_name):
package_data_file = os.path.join(self.pkgdata_dir, 'runtime', package_name)
package_data = ftools.read_file(package_data_file)
- find_pr = re.search("PKGR: r[0-9]+\.([0-9]+)", package_data)
- self.assertTrue(find_pr, "No PKG revision found in %s" % package_data_file)
+ find_pr = re.search(r"PKGR: r[0-9]+\.([0-9]+)", package_data)
+ self.assertTrue(find_pr, "No PKG revision found via regex 'PKGR: r[0-9]+\.([0-9]+)' in %s" % package_data_file)
return int(find_pr.group(1))
def get_task_stamp(self, package_name, recipe_task):
@@ -29,7 +32,7 @@ class BitbakePrTests(OESelftestTestCase):
package_stamps_path = "/".join(stampdata[:-1])
stamps = []
for stamp in os.listdir(package_stamps_path):
- find_stamp = re.match("%s\.%s\.([a-z0-9]{32})" % (re.escape(prefix), recipe_task), stamp)
+ find_stamp = re.match(r"%s\.%s\.([a-z0-9]{32})" % (re.escape(prefix), recipe_task), stamp)
if find_stamp:
stamps.append(find_stamp.group(1))
self.assertFalse(len(stamps) == 0, msg="Cound not find stamp for task %s for recipe %s" % (recipe_task, package_name))
@@ -37,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\"\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)
@@ -60,7 +63,7 @@ class BitbakePrTests(OESelftestTestCase):
pr_2 = self.get_pr_version(package_name)
stamp_2 = self.get_task_stamp(package_name, track_task)
- self.assertTrue(pr_2 - pr_1 == 1, "Step between same pkg. revision is greater than 1")
+ self.assertTrue(pr_2 - pr_1 == 1, "New PR %s did not increment as expected (from %s), difference should be 1" % (pr_2, pr_1))
self.assertTrue(stamp_1 != stamp_2, "Different pkg rev. but same stamp: %s" % stamp_1)
def run_test_pr_export_import(self, package_name, replace_current_db=True):
@@ -86,41 +89,32 @@ class BitbakePrTests(OESelftestTestCase):
self.increment_package_pr(package_name)
pr_2 = self.get_pr_version(package_name)
- self.assertTrue(pr_2 - pr_1 == 1, "Step between same pkg. revision is greater than 1")
+ self.assertTrue(pr_2 - pr_1 == 1, "New PR %s did not increment as expected (from %s), difference should be 1" % (pr_2, pr_1))
- @OETestID(930)
def test_import_export_replace_db(self):
self.run_test_pr_export_import('m4')
- @OETestID(931)
def test_import_export_override_db(self):
self.run_test_pr_export_import('m4', replace_current_db=False)
- @OETestID(932)
def test_pr_service_rpm_arch_dep(self):
self.run_test_pr_service('m4', 'rpm', 'do_package')
- @OETestID(934)
def test_pr_service_deb_arch_dep(self):
self.run_test_pr_service('m4', 'deb', 'do_package')
- @OETestID(933)
def test_pr_service_ipk_arch_dep(self):
self.run_test_pr_service('m4', 'ipk', 'do_package')
- @OETestID(935)
def test_pr_service_rpm_arch_indep(self):
self.run_test_pr_service('xcursor-transparent-theme', 'rpm', 'do_package')
- @OETestID(937)
def test_pr_service_deb_arch_indep(self):
self.run_test_pr_service('xcursor-transparent-theme', 'deb', 'do_package')
- @OETestID(936)
def test_pr_service_ipk_arch_indep(self):
self.run_test_pr_service('xcursor-transparent-theme', 'ipk', 'do_package')
- @OETestID(1419)
def test_stopping_prservice_message(self):
port = get_free_port()
diff --git a/meta/lib/oeqa/selftest/cases/pseudo.py b/meta/lib/oeqa/selftest/cases/pseudo.py
new file mode 100644
index 0000000000..33593d5ce9
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/pseudo.py
@@ -0,0 +1,27 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+import glob
+import os
+import shutil
+from oeqa.utils.commands import bitbake, get_test_layer
+from oeqa.selftest.case import OESelftestTestCase
+
+class Pseudo(OESelftestTestCase):
+
+ def test_pseudo_pyc_creation(self):
+ self.write_config("")
+
+ metaselftestpath = get_test_layer()
+ pycache_path = os.path.join(metaselftestpath, 'lib/__pycache__')
+ if os.path.exists(pycache_path):
+ shutil.rmtree(pycache_path)
+
+ bitbake('pseudo-pyc-test -c install')
+
+ test1_pyc_present = len(glob.glob(os.path.join(pycache_path, 'pseudo_pyc_test1.*.pyc')))
+ self.assertTrue(test1_pyc_present, 'test1 pyc file missing, should be created outside of pseudo context.')
+
+ test2_pyc_present = len(glob.glob(os.path.join(pycache_path, 'pseudo_pyc_test2.*.pyc')))
+ self.assertFalse(test2_pyc_present, 'test2 pyc file present, should not be created in pseudo context.')
diff --git a/meta/lib/oeqa/selftest/cases/recipetool.py b/meta/lib/oeqa/selftest/cases/recipetool.py
index 06f980e1b0..510dae6bad 100644
--- a/meta/lib/oeqa/selftest/cases/recipetool.py
+++ b/meta/lib/oeqa/selftest/cases/recipetool.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import shutil
import tempfile
@@ -5,7 +9,6 @@ import urllib.parse
from oeqa.utils.commands import runCmd, bitbake, get_bb_var
from oeqa.utils.commands import get_bb_vars, create_temp_layer
-from oeqa.core.decorator.oeid import OETestID
from oeqa.selftest.cases import devtool
templayerdir = None
@@ -22,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()
@@ -65,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)
@@ -89,22 +91,19 @@ class RecipetoolTests(RecipetoolBase):
for errorstr in checkerror:
self.assertIn(errorstr, result.output)
- @OETestID(1177)
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)
- @OETestID(1183)
def test_recipetool_appendfile_invalid(self):
# Test some commands that should error
self._try_recipetool_appendfile_fail('/etc/passwd', self.testfile, ['ERROR: /etc/passwd cannot be handled by this tool', 'useradd', 'extrausers'])
self._try_recipetool_appendfile_fail('/etc/timestamp', self.testfile, ['ERROR: /etc/timestamp cannot be handled by this tool'])
self._try_recipetool_appendfile_fail('/dev/console', self.testfile, ['ERROR: /dev/console cannot be handled by this tool'])
- @OETestID(1176)
def test_recipetool_appendfile_alternatives(self):
# Now try with a file we know should be an alternative
# (this is very much a fake example, but one we know is reliably an alternative)
@@ -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']
@@ -128,7 +127,6 @@ class RecipetoolTests(RecipetoolBase):
result = runCmd('diff -q %s %s' % (testfile2, copiedfile), ignore_status=True)
self.assertNotEqual(result.status, 0, 'New file should have been copied but was not %s' % result.output)
- @OETestID(1178)
def test_recipetool_appendfile_binary(self):
# Try appending a binary file
# /bin/ls can be a symlink to /usr/bin/ls
@@ -137,14 +135,13 @@ class RecipetoolTests(RecipetoolBase):
self.assertIn('WARNING: ', result.output)
self.assertIn('is a binary', result.output)
- @OETestID(1173)
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']
@@ -153,125 +150,102 @@ 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,
'}\n']
self._try_recipetool_appendfile('netbase', '/usr/share/scriptname', testfile2, '-r netbase', expectedlines, ['testfile', testfile2name])
- @OETestID(1174)
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']
_, output = self._try_recipetool_appendfile('netbase', '/usr/bin/selftest-recipetool-testbin', self.testfile, '-r netbase', expectedlines, ['testfile'])
self.assertNotIn('WARNING: ', output)
- @OETestID(1175)
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']
_, output = self._try_recipetool_appendfile('netbase', '/usr/share/something', self.testfile, '-r netbase -m mymachine', expectedlines, ['mymachine/testfile'])
self.assertNotIn('WARNING: ', output)
- @OETestID(1184)
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)
- @OETestID(1191)
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)
- @OETestID(1187)
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)
- @OETestID(1190)
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']
_, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-subdir', self.testfile, '', expectedlines, ['testfile'])
self.assertNotIn('WARNING: ', output)
- @OETestID(1189)
- def test_recipetool_appendfile_src_glob(self):
- # A file that's in SRC_URI as a glob
- expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
- '\n',
- 'SRC_URI += "file://testfile"\n',
- '\n',
- 'do_install_append() {\n',
- ' install -d ${D}${datadir}\n',
- ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-src-globfile\n',
- '}\n']
- _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-src-globfile', self.testfile, '', expectedlines, ['testfile'])
- self.assertNotIn('WARNING: ', output)
-
- @OETestID(1181)
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)
- @OETestID(1182)
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)
- @OETestID(1185)
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']
@@ -283,45 +257,41 @@ class RecipetoolTests(RecipetoolBase):
else:
self.fail('Patch warning not found in output:\n%s' % output)
- @OETestID(1188)
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']
_, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-scripted', self.testfile, '', expectedlines, ['testfile'])
self.assertNotIn('WARNING: ', output)
- @OETestID(1180)
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)
- @OETestID(1186)
def test_recipetool_appendfile_postinstall(self):
# A file that's created by a postinstall script (and explicitly mentioned in it)
# 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']
_, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-postinst', self.testfile, '-r selftest-recipetool-appendfile', expectedlines, ['testfile'])
- @OETestID(1179)
def test_recipetool_appendfile_extlayer(self):
# Try creating a bbappend in a layer that's not in bblayers.conf and has a different structure
exttemplayerdir = os.path.join(self.tempdir, 'extlayer')
@@ -337,7 +307,6 @@ class RecipetoolTests(RecipetoolBase):
'metadata/recipes/recipes-test/selftest-recipetool-appendfile/selftest-recipetool-appendfile/selftest-replaceme-orig']
self.assertEqual(sorted(createdfiles), sorted(expectedfiles))
- @OETestID(1192)
def test_recipetool_appendfile_wildcard(self):
def try_appendfile_wc(options):
@@ -362,7 +331,9 @@ class RecipetoolTests(RecipetoolBase):
filename = try_appendfile_wc('-w')
self.assertEqual(filename, recipefn.split('_')[0] + '_%.bbappend')
- @OETestID(1193)
+
+class RecipetoolCreateTests(RecipetoolBase):
+
def test_recipetool_create(self):
# Try adding a recipe
tempsrc = os.path.join(self.tempdir, 'srctree')
@@ -372,15 +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, [])
- @OETestID(1194)
- 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
@@ -393,22 +363,21 @@ 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)
- @OETestID(1392)
def test_recipetool_create_simple(self):
# Try adding a recipe
temprecipe = os.path.join(self.tempdir, 'recipe')
os.makedirs(temprecipe)
- pv = '1.7.3.0'
- srcuri = 'http://www.dest-unreach.org/socat/download/socat-%s.tar.bz2' % pv
+ pv = '1.7.4.1'
+ 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:
@@ -417,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
@@ -425,27 +394,51 @@ class RecipetoolTests(RecipetoolBase):
inherits = ['autotools']
self._test_recipe_contents(os.path.join(temprecipe, dirlist[0]), checkvars, inherits)
- @OETestID(1418)
def test_recipetool_create_cmake(self):
- bitbake('-c packagedata gtk+')
-
- # Try adding a recipe
temprecipe = os.path.join(self.tempdir, 'recipe')
os.makedirs(temprecipe)
- recipefile = os.path.join(temprecipe, 'navit_0.5.0.bb')
- srcuri = 'http://downloads.yoctoproject.org/mirror/sources/navit-0.5.0.tar.gz'
+ recipefile = os.path.join(temprecipe, 'taglib_1.11.1.bb')
+ srcuri = 'http://taglib.github.io/releases/taglib-1.11.1.tar.gz'
result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
self.assertTrue(os.path.isfile(recipefile))
checkvars = {}
- checkvars['LICENSE'] = set(['Unknown', 'GPLv2', 'LGPLv2'])
- checkvars['SRC_URI'] = 'http://downloads.yoctoproject.org/mirror/sources/navit-${PV}.tar.gz'
- checkvars['SRC_URI[md5sum]'] = '242f398e979a6b8c0f3c802b63435b68'
- checkvars['SRC_URI[sha256sum]'] = '13353481d7fc01a4f64e385dda460b51496366bba0fd2cc85a89a0747910e94d'
- checkvars['DEPENDS'] = set(['freetype', 'zlib', 'openssl', 'glib-2.0', 'virtual/libgl', 'virtual/egl', 'gtk+', 'libpng', 'libsdl', 'freeglut', 'dbus-glib', 'fribidi'])
- inherits = ['cmake', 'python-dir', 'gettext', 'pkgconfig']
+ 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'
+ checkvars['DEPENDS'] = set(['boost', 'zlib'])
+ inherits = ['cmake']
+ self._test_recipe_contents(recipefile, checkvars, inherits)
+
+ def test_recipetool_create_npm(self):
+ collections = get_bb_var('BBFILE_COLLECTIONS').split()
+ if "openembedded-layer" not in collections:
+ self.skipTest("Test needs meta-oe for nodejs")
+
+ temprecipe = os.path.join(self.tempdir, 'recipe')
+ os.makedirs(temprecipe)
+ recipefile = os.path.join(temprecipe, 'savoirfairelinux-node-server-example_1.0.0.bb')
+ shrinkwrap = os.path.join(temprecipe, 'savoirfairelinux-node-server-example', 'npm-shrinkwrap.json')
+ srcuri = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=1.0.0'
+ result = runCmd('recipetool create -o %s \'%s\'' % (temprecipe, srcuri))
+ self.assertTrue(os.path.isfile(recipefile))
+ self.assertTrue(os.path.isfile(shrinkwrap))
+ checkvars = {}
+ checkvars['SUMMARY'] = 'Node Server Example'
+ checkvars['HOMEPAGE'] = 'https://github.com/savoirfairelinux/node-server-example#readme'
+ 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'
+ inherits = ['npm']
self._test_recipe_contents(recipefile, checkvars, inherits)
- @OETestID(1638)
def test_recipetool_create_github(self):
# Basic test to see if github URL mangling works
temprecipe = os.path.join(self.tempdir, 'recipe')
@@ -456,11 +449,29 @@ 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'
- inherits = ['setuptools']
+ checkvars['SRC_URI'] = 'git://github.com/mesonbuild/meson;protocol=https;branch=master'
+ inherits = ['setuptools3']
+ self._test_recipe_contents(recipefile, checkvars, inherits)
+
+ def test_recipetool_create_python3_setuptools(self):
+ # Test creating python3 package from tarball (using setuptools3 class)
+ temprecipe = os.path.join(self.tempdir, 'recipe')
+ os.makedirs(temprecipe)
+ pn = 'python-magic'
+ pv = '0.4.15'
+ recipefile = os.path.join(temprecipe, '%s_%s.bb' % (pn, pv))
+ srcuri = 'https://files.pythonhosted.org/packages/84/30/80932401906eaf787f2e9bd86dc458f1d2e75b064b4c187341f29516945c/python-magic-%s.tar.gz' % pv
+ result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
+ self.assertTrue(os.path.isfile(recipefile))
+ checkvars = {}
+ checkvars['LICENSE'] = set(['MIT'])
+ checkvars['LIC_FILES_CHKSUM'] = 'file://LICENSE;md5=16a934f165e8c3245f241e77d401bb88'
+ checkvars['SRC_URI'] = 'https://files.pythonhosted.org/packages/84/30/80932401906eaf787f2e9bd86dc458f1d2e75b064b4c187341f29516945c/python-magic-${PV}.tar.gz'
+ checkvars['SRC_URI[md5sum]'] = 'e384c95a47218f66c6501cd6dd45ff59'
+ checkvars['SRC_URI[sha256sum]'] = 'f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5'
+ inherits = ['setuptools3']
self._test_recipe_contents(recipefile, checkvars, inherits)
- @OETestID(1639)
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')
@@ -473,23 +484,51 @@ class RecipetoolTests(RecipetoolBase):
checkvars = {}
checkvars['LICENSE'] = set(['Apache-2.0'])
checkvars['SRC_URI'] = 'https://github.com/mesonbuild/meson/releases/download/${PV}/meson-${PV}.tar.gz'
- inherits = ['setuptools']
+ inherits = ['setuptools3']
self._test_recipe_contents(recipefile, checkvars, inherits)
- @OETestID(1637)
- 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
@@ -498,13 +537,16 @@ class RecipetoolTests(RecipetoolBase):
dstdir = os.path.join(dstdir, p)
if not os.path.exists(dstdir):
os.makedirs(dstdir)
- self.track_for_cleanup(dstdir)
+ if p == "lib":
+ # Can race with other tests
+ self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
+ else:
+ self.track_for_cleanup(dstdir)
dstfile = os.path.join(dstdir, os.path.basename(srcfile))
if srcfile != dstfile:
shutil.copy(srcfile, dstfile)
self.track_for_cleanup(dstfile)
- @OETestID(1640)
def test_recipetool_load_plugin(self):
"""Test that recipetool loads only the first found plugin in BBPATH."""
@@ -531,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):
@@ -590,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
@@ -626,11 +790,9 @@ class RecipetoolAppendsrcBase(RecipetoolBase):
class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
- @OETestID(1273)
def test_recipetool_appendsrcfile_basic(self):
self._test_appendsrcfile('base-files', 'a-file')
- @OETestID(1274)
def test_recipetool_appendsrcfile_basic_wildcard(self):
testrecipe = 'base-files'
self._test_appendsrcfile(testrecipe, 'a-file', options='-w')
@@ -638,15 +800,12 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir)
self.assertEqual(os.path.basename(bbappendfile), '%s_%%.bbappend' % testrecipe)
- @OETestID(1281)
def test_recipetool_appendsrcfile_subdir_basic(self):
self._test_appendsrcfile('base-files', 'a-file', 'tmp')
- @OETestID(1282)
def test_recipetool_appendsrcfile_subdir_basic_dirdest(self):
self._test_appendsrcfile('base-files', destdir='tmp')
- @OETestID(1280)
def test_recipetool_appendsrcfile_srcdir_basic(self):
testrecipe = 'bash'
bb_vars = get_bb_vars(['S', 'WORKDIR'], testrecipe)
@@ -655,14 +814,12 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
subdir = os.path.relpath(srcdir, workdir)
self._test_appendsrcfile(testrecipe, 'a-file', srcdir=subdir)
- @OETestID(1275)
def test_recipetool_appendsrcfile_existing_in_src_uri(self):
testrecipe = 'base-files'
filepath = self._get_first_file_uri(testrecipe)
self.assertTrue(filepath, 'Unable to test, no file:// uri found in SRC_URI for %s' % testrecipe)
self._test_appendsrcfile(testrecipe, filepath, has_src_uri=False)
- @OETestID(1276)
def test_recipetool_appendsrcfile_existing_in_src_uri_diff_params(self):
testrecipe = 'base-files'
subdir = 'tmp'
@@ -672,7 +829,6 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
output = self._test_appendsrcfile(testrecipe, filepath, subdir, has_src_uri=False)
self.assertTrue(any('with different parameters' in l for l in output))
- @OETestID(1277)
def test_recipetool_appendsrcfile_replace_file_srcdir(self):
testrecipe = 'bash'
filepath = 'Makefile.in'
@@ -683,9 +839,10 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
self._test_appendsrcfile(testrecipe, filepath, srcdir=subdir)
bitbake('%s:do_unpack' % testrecipe)
- self.assertEqual(open(self.testfile, 'r').read(), open(os.path.join(srcdir, filepath), 'r').read())
+ with open(self.testfile, 'r') as testfile:
+ with open(os.path.join(srcdir, filepath), 'r') as makefilein:
+ self.assertEqual(testfile.read(), makefilein.read())
- @OETestID(1278)
def test_recipetool_appendsrcfiles_basic(self, destdir=None):
newfiles = [self.testfile]
for i in range(1, 5):
@@ -695,6 +852,5 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
newfiles.append(testfile)
self._test_appendsrcfiles('gcc', newfiles, destdir=destdir, options='-W')
- @OETestID(1279)
def test_recipetool_appendsrcfiles_basic_subdir(self):
self.test_recipetool_appendsrcfiles_basic(destdir='testdir')
diff --git a/meta/lib/oeqa/selftest/cases/recipeutils.py b/meta/lib/oeqa/selftest/cases/recipeutils.py
index dd2f55839a..f1dd63f65b 100644
--- a/meta/lib/oeqa/selftest/cases/recipeutils.py
+++ b/meta/lib/oeqa/selftest/cases/recipeutils.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
import time
@@ -6,7 +10,6 @@ import bb.tinfoil
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, get_test_layer
-from oeqa.core.decorator.oeid import OETestID
def setUpModule():
@@ -37,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"
@@ -49,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:
@@ -77,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:
@@ -102,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
new file mode 100644
index 0000000000..7caf8c3e7d
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/reproducible.py
@@ -0,0 +1,316 @@
+#
+# SPDX-License-Identifier: MIT
+#
+# Copyright 2019-2020 by Garmin Ltd. or its subsidiaries
+
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
+import bb.utils
+import functools
+import multiprocessing
+import textwrap
+import json
+import unittest
+import tempfile
+import shutil
+import stat
+import os
+import datetime
+
+exclude_packages = [
+ ]
+
+def is_excluded(package):
+ package_name = os.path.basename(package)
+ for i in exclude_packages:
+ if package_name.startswith(i):
+ return i
+ return None
+
+MISSING = 'MISSING'
+DIFFERENT = 'DIFFERENT'
+SAME = 'SAME'
+
+@functools.total_ordering
+class CompareResult(object):
+ def __init__(self):
+ self.reference = None
+ self.test = None
+ self.status = 'UNKNOWN'
+
+ def __eq__(self, other):
+ return (self.status, self.test) == (other.status, other.test)
+
+ def __lt__(self, other):
+ return (self.status, self.test) < (other.status, other.test)
+
+class PackageCompareResults(object):
+ def __init__(self):
+ self.total = []
+ self.missing = []
+ self.different = []
+ self.different_excluded = []
+ self.same = []
+ self.active_exclusions = set()
+
+ def add_result(self, r):
+ self.total.append(r)
+ if r.status == MISSING:
+ self.missing.append(r)
+ elif r.status == DIFFERENT:
+ exclusion = is_excluded(r.reference)
+ if exclusion:
+ self.different_excluded.append(r)
+ self.active_exclusions.add(exclusion)
+ else:
+ self.different.append(r)
+ else:
+ self.same.append(r)
+
+ def sort(self):
+ self.total.sort()
+ self.missing.sort()
+ self.different.sort()
+ self.different_excluded.sort()
+ self.same.sort()
+
+ def __str__(self):
+ return 'same=%i different=%i different_excluded=%i missing=%i total=%i\nunused_exclusions=%s' % (len(self.same), len(self.different), len(self.different_excluded), len(self.missing), len(self.total), self.unused_exclusions())
+
+ def unused_exclusions(self):
+ return sorted(set(exclude_packages) - self.active_exclusions)
+
+def compare_file(reference, test, diffutils_sysroot):
+ result = CompareResult()
+ result.reference = reference
+ result.test = test
+
+ if not os.path.exists(reference):
+ result.status = MISSING
+ return result
+
+ r = runCmd(['cmp', '--quiet', reference, test], native_sysroot=diffutils_sysroot, ignore_status=True, sync=False)
+
+ if r.status:
+ result.status = DIFFERENT
+ return result
+
+ result.status = SAME
+ return result
+
+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):
+ diffoscope_test_files = os.path.join(os.path.dirname(os.path.abspath(__file__)), "diffoscope")
+
+ def test_diffoscope(self):
+ bitbake("diffoscope-native -c addto_recipe_sysroot")
+ diffoscope_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "diffoscope-native")
+
+ # Check that diffoscope doesn't return an error when the files compare
+ # the same (a general check that diffoscope is working)
+ with tempfile.TemporaryDirectory() as tmpdir:
+ run_diffoscope('A', 'A', tmpdir,
+ native_sysroot=diffoscope_sysroot, cwd=self.diffoscope_test_files)
+
+ # Check that diffoscope generates an index.html file when the files are
+ # different
+ with tempfile.TemporaryDirectory() as tmpdir:
+ r = run_diffoscope('A', 'B', tmpdir,
+ native_sysroot=diffoscope_sysroot, ignore_status=True, cwd=self.diffoscope_test_files)
+
+ self.assertNotEqual(r.status, 0, msg="diffoscope was successful when an error was expected")
+ self.assertTrue(os.path.exists(os.path.join(tmpdir, 'index.html')), "HTML index not found!")
+
+class ReproducibleTests(OESelftestTestCase):
+ # Test the reproducibility of whatever is built between sstate_targets and targets
+
+ 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
+ sstate_targets = []
+ save_results = False
+ if 'OEQA_DEBUGGING_SAVED_OUTPUT' in os.environ:
+ save_results = os.environ['OEQA_DEBUGGING_SAVED_OUTPUT']
+
+ # This variable controls if one of the test builds is allowed to pull from
+ # an sstate cache/mirror. The other build is always done clean as a point of
+ # comparison.
+ # If you know that your sstate archives are reproducible, enabling this
+ # will test that and also make the test run faster. If your sstate is not
+ # reproducible, disable this in your derived test class
+ build_from_sstate = True
+
+ def setUpLocal(self):
+ super().setUpLocal()
+ needed_vars = ['TOPDIR', 'TARGET_PREFIX', 'BB_NUMBER_THREADS']
+ bb_vars = get_bb_vars(needed_vars)
+ for v in needed_vars:
+ setattr(self, v.lower(), bb_vars[v])
+
+ self.extraresults = {}
+ self.extraresults.setdefault('reproducible.rawlogs', {})['log'] = ''
+ self.extraresults.setdefault('reproducible', {}).setdefault('files', {})
+
+ def append_to_log(self, msg):
+ self.extraresults['reproducible.rawlogs']['log'] += msg
+
+ def compare_packages(self, reference_dir, test_dir, diffutils_sysroot):
+ result = PackageCompareResults()
+
+ old_cwd = os.getcwd()
+ try:
+ file_result = {}
+ os.chdir(test_dir)
+ with multiprocessing.Pool(processes=int(self.bb_number_threads or 0)) as p:
+ for root, dirs, files in os.walk('.'):
+ async_result = []
+ for f in files:
+ reference_path = os.path.join(reference_dir, root, f)
+ test_path = os.path.join(test_dir, root, f)
+ async_result.append(p.apply_async(compare_file, (reference_path, test_path, diffutils_sysroot)))
+
+ for a in async_result:
+ result.add_result(a.get())
+
+ finally:
+ os.chdir(old_cwd)
+
+ result.sort()
+ return result
+
+ def write_package_list(self, package_class, name, packages):
+ self.extraresults['reproducible']['files'].setdefault(package_class, {})[name] = [
+ {'reference': p.reference, 'test': p.test} for p in packages]
+
+ def copy_file(self, source, dest):
+ bb.utils.mkdirhier(os.path.dirname(dest))
+ shutil.copyfile(source, dest)
+
+ def do_test_build(self, name, use_sstate):
+ capture_vars = ['DEPLOY_DIR_' + c.upper() for c in self.package_classes]
+
+ tmpdir = os.path.join(self.topdir, name, 'tmp')
+ if os.path.exists(tmpdir):
+ bb.utils.remove(tmpdir, recurse=True)
+
+ config = textwrap.dedent('''\
+ PACKAGE_CLASSES = "{package_classes}"
+ INHIBIT_PACKAGE_STRIP = "1"
+ TMPDIR = "{tmpdir}"
+ LICENSE_FLAGS_ACCEPTED = "commercial"
+ DISTRO_FEATURES:append = ' systemd pam'
+ USERADDEXTENSION = "useradd-staticids"
+ USERADD_ERROR_DYNAMIC = "skip"
+ USERADD_UID_TABLES += "files/static-passwd"
+ USERADD_GID_TABLES += "files/static-group"
+ ''').format(package_classes=' '.join('package_%s' % c for c in self.package_classes),
+ tmpdir=tmpdir)
+
+ if not use_sstate:
+ if self.sstate_targets:
+ self.logger.info("Building prebuild for %s (sstate allowed)..." % (name))
+ self.write_config(config)
+ bitbake(' '.join(self.sstate_targets))
+
+ # This config fragment will disable using shared and the sstate
+ # mirror, forcing a complete build from scratch
+ config += textwrap.dedent('''\
+ SSTATE_DIR = "${TMPDIR}/sstate"
+ SSTATE_MIRRORS = ""
+ ''')
+
+ self.logger.info("Building %s (sstate%s allowed)..." % (name, '' if use_sstate else ' NOT'))
+ self.write_config(config)
+ d = get_bb_vars(capture_vars)
+ # targets used to be called images
+ bitbake(' '.join(getattr(self, 'images', self.targets)))
+ return d
+
+ def test_reproducible_builds(self):
+ def strip_topdir(s):
+ if s.startswith(self.topdir):
+ return s[len(self.topdir):]
+ return s
+
+ # Build native utilities
+ self.write_config('')
+ bitbake("diffoscope-native diffutils-native jquery-native -c addto_recipe_sysroot")
+ diffutils_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "diffutils-native")
+ diffoscope_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "diffoscope-native")
+ jquery_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "jquery-native")
+
+ if self.save_results:
+ os.makedirs(self.save_results, exist_ok=True)
+ datestr = datetime.datetime.now().strftime('%Y%m%d')
+ save_dir = tempfile.mkdtemp(prefix='oe-reproducible-%s-' % datestr, dir=self.save_results)
+ os.chmod(save_dir, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+ self.logger.info('Non-reproducible packages will be copied to %s', save_dir)
+
+ vars_A = self.do_test_build('reproducibleA', self.build_from_sstate)
+
+ vars_B = self.do_test_build('reproducibleB', False)
+
+ # NOTE: The temp directories from the reproducible build are purposely
+ # kept after the build so it can be diffed for debugging.
+
+ fails = []
+
+ for c in self.package_classes:
+ with self.subTest(package_class=c):
+ package_class = 'package_' + c
+
+ deploy_A = vars_A['DEPLOY_DIR_' + c.upper()]
+ deploy_B = vars_B['DEPLOY_DIR_' + c.upper()]
+
+ self.logger.info('Checking %s packages for differences...' % c)
+ result = self.compare_packages(deploy_A, deploy_B, diffutils_sysroot)
+
+ self.logger.info('Reproducibility summary for %s: %s' % (c, result))
+
+ self.append_to_log('\n'.join("%s: %s" % (r.status, r.test) for r in result.total))
+
+ self.write_package_list(package_class, 'missing', result.missing)
+ self.write_package_list(package_class, 'different', result.different)
+ self.write_package_list(package_class, 'different_excluded', result.different_excluded)
+ self.write_package_list(package_class, 'same', result.same)
+
+ if self.save_results:
+ for d in result.different:
+ self.copy_file(d.reference, '/'.join([save_dir, 'packages', strip_topdir(d.reference)]))
+ self.copy_file(d.test, '/'.join([save_dir, 'packages', strip_topdir(d.test)]))
+
+ for d in result.different_excluded:
+ self.copy_file(d.reference, '/'.join([save_dir, 'packages-excluded', strip_topdir(d.reference)]))
+ self.copy_file(d.test, '/'.join([save_dir, 'packages-excluded', strip_topdir(d.test)]))
+
+ if result.missing or result.different:
+ fails.append("The following %s packages are missing or different and not in exclusion list: %s" %
+ (c, '\n'.join(r.test for r in (result.missing + result.different))))
+
+ # Clean up empty directories
+ if self.save_results:
+ if not os.listdir(save_dir):
+ os.rmdir(save_dir)
+ else:
+ self.logger.info('Running diffoscope')
+ package_dir = os.path.join(save_dir, 'packages')
+ package_html_dir = os.path.join(package_dir, 'diff-html')
+
+ # Copy jquery to improve the diffoscope output usability
+ self.copy_file(os.path.join(jquery_sysroot, 'usr/share/javascript/jquery/jquery.min.js'), os.path.join(package_html_dir, 'jquery.js'))
+
+ 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:
+ self.fail('\n'.join(fails))
+
diff --git a/meta/lib/oeqa/selftest/cases/resulttooltests.py b/meta/lib/oeqa/selftest/cases/resulttooltests.py
new file mode 100644
index 0000000000..dac5c46801
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/resulttooltests.py
@@ -0,0 +1,98 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+import os
+import sys
+basepath = os.path.abspath(os.path.dirname(__file__) + '/../../../../../')
+lib_path = basepath + '/scripts/lib'
+sys.path = sys.path + [lib_path]
+from resulttool.report import ResultsTextReport
+from resulttool import regression as regression
+from resulttool import resultutils as resultutils
+from oeqa.selftest.case import OESelftestTestCase
+
+class ResultToolTests(OESelftestTestCase):
+ base_results_data = {'base_result1': {'configuration': {"TEST_TYPE": "runtime",
+ "TESTSERIES": "series1",
+ "IMAGE_BASENAME": "image",
+ "IMAGE_PKGTYPE": "ipk",
+ "DISTRO": "mydistro",
+ "MACHINE": "qemux86"},
+ 'result': {}},
+ 'base_result2': {'configuration': {"TEST_TYPE": "runtime",
+ "TESTSERIES": "series1",
+ "IMAGE_BASENAME": "image",
+ "IMAGE_PKGTYPE": "ipk",
+ "DISTRO": "mydistro",
+ "MACHINE": "qemux86-64"},
+ 'result': {}}}
+ target_results_data = {'target_result1': {'configuration': {"TEST_TYPE": "runtime",
+ "TESTSERIES": "series1",
+ "IMAGE_BASENAME": "image",
+ "IMAGE_PKGTYPE": "ipk",
+ "DISTRO": "mydistro",
+ "MACHINE": "qemux86"},
+ 'result': {}},
+ 'target_result2': {'configuration': {"TEST_TYPE": "runtime",
+ "TESTSERIES": "series1",
+ "IMAGE_BASENAME": "image",
+ "IMAGE_PKGTYPE": "ipk",
+ "DISTRO": "mydistro",
+ "MACHINE": "qemux86"},
+ 'result': {}},
+ 'target_result3': {'configuration': {"TEST_TYPE": "runtime",
+ "TESTSERIES": "series1",
+ "IMAGE_BASENAME": "image",
+ "IMAGE_PKGTYPE": "ipk",
+ "DISTRO": "mydistro",
+ "MACHINE": "qemux86-64"},
+ 'result': {}}}
+
+ def test_report_can_aggregate_test_result(self):
+ result_data = {'result': {'test1': {'status': 'PASSED'},
+ 'test2': {'status': 'PASSED'},
+ 'test3': {'status': 'FAILED'},
+ 'test4': {'status': 'ERROR'},
+ 'test5': {'status': 'SKIPPED'}}}
+ report = ResultsTextReport()
+ result_report = report.get_aggregated_test_result(None, result_data, 'DummyMachine')
+ self.assertTrue(result_report['passed'] == 2, msg="Passed count not correct:%s" % result_report['passed'])
+ self.assertTrue(result_report['failed'] == 2, msg="Failed count not correct:%s" % result_report['failed'])
+ self.assertTrue(result_report['skipped'] == 1, msg="Skipped count not correct:%s" % result_report['skipped'])
+
+ def test_regression_can_get_regression_base_target_pair(self):
+
+ results = {}
+ resultutils.append_resultsdata(results, ResultToolTests.base_results_data)
+ resultutils.append_resultsdata(results, ResultToolTests.target_results_data)
+ self.assertTrue('target_result1' in results['runtime/mydistro/qemux86/image'], msg="Pair not correct:%s" % results)
+ self.assertTrue('target_result3' in results['runtime/mydistro/qemux86-64/image'], msg="Pair not correct:%s" % results)
+
+ def test_regrresion_can_get_regression_result(self):
+ base_result_data = {'result': {'test1': {'status': 'PASSED'},
+ 'test2': {'status': 'PASSED'},
+ 'test3': {'status': 'FAILED'},
+ 'test4': {'status': 'ERROR'},
+ 'test5': {'status': 'SKIPPED'}}}
+ target_result_data = {'result': {'test1': {'status': 'PASSED'},
+ 'test2': {'status': 'FAILED'},
+ 'test3': {'status': 'PASSED'},
+ 'test4': {'status': 'ERROR'},
+ 'test5': {'status': 'SKIPPED'}}}
+ result, text = regression.compare_result(self.logger, "BaseTestRunName", "TargetTestRunName", base_result_data, target_result_data)
+ self.assertTrue(result['test2']['base'] == 'PASSED',
+ msg="regression not correct:%s" % result['test2']['base'])
+ self.assertTrue(result['test2']['target'] == 'FAILED',
+ msg="regression not correct:%s" % result['test2']['target'])
+ self.assertTrue(result['test3']['base'] == 'FAILED',
+ msg="regression not correct:%s" % result['test3']['base'])
+ self.assertTrue(result['test3']['target'] == 'PASSED',
+ msg="regression not correct:%s" % result['test3']['target'])
+
+ def test_merge_can_merged_results(self):
+ results = {}
+ resultutils.append_resultsdata(results, ResultToolTests.base_results_data, configmap=resultutils.flatten_map)
+ resultutils.append_resultsdata(results, ResultToolTests.target_results_data, configmap=resultutils.flatten_map)
+ self.assertEqual(len(results[''].keys()), 5, msg="Flattened results not correct %s" % str(results))
+
diff --git a/meta/lib/oeqa/selftest/cases/runcmd.py b/meta/lib/oeqa/selftest/cases/runcmd.py
index a1615cfd20..e9612389fe 100644
--- a/meta/lib/oeqa/selftest/cases/runcmd.py
+++ b/meta/lib/oeqa/selftest/cases/runcmd.py
@@ -1,7 +1,10 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd
from oeqa.utils import CommandError
-from oeqa.core.decorator.oeid import OETestID
import subprocess
import threading
@@ -24,111 +27,96 @@ class RunCmdTests(OESelftestTestCase):
# The delta is intentionally smaller than the timeout, to detect cases where
# we incorrectly apply the timeout more than once.
- TIMEOUT = 5
- DELTA = 3
+ TIMEOUT = 10
+ DELTA = 8
- @OETestID(1916)
def test_result_okay(self):
result = runCmd("true")
self.assertEqual(result.status, 0)
- @OETestID(1915)
def test_result_false(self):
result = runCmd("false", ignore_status=True)
self.assertEqual(result.status, 1)
- @OETestID(1917)
def test_shell(self):
# A shell is used for all string commands.
result = runCmd("false; true", ignore_status=True)
self.assertEqual(result.status, 0)
- @OETestID(1910)
def test_no_shell(self):
self.assertRaises(FileNotFoundError,
runCmd, "false; true", shell=False)
- @OETestID(1906)
def test_list_not_found(self):
self.assertRaises(FileNotFoundError,
runCmd, ["false; true"])
- @OETestID(1907)
def test_list_okay(self):
result = runCmd(["true"])
self.assertEqual(result.status, 0)
- @OETestID(1913)
def test_result_assertion(self):
self.assertRaisesRegexp(AssertionError, "Command 'echo .* false' returned non-zero exit status 1:\nfoobar",
runCmd, "echo foobar >&2; false", shell=True)
- @OETestID(1914)
def test_result_exception(self):
self.assertRaisesRegexp(CommandError, "Command 'echo .* false' returned non-zero exit status 1 with output: foobar",
runCmd, "echo foobar >&2; false", shell=True, assert_error=False)
- @OETestID(1911)
def test_output(self):
- result = runCmd("echo stdout; echo stderr >&2", shell=True)
+ result = runCmd("echo stdout; echo stderr >&2", shell=True, sync=False)
self.assertEqual("stdout\nstderr", result.output)
self.assertEqual("", result.error)
- @OETestID(1912)
def test_output_split(self):
- result = runCmd("echo stdout; echo stderr >&2", shell=True, stderr=subprocess.PIPE)
+ result = runCmd("echo stdout; echo stderr >&2", shell=True, stderr=subprocess.PIPE, sync=False)
self.assertEqual("stdout", result.output)
self.assertEqual("stderr", result.error)
- @OETestID(1920)
def test_timeout(self):
numthreads = threading.active_count()
start = time.time()
# Killing a hanging process only works when not using a shell?!
- result = runCmd(['sleep', '60'], timeout=self.TIMEOUT, ignore_status=True)
+ result = runCmd(['sleep', '60'], timeout=self.TIMEOUT, ignore_status=True, sync=False)
self.assertEqual(result.status, -signal.SIGTERM)
end = time.time()
self.assertLess(end - start, self.TIMEOUT + self.DELTA)
- self.assertEqual(numthreads, threading.active_count())
+ self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
- @OETestID(1921)
def test_timeout_split(self):
numthreads = threading.active_count()
start = time.time()
# Killing a hanging process only works when not using a shell?!
- result = runCmd(['sleep', '60'], timeout=self.TIMEOUT, ignore_status=True, stderr=subprocess.PIPE)
+ result = runCmd(['sleep', '60'], timeout=self.TIMEOUT, ignore_status=True, stderr=subprocess.PIPE, sync=False)
self.assertEqual(result.status, -signal.SIGTERM)
end = time.time()
self.assertLess(end - start, self.TIMEOUT + self.DELTA)
- self.assertEqual(numthreads, threading.active_count())
+ self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
- @OETestID(1918)
def test_stdin(self):
numthreads = threading.active_count()
- result = runCmd("cat", data=b"hello world", timeout=self.TIMEOUT)
+ result = runCmd("cat", data=b"hello world", timeout=self.TIMEOUT, sync=False)
self.assertEqual("hello world", result.output)
- self.assertEqual(numthreads, threading.active_count())
+ self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
+ self.assertEqual(numthreads, 1)
- @OETestID(1919)
def test_stdin_timeout(self):
numthreads = threading.active_count()
start = time.time()
- result = runCmd(['sleep', '60'], data=b"hello world", timeout=self.TIMEOUT, ignore_status=True)
+ result = runCmd(['sleep', '60'], data=b"hello world", timeout=self.TIMEOUT, ignore_status=True, sync=False)
self.assertEqual(result.status, -signal.SIGTERM)
end = time.time()
self.assertLess(end - start, self.TIMEOUT + self.DELTA)
- self.assertEqual(numthreads, threading.active_count())
+ self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
- @OETestID(1908)
def test_log(self):
log = MemLogger()
- result = runCmd("echo stdout; echo stderr >&2", shell=True, output_log=log)
+ result = runCmd("echo stdout; echo stderr >&2", shell=True, output_log=log, sync=False)
self.assertEqual(["Running: echo stdout; echo stderr >&2", "stdout", "stderr"], log.info_msgs)
self.assertEqual([], log.error_msgs)
- @OETestID(1909)
def test_log_split(self):
log = MemLogger()
- result = runCmd("echo stdout; echo stderr >&2", shell=True, output_log=log, stderr=subprocess.PIPE)
+ result = runCmd("echo stdout; echo stderr >&2", shell=True, output_log=log, stderr=subprocess.PIPE, sync=False)
self.assertEqual(["Running: echo stdout; echo stderr >&2", "stdout"], log.info_msgs)
self.assertEqual(["stderr"], log.error_msgs)
diff --git a/meta/lib/oeqa/selftest/cases/runqemu.py b/meta/lib/oeqa/selftest/cases/runqemu.py
index f69d4706a5..da22f77b27 100644
--- a/meta/lib/oeqa/selftest/cases/runqemu.py
+++ b/meta/lib/oeqa/selftest/cases/runqemu.py
@@ -1,14 +1,16 @@
#
# Copyright (c) 2017 Wind River Systems, Inc.
#
+# SPDX-License-Identifier: MIT
+#
import re
import tempfile
import time
import oe.types
+from oeqa.core.decorator import OETestTag
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import bitbake, runqemu, get_bb_var, runCmd
-from oeqa.core.decorator.oeid import OETestID
class RunqemuTests(OESelftestTestCase):
"""Runqemu test class"""
@@ -42,7 +44,6 @@ SYSLINUX_TIMEOUT = "10"
bitbake(self.recipe)
RunqemuTests.image_is_ready = True
- @OETestID(2001)
def test_boot_machine(self):
"""Test runqemu machine"""
cmd = "%s %s" % (self.cmd_common, self.machine)
@@ -50,7 +51,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
- @OETestID(2002)
def test_boot_machine_ext4(self):
"""Test runqemu machine ext4"""
cmd = "%s %s ext4" % (self.cmd_common, self.machine)
@@ -58,7 +58,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertIn('rootfs.ext4', f.read(), "Failed: %s" % cmd)
- @OETestID(2003)
def test_boot_machine_iso(self):
"""Test runqemu machine iso"""
cmd = "%s %s iso" % (self.cmd_common, self.machine)
@@ -66,7 +65,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertIn('media=cdrom', f.read(), "Failed: %s" % cmd)
- @OETestID(2004)
def test_boot_recipe_image(self):
"""Test runqemu recipe-image"""
cmd = "%s %s" % (self.cmd_common, self.recipe)
@@ -75,7 +73,6 @@ SYSLINUX_TIMEOUT = "10"
self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
- @OETestID(2005)
def test_boot_recipe_image_vmdk(self):
"""Test runqemu recipe-image vmdk"""
cmd = "%s %s wic.vmdk" % (self.cmd_common, self.recipe)
@@ -83,7 +80,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertIn('format=vmdk', f.read(), "Failed: %s" % cmd)
- @OETestID(2006)
def test_boot_recipe_image_vdi(self):
"""Test runqemu recipe-image vdi"""
cmd = "%s %s wic.vdi" % (self.cmd_common, self.recipe)
@@ -91,7 +87,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertIn('format=vdi', f.read(), "Failed: %s" % cmd)
- @OETestID(2007)
def test_boot_deploy(self):
"""Test runqemu deploy_dir_image"""
cmd = "%s %s" % (self.cmd_common, self.deploy_dir_image)
@@ -100,7 +95,6 @@ SYSLINUX_TIMEOUT = "10"
self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
- @OETestID(2008)
def test_boot_deploy_hddimg(self):
"""Test runqemu deploy_dir_image hddimg"""
cmd = "%s %s hddimg" % (self.cmd_common, self.deploy_dir_image)
@@ -108,7 +102,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertTrue(re.search('file=.*.hddimg', f.read()), "Failed: %s, %s" % (cmd, f.read()))
- @OETestID(2009)
def test_boot_machine_slirp(self):
"""Test runqemu machine slirp"""
cmd = "%s slirp %s" % (self.cmd_common, self.machine)
@@ -116,7 +109,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertIn(' -netdev user', f.read(), "Failed: %s" % cmd)
- @OETestID(2009)
def test_boot_machine_slirp_qcow2(self):
"""Test runqemu machine slirp qcow2"""
cmd = "%s slirp wic.qcow2 %s" % (self.cmd_common, self.machine)
@@ -124,7 +116,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertIn('format=qcow2', f.read(), "Failed: %s" % cmd)
- @OETestID(2010)
def test_boot_qemu_boot(self):
"""Test runqemu /path/to/image.qemuboot.conf"""
qemuboot_conf = "%s-%s.qemuboot.conf" % (self.recipe, self.machine)
@@ -136,7 +127,6 @@ SYSLINUX_TIMEOUT = "10"
with open(qemu.qemurunnerlog) as f:
self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
- @OETestID(2011)
def test_boot_rootfs(self):
"""Test runqemu /path/to/rootfs.ext4"""
rootfs = "%s-%s.ext4" % (self.recipe, self.machine)
@@ -158,6 +148,7 @@ SYSLINUX_TIMEOUT = "10"
# dedicated for MACHINE=qemux86-64 where it test that qemux86-64 will
# bootup various filesystem types, including live image(iso and hddimg)
# where live image was not supported on all qemu architecture.
+@OETestTag("machine")
class QemuTest(OESelftestTestCase):
@classmethod
@@ -172,12 +163,11 @@ class QemuTest(OESelftestTestCase):
bitbake(cls.recipe)
def _start_qemu_shutdown_check_if_shutdown_succeeded(self, qemu, timeout):
+ # Allow the runner's LoggingThread instance to exit without errors
+ # (such as the exception "Console connection closed unexpectedly")
+ # as qemu will disappear when we shut it down
+ qemu.runner.allowexit()
qemu.run_serial("shutdown -h now")
- # Stop thread will stop the LoggingThread instance used for logging
- # qemu through serial console, stop thread will prevent this code
- # from facing exception (Console connection closed unexpectedly)
- # when qemu was shutdown by the above shutdown command
- qemu.runner.stop_thread()
time_track = 0
try:
while True:
diff --git a/meta/lib/oeqa/selftest/cases/runtime_test.py b/meta/lib/oeqa/selftest/cases/runtime_test.py
index 906e460d4f..642f0eb637 100644
--- a/meta/lib/oeqa/selftest/cases/runtime_test.py
+++ b/meta/lib/oeqa/selftest/cases/runtime_test.py
@@ -1,20 +1,19 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu
from oeqa.utils.sshcontrol import SSHControl
-from oeqa.core.decorator.oeid import OETestID
import os
import re
import tempfile
import shutil
+import oe.lsb
+from oeqa.core.decorator.data import skipIfNotQemu
class TestExport(OESelftestTestCase):
- @classmethod
- def tearDownClass(cls):
- runCmd("rm -rf /tmp/sdk")
- super(TestExport, cls).tearDownClass()
-
- @OETestID(1499)
def test_testexport_basic(self):
"""
Summary: Check basic testexport functionality with only ping test enabled.
@@ -54,7 +53,6 @@ class TestExport(OESelftestTestCase):
# Verify ping test was succesful
self.assertEqual(0, result.status, 'oe-test runtime returned a non 0 status')
- @OETestID(1641)
def test_testexport_sdk(self):
"""
Summary: Check sdk functionality for testexport.
@@ -92,24 +90,24 @@ class TestExport(OESelftestTestCase):
msg = "Couldn't find SDK tarball: %s" % tarball_path
self.assertEqual(os.path.isfile(tarball_path), True, msg)
- # Extract SDK and run tar from SDK
- result = runCmd("%s -y -d /tmp/sdk" % tarball_path)
- self.assertEqual(0, result.status, "Couldn't extract SDK")
+ with tempfile.TemporaryDirectory() as tmpdirname:
+ # Extract SDK and run tar from SDK
+ result = runCmd("%s -y -d %s" % (tarball_path, tmpdirname))
+ self.assertEqual(0, result.status, "Couldn't extract SDK")
- env_script = result.output.split()[-1]
- result = runCmd(". %s; which tar" % env_script, shell=True)
- self.assertEqual(0, result.status, "Couldn't setup SDK environment")
- is_sdk_tar = True if "/tmp/sdk" in result.output else False
- self.assertTrue(is_sdk_tar, "Couldn't setup SDK environment")
+ env_script = result.output.split()[-1]
+ result = runCmd(". %s; which tar" % env_script, shell=True)
+ self.assertEqual(0, result.status, "Couldn't setup SDK environment")
+ is_sdk_tar = True if tmpdirname in result.output else False
+ self.assertTrue(is_sdk_tar, "Couldn't setup SDK environment")
- tar_sdk = result.output
- result = runCmd("%s --version" % tar_sdk)
- self.assertEqual(0, result.status, "Couldn't run tar from SDK")
+ tar_sdk = result.output
+ result = runCmd("%s --version" % tar_sdk)
+ self.assertEqual(0, result.status, "Couldn't run tar from SDK")
class TestImage(OESelftestTestCase):
- @OETestID(1644)
def test_testimage_install(self):
"""
Summary: Check install packages functionality for testimage/testexport.
@@ -122,15 +120,13 @@ 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)
- # Build core-image-sato and testimage
bitbake('core-image-full-cmdline socat')
bitbake('-c testimage core-image-full-cmdline')
- @OETestID(1883)
def test_testimage_dnf(self):
"""
Summary: Check package feeds functionality for dnf
@@ -153,25 +149,139 @@ class TestImage(OESelftestTestCase):
# Enable package feed signing
self.gpg_home = tempfile.mkdtemp(prefix="oeqa-feed-sign-")
+ self.track_for_cleanup(self.gpg_home)
signing_key_dir = os.path.join(self.testlayer_path, 'files', 'signing')
- runCmd('gpg --batch --homedir %s --import %s' % (self.gpg_home, os.path.join(signing_key_dir, 'key.secret')), native_sysroot=get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native"))
+ runCmd('gpgconf --list-dirs --homedir %s; gpg -v --batch --homedir %s --import %s' % (self.gpg_home, self.gpg_home, os.path.join(signing_key_dir, 'key.secret')), native_sysroot=get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native"), shell=True)
features += 'INHERIT += "sign_package_feed"\n'
features += 'PACKAGE_FEED_GPG_NAME = "testuser"\n'
features += 'PACKAGE_FEED_GPG_PASSPHRASE_FILE = "%s"\n' % os.path.join(signing_key_dir, 'key.passphrase')
features += 'GPG_PATH = "%s"\n' % self.gpg_home
+ features += 'PSEUDO_IGNORE_PATHS .= ",%s"\n' % self.gpg_home
self.write_config(features)
- # Build core-image-sato and testimage
bitbake('core-image-full-cmdline socat')
bitbake('-c testimage core-image-full-cmdline')
- # remove the oeqa-feed-sign temporal directory
- shutil.rmtree(self.gpg_home, ignore_errors=True)
+ def test_testimage_virgl_gtk_sdl(self):
+ """
+ Summary: Check host-assisted accelerate OpenGL functionality in qemu with gtk and SDL frontends
+ Expected: 1. Check that virgl kernel driver is loaded and 3d acceleration is enabled
+ 2. Check that kmscube demo runs without crashing.
+ Product: oe-core
+ Author: Alexander Kanavin <alex.kanavin@gmail.com>
+ """
+ if "DISPLAY" not in os.environ:
+ self.skipTest("virgl gtk test must be run inside a X session")
+ distro = oe.lsb.distro_identifier()
+ if distro and distro == 'debian-8':
+ self.skipTest('virgl isn\'t working with Debian 8')
+ if distro and distro == 'debian-9':
+ self.skipTest('virgl isn\'t working with Debian 9')
+ if distro and distro == 'centos-7':
+ self.skipTest('virgl isn\'t working with Centos 7')
+ if distro and distro == 'opensuseleap-15.0':
+ self.skipTest('virgl isn\'t working with Opensuse 15.0')
+
+ qemu_packageconfig = get_bb_var('PACKAGECONFIG', 'qemu-system-native')
+ 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'
+ if 'sdl' not in qemu_packageconfig:
+ features += 'PACKAGECONFIG:append:pn-qemu-system-native = " sdl"\n'
+ if 'opengl' not in qemu_distrofeatures:
+ 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_gtk = features + 'TEST_RUNQEMUPARAMS = "gtk gl"\n'
+ self.write_config(features_gtk)
+ bitbake('core-image-minimal')
+ bitbake('-c testimage core-image-minimal')
+ features_sdl = features + 'TEST_RUNQEMUPARAMS = "sdl gl"\n'
+ self.write_config(features_sdl)
+ bitbake('core-image-minimal')
+ bitbake('-c testimage core-image-minimal')
+
+ def test_testimage_virgl_headless(self):
+ """
+ Summary: Check host-assisted accelerate OpenGL functionality in qemu with egl-headless frontend
+ Expected: 1. Check that virgl kernel driver is loaded and 3d acceleration is enabled
+ 2. Check that kmscube demo runs without crashing.
+ Product: oe-core
+ 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.fail("No render nodes found in /dev/dri: %s. %s" %(content, render_hint))
+ except FileNotFoundError:
+ 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.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 += 'TEST_SUITES = "ping ssh virgl"\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')
+ bitbake('-c testimage core-image-minimal')
class Postinst(OESelftestTestCase):
- @OETestID(1540)
- @OETestID(1545)
- def test_postinst_rootfs_and_boot(self):
+
+ def init_manager_loop(self, init_manager):
+ import oe.path
+
+ vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal")
+ rootfs = vars["IMAGE_ROOTFS"]
+ self.assertIsNotNone(rootfs)
+ sysconfdir = vars["sysconfdir"]
+ self.assertIsNotNone(sysconfdir)
+ # Need to use oe.path here as sysconfdir starts with /
+ hosttestdir = oe.path.join(rootfs, sysconfdir, "postinst-test")
+ targettestdir = os.path.join(sysconfdir, "postinst-test")
+
+ for classes in ("package_rpm", "package_deb", "package_ipk"):
+ with self.subTest(init_manager=init_manager, package_class=classes):
+ features = 'CORE_IMAGE_EXTRA_INSTALL = "postinst-delayed-b"\n'
+ 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 += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n'
+ features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n'
+ features += 'VIRTUAL-RUNTIME_initscripts = ""\n'
+ self.write_config(features)
+
+ bitbake('core-image-minimal')
+
+ self.assertTrue(os.path.isfile(os.path.join(hosttestdir, "rootfs")),
+ "rootfs state file was not created")
+
+ with runqemu('core-image-minimal') as qemu:
+ # Make the test echo a string and search for that as
+ # run_serial()'s status code is useless.'
+ for filename in ("rootfs", "delayed-a", "delayed-b"):
+ status, output = qemu.run_serial("test -f %s && echo found" % os.path.join(targettestdir, filename))
+ self.assertIn("found", output, "%s was not present on boot" % filename)
+
+
+
+ @skipIfNotQemu('qemuall', 'Test only runs in qemu')
+ def test_postinst_rootfs_and_boot_sysvinit(self):
"""
Summary: The purpose of this test case is to verify Post-installation
scripts are called when rootfs is created and also test
@@ -185,46 +295,32 @@ class Postinst(OESelftestTestCase):
created by postinst_boot recipe is present on image.
Expected: The files are successfully created during rootfs and boot
time for 3 different package managers: rpm,ipk,deb and
- for initialization managers: sysvinit and systemd.
+ for initialization managers: sysvinit.
"""
+ self.init_manager_loop("sysvinit")
- import oe.path
- vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal")
- rootfs = vars["IMAGE_ROOTFS"]
- self.assertIsNotNone(rootfs)
- sysconfdir = vars["sysconfdir"]
- self.assertIsNotNone(sysconfdir)
- # Need to use oe.path here as sysconfdir starts with /
- hosttestdir = oe.path.join(rootfs, sysconfdir, "postinst-test")
- targettestdir = os.path.join(sysconfdir, "postinst-test")
-
- for init_manager in ("sysvinit", "systemd"):
- for classes in ("package_rpm", "package_deb", "package_ipk"):
- with self.subTest(init_manager=init_manager, package_class=classes):
- features = 'CORE_IMAGE_EXTRA_INSTALL = "postinst-delayed-b"\n'
- 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 += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n'
- features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n'
- features += 'VIRTUAL-RUNTIME_initscripts = ""\n'
- self.write_config(features)
-
- bitbake('core-image-minimal')
-
- self.assertTrue(os.path.isfile(os.path.join(hosttestdir, "rootfs")),
- "rootfs state file was not created")
+ @skipIfNotQemu('qemuall', 'Test only runs in qemu')
+ def test_postinst_rootfs_and_boot_systemd(self):
+ """
+ Summary: The purpose of this test case is to verify Post-installation
+ scripts are called when rootfs is created and also test
+ that script can be delayed to run at first boot.
+ Dependencies: NA
+ Steps: 1. Add proper configuration to local.conf file
+ 2. Build a "core-image-minimal" image
+ 3. Verify that file created by postinst_rootfs recipe is
+ present on rootfs dir.
+ 4. Boot the image created on qemu and verify that the file
+ created by postinst_boot recipe is present on image.
+ Expected: The files are successfully created during rootfs and boot
+ time for 3 different package managers: rpm,ipk,deb and
+ for initialization managers: systemd.
- with runqemu('core-image-minimal') as qemu:
- # Make the test echo a string and search for that as
- # run_serial()'s status code is useless.'
- for filename in ("rootfs", "delayed-a", "delayed-b"):
- status, output = qemu.run_serial("test -f %s && echo found" % os.path.join(targettestdir, filename))
- self.assertEqual(output, "found", "%s was not present on boot" % filename)
+ """
+ self.init_manager_loop("systemd")
def test_failing_postinst(self):
@@ -261,3 +357,80 @@ class Postinst(OESelftestTestCase):
self.assertFalse(os.path.isfile(os.path.join(hosttestdir, "rootfs-after-failure")),
"rootfs-after-failure file was created")
+class SystemTap(OESelftestTestCase):
+ """
+ Summary: The purpose of this test case is to verify native crosstap
+ works while talking to a target.
+ Expected: The script should successfully connect to the qemu machine
+ and run some systemtap examples on a qemu machine.
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(SystemTap, cls).setUpClass()
+ cls.image = "core-image-minimal"
+
+ def default_config(self):
+ return """
+# These aren't the actual IP addresses but testexport class needs something defined
+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"
+
+# enables kernel debug symbols
+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"
+"""
+
+ def test_crosstap_helloworld(self):
+ self.write_config(self.default_config())
+ bitbake('systemtap-native')
+ systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples")
+ bitbake(self.image)
+
+ with runqemu(self.image) as qemu:
+ cmd = "crosstap -r root@192.168.7.2 -s %s/general/helloworld.stp " % systemtap_examples
+ result = runCmd(cmd)
+ self.assertEqual(0, result.status, 'crosstap helloworld returned a non 0 status:%s' % result.output)
+
+ def test_crosstap_pstree(self):
+ self.write_config(self.default_config())
+
+ bitbake('systemtap-native')
+ systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples")
+ bitbake(self.image)
+
+ with runqemu(self.image) as qemu:
+ cmd = "crosstap -r root@192.168.7.2 -s %s/process/pstree.stp" % systemtap_examples
+ result = runCmd(cmd)
+ self.assertEqual(0, result.status, 'crosstap pstree returned a non 0 status:%s' % result.output)
+
+ def test_crosstap_syscalls_by_proc(self):
+ self.write_config(self.default_config())
+
+ bitbake('systemtap-native')
+ systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples")
+ bitbake(self.image)
+
+ with runqemu(self.image) as qemu:
+ cmd = "crosstap -r root@192.168.7.2 -s %s/process/ syscalls_by_proc.stp" % systemtap_examples
+ result = runCmd(cmd)
+ self.assertEqual(0, result.status, 'crosstap syscalls_by_proc returned a non 0 status:%s' % result.output)
+
+ def test_crosstap_syscalls_by_pid(self):
+ self.write_config(self.default_config())
+
+ bitbake('systemtap-native')
+ systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples")
+ bitbake(self.image)
+
+ with runqemu(self.image) as qemu:
+ cmd = "crosstap -r root@192.168.7.2 -s %s/process/ syscalls_by_pid.stp" % systemtap_examples
+ result = runCmd(cmd)
+ self.assertEqual(0, result.status, 'crosstap syscalls_by_pid returned a non 0 status:%s' % result.output)
+
diff --git a/meta/lib/oeqa/selftest/cases/selftest.py b/meta/lib/oeqa/selftest/cases/selftest.py
index 4b3cb14463..af080dcf03 100644
--- a/meta/lib/oeqa/selftest/cases/selftest.py
+++ b/meta/lib/oeqa/selftest/cases/selftest.py
@@ -1,12 +1,14 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import importlib
from oeqa.utils.commands import runCmd
import oeqa.selftest
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.core.decorator.oeid import OETestID
class ExternalLayer(OESelftestTestCase):
- @OETestID(1885)
def test_list_imported(self):
"""
Summary: Checks functionality to import tests from other layers.
diff --git a/meta/lib/oeqa/selftest/cases/signing.py b/meta/lib/oeqa/selftest/cases/signing.py
index 4fa99acbc9..6f3d4aeae9 100644
--- a/meta/lib/oeqa/selftest/cases/signing.py
+++ b/meta/lib/oeqa/selftest/cases/signing.py
@@ -1,5 +1,9 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
from oeqa.selftest.case import OESelftestTestCase
-from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
+from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, create_temp_layer
import os
import oe
import glob
@@ -7,7 +11,6 @@ import re
import shutil
import tempfile
from contextlib import contextmanager
-from oeqa.core.decorator.oeid import OETestID
from oeqa.utils.ftools import write_file
@@ -27,7 +30,8 @@ class Signing(OESelftestTestCase):
self.secret_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.secret")
nsysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native")
- runCmd('gpg --batch --homedir %s --import %s %s' % (self.gpg_dir, self.pub_key_path, self.secret_key_path), native_sysroot=nsysroot)
+
+ runCmd('gpg --agent-program=`which gpg-agent`\|--auto-expand-secmem --batch --homedir %s --import %s %s' % (self.gpg_dir, self.pub_key_path, self.secret_key_path), native_sysroot=nsysroot)
return nsysroot + get_bb_var("bindir_native")
@@ -40,7 +44,9 @@ class Signing(OESelftestTestCase):
origenv = os.environ.copy()
for e in os.environ:
- if builddir in os.environ[e]:
+ if builddir + "/" in os.environ[e]:
+ os.environ[e] = os.environ[e].replace(builddir + "/", newbuilddir + "/")
+ if os.environ[e].endswith(builddir):
os.environ[e] = os.environ[e].replace(builddir, newbuilddir)
os.chdir(newbuilddir)
@@ -51,7 +57,6 @@ class Signing(OESelftestTestCase):
os.environ[e] = origenv[e]
os.chdir(builddir)
- @OETestID(1362)
def test_signing_packages(self):
"""
Summary: Test that packages can be signed in the package feed
@@ -116,7 +121,6 @@ class Signing(OESelftestTestCase):
bitbake('core-image-minimal')
- @OETestID(1382)
def test_signing_sstate_archive(self):
"""
Summary: Test that sstate archives can be signed
@@ -141,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)
@@ -155,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.')
@@ -169,7 +173,6 @@ class Signing(OESelftestTestCase):
class LockedSignatures(OESelftestTestCase):
- @OETestID(1420)
def test_locked_signatures(self):
"""
Summary: Test locked signature mechanism
@@ -179,11 +182,11 @@ class LockedSignatures(OESelftestTestCase):
AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com>
"""
+ import uuid
+
test_recipe = 'ed'
locked_sigs_file = 'locked-sigs.inc'
- self.add_command_to_tearDown('rm -f %s' % os.path.join(self.builddir, locked_sigs_file))
-
bitbake(test_recipe)
# Generate locked sigs include file
bitbake('-S none %s' % test_recipe)
@@ -195,21 +198,29 @@ class LockedSignatures(OESelftestTestCase):
# Build a locked recipe
bitbake(test_recipe)
+ templayerdir = tempfile.mkdtemp(prefix='signingqa')
+ create_temp_layer(templayerdir, 'selftestsigning')
+ runCmd('bitbake-layers add-layer %s' % templayerdir)
+
# Make a change that should cause the locked task signature to change
+ # 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(self.testlayer_path, 'recipes-test', test_recipe, recipe_append_file)
- feature = 'SUMMARY += "test locked signature"\n'
+ recipe_append_path = os.path.join(templayerdir, 'recipes-test', test_recipe, recipe_append_file)
+ feature = 'SUMMARY:${PN} = "test locked signature%s"\n' % uuid.uuid4()
- os.mkdir(os.path.join(self.testlayer_path, 'recipes-test', test_recipe))
+ os.mkdir(os.path.join(templayerdir, 'recipes-test'))
+ os.mkdir(os.path.join(templayerdir, 'recipes-test', test_recipe))
write_file(recipe_append_path, feature)
- self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, 'recipes-test', test_recipe))
+ self.add_command_to_tearDown('bitbake-layers remove-layer %s' % templayerdir)
+ self.add_command_to_tearDown('rm -f %s' % os.path.join(self.builddir, locked_sigs_file))
+ self.add_command_to_tearDown('rm -rf %s' % templayerdir)
# Build the recipe again
ret = bitbake(test_recipe)
# Verify you get the warning and that the real task *isn't* run (i.e. the locked signature has worked)
- patt = r'WARNING: The %s:do_package sig is computed to be \S+, but the sig is locked to \S+ in SIGGEN_LOCKEDSIGS\S+' % test_recipe
+ patt = r'The %s:do_package sig is computed to be \S+, but the sig is locked to \S+ in SIGGEN_LOCKEDSIGS\S+' % test_recipe
found_warn = re.search(patt, ret.output)
self.assertIsNotNone(found_warn, "Didn't find the expected warning message. Output: %s" % ret.output)
diff --git a/meta/lib/oeqa/selftest/cases/sstate.py b/meta/lib/oeqa/selftest/cases/sstate.py
index bc2fdbd8cc..80ce9e353c 100644
--- a/meta/lib/oeqa/selftest/cases/sstate.py
+++ b/meta/lib/oeqa/selftest/cases/sstate.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import datetime
import unittest
import os
@@ -52,11 +56,11 @@ class SStateBase(OESelftestTestCase):
def search_sstate(self, filename_regex, distro_specific=True, distro_nonspecific=True):
result = []
for root, dirs, files in os.walk(self.sstate_path):
- if distro_specific and re.search("%s/[a-z0-9]{2}$" % self.hostdistro, root):
+ if distro_specific and re.search(r"%s/%s/[a-z0-9]{2}/[a-z0-9]{2}$" % (self.sstate_path, self.hostdistro), root):
for f in files:
if re.search(filename_regex, f):
result.append(f)
- if distro_nonspecific and re.search("%s/[a-z0-9]{2}$" % self.sstate_path, root):
+ if distro_nonspecific and re.search(r"%s/[a-z0-9]{2}/[a-z0-9]{2}$" % self.sstate_path, root):
for f in files:
if re.search(filename_regex, f):
result.append(f)
diff --git a/meta/lib/oeqa/selftest/cases/sstatetests.py b/meta/lib/oeqa/selftest/cases/sstatetests.py
index 077d6e5374..3038b40021 100644
--- a/meta/lib/oeqa/selftest/cases/sstatetests.py
+++ b/meta/lib/oeqa/selftest/cases/sstatetests.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import shutil
import glob
@@ -7,7 +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
-from oeqa.core.decorator.oeid import OETestID
+import oe
import bb.siggen
@@ -16,10 +20,13 @@ class SStateTests(SStateBase):
# Test that a git repository which changes is correctly handled by SRCREV = ${AUTOREV}
# when PV does not contain SRCPV
- tempdir = tempfile.mkdtemp(prefix='oeqa')
+ tempdir = tempfile.mkdtemp(prefix='sstate_autorev')
+ tempdldir = tempfile.mkdtemp(prefix='sstate_autorev_dldir')
self.track_for_cleanup(tempdir)
+ self.track_for_cleanup(tempdldir)
create_temp_layer(tempdir, 'selftestrecipetool')
self.add_command_to_tearDown('bitbake-layers remove-layer %s' % tempdir)
+ self.append_config("DL_DIR = \"%s\"" % tempdldir)
runCmd('bitbake-layers add-layer %s' % tempdir)
# Use dbus-wait as a local git repo we can add a commit between two builds in
@@ -33,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)
@@ -62,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:
@@ -73,19 +80,15 @@ class SStateTests(SStateBase):
else:
self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s (found %s)" % (', '.join(map(str, targets)), str(file_tracker)))
- @OETestID(975)
def test_sstate_creation_distro_specific_pass(self):
self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
- @OETestID(1374)
def test_sstate_creation_distro_specific_fail(self):
self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False)
- @OETestID(976)
def test_sstate_creation_distro_nonspecific_pass(self):
self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
- @OETestID(1375)
def test_sstate_creation_distro_nonspecific_fail(self):
self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False)
@@ -96,27 +99,24 @@ class SStateTests(SStateBase):
bitbake(['-ccleansstate'] + targets)
bitbake(targets)
- tgz_created = self.search_sstate('|'.join(map(str, [s + '.*?\.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 + '.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific)
+ 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 + '.*?\.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)))
- @OETestID(977)
def test_cleansstate_task_distro_specific_nonspecific(self):
targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
targets.append('linux-libc-headers')
self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True)
- @OETestID(1376)
def test_cleansstate_task_distro_nonspecific(self):
self.run_test_cleansstate_task(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
- @OETestID(1377)
def test_cleansstate_task_distro_specific(self):
targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
targets.append('linux-libc-headers')
@@ -130,15 +130,15 @@ class SStateTests(SStateBase):
bitbake(['-ccleansstate'] + targets)
bitbake(targets)
- results = self.search_sstate('|'.join(map(str, [s + '.*?\.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 + '.*?\.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")
@@ -146,24 +146,21 @@ class SStateTests(SStateBase):
bitbake(['-cclean'] + targets)
bitbake(targets)
- file_tracker_2 = self.search_sstate('|'.join(map(str, [s + '.*?\.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)))
- @OETestID(175)
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)
- @OETestID(1372)
def test_rebuild_distro_specific_sstate_cross_target(self):
self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch], temp_sstate_location=True)
- @OETestID(1373)
def test_rebuild_distro_specific_sstate_native_target(self):
self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True)
@@ -178,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 = []
@@ -192,25 +189,24 @@ 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 + '.*?\.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 + '.*?\.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 + '.*?\.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)))
- @OETestID(973)
def test_sstate_cache_management_script_using_pr_1(self):
global_config = []
target_config = []
@@ -218,7 +214,6 @@ class SStateTests(SStateBase):
target_config.append('PR = "0"')
self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
- @OETestID(978)
def test_sstate_cache_management_script_using_pr_2(self):
global_config = []
target_config = []
@@ -228,7 +223,6 @@ class SStateTests(SStateBase):
target_config.append('PR = "1"')
self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
- @OETestID(979)
def test_sstate_cache_management_script_using_pr_3(self):
global_config = []
target_config = []
@@ -240,7 +234,6 @@ class SStateTests(SStateBase):
target_config.append('PR = "1"')
self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
- @OETestID(974)
def test_sstate_cache_management_script_using_machine(self):
global_config = []
target_config = []
@@ -250,7 +243,6 @@ class SStateTests(SStateBase):
target_config.append('')
self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
- @OETestID(1270)
def test_sstate_32_64_same_hash(self):
"""
The sstate checksums for both native and target should not vary whether
@@ -267,9 +259,10 @@ BUILD_ARCH = "x86_64"
BUILD_OS = "linux"
SDKMACHINE = "x86_64"
PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
""")
self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
- bitbake("core-image-sato -S none")
+ bitbake("core-image-weston -S none")
self.write_config("""
MACHINE = "qemux86"
TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
@@ -278,14 +271,15 @@ BUILD_ARCH = "i686"
BUILD_OS = "linux"
SDKMACHINE = "i686"
PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
""")
self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
- bitbake("core-image-sato -S none")
+ bitbake("core-image-weston -S none")
def get_files(d):
f = []
for root, dirs, files in os.walk(d):
- if "core-image-sato" in root:
+ if "core-image-weston" in root:
# SDKMACHINE changing will change
# do_rootfs/do_testimage/do_build stamps of images which
# is safe to ignore.
@@ -299,7 +293,6 @@ PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
self.assertCountEqual(files1, files2)
- @OETestID(1271)
def test_sstate_nativelsbstring_same_hash(self):
"""
The sstate checksums should be independent of whichever NATIVELSBSTRING is
@@ -311,16 +304,18 @@ PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
TCLIBCAPPEND = \"\"
NATIVELSBSTRING = \"DistroA\"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
""")
self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
- bitbake("core-image-sato -S none")
+ bitbake("core-image-weston -S none")
self.write_config("""
TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
TCLIBCAPPEND = \"\"
NATIVELSBSTRING = \"DistroB\"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
""")
self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
- bitbake("core-image-sato -S none")
+ bitbake("core-image-weston -S none")
def get_files(d):
f = []
@@ -333,7 +328,6 @@ NATIVELSBSTRING = \"DistroB\"
self.maxDiff = None
self.assertCountEqual(files1, files2)
- @OETestID(1368)
def test_sstate_allarch_samesigs(self):
"""
The sstate checksums of allarch packages should be independent of whichever
@@ -346,15 +340,18 @@ NATIVELSBSTRING = \"DistroB\"
TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
TCLIBCAPPEND = \"\"
MACHINE = \"qemux86-64\"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
"""
+ #OLDEST_KERNEL is arch specific so set to a different value here for testing
configB = """
TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
TCLIBCAPPEND = \"\"
MACHINE = \"qemuarm\"
+OLDEST_KERNEL = \"3.3.0\"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
"""
- self.sstate_allarch_samesigs(configA, configB)
+ self.sstate_common_samesigs(configA, configB, allarch=True)
- @OETestID(1645)
def test_sstate_nativesdk_samesigs_multilib(self):
"""
check nativesdk stamps are the same between the two MACHINE values.
@@ -366,7 +363,8 @@ 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 = """
TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
@@ -374,10 +372,11 @@ TCLIBCAPPEND = \"\"
MACHINE = \"qemuarm\"
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")
@@ -405,7 +404,13 @@ MULTILIBS = \"\"
self.maxDiff = None
self.assertEqual(files1, files2)
- @OETestID(1369)
+ 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
@@ -419,7 +424,8 @@ 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")
bitbake("world meta-toolchain -S none")
@@ -429,7 +435,8 @@ 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")
bitbake("world meta-toolchain -S none")
@@ -452,7 +459,46 @@ DEFAULTTUNE_virtclass-multilib-lib32 = "x86"
self.assertCountEqual(files1, files2)
- @OETestID(1498)
+ def test_sstate_multilib_or_not_native_samesigs(self):
+ """The sstate checksums of two native recipes (and their dependencies)
+ where the target is using multilib in one but not the other
+ should be the same. We use the qemux86copy machine to test
+ this.
+ """
+
+ self.write_config("""
+TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
+TCLIBCAPPEND = \"\"
+MACHINE = \"qemux86\"
+require conf/multilib.conf
+MULTILIBS = "multilib:lib32"
+DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
+""")
+ self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
+ bitbake("binutils-native -S none")
+ self.write_config("""
+TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
+TCLIBCAPPEND = \"\"
+MACHINE = \"qemux86copy\"
+BB_SIGNATURE_HANDLER = "OEBasicHash"
+""")
+ self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
+ bitbake("binutils-native -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)
+
+
def test_sstate_noop_samesigs(self):
"""
The sstate checksums of two builds with these variables changed or
@@ -467,8 +513,9 @@ 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"
""")
self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
self.track_for_cleanup(self.topdir + "/download1")
@@ -482,9 +529,10 @@ 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"
""")
self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
self.track_for_cleanup(self.topdir + "/download2")
@@ -535,3 +583,44 @@ http_proxy = "http://example.com/"
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
new file mode 100644
index 0000000000..79ab45235d
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/sysroot.py
@@ -0,0 +1,37 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
+import uuid
+
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake
+
+class SysrootTests(OESelftestTestCase):
+ def test_sysroot_cleanup(self):
+ """
+ Build sysroot test which depends on virtual/sysroot-test for one machine,
+ switch machine, switch provider of virtual/sysroot-test and check that the
+ sysroot is correctly cleaned up. The files in the two providers overlap
+ so can cause errors if the sysroot code doesn't function correctly.
+ Yes, sysroot-test should be machine specific really to avoid this, however
+ the sysroot cleanup should also work [YOCTO #13702].
+ """
+
+ uuid1 = uuid.uuid4()
+ uuid2 = uuid.uuid4()
+
+ 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"
+""" % (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"
+""" % (uuid1, uuid2))
+ bitbake("sysroot-test")
diff --git a/meta/lib/oeqa/selftest/cases/tinfoil.py b/meta/lib/oeqa/selftest/cases/tinfoil.py
index f889a47b26..8fd48bb054 100644
--- a/meta/lib/oeqa/selftest/cases/tinfoil.py
+++ b/meta/lib/oeqa/selftest/cases/tinfoil.py
@@ -1,3 +1,7 @@
+#
+# SPDX-License-Identifier: MIT
+#
+
import os
import re
import time
@@ -6,12 +10,10 @@ import bb.tinfoil
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd
-from oeqa.core.decorator.oeid import OETestID
class TinfoilTests(OESelftestTestCase):
""" Basic tests for the tinfoil API """
- @OETestID(1568)
def test_getvar(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(True)
@@ -19,7 +21,6 @@ class TinfoilTests(OESelftestTestCase):
if not machine:
self.fail('Unable to get MACHINE value - returned %s' % machine)
- @OETestID(1569)
def test_expand(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(True)
@@ -28,7 +29,6 @@ class TinfoilTests(OESelftestTestCase):
if not pid:
self.fail('Unable to expand "%s" - returned %s' % (expr, pid))
- @OETestID(1570)
def test_getvar_bb_origenv(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(True)
@@ -37,7 +37,6 @@ class TinfoilTests(OESelftestTestCase):
self.fail('Unable to get BB_ORIGENV value - returned %s' % origenv)
self.assertEqual(origenv.getVar('HOME', False), os.environ['HOME'])
- @OETestID(1571)
def test_parse_recipe(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(config_only=False, quiet=2)
@@ -48,7 +47,6 @@ class TinfoilTests(OESelftestTestCase):
rd = tinfoil.parse_recipe_file(best[3])
self.assertEqual(testrecipe, rd.getVar('PN'))
- @OETestID(1572)
def test_parse_recipe_copy_expand(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(config_only=False, quiet=2)
@@ -67,21 +65,6 @@ class TinfoilTests(OESelftestTestCase):
localdata.setVar('PN', 'hello')
self.assertEqual('hello', localdata.getVar('BPN'))
- @OETestID(1573)
- def test_parse_recipe_initial_datastore(self):
- with bb.tinfoil.Tinfoil() as tinfoil:
- tinfoil.prepare(config_only=False, quiet=2)
- testrecipe = 'mdadm'
- best = tinfoil.find_best_provider(testrecipe)
- if not best:
- self.fail('Unable to find recipe providing %s' % testrecipe)
- dcopy = bb.data.createCopy(tinfoil.config_data)
- dcopy.setVar('MYVARIABLE', 'somevalue')
- rd = tinfoil.parse_recipe_file(best[3], config_data=dcopy)
- # Check we can get variable values
- self.assertEqual('somevalue', rd.getVar('MYVARIABLE'))
-
- @OETestID(1574)
def test_list_recipes(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(config_only=False, quiet=2)
@@ -100,7 +83,6 @@ class TinfoilTests(OESelftestTestCase):
if checkpns:
self.fail('Unable to find pkg_fn entries for: %s' % ', '.join(checkpns))
- @OETestID(1575)
def test_wait_event(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(config_only=True)
@@ -112,21 +94,24 @@ 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 5s in total so we'd detect spurious heartbeat events for example
- while time.time() - start < 5:
+ # Wait for maximum 60s in total so we'd detect spurious heartbeat events for example
+ 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
event = tinfoil.wait_event(1)
if event:
if isinstance(event, bb.command.CommandCompleted):
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
@@ -136,7 +121,6 @@ class TinfoilTests(OESelftestTestCase):
self.assertTrue(commandcomplete, 'Timed out waiting for CommandCompleted event from bitbake server')
self.assertTrue(eventreceived, 'Did not receive FilesMatchingFound event from bitbake server')
- @OETestID(1576)
def test_setvariable_clean(self):
# First check that setVariable affects the datastore
with bb.tinfoil.Tinfoil() as tinfoil:
@@ -159,7 +143,6 @@ class TinfoilTests(OESelftestTestCase):
value = tinfoil.run_command('getVariable', 'TESTVAR')
self.assertEqual(value, 'specialvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()')
- @OETestID(1884)
def test_datastore_operations(self):
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(config_only=True)
@@ -190,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 79925f942f..6f3dc27743 100644
--- a/meta/lib/oeqa/selftest/cases/wic.py
+++ b/meta/lib/oeqa/selftest/cases/wic.py
@@ -1,22 +1,7 @@
-#!/usr/bin/env python
-# ex:ts=4:sw=4:sts=4:et
-# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (c) 2015, Intel Corporation.
-# All rights reserved.
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# SPDX-License-Identifier: GPL-2.0-only
#
# AUTHORS
# Ed Bartosh <ed.bartosh@linux.intel.com>
@@ -26,6 +11,7 @@
import os
import sys
import unittest
+import hashlib
from glob import glob
from shutil import rmtree, copy
@@ -34,7 +20,6 @@ from tempfile import NamedTemporaryFile
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu
-from oeqa.core.decorator.oeid import OETestID
@lru_cache(maxsize=32)
@@ -60,6 +45,30 @@ def only_for_arch(archs, image='core-image-minimal'):
return wrapped_f
return wrapper
+def extract_files(debugfs_output):
+ """
+ extract file names from the output of debugfs -R 'ls -p',
+ which looks like this:
+
+ /2/040755/0/0/.//\n
+ /2/040755/0/0/..//\n
+ /11/040700/0/0/lost+found^M//\n
+ /12/040755/1002/1002/run//\n
+ /13/040755/1002/1002/sys//\n
+ /14/040755/1002/1002/bin//\n
+ /80/040755/1002/1002/var//\n
+ /92/040755/1002/1002/tmp//\n
+ """
+ # NOTE the occasional ^M in file names
+ return [line.split('/')[5].strip() for line in \
+ debugfs_output.strip().split('/\n')]
+
+def files_own_by_root(debugfs_output):
+ for line in debugfs_output.strip().split('/\n'):
+ if line.split('/')[3:5] != ['0', '0']:
+ print(debugfs_output)
+ return False
+ return True
class WicTestCase(OESelftestTestCase):
"""Wic test class."""
@@ -82,6 +91,7 @@ class WicTestCase(OESelftestTestCase):
self.skipTest('wic-tools cannot be built due its (intltool|gettext)-native dependency and NLS disable')
bitbake('core-image-minimal')
+ bitbake('core-image-minimal-mtdutils')
WicTestCase.image_is_ready = True
rmtree(self.resultdir, ignore_errors=True)
@@ -103,63 +113,51 @@ class WicTestCase(OESelftestTestCase):
class Wic(WicTestCase):
- @OETestID(1552)
def test_version(self):
"""Test wic --version"""
runCmd('wic --version')
- @OETestID(1208)
def test_help(self):
"""Test wic --help and wic -h"""
runCmd('wic --help')
runCmd('wic -h')
- @OETestID(1209)
def test_createhelp(self):
"""Test wic create --help"""
runCmd('wic create --help')
- @OETestID(1210)
def test_listhelp(self):
"""Test wic list --help"""
runCmd('wic list --help')
- @OETestID(1553)
def test_help_create(self):
"""Test wic help create"""
runCmd('wic help create')
- @OETestID(1554)
def test_help_list(self):
"""Test wic help list"""
runCmd('wic help list')
- @OETestID(1215)
def test_help_overview(self):
"""Test wic help overview"""
runCmd('wic help overview')
- @OETestID(1216)
def test_help_plugins(self):
"""Test wic help plugins"""
runCmd('wic help plugins')
- @OETestID(1217)
def test_help_kickstart(self):
"""Test wic help kickstart"""
runCmd('wic help kickstart')
- @OETestID(1555)
def test_list_images(self):
"""Test wic list images"""
runCmd('wic list images')
- @OETestID(1556)
def test_list_source_plugins(self):
"""Test wic list source-plugins"""
runCmd('wic list source-plugins')
- @OETestID(1557)
def test_listed_images_help(self):
"""Test wic listed images help"""
output = runCmd('wic list images').output
@@ -167,24 +165,20 @@ class Wic(WicTestCase):
for image in imagelist:
runCmd('wic list %s help' % image)
- @OETestID(1213)
def test_unsupported_subcommand(self):
"""Test unsupported subcommand"""
self.assertNotEqual(0, runCmd('wic unsupported', ignore_status=True).status)
- @OETestID(1214)
def test_no_command(self):
"""Test wic without command"""
self.assertEqual(1, runCmd('wic', ignore_status=True).status)
- @OETestID(1211)
def test_build_image_name(self):
"""Test wic create wictestdisk --image-name=core-image-minimal"""
cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
- @OETestID(1157)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_gpt_image(self):
"""Test creation of core-image-minimal with gpt table and UUID boot"""
@@ -192,13 +186,12 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
- @OETestID(1346)
@only_for_arch(['i586', 'i686', 'x86_64'])
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)
@@ -207,7 +200,6 @@ class Wic(WicTestCase):
self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.direct")))
self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.iso")))
- @OETestID(1348)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_qemux86_directdisk(self):
"""Test creation of qemux-86-directdisk image"""
@@ -215,7 +207,6 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "qemux86-directdisk-*direct")))
- @OETestID(1350)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_mkefidisk(self):
"""Test creation of mkefidisk image"""
@@ -223,11 +214,10 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "mkefidisk-*direct")))
- @OETestID(1385)
@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)
@@ -235,11 +225,10 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "directdisk-bootloader-config-*direct")))
- @OETestID(1560)
@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)
@@ -247,7 +236,17 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "systemd-bootdisk-*direct")))
- @OETestID(1561)
+ def test_efi_bootpart(self):
+ """Test creation of efi-bootpart image"""
+ cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
+ kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
+ self.append_config('IMAGE_EFI_BOOT_FILES = "%s;kernel"\n' % kimgtype)
+ runCmd(cmd)
+ sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
+ images = glob(self.resultdir + "mkefidisk-*.direct")
+ result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
+ self.assertIn("kernel",result.output)
+
def test_sdimage_bootpart(self):
"""Test creation of sdimage-bootpart image"""
cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir
@@ -256,13 +255,12 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct")))
- @OETestID(1562)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_default_output_dir(self):
"""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)
@@ -270,7 +268,6 @@ class Wic(WicTestCase):
runCmd(cmd)
self.assertEqual(1, len(glob("directdisk-*.direct")))
- @OETestID(1212)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_build_artifacts(self):
"""Test wic create directdisk providing all artifacts."""
@@ -288,7 +285,6 @@ class Wic(WicTestCase):
"-o %(resultdir)s" % bbvars)
self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
- @OETestID(1264)
def test_compress_gzip(self):
"""Test compressing an image with gzip"""
runCmd("wic create wictestdisk "
@@ -296,7 +292,6 @@ class Wic(WicTestCase):
"-c gzip -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.gz")))
- @OETestID(1265)
def test_compress_bzip2(self):
"""Test compressing an image with bzip2"""
runCmd("wic create wictestdisk "
@@ -304,7 +299,6 @@ class Wic(WicTestCase):
"-c bzip2 -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.bz2")))
- @OETestID(1266)
def test_compress_xz(self):
"""Test compressing an image with xz"""
runCmd("wic create wictestdisk "
@@ -312,7 +306,6 @@ class Wic(WicTestCase):
"--compress-with=xz -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.xz")))
- @OETestID(1267)
def test_wrong_compressor(self):
"""Test how wic breaks if wrong compressor is provided"""
self.assertEqual(2, runCmd("wic create wictestdisk "
@@ -320,23 +313,22 @@ class Wic(WicTestCase):
"-c wrong -o %s" % self.resultdir,
ignore_status=True).status)
- @OETestID(1558)
def test_debug_short(self):
"""Test -D option"""
runCmd("wic create wictestdisk "
"--image-name=core-image-minimal "
"-D -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
+ self.assertEqual(1, len(glob(self.resultdir + "tmp.wic*")))
- @OETestID(1658)
def test_debug_long(self):
"""Test --debug option"""
runCmd("wic create wictestdisk "
"--image-name=core-image-minimal "
"--debug -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
+ self.assertEqual(1, len(glob(self.resultdir + "tmp.wic*")))
- @OETestID(1563)
def test_skip_build_check_short(self):
"""Test -s option"""
runCmd("wic create wictestdisk "
@@ -344,7 +336,6 @@ class Wic(WicTestCase):
"-s -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
- @OETestID(1671)
def test_skip_build_check_long(self):
"""Test --skip-build-check option"""
runCmd("wic create wictestdisk "
@@ -353,7 +344,6 @@ class Wic(WicTestCase):
"--outdir %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
- @OETestID(1564)
def test_build_rootfs_short(self):
"""Test -f option"""
runCmd("wic create wictestdisk "
@@ -361,7 +351,6 @@ class Wic(WicTestCase):
"-f -o %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
- @OETestID(1656)
def test_build_rootfs_long(self):
"""Test --build-rootfs option"""
runCmd("wic create wictestdisk "
@@ -370,7 +359,6 @@ class Wic(WicTestCase):
"--outdir %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
- @OETestID(1268)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_rootfs_indirect_recipes(self):
"""Test usage of rootfs plugin with rootfs recipes"""
@@ -381,7 +369,6 @@ class Wic(WicTestCase):
"--outdir %s" % self.resultdir)
self.assertEqual(1, len(glob(self.resultdir + "directdisk-multi-rootfs*.direct")))
- @OETestID(1269)
@only_for_arch(['i586', 'i686', 'x86_64'])
def test_rootfs_artifacts(self):
"""Test usage of rootfs plugin with rootfs paths"""
@@ -401,7 +388,6 @@ class Wic(WicTestCase):
"--outdir %(resultdir)s" % bbvars)
self.assertEqual(1, len(glob(self.resultdir + "%(wks)s-*.direct" % bbvars)))
- @OETestID(1661)
def test_exclude_path(self):
"""Test --exclude-path wks option."""
@@ -446,24 +432,6 @@ part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --r
runCmd("dd if=%s of=%s skip=%d count=%d" %
(wicimg, part_file, start, length))
- def extract_files(debugfs_output):
- """
- extract file names from the output of debugfs -R 'ls -p',
- which looks like this:
-
- /2/040755/0/0/.//\n
- /2/040755/0/0/..//\n
- /11/040700/0/0/lost+found^M//\n
- /12/040755/1002/1002/run//\n
- /13/040755/1002/1002/sys//\n
- /14/040755/1002/1002/bin//\n
- /80/040755/1002/1002/var//\n
- /92/040755/1002/1002/tmp//\n
- """
- # NOTE the occasional ^M in file names
- return [line.split('/')[5].strip() for line in \
- debugfs_output.strip().split('/\n')]
-
# Test partition 1, should contain the normal root directories, except
# /usr.
res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \
@@ -504,7 +472,104 @@ part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --r
finally:
os.environ['PATH'] = oldpath
- @OETestID(1662)
+ def test_include_path(self):
+ """Test --include-path wks option."""
+
+ oldpath = os.environ['PATH']
+ os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
+
+ try:
+ include_path = os.path.join(self.resultdir, 'test-include')
+ os.makedirs(include_path)
+ with open(os.path.join(include_path, 'test-file'), 'w') as t:
+ t.write("test\n")
+ wks_file = os.path.join(include_path, 'temp.wks')
+ with open(wks_file, 'w') as wks:
+ rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
+ wks.write("""
+part /part1 --source rootfs --ondisk mmcblk0 --fstype=ext4
+part /part2 --source rootfs --ondisk mmcblk0 --fstype=ext4 --include-path %s"""
+ % (include_path))
+ runCmd("wic create %s -e core-image-minimal -o %s" \
+ % (wks_file, self.resultdir))
+
+ part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
+ part2 = glob(os.path.join(self.resultdir, 'temp-*.direct.p2'))[0]
+
+ # Test partition 1, should not contain 'test-file'
+ res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part1))
+ files = extract_files(res.output)
+ self.assertNotIn('test-file', files)
+ self.assertEqual(True, files_own_by_root(res.output))
+
+ # Test partition 2, should contain 'test-file'
+ res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part2))
+ files = extract_files(res.output)
+ self.assertIn('test-file', files)
+ self.assertEqual(True, files_own_by_root(res.output))
+
+ finally:
+ os.environ['PATH'] = oldpath
+
+ def test_include_path_embeded(self):
+ """Test --include-path wks option."""
+
+ oldpath = os.environ['PATH']
+ os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
+
+ try:
+ include_path = os.path.join(self.resultdir, 'test-include')
+ os.makedirs(include_path)
+ with open(os.path.join(include_path, 'test-file'), 'w') as t:
+ t.write("test\n")
+ wks_file = os.path.join(include_path, 'temp.wks')
+ with open(wks_file, 'w') as wks:
+ wks.write("""
+part / --source rootfs --fstype=ext4 --include-path %s --include-path core-image-minimal-mtdutils export/"""
+ % (include_path))
+ runCmd("wic create %s -e core-image-minimal -o %s" \
+ % (wks_file, self.resultdir))
+
+ part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
+
+ res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part1))
+ files = extract_files(res.output)
+ self.assertIn('test-file', files)
+ self.assertEqual(True, files_own_by_root(res.output))
+
+ res = runCmd("debugfs -R 'ls -p /export/etc/' %s 2>/dev/null" % (part1))
+ files = extract_files(res.output)
+ self.assertIn('passwd', files)
+ self.assertEqual(True, files_own_by_root(res.output))
+
+ finally:
+ os.environ['PATH'] = oldpath
+
+ def test_include_path_errors(self):
+ """Test --include-path wks option error handling."""
+ wks_file = 'temp.wks'
+
+ # Absolute argument.
+ with open(wks_file, 'w') as wks:
+ wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils /export")
+ 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 --include-path core-image-minimal-mtdutils ././..")
+ 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)
+
+ # 3 Argument pointing to parent directory.
+ with open(wks_file, 'w') as wks:
+ wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils export/ dummy")
+ 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_exclude_path_errors(self):
"""Test --exclude-path wks option error handling."""
wks_file = 'temp.wks'
@@ -523,9 +588,175 @@ part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --r
% (wks_file, self.resultdir), ignore_status=True).status)
os.remove(wks_file)
+ def test_permissions(self):
+ """Test permissions are respected"""
+
+ # prepare wicenv and rootfs
+ bitbake('core-image-minimal core-image-minimal-mtdutils -c do_rootfs_wicenv')
+
+ oldpath = os.environ['PATH']
+ os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
+
+ t_normal = """
+part / --source rootfs --fstype=ext4
+"""
+ t_exclude = """
+part / --source rootfs --fstype=ext4 --exclude-path=home
+"""
+ t_multi = """
+part / --source rootfs --ondisk sda --fstype=ext4
+part /export --source rootfs --rootfs=core-image-minimal-mtdutils --fstype=ext4
+"""
+ t_change = """
+part / --source rootfs --ondisk sda --fstype=ext4 --exclude-path=etc/   
+part /etc --source rootfs --fstype=ext4 --change-directory=etc
+"""
+ tests = [t_normal, t_exclude, t_multi, t_change]
+
+ try:
+ for test in tests:
+ include_path = os.path.join(self.resultdir, 'test-include')
+ os.makedirs(include_path)
+ wks_file = os.path.join(include_path, 'temp.wks')
+ with open(wks_file, 'w') as wks:
+ wks.write(test)
+ runCmd("wic create %s -e core-image-minimal -o %s" \
+ % (wks_file, self.resultdir))
+
+ for part in glob(os.path.join(self.resultdir, 'temp-*.direct.p*')):
+ res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part))
+ self.assertEqual(True, files_own_by_root(res.output))
+
+ config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "%s"\n' % wks_file
+ self.append_config(config)
+ bitbake('core-image-minimal')
+ tmpdir = os.path.join(get_bb_var('WORKDIR', 'core-image-minimal'),'build-wic')
+
+ # check each partition for permission
+ for part in glob(os.path.join(tmpdir, 'temp-*.direct.p*')):
+ res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part))
+ self.assertTrue(files_own_by_root(res.output)
+ ,msg='Files permission incorrect using wks set "%s"' % test)
+
+ # clean config and result directory for next cases
+ self.remove_config(config)
+ rmtree(self.resultdir, ignore_errors=True)
+
+ finally:
+ os.environ['PATH'] = oldpath
+
+ def test_change_directory(self):
+ """Test --change-directory wks option."""
+
+ oldpath = os.environ['PATH']
+ os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
+
+ try:
+ include_path = os.path.join(self.resultdir, 'test-include')
+ os.makedirs(include_path)
+ wks_file = os.path.join(include_path, 'temp.wks')
+ with open(wks_file, 'w') as wks:
+ wks.write("part /etc --source rootfs --fstype=ext4 --change-directory=etc")
+ runCmd("wic create %s -e core-image-minimal -o %s" \
+ % (wks_file, self.resultdir))
+
+ part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
+
+ res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part1))
+ files = extract_files(res.output)
+ self.assertIn('passwd', files)
+
+ finally:
+ os.environ['PATH'] = oldpath
+
+ def test_change_directory_errors(self):
+ """Test --change-directory wks option error handling."""
+ wks_file = 'temp.wks'
+
+ # Absolute argument.
+ with open(wks_file, 'w') as wks:
+ wks.write("part / --source rootfs --fstype=ext4 --change-directory /usr")
+ 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 --change-directory ././..")
+ 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_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):
- @OETestID(1496)
def test_bmap_short(self):
"""Test generation of .bmap file -m option"""
cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir
@@ -533,7 +764,6 @@ class Wic2(WicTestCase):
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap")))
- @OETestID(1655)
def test_bmap_long(self):
"""Test generation of .bmap file --bmap option"""
cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir
@@ -541,7 +771,6 @@ class Wic2(WicTestCase):
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap")))
- @OETestID(1347)
def test_image_env(self):
"""Test generation of <image>.env files."""
image = 'core-image-minimal'
@@ -556,7 +785,9 @@ class Wic2(WicTestCase):
wicvars = set(bb_vars['WICVARS'].split())
# filter out optional variables
wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES',
- 'INITRD', 'INITRD_LIVE', 'ISODIR'))
+ 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE',
+ 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME',
+ 'APPEND', 'IMAGE_EFI_BOOT_FILES'))
with open(path) as envfile:
content = dict(line.split("=", 1) for line in envfile)
# test if variables used by wic present in the .env file
@@ -564,7 +795,6 @@ class Wic2(WicTestCase):
self.assertTrue(var in content, "%s is not in .env file" % var)
self.assertTrue(content[var])
- @OETestID(1559)
def test_image_vars_dir_short(self):
"""Test image vars directory selection -v option"""
image = 'core-image-minimal'
@@ -577,7 +807,6 @@ class Wic2(WicTestCase):
self.resultdir))
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
- @OETestID(1665)
def test_image_vars_dir_long(self):
"""Test image vars directory selection --vars option"""
image = 'core-image-minimal'
@@ -593,12 +822,11 @@ class Wic2(WicTestCase):
self.resultdir))
self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
- @OETestID(1351)
@only_for_arch(['i586', 'i686', 'x86_64'])
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)
@@ -614,17 +842,16 @@ class Wic2(WicTestCase):
self.assertTrue(os.path.islink(path))
self.assertTrue(os.path.isfile(os.path.realpath(path)))
- @OETestID(1424)
@only_for_arch(['i586', 'i686', 'x86_64'])
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)
@@ -636,7 +863,6 @@ class Wic2(WicTestCase):
self.assertEqual(output, 'UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba\t/media\text4\tdefaults\t0\t0')
@only_for_arch(['i586', 'i686', 'x86_64'])
- @OETestID(1852)
def test_qemu_efi(self):
"""Test core-image-minimal efi image under qemu"""
config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n'
@@ -645,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))
@@ -662,83 +888,192 @@ class Wic2(WicTestCase):
tempf.write("part " \
"--source rootfs --ondisk hda --align 4 --fixed-size %d "
"--fstype=ext4\n" % size)
- wksname = os.path.splitext(os.path.basename(wkspath))[0]
- return wkspath, wksname
+ return wkspath
- @OETestID(1847)
- def test_fixed_size(self):
- """
- Test creation of a simple image with partition size controlled through
- --fixed-size flag
- """
- wkspath, wksname = Wic2._make_fixed_size_wks(200)
+ def _get_wic_partitions(self, wkspath, native_sysroot=None, ignore_status=False):
+ p = runCmd("wic create %s -e core-image-minimal -o %s" % (wkspath, self.resultdir),
+ ignore_status=ignore_status)
+
+ if p.status:
+ return (p, None)
+
+ wksname = os.path.splitext(os.path.basename(wkspath))[0]
- runCmd("wic create %s -e core-image-minimal -o %s" \
- % (wkspath, self.resultdir))
- os.remove(wkspath)
wicout = glob(self.resultdir + "%s-*direct" % wksname)
- self.assertEqual(1, len(wicout))
+
+ if not wicout:
+ return (p, None)
wicimg = wicout[0]
- native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
+ if not native_sysroot:
+ native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
# verify partition size with wic
- res = runCmd("parted -m %s unit mib p 2>/dev/null" % wicimg,
+ res = runCmd("parted -m %s unit kib p 2>/dev/null" % wicimg,
native_sysroot=native_sysroot)
# parse parted output which looks like this:
# BYT;\n
# /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
# 1:0.00MiB:200MiB:200MiB:ext4::;\n
- partlns = res.output.splitlines()[2:]
+ return (p, res.output.splitlines()[2:])
- self.assertEqual(1, len(partlns))
- self.assertEqual("1:0.00MiB:200MiB:200MiB:ext4::;", partlns[0])
+ def test_fixed_size(self):
+ """
+ Test creation of a simple image with partition size controlled through
+ --fixed-size flag
+ """
+ wkspath = Wic2._make_fixed_size_wks(200)
+ _, partlns = self._get_wic_partitions(wkspath)
+ os.remove(wkspath)
+
+ self.assertEqual(partlns, [
+ "1:4.00kiB:204804kiB:204800kiB:ext4::;",
+ ])
- @OETestID(1848)
def test_fixed_size_error(self):
"""
Test creation of a simple image with partition size controlled through
--fixed-size flag. The size of partition is intentionally set to 1MiB
in order to trigger an error in wic.
"""
- wkspath, wksname = Wic2._make_fixed_size_wks(1)
-
- self.assertEqual(1, runCmd("wic create %s -e core-image-minimal -o %s" \
- % (wkspath, self.resultdir), ignore_status=True).status)
+ wkspath = Wic2._make_fixed_size_wks(1)
+ p, _ = self._get_wic_partitions(wkspath, ignore_status=True)
os.remove(wkspath)
- wicout = glob(self.resultdir + "%s-*direct" % wksname)
- self.assertEqual(0, len(wicout))
+
+ self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
+
+ def test_offset(self):
+ native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that partitions are placed at the correct offsets, default KB
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \
+ "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
+ self.assertEqual(partlns, [
+ "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;",
+ "2:102432kiB:204832kiB:102400kiB:ext4:primary:;",
+ ])
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that partitions are placed at the correct offsets, same with explicit KB
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \
+ "part /bar --ondisk hda --offset 102432K --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
+ self.assertEqual(partlns, [
+ "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;",
+ "2:102432kiB:204832kiB:102400kiB:ext4:primary:;",
+ ])
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that partitions are placed at the correct offsets using MB
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \
+ "part /bar --ondisk hda --offset 101M --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
+ self.assertEqual(partlns, [
+ "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;",
+ "2:103424kiB:205824kiB:102400kiB:ext4:primary:;",
+ ])
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that partitions can be placed on a 512 byte sector boundary
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --offset 65s --fixed-size 99M --fstype=ext4\n" \
+ "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
+ self.assertEqual(partlns, [
+ "1:32.5kiB:101408kiB:101376kiB:ext4:primary:;",
+ "2:102432kiB:204832kiB:102400kiB:ext4:primary:;",
+ ])
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that a partition can be placed immediately after a MSDOS partition table
+ tempf.write("bootloader --ptable msdos\n" \
+ "part / --source rootfs --ondisk hda --offset 1s --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
+ self.assertEqual(partlns, [
+ "1:0.50kiB:102400kiB:102400kiB:ext4::;",
+ ])
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that image creation fails if the partitions would overlap
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \
+ "part /bar --ondisk hda --offset 102431 --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ p, _ = self._get_wic_partitions(tempf.name, ignore_status=True)
+ self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ # Test that partitions are not allowed to overlap with the booloader
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --offset 8 --fixed-size 100M --fstype=ext4\n")
+ tempf.flush()
+
+ p, _ = self._get_wic_partitions(tempf.name, ignore_status=True)
+ self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
+
+ def test_extra_space(self):
+ native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
+
+ with NamedTemporaryFile("w", suffix=".wks") as tempf:
+ tempf.write("bootloader --ptable gpt\n" \
+ "part / --source rootfs --ondisk hda --extra-space 200M --fstype=ext4\n")
+ tempf.flush()
+
+ _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
+ self.assertEqual(len(partlns), 1)
+ size = partlns[0].split(':')[3]
+ self.assertRegex(size, r'^[0-9]+kiB$')
+ size = int(size[:-3])
+ self.assertGreaterEqual(size, 204800)
@only_for_arch(['i586', 'i686', 'x86_64'])
- @OETestID(1854)
def test_rawcopy_plugin_qemu(self):
"""Test rawcopy plugin in qemu"""
- # build ext4 and wic images
- for fstype in ("ext4", "wic"):
- config = 'IMAGE_FSTYPES = "%s"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' % fstype
- 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:
+ # build ext4 and then use it for a wic image
+ config = 'IMAGE_FSTYPES = "ext4"\n'
+ self.append_config(config)
+ self.assertEqual(0, bitbake('core-image-minimal').status)
+ self.remove_config(config)
+
+ config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n'
+ self.append_config(config)
+ self.assertEqual(0, bitbake('core-image-minimal-mtdutils').status)
+ self.remove_config(config)
+
+ 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')
- @OETestID(1853)
- 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)
@@ -746,7 +1081,124 @@ class Wic2(WicTestCase):
out = glob(self.resultdir + "%s-*direct" % wksname)
self.assertEqual(1, len(out))
- @OETestID(1849)
+ 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'
+ self.append_config(config)
+ self.assertEqual(0, bitbake('core-image-minimal').status)
+ self.remove_config(config)
+
+ bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'])
+ deploy_dir = bb_vars['DEPLOY_DIR_IMAGE']
+ machine = bb_vars['MACHINE']
+ image_path = os.path.join(deploy_dir, 'core-image-minimal-%s.wic' % machine)
+ self.assertEqual(True, os.path.exists(image_path))
+
+ sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
+
+ # Fstype column from 'wic ls' should be empty for the second partition
+ # as listed in test_empty_plugin.wks
+ result = runCmd("wic ls %s -n %s | awk -F ' ' '{print $1 \" \" $5}' | grep '^2' | wc -w" % (image_path, sysroot))
+ self.assertEqual('1', result.output)
+
+ @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'
+ self.append_config(config)
+ self.assertEqual(0, bitbake('core-image-minimal').status)
+ self.remove_config(config)
+
+ 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)
+ self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
+ self.assertEqual(output, '2')
+ # Check that /dev/sda1 is /boot and that either /dev/root OR /dev/sda2 is /
+ cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' -e '/dev/root /|/dev/sda2 /'"
+ status, output = qemu.run_serial(cmd)
+ self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
+ self.assertEqual(output, '2')
+ # 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 "BOOTABLE" flag is set on boot partition (required for PC-Bios)
+ # Trailing "cat" seems to be required; otherwise run_serial() sends back echo of the input command
+ cmd = "fdisk -l /dev/sda | grep /dev/sda1 | awk {print'$2'} | cat"
+ status, output = qemu.run_serial(cmd)
+ self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
+ self.assertEqual(output, '*')
+
+ @only_for_arch(['i586', 'i686', 'x86_64'])
+ def test_biosplusefi_plugin(self):
+ """Test biosplusefi plugin"""
+ # Wic generation below may fail depending on the order of the unittests
+ # This is because bootimg-pcbios (that bootimg-biosplusefi uses) generate its MBR inside STAGING_DATADIR directory
+ # which may or may not exists depending on what was built already
+ # 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'
+ self.append_config(config)
+ self.assertEqual(0, bitbake('core-image-minimal').status)
+ self.remove_config(config)
+
+ img = 'core-image-minimal'
+ with NamedTemporaryFile("w", suffix=".wks") as wks:
+ wks.writelines(['part /boot --active --source bootimg-biosplusefi --sourceparams="loader=grub-efi"\n',
+ 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\
+ 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n'])
+ wks.flush()
+ cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
+ runCmd(cmd)
+ wksname = os.path.splitext(os.path.basename(wks.name))[0]
+ 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'
@@ -766,7 +1218,6 @@ class Wic2(WicTestCase):
out = glob(self.resultdir + "%s-*direct" % wksname)
self.assertEqual(1, len(out))
- @OETestID(1851)
def test_kickstart_parser(self):
"""Test wks parser options"""
with NamedTemporaryFile("w", suffix=".wks") as wks:
@@ -779,7 +1230,6 @@ class Wic2(WicTestCase):
out = glob(self.resultdir + "%s-*direct" % wksname)
self.assertEqual(1, len(out))
- @OETestID(1850)
def test_image_bootpart_globbed(self):
"""Test globbed sources with image-bootpart plugin"""
img = "core-image-minimal"
@@ -790,7 +1240,6 @@ class Wic2(WicTestCase):
self.remove_config(config)
self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct")))
- @OETestID(1855)
def test_sparse_copy(self):
"""Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs"""
libpath = os.path.join(get_bb_var('COREBASE'), 'scripts', 'lib', 'wic')
@@ -819,7 +1268,6 @@ class Wic2(WicTestCase):
self.assertEqual(dest_stat.st_blocks, 8)
os.unlink(dest)
- @OETestID(1857)
def test_wic_ls(self):
"""Test listing image content using 'wic ls'"""
runCmd("wic create wictestdisk "
@@ -838,7 +1286,6 @@ class Wic2(WicTestCase):
result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
self.assertEqual(6, len(result.output.split('\n')))
- @OETestID(1856)
def test_wic_cp(self):
"""Test copy files and directories to the the wic image."""
runCmd("wic create wictestdisk "
@@ -878,7 +1325,13 @@ class Wic2(WicTestCase):
self.assertEqual(8, len(result.output.split('\n')))
self.assertTrue(os.path.basename(testdir) in result.output)
- @OETestID(1858)
+ # copy the file from the partition and check if it success
+ dest = '%s-cp' % testfile.name
+ runCmd("wic cp %s:1/%s %s -n %s" % (images[0],
+ os.path.basename(testfile.name), dest, sysroot))
+ self.assertTrue(os.path.exists(dest))
+
+
def test_wic_rm(self):
"""Test removing files and directories from the the wic image."""
runCmd("wic create mkefidisk "
@@ -905,7 +1358,6 @@ class Wic2(WicTestCase):
self.assertNotIn('\nBZIMAGE ', result.output)
self.assertNotIn('\nEFI <DIR> ', result.output)
- @OETestID(1922)
def test_mkfs_extraopts(self):
"""Test wks option --mkfs-extraopts for empty and not empty partitions"""
img = 'core-image-minimal'
@@ -964,11 +1416,11 @@ class Wic2(WicTestCase):
result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path))
self.assertTrue("0 B, 0 bytes, 0 sectors" in result.output)
- os.rename(image_path, image_path + '.bak')
- os.rename(new_image_path, image_path)
+ bb.utils.rename(image_path, image_path + '.bak')
+ 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))
@@ -976,7 +1428,7 @@ class Wic2(WicTestCase):
if os.path.exists(new_image_path):
os.unlink(new_image_path)
if os.path.exists(image_path + '.bak'):
- os.rename(image_path + '.bak', image_path)
+ bb.utils.rename(image_path + '.bak', image_path)
def test_wic_ls_ext(self):
"""Test listing content of the ext partition using 'wic ls'"""
@@ -1019,6 +1471,16 @@ class Wic2(WicTestCase):
newdirs = set(line.split()[-1] for line in result.output.split('\n') if line)
self.assertEqual(newdirs.difference(dirs), set([os.path.basename(testfile.name)]))
+ # check if the file to copy is in the partition
+ result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
+ self.assertTrue('fstab' in [line.split()[-1] for line in result.output.split('\n') if line])
+
+ # copy file from the partition, replace the temporary file content with it and
+ # check for the file size to validate the copy
+ runCmd("wic cp %s:2/etc/fstab %s -n %s" % (images[0], testfile.name, sysroot))
+ self.assertTrue(os.stat(testfile.name).st_size > 0)
+
+
def test_wic_rm_ext(self):
"""Test removing files from the ext partition."""
runCmd("wic create mkefidisk "
@@ -1039,3 +1501,10 @@ class Wic2(WicTestCase):
# check if it's removed
result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
self.assertTrue('fstab' not in [line.split()[-1] for line in result.output.split('\n') if line])
+
+ # remove non-empty directory
+ runCmd("wic rm -r %s:2/etc/ -n %s" % (images[0], sysroot))
+
+ # check if it's removed
+ result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
+ self.assertTrue('etc' not in [line.split()[-1] for line in result.output.split('\n') if line])
diff --git a/meta/lib/oeqa/selftest/context.py b/meta/lib/oeqa/selftest/context.py
index c56e53dcdd..78c7a467e2 100644
--- a/meta/lib/oeqa/selftest/context.py
+++ b/meta/lib/oeqa/selftest/context.py
@@ -1,30 +1,132 @@
+#
# Copyright (C) 2017 Intel Corporation
-# Released under the MIT license (see COPYING.MIT)
+#
+# SPDX-License-Identifier: MIT
+#
import os
import time
import glob
import sys
import importlib
-import signal
-from shutil import copyfile
+import subprocess
+import unittest
from random import choice
import oeqa
import oe
+import bb.utils
from oeqa.core.context import OETestContext, OETestContextExecutor
from oeqa.core.exception import OEQAPreRun, OEQATestNotFound
from oeqa.utils.commands import runCmd, get_bb_vars, get_test_layer
+class NonConcurrentTestSuite(unittest.TestSuite):
+ def __init__(self, suite, processes, setupfunc, removefunc):
+ super().__init__([suite])
+ self.processes = processes
+ self.suite = suite
+ self.setupfunc = setupfunc
+ self.removefunc = removefunc
+
+ def run(self, result):
+ (builddir, newbuilddir) = self.setupfunc("-st", None, self.suite)
+ ret = super().run(result)
+ os.chdir(builddir)
+ if newbuilddir and ret.wasSuccessful() and self.removefunc:
+ self.removefunc(newbuilddir)
+
+def removebuilddir(d):
+ delay = 5
+ while delay and (os.path.exists(d + "/bitbake.lock") or os.path.exists(d + "/cache/hashserv.db-wal")):
+ time.sleep(1)
+ delay = delay - 1
+ # Deleting these directories takes a lot of time, use autobuilder
+ # clobberdir if its available
+ clobberdir = os.path.expanduser("~/yocto-autobuilder-helper/janitor/clobberdir")
+ if os.path.exists(clobberdir):
+ try:
+ subprocess.check_call([clobberdir, d])
+ return
+ except subprocess.CalledProcessError:
+ pass
+ bb.utils.prunedir(d, ionice=True)
+
class OESelftestTestContext(OETestContext):
- def __init__(self, td=None, logger=None, machines=None, config_paths=None):
+ def __init__(self, td=None, logger=None, machines=None, config_paths=None, newbuilddir=None, keep_builddir=None):
super(OESelftestTestContext, self).__init__(td, logger)
self.machines = machines
self.custommachine = None
self.config_paths = config_paths
+ self.newbuilddir = newbuilddir
+
+ if keep_builddir:
+ self.removebuilddir = None
+ else:
+ self.removebuilddir = removebuilddir
+
+ def setup_builddir(self, suffix, selftestdir, suite):
+ builddir = os.environ['BUILDDIR']
+ if not selftestdir:
+ selftestdir = get_test_layer()
+ if self.newbuilddir:
+ newbuilddir = os.path.join(self.newbuilddir, 'build' + suffix)
+ else:
+ newbuilddir = builddir + suffix
+ newselftestdir = newbuilddir + "/meta-selftest"
+
+ if os.path.exists(newbuilddir):
+ self.logger.error("Build directory %s already exists, aborting" % newbuilddir)
+ sys.exit(1)
+
+ bb.utils.mkdirhier(newbuilddir)
+ oe.path.copytree(builddir + "/conf", newbuilddir + "/conf")
+ oe.path.copytree(builddir + "/cache", newbuilddir + "/cache")
+ oe.path.copytree(selftestdir, newselftestdir)
+
+ for e in os.environ:
+ if builddir + "/" in os.environ[e]:
+ os.environ[e] = os.environ[e].replace(builddir + "/", newbuilddir + "/")
+ if os.environ[e].endswith(builddir):
+ os.environ[e] = os.environ[e].replace(builddir, newbuilddir)
+
+ subprocess.check_output("git init; git add *; git commit -a -m 'initial'", cwd=newselftestdir, shell=True)
+
+ # Tried to used bitbake-layers add/remove but it requires recipe parsing and hence is too slow
+ subprocess.check_output("sed %s/conf/bblayers.conf -i -e 's#%s#%s#g'" % (newbuilddir, selftestdir, newselftestdir), cwd=newbuilddir, shell=True)
+
+ os.chdir(newbuilddir)
+
+ def patch_test(t):
+ if not hasattr(t, "tc"):
+ return
+ cp = t.tc.config_paths
+ for p in cp:
+ if selftestdir in cp[p] and newselftestdir not in cp[p]:
+ cp[p] = cp[p].replace(selftestdir, newselftestdir)
+ if builddir in cp[p] and newbuilddir not in cp[p]:
+ cp[p] = cp[p].replace(builddir, newbuilddir)
+
+ def patch_suite(s):
+ for x in s:
+ if isinstance(x, unittest.TestSuite):
+ patch_suite(x)
+ else:
+ patch_test(x)
+
+ patch_suite(suite)
+
+ return (builddir, newbuilddir)
+
+ def prepareSuite(self, suites, processes):
+ if processes:
+ from oeqa.core.utils.concurrencytest import ConcurrentTestSuite
+
+ return ConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
+ else:
+ return NonConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
def runTests(self, processes=None, machine=None, skips=[]):
if machine:
@@ -74,7 +176,19 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
parser.add_argument('--machine', required=False, choices=['random', 'all'],
help='Run tests on different machines (random/all).')
-
+
+ parser.add_argument('-t', '--select-tag', dest="select_tags",
+ action='append', default=None,
+ help='Filter all (unhidden) tests to any that match any of the specified tag(s).')
+ parser.add_argument('-T', '--exclude-tag', dest="exclude_tags",
+ action='append', default=None,
+ help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)')
+
+ parser.add_argument('-K', '--keep-builddir', action='store_true',
+ help='Keep the test build directory even if all tests pass')
+
+ parser.add_argument('-B', '--newbuilddir', help='New build directory to use for tests.')
+ parser.add_argument('-v', '--verbose', action='store_true')
parser.set_defaults(func=self.run)
def _get_available_machines(self):
@@ -125,26 +239,24 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
builddir = os.environ.get("BUILDDIR")
self.tc_kwargs['init']['config_paths'] = {}
- self.tc_kwargs['init']['config_paths']['testlayer_path'] = \
- get_test_layer()
+ self.tc_kwargs['init']['config_paths']['testlayer_path'] = get_test_layer()
self.tc_kwargs['init']['config_paths']['builddir'] = builddir
- self.tc_kwargs['init']['config_paths']['localconf'] = \
- os.path.join(builddir, "conf/local.conf")
- self.tc_kwargs['init']['config_paths']['localconf_backup'] = \
- os.path.join(builddir, "conf/local.conf.orig")
- self.tc_kwargs['init']['config_paths']['localconf_class_backup'] = \
- os.path.join(builddir, "conf/local.conf.bk")
- self.tc_kwargs['init']['config_paths']['bblayers'] = \
- os.path.join(builddir, "conf/bblayers.conf")
- self.tc_kwargs['init']['config_paths']['bblayers_backup'] = \
- os.path.join(builddir, "conf/bblayers.conf.orig")
- self.tc_kwargs['init']['config_paths']['bblayers_class_backup'] = \
- os.path.join(builddir, "conf/bblayers.conf.bk")
-
- copyfile(self.tc_kwargs['init']['config_paths']['localconf'],
- self.tc_kwargs['init']['config_paths']['localconf_backup'])
- copyfile(self.tc_kwargs['init']['config_paths']['bblayers'],
- self.tc_kwargs['init']['config_paths']['bblayers_backup'])
+ self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf")
+ self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf")
+ self.tc_kwargs['init']['newbuilddir'] = args.newbuilddir
+ self.tc_kwargs['init']['keep_builddir'] = args.keep_builddir
+
+ def tag_filter(tags):
+ if args.exclude_tags:
+ if any(tag in args.exclude_tags for tag in tags):
+ return True
+ if args.select_tags:
+ if not tags or not any(tag in args.select_tags for tag in tags):
+ return True
+ return False
+
+ if args.select_tags or args.exclude_tags:
+ self.tc_kwargs['load']['tags_filter'] = tag_filter
self.tc_kwargs['run']['skips'] = args.skips
self.tc_kwargs['run']['processes'] = args.processes
@@ -257,14 +369,9 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
return rc
- def _signal_clean_handler(self, signum, frame):
- sys.exit(1)
-
def run(self, logger, args):
self._process_args(logger, args)
- signal.signal(signal.SIGTERM, self._signal_clean_handler)
-
rc = None
try:
if args.machine:
@@ -293,20 +400,6 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
rc = self._internal_run(logger, args)
finally:
config_paths = self.tc_kwargs['init']['config_paths']
- if os.path.exists(config_paths['localconf_backup']):
- copyfile(config_paths['localconf_backup'],
- config_paths['localconf'])
- os.remove(config_paths['localconf_backup'])
-
- if os.path.exists(config_paths['bblayers_backup']):
- copyfile(config_paths['bblayers_backup'],
- config_paths['bblayers'])
- os.remove(config_paths['bblayers_backup'])
-
- if os.path.exists(config_paths['localconf_class_backup']):
- os.remove(config_paths['localconf_class_backup'])
- if os.path.exists(config_paths['bblayers_class_backup']):
- os.remove(config_paths['bblayers_class_backup'])
output_link = os.path.join(os.path.dirname(args.output_log),
"%s-results.log" % self.name)