summaryrefslogtreecommitdiff
path: root/tools/binman/ftest.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/binman/ftest.py')
-rw-r--r--tools/binman/ftest.py260
1 files changed, 227 insertions, 33 deletions
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index fa1f421c052..0b1774046f7 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -23,7 +23,6 @@ import urllib.error
from binman import bintool
from binman import cbfs_util
from binman import cmdline
-from binman import comp_util
from binman import control
from binman import elf
from binman import elf_test
@@ -107,6 +106,8 @@ BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
# Extra properties expected to be in the device tree when allow-repack is used
REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
+# Supported compression bintools
+COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
class TestFunctional(unittest.TestCase):
"""Functional tests for binman
@@ -212,7 +213,9 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('tee.elf',
tools.read_file(cls.ElfTestFile('elf_sections')))
- cls.have_lz4 = comp_util.HAVE_LZ4
+ cls.comp_bintools = {}
+ for name in COMP_BINTOOLS:
+ cls.comp_bintools[name] = bintool.Bintool.create(name)
@classmethod
def tearDownClass(cls):
@@ -242,9 +245,13 @@ class TestFunctional(unittest.TestCase):
cls.toolpath = toolpath
cls.verbosity = verbosity
+ def _CheckBintool(self, bintool):
+ if not bintool.is_present():
+ self.skipTest('%s not available' % bintool.name)
+
def _CheckLz4(self):
- if not self.have_lz4:
- self.skipTest('lz4 --no-frame-crc not available')
+ bintool = self.comp_bintools['lz4']
+ self._CheckBintool(bintool)
def _CleanupOutputDir(self):
"""Remove the temporary output directory"""
@@ -1693,7 +1700,7 @@ class TestFunctional(unittest.TestCase):
"""Test for an fill entry type with no size"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('070_fill_no_size.dts')
- self.assertIn("'fill' entry must have a size property",
+ self.assertIn("'fill' entry is missing properties: size",
str(e.exception))
def _HandleGbbCommand(self, pipe_list):
@@ -1967,7 +1974,8 @@ class TestFunctional(unittest.TestCase):
self._ResetDtbs()
def _decompress(self, data):
- return comp_util.decompress(data, 'lz4')
+ bintool = self.comp_bintools['lz4']
+ return bintool.decompress(data)
def testCompress(self):
"""Test compression of blobs"""
@@ -2855,8 +2863,10 @@ class TestFunctional(unittest.TestCase):
def testExtractCbfsRaw(self):
"""Test extracting CBFS compressed data without decompressing it"""
+ bintool = self.comp_bintools['lzma_alone']
+ self._CheckBintool(bintool)
data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
- dtb = comp_util.decompress(data, 'lzma', with_header=False)
+ dtb = bintool.decompress(data)
self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
def testExtractBadEntry(self):
@@ -4412,6 +4422,15 @@ class TestFunctional(unittest.TestCase):
}
self.assertEqual(expected, props)
+ def testLz4Missing(self):
+ """Test that binman still produces an image if lz4 is missing"""
+ with test_util.capture_sys_output() as (_, stderr):
+ self._DoTestFile('185_compress_section.dts',
+ force_missing_bintools='lz4')
+ err = stderr.getvalue()
+ self.assertRegex(err,
+ "Image 'main-section'.*missing bintools.*: lz4")
+
def testCompressExtra(self):
"""Test compression of a section with no fixed size"""
self._CheckLz4()
@@ -4427,15 +4446,18 @@ class TestFunctional(unittest.TestCase):
rest = base[len(U_BOOT_DATA):]
# Check compressed data
- section1 = self._decompress(rest)
- expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
- self.assertEquals(expect1, rest[:len(expect1)])
+ bintool = self.comp_bintools['lz4']
+ expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
+ data1 = rest[:len(expect1)]
+ section1 = self._decompress(data1)
+ self.assertEquals(expect1, data1)
self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
rest1 = rest[len(expect1):]
- section2 = self._decompress(rest1)
- expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
- self.assertEquals(expect2, rest1[:len(expect2)])
+ expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
+ data2 = rest1[:len(expect2)]
+ section2 = self._decompress(data2)
+ self.assertEquals(expect2, data2)
self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
rest2 = rest1[len(expect2):]
@@ -4807,6 +4829,8 @@ class TestFunctional(unittest.TestCase):
def testUpdateFdtInElf(self):
"""Test that we can update the devicetree in an ELF file"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
outfile = os.path.join(self._indir, 'u-boot.out')
begin_sym = 'dtb_embed_begin'
@@ -4858,6 +4882,8 @@ class TestFunctional(unittest.TestCase):
def testUpdateFdtInElfNoSyms(self):
"""Test that missing symbols are detected with --update-fdt-in-elf"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
outfile = ''
begin_sym = 'wrong_begin'
@@ -4871,6 +4897,8 @@ class TestFunctional(unittest.TestCase):
def testUpdateFdtInElfTooSmall(self):
"""Test that an over-large dtb is detected with --update-fdt-in-elf"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
outfile = os.path.join(self._indir, 'u-boot.out')
begin_sym = 'dtb_embed_begin'
@@ -5209,15 +5237,6 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self._DoBinman(*args)
self.assertIn('failed to fetch with all methods', stdout.getvalue())
- def testInvalidCompress(self):
- with self.assertRaises(ValueError) as e:
- comp_util.compress(b'', 'invalid')
- self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
-
- with self.assertRaises(ValueError) as e:
- comp_util.decompress(b'1234', 'invalid')
- self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
-
def testBintoolDocs(self):
"""Test for creation of bintool documentation"""
with test_util.capture_sys_output() as (stdout, stderr):
@@ -5344,6 +5363,8 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
def testFitSplitElf(self):
"""Test an image with an FIT with an split-elf operation"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
entry_args = {
'of-list': 'test-fdt1 test-fdt2',
'default-dt': 'test-fdt2',
@@ -5421,6 +5442,8 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
def testFitSplitElfBadElf(self):
"""Test a FIT split-elf operation with an invalid ELF file"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
entry_args = {
'of-list': 'test-fdt1 test-fdt2',
@@ -5440,6 +5463,8 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
def testFitSplitElfBadDirective(self):
"""Test a FIT split-elf invalid fit,xxx directive in an image node"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
err = self._check_bad_fit('227_fit_bad_dir.dts')
self.assertIn(
"Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
@@ -5447,13 +5472,24 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
def testFitSplitElfBadDirectiveConfig(self):
"""Test a FIT split-elf with invalid fit,xxx directive in config"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
err = self._check_bad_fit('228_fit_bad_dir_config.dts')
self.assertEqual(
"Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
err)
def checkFitSplitElf(self, **kwargs):
- """Test an split-elf FIT with a missing ELF file"""
+ """Test an split-elf FIT with a missing ELF file
+
+ Args:
+ kwargs (dict of str): Arguments to pass to _DoTestFile()
+
+ Returns:
+ tuple:
+ str: stdout result
+ str: stderr result
+ """
entry_args = {
'of-list': 'test-fdt1 test-fdt2',
'default-dt': 'test-fdt2',
@@ -5464,23 +5500,36 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
with test_util.capture_sys_output() as (stdout, stderr):
self._DoTestFile(
'226_fit_split_elf.dts', entry_args=entry_args,
- extra_indirs=[test_subdir], **kwargs)
- err = stderr.getvalue()
- return err
+ extra_indirs=[test_subdir], verbosity=3, **kwargs)
+ out = stdout.getvalue()
+ err = stderr.getvalue()
+ return out, err
def testFitSplitElfMissing(self):
"""Test an split-elf FIT with a missing ELF file"""
- err = self.checkFitSplitElf(allow_missing=True)
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ out, err = self.checkFitSplitElf(allow_missing=True)
self.assertRegex(
err,
"Image '.*' is missing external blobs and is non-functional: .*")
+ self.assertNotRegex(out, '.*Faked blob.*')
+ fname = tools.get_output_filename('binman-fake/missing.elf')
+ self.assertFalse(os.path.exists(fname))
def testFitSplitElfFaked(self):
"""Test an split-elf FIT with faked ELF file"""
- err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
self.assertRegex(
err,
"Image '.*' is missing external blobs and is non-functional: .*")
+ self.assertRegex(
+ out,
+ "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
+ fname = tools.get_output_filename('binman-fake/missing.elf')
+ self.assertTrue(os.path.exists(fname))
def testPreLoad(self):
"""Test an image with a pre-load header"""
@@ -5694,14 +5743,159 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertIsNotNone(path)
self.assertEqual(expected_fdtmap, fdtmap)
- @unittest.expectedFailure
def testReplaceSectionSimple(self):
"""Test replacing a simple section with arbitrary data"""
new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
- data, expected_fdtmap, _ = self._RunReplaceCmd(
- 'section', new_data,
- dts='234_replace_section_simple.dts')
- self.assertEqual(new_data, data)
+ with self.assertRaises(ValueError) as exc:
+ self._RunReplaceCmd('section', new_data,
+ dts='234_replace_section_simple.dts')
+ self.assertIn(
+ "Node '/section': Replacing sections is not implemented yet",
+ str(exc.exception))
+
+ def testMkimageImagename(self):
+ """Test using mkimage with -n holding the data too"""
+ data = self._DoReadFile('235_mkimage_name.dts')
+
+ # Check that the data appears in the file somewhere
+ self.assertIn(U_BOOT_SPL_DATA, data)
+
+ # Get struct image_header -> ih_name
+ name = data[0x20:0x40]
+
+ # Build the filename that we expect to be placed in there, by virtue of
+ # the -n paraameter
+ expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
+
+ # Check that the image name is set to the temporary filename used
+ self.assertEqual(expect.encode('utf-8')[:0x20], name)
+
+ def testMkimageImage(self):
+ """Test using mkimage with -n holding the data too"""
+ data = self._DoReadFile('236_mkimage_image.dts')
+
+ # Check that the data appears in the file somewhere
+ self.assertIn(U_BOOT_SPL_DATA, data)
+
+ # Get struct image_header -> ih_name
+ name = data[0x20:0x40]
+
+ # Build the filename that we expect to be placed in there, by virtue of
+ # the -n paraameter
+ expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
+
+ # Check that the image name is set to the temporary filename used
+ self.assertEqual(expect.encode('utf-8')[:0x20], name)
+
+ # Check the corect data is in the imagename file
+ self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
+
+ def testMkimageImageNoContent(self):
+ """Test using mkimage with -n and no data"""
+ with self.assertRaises(ValueError) as exc:
+ self._DoReadFile('237_mkimage_image_no_content.dts')
+ self.assertIn('Could not complete processing of contents',
+ str(exc.exception))
+
+ def testMkimageImageBad(self):
+ """Test using mkimage with imagename node and data-to-imagename"""
+ with self.assertRaises(ValueError) as exc:
+ self._DoReadFile('238_mkimage_image_bad.dts')
+ self.assertIn('Cannot use both imagename node and data-to-imagename',
+ str(exc.exception))
+
+ def testCollectionOther(self):
+ """Test a collection where the data comes from another section"""
+ data = self._DoReadFile('239_collection_other.dts')
+ self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
+ tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
+ tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
+ data)
+
+ def testMkimageCollection(self):
+ """Test using a collection referring to an entry in a mkimage entry"""
+ data = self._DoReadFile('240_mkimage_coll.dts')
+ expect = U_BOOT_SPL_DATA + U_BOOT_DATA
+ self.assertEqual(expect, data[:len(expect)])
+
+ def testCompressDtbPrependInvalid(self):
+ """Test that invalid header is detected"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFileDtb('235_compress_dtb_prepend_invalid.dts')
+ self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
+ "'u-boot-dtb': 'invalid'", str(e.exception))
+
+ def testCompressDtbPrependLength(self):
+ """Test that compress with length header works as expected"""
+ data = self._DoReadFileRealDtb('236_compress_dtb_prepend_length.dts')
+ image = control.images['image']
+ entries = image.GetEntries()
+ self.assertIn('u-boot-dtb', entries)
+ u_boot_dtb = entries['u-boot-dtb']
+ self.assertIn('fdtmap', entries)
+ fdtmap = entries['fdtmap']
+
+ image_fname = tools.get_output_filename('image.bin')
+ orig = control.ReadEntry(image_fname, 'u-boot-dtb')
+ dtb = fdt.Fdt.FromData(orig)
+ dtb.Scan()
+ props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
+ expected = {
+ 'u-boot:size': len(U_BOOT_DATA),
+ 'u-boot-dtb:uncomp-size': len(orig),
+ 'u-boot-dtb:size': u_boot_dtb.size,
+ 'fdtmap:size': fdtmap.size,
+ 'size': len(data),
+ }
+ self.assertEqual(expected, props)
+
+ # Check implementation
+ self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+ rest = data[len(U_BOOT_DATA):]
+ comp_data_len = struct.unpack('<I', rest[:4])[0]
+ comp_data = rest[4:4 + comp_data_len]
+ orig2 = self._decompress(comp_data)
+ self.assertEqual(orig, orig2)
+
+ def testInvalidCompress(self):
+ """Test that invalid compress algorithm is detected"""
+ with self.assertRaises(ValueError) as e:
+ self._DoTestFile('237_compress_dtb_invalid.dts')
+ self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
+
+ def testCompUtilCompressions(self):
+ """Test compression algorithms"""
+ for bintool in self.comp_bintools.values():
+ self._CheckBintool(bintool)
+ data = bintool.compress(COMPRESS_DATA)
+ self.assertNotEqual(COMPRESS_DATA, data)
+ orig = bintool.decompress(data)
+ self.assertEquals(COMPRESS_DATA, orig)
+
+ def testCompUtilVersions(self):
+ """Test tool version of compression algorithms"""
+ for bintool in self.comp_bintools.values():
+ self._CheckBintool(bintool)
+ version = bintool.version()
+ self.assertRegex(version, '^v?[0-9]+[0-9.]*')
+
+ def testCompUtilPadding(self):
+ """Test padding of compression algorithms"""
+ # Skip zstd because it doesn't support padding
+ for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
+ self._CheckBintool(bintool)
+ data = bintool.compress(COMPRESS_DATA)
+ self.assertNotEqual(COMPRESS_DATA, data)
+ data += tools.get_bytes(0, 64)
+ orig = bintool.decompress(data)
+ self.assertEquals(COMPRESS_DATA, orig)
+
+ def testCompressDtbZstd(self):
+ """Test that zstd compress of device-tree files failed"""
+ with self.assertRaises(ValueError) as e:
+ self._DoTestFile('238_compress_dtb_zstd.dts')
+ self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
+ "requires a length header", str(e.exception))
if __name__ == "__main__":