[v7,3/3] selftest: add a unit-test for fit-image bbclass

Submitted by Nandor Han on May 27, 2020, 6:06 a.m. | Patch ID: 172882

Details

Message ID d99fc8598434c9af38c56bb1349f4dce4af0ea8b.1590559408.git.nandor.han@vaisala.com
State New
Headers show

Commit Message

Nandor Han May 27, 2020, 6:06 a.m.
The unit-test will test the basic functionality of `fit-image.bbclass`.

Signed-off-by: Nandor Han <nandor.han@vaisala.com>
---
 .../fit-image-test/files/dt-fake.dtb          |   3 +
 .../fit-image-test/files/zImage-fake          |   3 +
 .../fit-image-test/fit-image-test.bb          |  17 ++
 meta/lib/oeqa/selftest/cases/fit_image.py     | 212 ++++++++++++++++++
 4 files changed, 235 insertions(+)
 create mode 100644 meta-selftest/recipes-test/fit-image-test/files/dt-fake.dtb
 create mode 100644 meta-selftest/recipes-test/fit-image-test/files/zImage-fake
 create mode 100644 meta-selftest/recipes-test/fit-image-test/fit-image-test.bb
 create mode 100644 meta/lib/oeqa/selftest/cases/fit_image.py

Patch hide | download patch | download mbox

