"Das U-Boot" Source Tree
at master 734 lines 34 kB view raw
1.. SPDX-License-Identifier: GPL-2.0+ 2 3.. toctree:: 4 :maxdepth: 1 5 6Binman Tests 7============ 8 9.. contents:: 10 :depth: 2 11 :local: 12 13There is some material on writing tests in the main Binman documentation 14(see :doc:`package/index`). This short guide is separate so people don't 15feel they have to read as much. 16 17Code and output is mostly included verbatim, which makes the doc longer, but 18avoids its becoming confusing when the output or referenced code changes in the 19future. 20 21Purpose 22------- 23 24The main purpose of tests in Binman is to make sure that Binman actually does 25what it is supposed to. Various people contribute code, refactoring is done 26over time, but U-Boot users (developers, SoC vendors, board vendors) rely on 27Binman producing images which function correctly. Without tests, a one-line 28change could unintentionally break a corner-case and the problem might not be 29noticed for months. Debugging an image-generation problem with a board you 30don't have can be very hard. 31 32A secondary purpose is productivity. U-Boot contributors are busy and often 33have too much on their plate. Trying to figure out why their patch broke 34some other vendor's workflow can be very time-consuming and frustrating. By 35building in tests from the start, this is largely avoided. If your change has 36full test coverage and doesn't break any test, all is well and no one can 37complain. 38 39A lessor purpose is to document what Binman actually does. If a test covers a 40feature, it works. If there is no test coverage, no one can say for sure 41whether it works in all expected situations, certainly not wihout manual 42effort. 43 44In fact, strictly speaking it isn't completely clear what 'works' even means in 45the case where these is no test to cover the code. We are often left guessing 46as to what the documentation means, what was actually intended, etc. 47 48Finally, code-coverage helps to remove 'zombie code', copied from elsewhere 49because it looks reasonable, but not actually needed. The same situation arises 50in silicon-chip design, where a part of the chip is not validated. If it isn't 51validated, it can be assumed not to work, either now or later, so it is best to 52remove that logic to avoid it causing problems. 53 54Setting up 55---------- 56 57Binman tests use various utility programs. Most of these are documented in 58:doc:`../build/gcc`. But some are SoC-specific. To fetch these, tell Binman to 59fetch or build any missing tools: 60 61.. code-block:: bash 62 63 $ binman tool -f missing 64 65When this completes successfully, you can list the tools. You should see 66something like this: 67 68.. code-block:: bash 69 70 $ binman tool -l 71 Name Version Description Path 72 --------------- ----------- ------------------------- ------------------------------ 73 bootgen ****** Bootg Xilinx Bootgen /home/sglass/.binman-tools/bootgen 74 bzip2 1.0.8 bzip2 compression /usr/bin/bzip2 75 cbfstool unknown Manipulate CBFS files /home/sglass/bin/cbfstool 76 fdt_add_pubkey unknown Generate image for U-Boot /home/sglass/bin/fdt_add_pubkey 77 fdtgrep unknown Grep devicetree files /home/sglass/bin/fdtgrep 78 fiptool v2.11.0(rele Manipulate ATF FIP files /home/sglass/.binman-tools/fiptool 79 futility v0.0.1-9f2e9 Chromium OS firmware utili /home/sglass/.binman-tools/futility 80 gzip 1.12 gzip compression /usr/bin/gzip 81 ifwitool unknown Manipulate Intel IFWI file /home/sglass/.binman-tools/ifwitool 82 lz4 v1.9.4 lz4 compression /usr/bin/lz4 83 lzma_alone 9.22 beta lzma_alone compression /usr/bin/lzma_alone 84 lzop v1.04 lzo compression /usr/bin/lzop 85 mkeficapsule 2024.10-rc5- mkeficapsule tool for gene /home/sglass/bin/mkeficapsule 86 mkimage 2024.10-rc5- Generate image for U-Boot /home/sglass/bin/mkimage 87 openssl 3.0.13 30 Ja openssl cryptography toolk /usr/bin/openssl 88 xz 5.4.5 xz compression /usr/bin/xz 89 zstd v1.5.5 zstd compression /usr/bin/zstd 90 91The tools are written to ``~/.binman-tools`` so add that to your ``PATH``. 92It's fine to have some of the tools elsewhere (e.g. ``~/bin``) so long as they 93are up-to-date. This allows you use the version of the tools intended for 94running tests. 95 96Now you should be able to actually run the tests: 97 98.. code-block:: bash 99 100 $ binman test 101 ======================== Running binman tests ======================== 102 ...................................................................... 103 ...................................................................... 104 ...................................................................... 105 ...................................................................... 106 ...................................................................... 107 ...................................................................... 108 ...................................................................... 109 ...................................................................... 110 ........ 111 ---------------------------------------------------------------------- 112 Ran 568 tests in 2.578s 113 114 OK 115 116If this doesn't work, see if you can have some missing tools. Check that the 117dependencies are all there as above. If it is very slow, try installing 118concurrencytest so that the tests run in parallel. 119 120The next thing to set up is code coverage, using the -T flag: 121 122.. code-block:: bash 123 124 $ binman test -T 125 ======================== Running binman tests ======================== 126 ...................................................................... 127 ...................................................................... 128 ...................................................................... 129 ...................................................................... 130 ...................................................................... 131 ...................................................................... 132 ...................................................................... 133 ...................................................................... 134 ........ 135 ---------------------------------------------------------------------- 136 Ran 568 tests in 17.367s 137 138 OK 139 140 99% 141 Name Stmts Miss Cover 142 --------------------------------------------------------------------------- 143 tools/binman/__init__.py 0 0 100% 144 tools/binman/bintool.py 263 0 100% 145 tools/binman/btool/bootgen.py 21 0 100% 146 tools/binman/btool/btool_gzip.py 5 0 100% 147 tools/binman/btool/bzip2.py 5 0 100% 148 tools/binman/btool/cbfstool.py 24 0 100% 149 tools/binman/btool/cst.py 15 4 73% 150 tools/binman/btool/fdt_add_pubkey.py 21 0 100% 151 tools/binman/btool/fdtgrep.py 26 0 100% 152 tools/binman/btool/fiptool.py 19 0 100% 153 tools/binman/btool/futility.py 19 0 100% 154 tools/binman/btool/ifwitool.py 22 0 100% 155 tools/binman/btool/lz4.py 22 0 100% 156 tools/binman/btool/lzma_alone.py 34 0 100% 157 tools/binman/btool/lzop.py 5 0 100% 158 tools/binman/btool/mkeficapsule.py 27 0 100% 159 tools/binman/btool/mkimage.py 23 0 100% 160 tools/binman/btool/openssl.py 42 0 100% 161 tools/binman/btool/xz.py 5 0 100% 162 tools/binman/btool/zstd.py 5 0 100% 163 tools/binman/cbfs_util.py 376 0 100% 164 tools/binman/cmdline.py 90 0 100% 165 tools/binman/control.py 409 0 100% 166 tools/binman/elf.py 241 0 100% 167 tools/binman/entry.py 548 0 100% 168 tools/binman/etype/alternates_fdt.py 58 0 100% 169 tools/binman/etype/atf_bl31.py 5 0 100% 170 tools/binman/etype/atf_fip.py 67 0 100% 171 tools/binman/etype/blob.py 49 0 100% 172 tools/binman/etype/blob_dtb.py 46 0 100% 173 tools/binman/etype/blob_ext.py 9 0 100% 174 tools/binman/etype/blob_ext_list.py 32 0 100% 175 tools/binman/etype/blob_named_by_arg.py 9 0 100% 176 tools/binman/etype/blob_phase.py 22 0 100% 177 tools/binman/etype/cbfs.py 101 0 100% 178 tools/binman/etype/collection.py 30 0 100% 179 tools/binman/etype/cros_ec_rw.py 5 0 100% 180 tools/binman/etype/efi_capsule.py 59 0 100% 181 tools/binman/etype/efi_empty_capsule.py 33 0 100% 182 tools/binman/etype/encrypted.py 34 0 100% 183 tools/binman/etype/fdtmap.py 62 0 100% 184 tools/binman/etype/files.py 35 0 100% 185 tools/binman/etype/fill.py 13 0 100% 186 tools/binman/etype/fit.py 311 0 100% 187 tools/binman/etype/fmap.py 37 0 100% 188 tools/binman/etype/gbb.py 37 0 100% 189 tools/binman/etype/image_header.py 53 0 100% 190 tools/binman/etype/intel_cmc.py 4 0 100% 191 tools/binman/etype/intel_descriptor.py 39 0 100% 192 tools/binman/etype/intel_fit.py 12 0 100% 193 tools/binman/etype/intel_fit_ptr.py 17 0 100% 194 tools/binman/etype/intel_fsp.py 4 0 100% 195 tools/binman/etype/intel_fsp_m.py 4 0 100% 196 tools/binman/etype/intel_fsp_s.py 4 0 100% 197 tools/binman/etype/intel_fsp_t.py 4 0 100% 198 tools/binman/etype/intel_ifwi.py 67 0 100% 199 tools/binman/etype/intel_me.py 4 0 100% 200 tools/binman/etype/intel_mrc.py 6 0 100% 201 tools/binman/etype/intel_refcode.py 6 0 100% 202 tools/binman/etype/intel_vbt.py 4 0 100% 203 tools/binman/etype/intel_vga.py 4 0 100% 204 tools/binman/etype/mkimage.py 84 0 100% 205 tools/binman/etype/null.py 9 0 100% 206 tools/binman/etype/nxp_imx8mcst.py 78 59 24% 207 tools/binman/etype/nxp_imx8mimage.py 38 6 84% 208 tools/binman/etype/opensbi.py 5 0 100% 209 tools/binman/etype/powerpc_mpc85xx_bootpg_resetvec.py 6 0 100% 210 tools/binman/etype/pre_load.py 76 0 100% 211 tools/binman/etype/rockchip_tpl.py 5 0 100% 212 tools/binman/etype/scp.py 5 0 100% 213 tools/binman/etype/section.py 418 0 100% 214 tools/binman/etype/tee_os.py 31 0 100% 215 tools/binman/etype/text.py 21 0 100% 216 tools/binman/etype/ti_board_config.py 139 0 100% 217 tools/binman/etype/ti_dm.py 5 0 100% 218 tools/binman/etype/ti_secure.py 65 0 100% 219 tools/binman/etype/ti_secure_rom.py 117 0 100% 220 tools/binman/etype/u_boot.py 7 0 100% 221 tools/binman/etype/u_boot_dtb.py 9 0 100% 222 tools/binman/etype/u_boot_dtb_with_ucode.py 51 0 100% 223 tools/binman/etype/u_boot_elf.py 19 0 100% 224 tools/binman/etype/u_boot_env.py 27 0 100% 225 tools/binman/etype/u_boot_expanded.py 4 0 100% 226 tools/binman/etype/u_boot_img.py 7 0 100% 227 tools/binman/etype/u_boot_nodtb.py 7 0 100% 228 tools/binman/etype/u_boot_spl.py 8 0 100% 229 tools/binman/etype/u_boot_spl_bss_pad.py 14 0 100% 230 tools/binman/etype/u_boot_spl_dtb.py 9 0 100% 231 tools/binman/etype/u_boot_spl_elf.py 8 0 100% 232 tools/binman/etype/u_boot_spl_expanded.py 12 0 100% 233 tools/binman/etype/u_boot_spl_nodtb.py 8 0 100% 234 tools/binman/etype/u_boot_spl_pubkey_dtb.py 32 0 100% 235 tools/binman/etype/u_boot_spl_with_ucode_ptr.py 8 0 100% 236 tools/binman/etype/u_boot_tpl.py 8 0 100% 237 tools/binman/etype/u_boot_tpl_bss_pad.py 14 0 100% 238 tools/binman/etype/u_boot_tpl_dtb.py 9 0 100% 239 tools/binman/etype/u_boot_tpl_dtb_with_ucode.py 8 0 100% 240 tools/binman/etype/u_boot_tpl_elf.py 8 0 100% 241 tools/binman/etype/u_boot_tpl_expanded.py 12 0 100% 242 tools/binman/etype/u_boot_tpl_nodtb.py 8 0 100% 243 tools/binman/etype/u_boot_tpl_with_ucode_ptr.py 12 0 100% 244 tools/binman/etype/u_boot_ucode.py 33 0 100% 245 tools/binman/etype/u_boot_vpl.py 8 0 100% 246 tools/binman/etype/u_boot_vpl_bss_pad.py 14 0 100% 247 tools/binman/etype/u_boot_vpl_dtb.py 9 0 100% 248 tools/binman/etype/u_boot_vpl_elf.py 8 0 100% 249 tools/binman/etype/u_boot_vpl_expanded.py 12 0 100% 250 tools/binman/etype/u_boot_vpl_nodtb.py 8 0 100% 251 tools/binman/etype/u_boot_with_ucode_ptr.py 42 0 100% 252 tools/binman/etype/vblock.py 38 0 100% 253 tools/binman/etype/x86_reset16.py 7 0 100% 254 tools/binman/etype/x86_reset16_spl.py 7 0 100% 255 tools/binman/etype/x86_reset16_tpl.py 7 0 100% 256 tools/binman/etype/x86_start16.py 7 0 100% 257 tools/binman/etype/x86_start16_spl.py 7 0 100% 258 tools/binman/etype/x86_start16_tpl.py 7 0 100% 259 tools/binman/etype/x509_cert.py 71 0 100% 260 tools/binman/etype/xilinx_bootgen.py 72 0 100% 261 tools/binman/fip_util.py 202 0 100% 262 tools/binman/fmap_util.py 49 0 100% 263 tools/binman/image.py 181 0 100% 264 tools/binman/state.py 201 0 100% 265 --------------------------------------------------------------------------- 266 TOTAL 5954 69 99% 267 268 To get a report in 'htmlcov/index.html', type: python3-coverage html 269 Coverage error: 99%, but should be 100% 270 ValueError: Test coverage failure 271 272Unfortunately the run failed. As it suggests, create a report: 273 274.. code-block:: bash 275 276 $ python3-coverage html 277 Wrote HTML report to htmlcov/index.html 278 279If you open that file in the browser, you can see which files are not reaching 280100% and click on them. Here is ``nxp_imx8mimage.py``, for example: 281 282.. code-block:: python 283 284 43 # Generate mkimage configuration file similar to imx8mimage.cfg 285 44 # and pass it to mkimage to generate SPL image for us here. 286 45 cfg_fname = tools.get_output_filename('nxp.imx8mimage.cfg.%s' % uniq) 287 46 with open(cfg_fname, 'w') as outf: 288 47 print('ROM_VERSION v%d' % self.rom_version, file=outf) 289 48 print('BOOT_FROM %s' % self.boot_from, file=outf) 290 49 print('LOADER %s %#x' % (input_fname, self.loader_address), file=outf) 291 50 292 51 output_fname = tools.get_output_filename(f'cfg-out.{uniq}') 293 52 args = ['-d', input_fname, '-n', cfg_fname, '-T', 'imx8mimage', 294 53 output_fname] 295 54 if self.mkimage.run_cmd(*args) is not None: 296 55 return tools.read_file(output_fname) 297 56 else: 298 57 # Bintool is missing; just use the input data as the output 299 58 x self.record_missing_bintool(self.mkimage) 300 59 x return data 301 60 302 61 def SetImagePos(self, image_pos): 303 62 # Customized SoC specific SetImagePos which skips the mkimage etype 304 63 # implementation and removes the 0x48 offset introduced there. That 305 64 # offset is only used for uImage/fitImage, which is not the case in 306 65 # here. 307 66 upto = 0x00 308 67 for entry in super().GetEntries().values(): 309 68 x entry.SetOffsetSize(upto, None) 310 69 311 70 # Give up if any entries lack a size 312 71 x if entry.size is None: 313 72 x return 314 73 x upto += entry.size 315 74 316 75 Entry_section.SetImagePos(self, image_pos) 317 318Most of the file is covered, but the lines marked with ``x`` indicate missing 319coverage. The will show up red in your browser. 320 321What is a test? 322--------------- 323 324A test is a function in ``ftest.py`` which uses an image description in 325``tools/binman/test`` to perform some operations and exercise the code. Some 326tests are just a few lines; some are more complicated. 327 328Here is a simple test: 329 330.. code-block:: python 331 332 def testSimple(self): 333 """Test a simple binman with a single file""" 334 data = self._DoReadFile('005_simple.dts') 335 self.assertEqual(U_BOOT_DATA, data) 336 337This test tells Binman to build an image using the description. Then it checks 338that the resulting image looks correct. The image description is: 339 340.. code-block:: devicetree 341 342 /dts-v1/; 343 344 / { 345 #address-cells = <1>; 346 #size-cells = <1>; 347 348 binman { 349 u-boot { 350 }; 351 }; 352 }; 353 354As you will know from the Binman documentation, this says that there is 355one image and it contains the U-Boot binary. So this test builds an image 356consisting of a U-Boot binary, then checks that it does indeed have just a 357U-Boot binary in it. 358 359Test data 360--------- 361 362Using real binaries (like ``u-boot.bin``) to test Binman would be quite tedious. 363Every output file would be large and it would be hard to tell by looking at the 364output (e.g. with a hex dump) if a particular entry contains ``u-boot.bin`` or 365``u-boot-spl.bin`` or something else. 366 367Binman gets around this by using simple placeholders. Here is the placeholder 368for u-boot.bin: 369 370.. code-block:: python 371 372 U_BOOT_DATA = b'1234' 373 374This is just bytes. So the test above checks that the output image contains 375these four bytes. This makes verification fast for Binman and very easy for 376humans. 377 378Even the devicetree is a placeholder: 379 380.. code-block:: python 381 382 U_BOOT_DTB_DATA = b'udtb' 383 384But for some tests you need to use the real devicetree. In that case you can 385use ``_DoReadFileRealDtb()``. See ``testUpdateFdtAll()`` for an example of how 386to check the devicetree updated by Binman. 387 388Test structure 389-------------- 390 391Each test is designed to test just one thing. Binman tests are named according 392to what they are testing. Individually they don't do very much, but as a whole 393they test every line of code in Binman. 394 395So ``testSimple()`` is designed to check that Binman can build the 396simplest-possible image that isn't completely empty. 397 398Another type of test is one which checks error-handling, for example: 399 400.. code-block:: python 401 402 def testFillNoSize(self): 403 """Test for an fill entry type with no size""" 404 with self.assertRaises(ValueError) as e: 405 self._DoReadFile('070_fill_no_size.dts') 406 self.assertIn("'fill' entry is missing properties: size", 407 str(e.exception)) 408 409This test deliberately tries to provoke an error. The image description is: 410 411.. code-block:: devicetree 412 413 // SPDX-License-Identifier: GPL-2.0+ 414 /dts-v1/; 415 416 / { 417 #address-cells = <1>; 418 #size-cells = <1>; 419 420 binman { 421 size = <16>; 422 fill { 423 fill-byte = [ff]; 424 }; 425 }; 426 }; 427 428You can see that there is no size for the 'fill' entry, so we would expect 429Binman to complain. The test checks that it actually does. It also checks the 430error message produced by Binman. Sometimes you need to add several tests, each 431with their own broken image description, in order to check all the error cases. 432 433Sometimes you need to capture the console output of Binman, to check it is 434correct. You can to this with ``test_util.capture_sys_output()``, for example: 435 436.. code-block:: python 437 438 with test_util.capture_sys_output() as (_, stderr): 439 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility', 440 entry_args=entry_args) 441 err = stderr.getvalue() 442 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility") 443 444The test collects the output and checks it with a regular expression. If you 445need to see the test output (e.g. to debug it), you will have to remove that 446capture line. 447 448How to add a new test 449--------------------- 450 451This section explains the process of writing a new test. It uses an example to 452help with this, but your code will be different. 453 454Generally you are adding a test because you are adding a new entry type 455('etype'). So start by creating the shortest and simplest image-description you 456can, which contains the new etype. Put it in a numbered file in 457``tool/binman/test`` so that it comes last. All the numbers are unique and there 458are no gaps. 459 460Example from ``tools/binman/test/339_nxp_imx8.dts``: 461 462.. code-block:: devicetree 463 464 // SPDX-License-Identifier: GPL-2.0+ 465 466 /dts-v1/; 467 468 / { 469 #address-cells = <1>; 470 #size-cells = <1>; 471 472 binman { 473 nxp-imx8mimage { 474 args; /* TODO: Needed by mkimage etype superclass */ 475 nxp,boot-from = "sd"; 476 nxp,rom-version = <1>; 477 nxp,loader-address = <0x10>; 478 }; 479 }; 480 }; 481 482Note that you should use tabs in the file, not spaces. You can see that this has 483been cut down to the bare minimum, just enough to include the etype and the 484arguments it needs. This is of course not a real image. It will not boot on 485anything. But that's fine; we are just trying to test this one etype. Try not 486to add any other sections and etypes unless they are absolutely essential for 487your test to work. This helps others too: they don't need to understand the full 488complexity of your etype just to read your test. 489 490Then create your test by adding a new function at the end of ``ftest.py``: 491 492.. code-block:: python 493 494 def testNxpImx8Image(self): 495 """Test that binman can produce an iMX8 image""" 496 self._DoTestFile('339_nxp_imx8.dts') 497 498This uses the test file that you created. It doesn't check anything, it just 499runs the image description through binman. 500 501Let's run it: 502 503.. code-block:: bash 504 505 $ binman test testNxpImx8Image 506 ======================== Running binman tests ======================== 507 . 508 ---------------------------------------------------------------------- 509 Ran 1 test in 0.242s 510 511 OK 512 513So the test passes. It doesn't really do a lot, but it does exercise the etype. 514The next step is to update it to actually check the output: 515 516.. code-block:: python 517 518 def testNxpImx8Image(self): 519 """Test that binman can produce an iMX8 image""" 520 data = self._DoReadFile('339_nxp_imx8.dts') 521 print('data', len(data)) 522 523The ``_DoReadFile()`` function is documented in the code. It returns the image 524contents as the first part of a tuple. 525 526Running this we see: 527 528.. code-block:: bash 529 530 data 2200 531 532So it is producing a little over 8K of data. Your etype will be different, but 533in any case you can add Python code to check that this data is actually correct, 534based on your knowledge of your etype. Note that you should not be checking 535whether the external tools (called 'bintools' in Binman) are actually working, 536since presumably they have their own tests. You just need to check that the 537image seems reasonable, e.g. is not empty, contains the expected sections, etc. 538 539When your etype does use a bintool, it also needs tests, but generally it will 540be tested by virtue of the etype test. This is because your etype must call the 541bintool to create the image. Sometimes you might need to add a test for a 542bintool error-condition, though. 543 544Finishing code coverage 545----------------------- 546 547The objective is to have test-coverage for every line of code that you add to 548Binman. So how can you tell? First, get a coverage report as described above. 549Look through the output for any files which are not at 100%. Add more test cases 550(image descriptions and new functions in ``ftest.py``) until you have covered 551each line. 552 553In the above example, here are some possible steps: 554 555#. The first red bit is where the ``mkimage`` call returns None. This can be 556 traced to ``Bintoolmkimage.mkimage()`` which calls 557 ``Bintool.run_cmd_result()`` and ``None`` means that ``mkimage`` is missing. 558 So the etype has code to handle that case, but it is never used. You can 559 look for other examples of ``self.mkimage`` returning ``None`` - e.g. 560 ``Entry_mkimage.BuildSectionData()`` does this. The clue for finding this is 561 that the ``nxp-imx8mimage`` etype is based on ``Entry_mkimage``: 562 563 .. code-block:: python 564 565 class Entry_nxp_imx8mimage(Entry_mkimage): 566 567 It must be tested somewhere...in this case ``testMkimage()`` doesn't do it, 568 but ``testMkimageMissing()`` immediately below that does. So you can create a 569 similar test, e.g.: 570 571 .. code-block:: python 572 573 def testNxpImx8ImageMkimageMissing(self): 574 """Test that binman can produce an iMX8 image""" 575 with test_util.capture_sys_output() as (_, stderr): 576 self._DoTestFile('339_nxp_imx8.dts', 577 force_missing_bintools='mkimage') 578 err = stderr.getvalue() 579 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage") 580 581 Note that this uses exactly the same image description as the first test. 582 It just checks what happens when the tool is missing. Checking the coverage 583 again, you will see that the first red bit has gone: 584 585 .. code-block:: bash 586 587 $ binman test -T 588 $ python3-coverage html 589 590#. The second red bit is for ``SetImagePos()``. You can see that it is iterating 591 through the sub-entries inside the ``nxp-imx8mimage`` entry. In the case of 592 the 339 file, there are no such entries, so this code inside the for() loop 593 isn't used: 594 595 .. code-block:: python 596 597 def SetImagePos(self, image_pos): 598 # Customized SoC specific SetImagePos which skips the mkimage etype 599 # implementation and removes the 0x48 offset introduced there. That 600 # offset is only used for uImage/fitImage, which is not the case in 601 # here. 602 upto = 0x00 603 for entry in super().GetEntries().values(): 604 entry.SetOffsetSize(upto, None) 605 606 # Give up if any entries lack a size 607 if entry.size is None: 608 return 609 upto += entry.size 610 611 Entry_section.SetImagePos(self, image_pos) 612 613 The solution is to add an entry, e.g. in ``340_nxp_imx8_non_empty.dts``: 614 615 .. code-block:: devicetree 616 617 // SPDX-License-Identifier: GPL-2.0+ 618 619 /dts-v1/; 620 621 / { 622 #address-cells = <1>; 623 #size-cells = <1>; 624 625 binman { 626 nxp-imx8mimage { 627 args; /* TODO: Needed by mkimage etype superclass */ 628 nxp,boot-from = "sd"; 629 nxp,rom-version = <1>; 630 nxp,loader-address = <0x10>; 631 632 u-boot { 633 }; 634 }; 635 }; 636 }; 637 638 Now write a little test to use it: 639 640 .. code-block:: python 641 642 def testNxpImx8ImageNonEmpty(self): 643 """Test that binman can produce an iMX8 image with something in it""" 644 data = self._DoReadFile('340_nxp_imx8_non_empty.dts') 645 # check data here 646 647 With that, the second red bit goes away, because the for() loop is now used. 648 649#. There is one more red bit left, the ``return`` in ``SetImagePos()``. The 650 above effort got the for() loop to be executed, but it doesn't cover the 651 ``return``. It might have been copied from some other etype, e.g. the mkimage 652 one. See ``Entry_mkimage.SetImagePos()`` which contains the code: 653 654 .. code-block:: python 655 656 for entry in self.GetEntries().values(): 657 entry.SetOffsetSize(upto, None) 658 659 # Give up if any entries lack a size 660 if entry.size is None: 661 return 662 upto += entry.size 663 664 But which test covers that code for mkimage? By figuring that out, you could 665 use a similar technique. One way to find out is to delete the two lines in 666 ``Entry_mkimage`` which check for entry.size being None and returning, then 667 see what breaks with ``binman test``: 668 669 .. code-block:: bash 670 671 ERROR: binman.ftest.TestFunctional.testMkimageCollection (subunit.RemotedTestCase) 672 binman.ftest.TestFunctional.testMkimageCollection 673 ---------------------------------------------------------------------- 674 testtools.testresult.real._StringException: Traceback (most recent call last): 675 TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' 676 677 ====================================================================== 678 ERROR: binman.ftest.TestFunctional.testMkimageImage (subunit.RemotedTestCase) 679 binman.ftest.TestFunctional.testMkimageImage 680 ---------------------------------------------------------------------- 681 testtools.testresult.real._StringException: Traceback (most recent call last): 682 TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' 683 684 ====================================================================== 685 ERROR: binman.ftest.TestFunctional.testMkimageSpecial (subunit.RemotedTestCase) 686 binman.ftest.TestFunctional.testMkimageSpecial 687 ---------------------------------------------------------------------- 688 testtools.testresult.real._StringException: Traceback (most recent call last): 689 TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' 690 691 We can verify that you got the right test, by putting the lines back in and 692 getting coverage for just that test: 693 694 .. code-block:: bash 695 696 binman test -T testMkimageCollection 697 python3-coverage html 698 699 You will see a lot of red since we are seeing test coverage just for one 700 test, but if you look in ``mkimage.py`` at ``SetImagePos()`` you will see 701 that the ``return`` is covered (i.e. it is marked green). 702 703 Looking at the ``.dts`` files for each of these tests, none jumps out as 704 being relevant to our case. It seems that this code just isn't needed, so the 705 best solution is to delete those two lines from the function: 706 707 .. code-block:: python 708 709 def SetImagePos(self, image_pos): 710 # Customized SoC specific SetImagePos which skips the mkimage etype 711 # implementation and removes the 0x48 offset introduced there. That 712 # offset is only used for uImage/fitImage, which is not the case in 713 # here. 714 upto = 0x00 715 for entry in super().GetEntries().values(): 716 entry.SetOffsetSize(upto, None) 717 upto += entry.size 718 719 Entry_section.SetImagePos(self, image_pos) 720 721We should check the updated code on a real build, to make sure it really 722isn't needed, of course. 723 724Now, the test coverage is complete! 725 726If we later discover a case where those lines are needed, we can add the 727lines back, along with a test for this case. 728 729Getting help 730------------ 731 732If you are stuck and cannot work out how to add test coverage for your entry 733type, ask on the U-Boot mailing list, cc ``Simon Glass <sjg@chromium.org>`` or 734on irc ``sjg1``