diff --git a/meta-selftest/recipes-test/fit-image-test/files/dt-fake.dtb b/meta-selftest/recipes-test/fit-image-test/files/dt-fake.dtb
new file mode 100644
index 0000000000..7fa871ff00
--- /dev/null
+++ b/meta-selftest/recipes-test/fit-image-test/files/dt-fake.dtb
@@ -0,0 +1,3 @@ 
+Z�P�acn�ZWD1\�!΄�l�V
+t(��H����z��jb4.���݁�W;I�ƶ����b�e���Ñ�5�x�&�9,��g
+�;���!cV
diff --git a/meta-selftest/recipes-test/fit-image-test/files/zImage-fake b/meta-selftest/recipes-test/fit-image-test/files/zImage-fake
new file mode 100644
index 0000000000..7fa871ff00
--- /dev/null
+++ b/meta-selftest/recipes-test/fit-image-test/files/zImage-fake
@@ -0,0 +1,3 @@ 
+Z�P�acn�ZWD1\�!΄�l�V
+t(��H����z��jb4.���݁�W;I�ƶ����b�e���Ñ�5�x�&�9,��g
+�;���!cV
diff --git a/meta-selftest/recipes-test/fit-image-test/fit-image-test.bb b/meta-selftest/recipes-test/fit-image-test/fit-image-test.bb
new file mode 100644
index 0000000000..c7f325ec8a
--- /dev/null
+++ b/meta-selftest/recipes-test/fit-image-test/fit-image-test.bb
@@ -0,0 +1,17 @@ 
+SUMMARY = "Recipe for testing the fit_image bbclass"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+
+DEPENDS += "\
+    python3-fdt-native \
+"
+
+SRC_URI = "\
+    file://zImage-fake \
+    file://dt-fake.dtb \
+"
+
+inherit fit_image
+
+include test_recipe.inc
+
diff --git a/meta/lib/oeqa/selftest/cases/fit_image.py b/meta/lib/oeqa/selftest/cases/fit_image.py
new file mode 100644
index 0000000000..866e48b20e
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/fit_image.py
@@ -0,0 +1,212 @@ 
+import os
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import get_bb_var, bitbake, get_bb_vars
+
+class FitImage(OESelftestTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        super(FitImage, cls).setUpClass()
+        cls.recipe_name = 'fit-image-test'
+        cls.build_dir = get_bb_var('B', cls.recipe_name)
+        cls.fit_blob_path = os.path.join(cls.build_dir, 'image-fit.itb')
+
+        bitbake('python3-fdt-native')
+        fdt_sitepackage=get_bb_var("S", "python3-fdt-native")
+        os.sys.path.append(fdt_sitepackage)
+        import fdt
+
+        bitbake('{recipe_name} -c cleanall'.format(recipe_name=cls.recipe_name))
+
+    @classmethod
+    def tearDownClass(cls):
+        bitbake('{recipe_name} -c cleanall'.format(recipe_name=cls.recipe_name))
+        super(FitImage, cls).tearDownClass()
+
+    def _get_fit_configuration(self):
+        configuration = """
+KERNEL_IMAGE_NODE[name] = "kernel"
+KERNEL_IMAGE_NODE[description] = "${PF}"
+KERNEL_IMAGE_NODE[data] = '/incbin/("${WORKDIR}/zImage-fake")'
+KERNEL_IMAGE_NODE[type] = "kernel"
+KERNEL_IMAGE_NODE[arch] = "arm"
+KERNEL_IMAGE_NODE[os] = "linux"
+KERNEL_IMAGE_NODE[compression] = "none"
+KERNEL_IMAGE_NODE[load] = "0x84000000"
+KERNEL_IMAGE_NODE[entry] = "0x84000000"
+KERNEL_IMAGE_NODE[hash] = "sha256"
+
+FDT_IMAGE_NODE[name] = "fdt"
+FDT_IMAGE_NODE[description] = "FDT blob"
+FDT_IMAGE_NODE[data] = '/incbin/("${WORKDIR}/dt-fake.dtb")'
+FDT_IMAGE_NODE[type] = "flat_dt"
+FDT_IMAGE_NODE[arch] = "arm"
+FDT_IMAGE_NODE[compression] = "none"
+FDT_IMAGE_NODE[hash] = "sha256"
+
+CONF1_CONF_NODE[name] = "conf"
+CONF1_CONF_NODE[description] = "Linux kernel and FDT blob"
+CONF1_CONF_NODE[kernel] = "kernel"
+CONF1_CONF_NODE[fdt] = "fdt"
+
+FIT_IMAGES_NODE = "KERNEL_IMAGE_NODE FDT_IMAGE_NODE"
+FIT_CONFIGURATIONS_NODE = "CONF1_CONF_NODE"
+FIT_CONFIGURATIONS_NODE[default] = "${@d.getVarFlag('CONF1_CONF_NODE', 'name') or ""}"
+"""
+        return configuration
+
+    def setUp(self):
+        super(FitImage, self).setUp()
+        self.write_recipeinc(self.recipe_name, self._get_fit_configuration())
+
+    def tearDown(self):
+        self.delete_recipeinc(self.recipe_name)
+        super(FitImage, self).tearDown()
+
+    def test_fit_source_is_generated_correctly(self):
+        ret = bitbake("{recipe} -D -f -c generate_fit_image".format(recipe=self.recipe_name)).output
+        self.logger.info('HN {log}'.format(log=ret))
+
+    def test_fit_blob_is_generated_successfully(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>
+        """
+
+        bitbake("{recipe} -c generate_fit_image".format(recipe=self.recipe_name))
+        self.assertExists(self.fit_blob_path, "FIT Blob not generated")
+
+    def test_that_fit_blob_name_is_configurable(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.
+        """
+        fit_image_name = "custom-fit-blob-name"
+        fit_blob_path = os.path.join(self.build_dir, "{name}.itb".format(name=fit_image_name))
+
+        self.append_recipeinc(self.recipe_name, 'FIT_IMAGE_FILENAME = "{name}"'.format(name=fit_image_name))
+        bitbake("{recipe} -c generate_fit_image".format(recipe=self.recipe_name))
+
+        self.assertExists(fit_blob_path, "FIT Blob not generated")
+
+    def _fail_when_property_missing(self, property):
+        self.remove_recipeinc(self.recipe_name, property)
+        with self.assertRaises(AssertionError):
+            ret = bitbake("{recipe} -f -c generate_fit_image".format(recipe=self.recipe_name))
+
+    def test_fail_when_image_node_name_property_missing(self):
+        self._fail_when_property_missing('KERNEL_IMAGE_NODE[name] = "kernel"')
+
+    def test_fail_when_image_node_description_property_missing(self):
+        self._fail_when_property_missing('KERNEL_IMAGE_NODE[description] = "${PF}"')
+
+    def test_fail_when_image_node_data_property_missing(self):
+        self._fail_when_property_missing('KERNEL_IMAGE_NODE[data] = \'/incbin/("${WORKDIR}/zImage-fake")\'')
+
+    def test_fail_when_image_node_compression_property_missing(self):
+        self._fail_when_property_missing('KERNEL_IMAGE_NODE[type] = "kernel"')
+
+    def test_fail_when_conf_node_name_property_missing(self):
+        self._fail_when_property_missing('CONF1_CONF_NODE[name] = "conf"')
+
+    def test_fail_when_conf_node_description_property_missing(self):
+        self._fail_when_property_missing('CONF1_CONF_NODE[description] = "Linux kernel and FDT blob"')
+
+    def test_that_number_of_nodes_is_correct(self):
+        pass
+
+    def _extract_fit_source(self, text):
+        import re
+        mylines = []
+        copy = False
+
+        for myline in text:
+            if re.match('^DEBUG:.+', myline):
+                copy = False
+
+            if copy:
+                mylines.append(myline.rstrip('\r\n').strip())
+
+            if re.match('^DEBUG:.+do_generate_fit_image: Generated FIT source is:$', myline):
+                copy = True
+
+        sf = ''.join(mylines)
+        self.logger.info('LOG: {log}\nFIT SOURCE {sf}'.format(log=text, sf=sf))
+
+    def _verify_node(self, var_name, path, properties):
+        import fdt
+
+        # I'm creating variables in the recipe that contain the flags value.
+        # I wasn't able to find a better way to read a flag of a variable in the test.
+        for p in properties:
+            self.append_recipeinc(
+                self.recipe_name, 'FIT_IMAGE_TEST_{pu} = "${{@d.getVarFlag(\'{var}\', \'{p}\')}}"'.format(
+                    pu=p.upper(), p=p, var=var_name))
+
+        ret = bitbake("{recipe} -D -c generate_fit_image".format(recipe=self.recipe_name))
+        self._extract_fit_source(ret.output)
+
+        with open(self.fit_blob_path, 'rb') as fb:
+            fit_blob = fb.read()
+
+        dt = fdt.parse_dtb(fit_blob)
+
+        try:
+            node = dt.get_node(path)
+        except ValueError:
+            self.assertTrue(False, '{node} node not generated'.format(node=path))
+
+        node_flags = get_bb_vars(['FIT_IMAGE_TEST_{p}'.format(p=p.upper()) for p in properties],
+            self.recipe_name)
+
+        for p in properties:
+            self.assertTrue(
+                node.exist_property(p),
+                'Missing property {p} from node {n}'.format(p=p.upper(), n=path))
+
+            self.assertTrue(
+                node_flags['FIT_IMAGE_TEST_{p}'.format(p=p.upper())],
+                node.get_property(p))
+
+
+    def _verify_image_node(self, var_name, name, properties):
+        self._verify_node(var_name, 'images/{name}'.format(name=name), properties)
+
+    def _verify_config_node(self, var_name, name, properties):
+        self._verify_node(var_name, 'configurations/{name}'.format(name=name), properties)
+
+    def test_that_kernel_node_is_generated_successfully(self):
+        properties = [
+            'description',
+            'data',
+            'type',
+            'arch',
+            'os',
+            'compression',
+            'load',
+            'entry'
+        ]
+        self._verify_image_node('KERNEL_IMAGE_NODE', 'kernel', properties)
+
+    def test_that_fdt_node_is_generated_successfully(self):
+        properties = [
+            'description',
+            'data',
+            'type',
+            'arch',
+            'compression'
+        ]
+        self._verify_image_node('FDT_IMAGE_NODE', 'fdt', properties)
+
+    def test_that_conf_node_is_generated_successfully(self):
+        properties = [
+            'description',
+            'kernel',
+            'fdt'
+        ]
+        self._verify_config_node('CONF1_CONF_NODE', 'conf', properties)