1# 2# Copyright (c) 2015, Intel Corporation. 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6# AUTHORS 7# Ed Bartosh <ed.bartosh@linux.intel.com> 8 9"""Test cases for wic.""" 10 11import os 12import sys 13import unittest 14import hashlib 15 16from glob import glob 17from shutil import rmtree, copy 18from tempfile import NamedTemporaryFile 19 20from oeqa.selftest.case import OESelftestTestCase 21from oeqa.core.decorator import OETestTag 22from oeqa.core.decorator.data import skipIfNotArch 23from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu 24 25 26def extract_files(debugfs_output): 27 """ 28 extract file names from the output of debugfs -R 'ls -p', 29 which looks like this: 30 31 /2/040755/0/0/.//\n 32 /2/040755/0/0/..//\n 33 /11/040700/0/0/lost+found^M//\n 34 /12/040755/1002/1002/run//\n 35 /13/040755/1002/1002/sys//\n 36 /14/040755/1002/1002/bin//\n 37 /80/040755/1002/1002/var//\n 38 /92/040755/1002/1002/tmp//\n 39 """ 40 # NOTE the occasional ^M in file names 41 return [line.split('/')[5].strip() for line in \ 42 debugfs_output.strip().split('/\n')] 43 44def files_own_by_root(debugfs_output): 45 for line in debugfs_output.strip().split('/\n'): 46 if line.split('/')[3:5] != ['0', '0']: 47 print(debugfs_output) 48 return False 49 return True 50 51class WicTestCase(OESelftestTestCase): 52 """Wic test class.""" 53 54 image_is_ready = False 55 wicenv_cache = {} 56 57 def setUpLocal(self): 58 """This code is executed before each test method.""" 59 self.resultdir = os.path.join(self.builddir, "wic-tmp") 60 super(WicTestCase, self).setUpLocal() 61 62 # Do this here instead of in setUpClass as the base setUp does some 63 # clean up which can result in the native tools built earlier in 64 # setUpClass being unavailable. 65 if not WicTestCase.image_is_ready: 66 if self.td['USE_NLS'] != 'yes': 67 self.skipTest('wic-tools needs USE_NLS=yes') 68 69 bitbake('wic-tools core-image-minimal core-image-minimal-mtdutils') 70 WicTestCase.image_is_ready = True 71 rmtree(self.resultdir, ignore_errors=True) 72 73 def tearDownLocal(self): 74 """Remove resultdir as it may contain images.""" 75 rmtree(self.resultdir, ignore_errors=True) 76 super(WicTestCase, self).tearDownLocal() 77 78 def _get_image_env_path(self, image): 79 """Generate and obtain the path to <image>.env""" 80 if image not in WicTestCase.wicenv_cache: 81 bitbake('%s -c do_rootfs_wicenv' % image) 82 stdir = get_bb_var('STAGING_DIR', image) 83 machine = self.td["MACHINE"] 84 WicTestCase.wicenv_cache[image] = os.path.join(stdir, machine, 'imgdata') 85 return WicTestCase.wicenv_cache[image] 86 87class CLITests(OESelftestTestCase): 88 def test_version(self): 89 """Test wic --version""" 90 runCmd('wic --version') 91 92 def test_help(self): 93 """Test wic --help and wic -h""" 94 runCmd('wic --help') 95 runCmd('wic -h') 96 97 def test_createhelp(self): 98 """Test wic create --help""" 99 runCmd('wic create --help') 100 101 def test_listhelp(self): 102 """Test wic list --help""" 103 runCmd('wic list --help') 104 105 def test_help_create(self): 106 """Test wic help create""" 107 runCmd('wic help create') 108 109 def test_help_list(self): 110 """Test wic help list""" 111 runCmd('wic help list') 112 113 def test_help_overview(self): 114 """Test wic help overview""" 115 runCmd('wic help overview') 116 117 def test_help_plugins(self): 118 """Test wic help plugins""" 119 runCmd('wic help plugins') 120 121 def test_help_kickstart(self): 122 """Test wic help kickstart""" 123 runCmd('wic help kickstart') 124 125 def test_list_images(self): 126 """Test wic list images""" 127 runCmd('wic list images') 128 129 def test_list_source_plugins(self): 130 """Test wic list source-plugins""" 131 runCmd('wic list source-plugins') 132 133 def test_listed_images_help(self): 134 """Test wic listed images help""" 135 output = runCmd('wic list images').output 136 imagelist = [line.split()[0] for line in output.splitlines()] 137 for image in imagelist: 138 runCmd('wic list %s help' % image) 139 140 def test_unsupported_subcommand(self): 141 """Test unsupported subcommand""" 142 self.assertNotEqual(0, runCmd('wic unsupported', ignore_status=True).status) 143 144 def test_no_command(self): 145 """Test wic without command""" 146 self.assertEqual(1, runCmd('wic', ignore_status=True).status) 147 148class Wic(WicTestCase): 149 def test_build_image_name(self): 150 """Test wic create wictestdisk --image-name=core-image-minimal""" 151 cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir 152 runCmd(cmd) 153 self.assertEqual(1, len(glob(os.path.join (self.resultdir, "wictestdisk-*.direct")))) 154 155 @skipIfNotArch(['i586', 'i686', 'x86_64']) 156 def test_gpt_image(self): 157 """Test creation of core-image-minimal with gpt table and UUID boot""" 158 cmd = "wic create directdisk-gpt --image-name core-image-minimal -o %s" % self.resultdir 159 runCmd(cmd) 160 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-*.direct")))) 161 162 @skipIfNotArch(['i586', 'i686', 'x86_64']) 163 def test_iso_image(self): 164 """Test creation of hybrid iso image with legacy and EFI boot""" 165 config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\ 166 'MACHINE_FEATURES:append = " efi"\n'\ 167 'DEPENDS:pn-core-image-minimal += "syslinux"\n' 168 self.append_config(config) 169 bitbake('core-image-minimal core-image-minimal-initramfs') 170 self.remove_config(config) 171 cmd = "wic create mkhybridiso --image-name core-image-minimal -o %s" % self.resultdir 172 runCmd(cmd) 173 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "HYBRID_ISO_IMG-*.direct")))) 174 self.assertEqual(1, len(glob(os.path.join (self.resultdir, "HYBRID_ISO_IMG-*.iso")))) 175 176 @skipIfNotArch(['i586', 'i686', 'x86_64']) 177 def test_qemux86_directdisk(self): 178 """Test creation of qemux-86-directdisk image""" 179 cmd = "wic create qemux86-directdisk -e core-image-minimal -o %s" % self.resultdir 180 runCmd(cmd) 181 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "qemux86-directdisk-*direct")))) 182 183 @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64']) 184 def test_mkefidisk(self): 185 """Test creation of mkefidisk image""" 186 cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir 187 runCmd(cmd) 188 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "mkefidisk-*direct")))) 189 190 @skipIfNotArch(['i586', 'i686', 'x86_64']) 191 def test_bootloader_config(self): 192 """Test creation of directdisk-bootloader-config image""" 193 config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n' 194 self.append_config(config) 195 bitbake('core-image-minimal') 196 self.remove_config(config) 197 cmd = "wic create directdisk-bootloader-config -e core-image-minimal -o %s" % self.resultdir 198 runCmd(cmd) 199 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-bootloader-config-*direct")))) 200 201 @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64']) 202 def test_systemd_bootdisk(self): 203 """Test creation of systemd-bootdisk image""" 204 config = 'MACHINE_FEATURES:append = " efi"\n' 205 self.append_config(config) 206 bitbake('core-image-minimal') 207 self.remove_config(config) 208 cmd = "wic create systemd-bootdisk -e core-image-minimal -o %s" % self.resultdir 209 runCmd(cmd) 210 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "systemd-bootdisk-*direct")))) 211 212 def test_efi_bootpart(self): 213 """Test creation of efi-bootpart image""" 214 cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir 215 kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal') 216 self.append_config('IMAGE_EFI_BOOT_FILES = "%s;kernel"\n' % kimgtype) 217 runCmd(cmd) 218 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 219 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct")) 220 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 221 self.assertIn("kernel",result.output) 222 223 def test_sdimage_bootpart(self): 224 """Test creation of sdimage-bootpart image""" 225 cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir 226 kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal') 227 self.write_config('IMAGE_BOOT_FILES = "%s"\n' % kimgtype) 228 runCmd(cmd) 229 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct")))) 230 231 # TODO this doesn't have to be x86-specific 232 @skipIfNotArch(['i586', 'i686', 'x86_64']) 233 def test_default_output_dir(self): 234 """Test default output location""" 235 for fname in glob("directdisk-*.direct"): 236 os.remove(fname) 237 config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n' 238 self.append_config(config) 239 bitbake('core-image-minimal') 240 self.remove_config(config) 241 cmd = "wic create directdisk -e core-image-minimal" 242 runCmd(cmd) 243 self.assertEqual(1, len(glob("directdisk-*.direct"))) 244 245 @skipIfNotArch(['i586', 'i686', 'x86_64']) 246 def test_build_artifacts(self): 247 """Test wic create directdisk providing all artifacts.""" 248 bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'], 249 'wic-tools') 250 bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'], 251 'core-image-minimal')) 252 bbvars = {key.lower(): value for key, value in bb_vars.items()} 253 bbvars['resultdir'] = self.resultdir 254 runCmd("wic create directdisk " 255 "-b %(staging_datadir)s " 256 "-k %(deploy_dir_image)s " 257 "-n %(recipe_sysroot_native)s " 258 "-r %(image_rootfs)s " 259 "-o %(resultdir)s" % bbvars) 260 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-*.direct")))) 261 262 def test_compress_gzip(self): 263 """Test compressing an image with gzip""" 264 runCmd("wic create wictestdisk " 265 "--image-name core-image-minimal " 266 "-c gzip -o %s" % self.resultdir) 267 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.gz")))) 268 269 def test_compress_bzip2(self): 270 """Test compressing an image with bzip2""" 271 runCmd("wic create wictestdisk " 272 "--image-name=core-image-minimal " 273 "-c bzip2 -o %s" % self.resultdir) 274 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.bz2")))) 275 276 def test_compress_xz(self): 277 """Test compressing an image with xz""" 278 runCmd("wic create wictestdisk " 279 "--image-name=core-image-minimal " 280 "--compress-with=xz -o %s" % self.resultdir) 281 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.xz")))) 282 283 def test_wrong_compressor(self): 284 """Test how wic breaks if wrong compressor is provided""" 285 self.assertEqual(2, runCmd("wic create wictestdisk " 286 "--image-name=core-image-minimal " 287 "-c wrong -o %s" % self.resultdir, 288 ignore_status=True).status) 289 290 def test_debug_short(self): 291 """Test -D option""" 292 runCmd("wic create wictestdisk " 293 "--image-name=core-image-minimal " 294 "-D -o %s" % self.resultdir) 295 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct")))) 296 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "tmp.wic*")))) 297 298 def test_debug_long(self): 299 """Test --debug option""" 300 runCmd("wic create wictestdisk " 301 "--image-name=core-image-minimal " 302 "--debug -o %s" % self.resultdir) 303 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct")))) 304 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "tmp.wic*")))) 305 306 def test_skip_build_check_short(self): 307 """Test -s option""" 308 runCmd("wic create wictestdisk " 309 "--image-name=core-image-minimal " 310 "-s -o %s" % self.resultdir) 311 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct")))) 312 313 def test_skip_build_check_long(self): 314 """Test --skip-build-check option""" 315 runCmd("wic create wictestdisk " 316 "--image-name=core-image-minimal " 317 "--skip-build-check " 318 "--outdir %s" % self.resultdir) 319 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct")))) 320 321 def test_build_rootfs_short(self): 322 """Test -f option""" 323 runCmd("wic create wictestdisk " 324 "--image-name=core-image-minimal " 325 "-f -o %s" % self.resultdir) 326 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct")))) 327 328 def test_build_rootfs_long(self): 329 """Test --build-rootfs option""" 330 runCmd("wic create wictestdisk " 331 "--image-name=core-image-minimal " 332 "--build-rootfs " 333 "--outdir %s" % self.resultdir) 334 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct")))) 335 336 # TODO this doesn't have to be x86-specific 337 @skipIfNotArch(['i586', 'i686', 'x86_64']) 338 def test_rootfs_indirect_recipes(self): 339 """Test usage of rootfs plugin with rootfs recipes""" 340 runCmd("wic create directdisk-multi-rootfs " 341 "--image-name=core-image-minimal " 342 "--rootfs rootfs1=core-image-minimal " 343 "--rootfs rootfs2=core-image-minimal " 344 "--outdir %s" % self.resultdir) 345 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-multi-rootfs*.direct")))) 346 347 # TODO this doesn't have to be x86-specific 348 @skipIfNotArch(['i586', 'i686', 'x86_64']) 349 def test_rootfs_artifacts(self): 350 """Test usage of rootfs plugin with rootfs paths""" 351 bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'], 352 'wic-tools') 353 bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'], 354 'core-image-minimal')) 355 bbvars = {key.lower(): value for key, value in bb_vars.items()} 356 bbvars['wks'] = "directdisk-multi-rootfs" 357 bbvars['resultdir'] = self.resultdir 358 runCmd("wic create %(wks)s " 359 "--bootimg-dir=%(staging_datadir)s " 360 "--kernel-dir=%(deploy_dir_image)s " 361 "--native-sysroot=%(recipe_sysroot_native)s " 362 "--rootfs-dir rootfs1=%(image_rootfs)s " 363 "--rootfs-dir rootfs2=%(image_rootfs)s " 364 "--outdir %(resultdir)s" % bbvars) 365 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "%(wks)s-*.direct" % bbvars)))) 366 367 def test_exclude_path(self): 368 """Test --exclude-path wks option.""" 369 370 oldpath = os.environ['PATH'] 371 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 372 373 try: 374 wks_file = 'temp.wks' 375 with open(wks_file, 'w') as wks: 376 rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal') 377 wks.write(""" 378part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr 379part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr 380part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr""" 381 % (rootfs_dir, rootfs_dir)) 382 runCmd("wic create %s -e core-image-minimal -o %s" \ 383 % (wks_file, self.resultdir)) 384 385 os.remove(wks_file) 386 wicout = glob(os.path.join(self.resultdir, "%s-*direct" % 'temp')) 387 self.assertEqual(1, len(wicout)) 388 389 wicimg = wicout[0] 390 391 # verify partition size with wic 392 res = runCmd("parted -m %s unit b p 2>/dev/null" % wicimg) 393 394 # parse parted output which looks like this: 395 # BYT;\n 396 # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n 397 # 1:0.00MiB:200MiB:200MiB:ext4::;\n 398 partlns = res.output.splitlines()[2:] 399 400 self.assertEqual(3, len(partlns)) 401 402 for part in [1, 2, 3]: 403 part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part) 404 partln = partlns[part-1].split(":") 405 self.assertEqual(7, len(partln)) 406 start = int(partln[1].rstrip("B")) / 512 407 length = int(partln[3].rstrip("B")) / 512 408 runCmd("dd if=%s of=%s skip=%d count=%d" % 409 (wicimg, part_file, start, length)) 410 411 # Test partition 1, should contain the normal root directories, except 412 # /usr. 413 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ 414 os.path.join(self.resultdir, "selftest_img.part1")) 415 files = extract_files(res.output) 416 self.assertIn("etc", files) 417 self.assertNotIn("usr", files) 418 419 # Partition 2, should contain common directories for /usr, not root 420 # directories. 421 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ 422 os.path.join(self.resultdir, "selftest_img.part2")) 423 files = extract_files(res.output) 424 self.assertNotIn("etc", files) 425 self.assertNotIn("usr", files) 426 self.assertIn("share", files) 427 428 # Partition 3, should contain the same as partition 2, including the bin 429 # directory, but not the files inside it. 430 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ 431 os.path.join(self.resultdir, "selftest_img.part3")) 432 files = extract_files(res.output) 433 self.assertNotIn("etc", files) 434 self.assertNotIn("usr", files) 435 self.assertIn("share", files) 436 self.assertIn("bin", files) 437 res = runCmd("debugfs -R 'ls -p bin' %s 2>/dev/null" % \ 438 os.path.join(self.resultdir, "selftest_img.part3")) 439 files = extract_files(res.output) 440 self.assertIn(".", files) 441 self.assertIn("..", files) 442 self.assertEqual(2, len(files)) 443 444 for part in [1, 2, 3]: 445 part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part) 446 os.remove(part_file) 447 448 finally: 449 os.environ['PATH'] = oldpath 450 451 def test_include_path(self): 452 """Test --include-path wks option.""" 453 454 oldpath = os.environ['PATH'] 455 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 456 457 try: 458 include_path = os.path.join(self.resultdir, 'test-include') 459 os.makedirs(include_path) 460 with open(os.path.join(include_path, 'test-file'), 'w') as t: 461 t.write("test\n") 462 wks_file = os.path.join(include_path, 'temp.wks') 463 with open(wks_file, 'w') as wks: 464 rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal') 465 wks.write(""" 466part /part1 --source rootfs --ondisk mmcblk0 --fstype=ext4 467part /part2 --source rootfs --ondisk mmcblk0 --fstype=ext4 --include-path %s""" 468 % (include_path)) 469 runCmd("wic create %s -e core-image-minimal -o %s" \ 470 % (wks_file, self.resultdir)) 471 472 part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0] 473 part2 = glob(os.path.join(self.resultdir, 'temp-*.direct.p2'))[0] 474 475 # Test partition 1, should not contain 'test-file' 476 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part1)) 477 files = extract_files(res.output) 478 self.assertNotIn('test-file', files) 479 self.assertEqual(True, files_own_by_root(res.output)) 480 481 # Test partition 2, should contain 'test-file' 482 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part2)) 483 files = extract_files(res.output) 484 self.assertIn('test-file', files) 485 self.assertEqual(True, files_own_by_root(res.output)) 486 487 finally: 488 os.environ['PATH'] = oldpath 489 490 def test_include_path_embeded(self): 491 """Test --include-path wks option.""" 492 493 oldpath = os.environ['PATH'] 494 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 495 496 try: 497 include_path = os.path.join(self.resultdir, 'test-include') 498 os.makedirs(include_path) 499 with open(os.path.join(include_path, 'test-file'), 'w') as t: 500 t.write("test\n") 501 wks_file = os.path.join(include_path, 'temp.wks') 502 with open(wks_file, 'w') as wks: 503 wks.write(""" 504part / --source rootfs --fstype=ext4 --include-path %s --include-path core-image-minimal-mtdutils export/""" 505 % (include_path)) 506 runCmd("wic create %s -e core-image-minimal -o %s" \ 507 % (wks_file, self.resultdir)) 508 509 part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0] 510 511 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part1)) 512 files = extract_files(res.output) 513 self.assertIn('test-file', files) 514 self.assertEqual(True, files_own_by_root(res.output)) 515 516 res = runCmd("debugfs -R 'ls -p /export/etc/' %s 2>/dev/null" % (part1)) 517 files = extract_files(res.output) 518 self.assertIn('passwd', files) 519 self.assertEqual(True, files_own_by_root(res.output)) 520 521 finally: 522 os.environ['PATH'] = oldpath 523 524 def test_include_path_errors(self): 525 """Test --include-path wks option error handling.""" 526 wks_file = 'temp.wks' 527 528 # Absolute argument. 529 with open(wks_file, 'w') as wks: 530 wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils /export") 531 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 532 % (wks_file, self.resultdir), ignore_status=True).status) 533 os.remove(wks_file) 534 535 # Argument pointing to parent directory. 536 with open(wks_file, 'w') as wks: 537 wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils ././..") 538 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 539 % (wks_file, self.resultdir), ignore_status=True).status) 540 os.remove(wks_file) 541 542 # 3 Argument pointing to parent directory. 543 with open(wks_file, 'w') as wks: 544 wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils export/ dummy") 545 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 546 % (wks_file, self.resultdir), ignore_status=True).status) 547 os.remove(wks_file) 548 549 def test_exclude_path_errors(self): 550 """Test --exclude-path wks option error handling.""" 551 wks_file = 'temp.wks' 552 553 # Absolute argument. 554 with open(wks_file, 'w') as wks: 555 wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path /usr") 556 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 557 % (wks_file, self.resultdir), ignore_status=True).status) 558 os.remove(wks_file) 559 560 # Argument pointing to parent directory. 561 with open(wks_file, 'w') as wks: 562 wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path ././..") 563 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 564 % (wks_file, self.resultdir), ignore_status=True).status) 565 os.remove(wks_file) 566 567 def test_permissions(self): 568 """Test permissions are respected""" 569 570 # prepare wicenv and rootfs 571 bitbake('core-image-minimal core-image-minimal-mtdutils -c do_rootfs_wicenv') 572 573 oldpath = os.environ['PATH'] 574 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 575 576 t_normal = """ 577part / --source rootfs --fstype=ext4 578""" 579 t_exclude = """ 580part / --source rootfs --fstype=ext4 --exclude-path=home 581""" 582 t_multi = """ 583part / --source rootfs --ondisk sda --fstype=ext4 584part /export --source rootfs --rootfs=core-image-minimal-mtdutils --fstype=ext4 585""" 586 t_change = """ 587part / --source rootfs --ondisk sda --fstype=ext4 --exclude-path=etc/ 588part /etc --source rootfs --fstype=ext4 --change-directory=etc 589""" 590 tests = [t_normal, t_exclude, t_multi, t_change] 591 592 try: 593 for test in tests: 594 include_path = os.path.join(self.resultdir, 'test-include') 595 os.makedirs(include_path) 596 wks_file = os.path.join(include_path, 'temp.wks') 597 with open(wks_file, 'w') as wks: 598 wks.write(test) 599 runCmd("wic create %s -e core-image-minimal -o %s" \ 600 % (wks_file, self.resultdir)) 601 602 for part in glob(os.path.join(self.resultdir, 'temp-*.direct.p*')): 603 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part)) 604 self.assertEqual(True, files_own_by_root(res.output)) 605 606 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "%s"\n' % wks_file 607 self.append_config(config) 608 bitbake('core-image-minimal') 609 tmpdir = os.path.join(get_bb_var('WORKDIR', 'core-image-minimal'),'build-wic') 610 611 # check each partition for permission 612 for part in glob(os.path.join(tmpdir, 'temp-*.direct.p*')): 613 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part)) 614 self.assertTrue(files_own_by_root(res.output) 615 ,msg='Files permission incorrect using wks set "%s"' % test) 616 617 # clean config and result directory for next cases 618 self.remove_config(config) 619 rmtree(self.resultdir, ignore_errors=True) 620 621 finally: 622 os.environ['PATH'] = oldpath 623 624 def test_change_directory(self): 625 """Test --change-directory wks option.""" 626 627 oldpath = os.environ['PATH'] 628 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 629 630 try: 631 include_path = os.path.join(self.resultdir, 'test-include') 632 os.makedirs(include_path) 633 wks_file = os.path.join(include_path, 'temp.wks') 634 with open(wks_file, 'w') as wks: 635 wks.write("part /etc --source rootfs --fstype=ext4 --change-directory=etc") 636 runCmd("wic create %s -e core-image-minimal -o %s" \ 637 % (wks_file, self.resultdir)) 638 639 part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0] 640 641 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part1)) 642 files = extract_files(res.output) 643 self.assertIn('passwd', files) 644 645 finally: 646 os.environ['PATH'] = oldpath 647 648 def test_change_directory_errors(self): 649 """Test --change-directory wks option error handling.""" 650 wks_file = 'temp.wks' 651 652 # Absolute argument. 653 with open(wks_file, 'w') as wks: 654 wks.write("part / --source rootfs --fstype=ext4 --change-directory /usr") 655 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 656 % (wks_file, self.resultdir), ignore_status=True).status) 657 os.remove(wks_file) 658 659 # Argument pointing to parent directory. 660 with open(wks_file, 'w') as wks: 661 wks.write("part / --source rootfs --fstype=ext4 --change-directory ././..") 662 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 663 % (wks_file, self.resultdir), ignore_status=True).status) 664 os.remove(wks_file) 665 666 def test_no_fstab_update(self): 667 """Test --no-fstab-update wks option.""" 668 669 oldpath = os.environ['PATH'] 670 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 671 672 # Get stock fstab from base-files recipe 673 bitbake('base-files -c do_install') 674 bf_fstab = os.path.join(get_bb_var('D', 'base-files'), 'etc', 'fstab') 675 self.assertEqual(True, os.path.exists(bf_fstab)) 676 bf_fstab_md5sum = runCmd('md5sum %s 2>/dev/null' % bf_fstab).output.split(" ")[0] 677 678 try: 679 no_fstab_update_path = os.path.join(self.resultdir, 'test-no-fstab-update') 680 os.makedirs(no_fstab_update_path) 681 wks_file = os.path.join(no_fstab_update_path, 'temp.wks') 682 with open(wks_file, 'w') as wks: 683 wks.writelines(['part / --source rootfs --fstype=ext4 --label rootfs\n', 684 'part /mnt/p2 --source rootfs --rootfs-dir=core-image-minimal ', 685 '--fstype=ext4 --label p2 --no-fstab-update\n']) 686 runCmd("wic create %s -e core-image-minimal -o %s" \ 687 % (wks_file, self.resultdir)) 688 689 part_fstab_md5sum = [] 690 for i in range(1, 3): 691 part = glob(os.path.join(self.resultdir, 'temp-*.direct.p') + str(i))[0] 692 part_fstab = runCmd("debugfs -R 'cat etc/fstab' %s 2>/dev/null" % (part)) 693 part_fstab_md5sum.append(hashlib.md5((part_fstab.output + "\n\n").encode('utf-8')).hexdigest()) 694 695 # '/etc/fstab' in partition 2 should contain the same stock fstab file 696 # as the one installed by the base-file recipe. 697 self.assertEqual(bf_fstab_md5sum, part_fstab_md5sum[1]) 698 699 # '/etc/fstab' in partition 1 should contain an updated fstab file. 700 self.assertNotEqual(bf_fstab_md5sum, part_fstab_md5sum[0]) 701 702 finally: 703 os.environ['PATH'] = oldpath 704 705 def test_no_fstab_update_errors(self): 706 """Test --no-fstab-update wks option error handling.""" 707 wks_file = 'temp.wks' 708 709 # Absolute argument. 710 with open(wks_file, 'w') as wks: 711 wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update /etc") 712 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 713 % (wks_file, self.resultdir), ignore_status=True).status) 714 os.remove(wks_file) 715 716 # Argument pointing to parent directory. 717 with open(wks_file, 'w') as wks: 718 wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update ././..") 719 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ 720 % (wks_file, self.resultdir), ignore_status=True).status) 721 os.remove(wks_file) 722 723 def test_extra_space(self): 724 """Test --extra-space wks option.""" 725 extraspace = 1024**3 726 runCmd("wic create wictestdisk " 727 "--image-name core-image-minimal " 728 "--extra-space %i -o %s" % (extraspace ,self.resultdir)) 729 wicout = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 730 self.assertEqual(1, len(wicout)) 731 size = os.path.getsize(wicout[0]) 732 self.assertTrue(size > extraspace, msg="Extra space not present (%s vs %s)" % (size, extraspace)) 733 734 def test_no_table(self): 735 """Test --no-table wks option.""" 736 wks_file = 'temp.wks' 737 738 # Absolute argument. 739 with open(wks_file, 'w') as wks: 740 wks.write("part testspace --no-table --fixed-size 16k --offset 4080k") 741 runCmd("wic create %s --image-name core-image-minimal -o %s" % (wks_file, self.resultdir)) 742 743 wicout = glob(os.path.join(self.resultdir, "*.*")) 744 745 self.assertEqual(1, len(wicout)) 746 size = os.path.getsize(wicout[0]) 747 self.assertEqual(size, 4 * 1024 * 1024) 748 749 os.remove(wks_file) 750 751class Wic2(WicTestCase): 752 753 def test_bmap_short(self): 754 """Test generation of .bmap file -m option""" 755 cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir 756 runCmd(cmd) 757 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 758 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap")))) 759 760 def test_bmap_long(self): 761 """Test generation of .bmap file --bmap option""" 762 cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir 763 runCmd(cmd) 764 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 765 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap")))) 766 767 def test_image_env(self): 768 """Test generation of <image>.env files.""" 769 image = 'core-image-minimal' 770 imgdatadir = self._get_image_env_path(image) 771 772 bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image) 773 basename = bb_vars['IMAGE_BASENAME'] 774 self.assertEqual(basename, image) 775 path = os.path.join(imgdatadir, basename) + '.env' 776 self.assertTrue(os.path.isfile(path), msg="File %s wasn't generated as expected" % path) 777 778 wicvars = set(bb_vars['WICVARS'].split()) 779 # filter out optional variables 780 wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES', 781 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE', 782 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME', 783 'APPEND', 'IMAGE_EFI_BOOT_FILES')) 784 with open(path) as envfile: 785 content = dict(line.split("=", 1) for line in envfile) 786 # test if variables used by wic present in the .env file 787 for var in wicvars: 788 self.assertTrue(var in content, "%s is not in .env file" % var) 789 self.assertTrue(content[var], "%s doesn't have a value (%s)" % (var, content[var])) 790 791 def test_image_vars_dir_short(self): 792 """Test image vars directory selection -v option""" 793 image = 'core-image-minimal' 794 imgenvdir = self._get_image_env_path(image) 795 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 796 797 runCmd("wic create wictestdisk " 798 "--image-name=%s -v %s -n %s -o %s" 799 % (image, imgenvdir, native_sysroot, 800 self.resultdir)) 801 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 802 803 def test_image_vars_dir_long(self): 804 """Test image vars directory selection --vars option""" 805 image = 'core-image-minimal' 806 imgenvdir = self._get_image_env_path(image) 807 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 808 809 runCmd("wic create wictestdisk " 810 "--image-name=%s " 811 "--vars %s " 812 "--native-sysroot %s " 813 "--outdir %s" 814 % (image, imgenvdir, native_sysroot, 815 self.resultdir)) 816 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 817 818 # TODO this test could also work on aarch64 819 @skipIfNotArch(['i586', 'i686', 'x86_64']) 820 def test_wic_image_type(self): 821 """Test building wic images by bitbake""" 822 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ 823 'MACHINE_FEATURES:append = " efi"\n' 824 self.append_config(config) 825 image = 'wic-image-minimal' 826 bitbake(image) 827 self.remove_config(config) 828 829 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image) 830 prefix = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.' % bb_vars['IMAGE_LINK_NAME']) 831 832 # check if we have result image and manifests symlinks 833 # pointing to existing files 834 for suffix in ('wic', 'manifest'): 835 path = prefix + suffix 836 self.assertTrue(os.path.islink(path), msg="Link %s wasn't generated as expected" % path) 837 self.assertTrue(os.path.isfile(os.path.realpath(path)), msg="File linked to by %s wasn't generated as expected" % path) 838 839 # TODO this should work on aarch64 840 @skipIfNotArch(['i586', 'i686', 'x86_64']) 841 @OETestTag("runqemu") 842 def test_qemu(self): 843 """Test wic-image-minimal under qemu""" 844 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ 845 'MACHINE_FEATURES:append = " efi"\n' 846 self.append_config(config) 847 bitbake('wic-image-minimal') 848 self.remove_config(config) 849 850 with runqemu('wic-image-minimal', ssh=False, runqemuparams='nographic') as qemu: 851 cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' " \ 852 "-e '/dev/root /|/dev/sda2 /' -e '/dev/sda3 /media' -e '/dev/sda4 /mnt'" 853 status, output = qemu.run_serial(cmd) 854 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 855 self.assertEqual(output, '4') 856 cmd = "grep UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba /etc/fstab" 857 status, output = qemu.run_serial(cmd) 858 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 859 self.assertEqual(output, 'UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba\t/media\text4\tdefaults\t0\t0') 860 861 @skipIfNotArch(['i586', 'i686', 'x86_64']) 862 @OETestTag("runqemu") 863 def test_qemu_efi(self): 864 """Test core-image-minimal efi image under qemu""" 865 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n' 866 self.append_config(config) 867 bitbake('core-image-minimal ovmf') 868 self.remove_config(config) 869 870 with runqemu('core-image-minimal', ssh=False, 871 runqemuparams='nographic ovmf', image_fstype='wic') as qemu: 872 cmd = "grep sda. /proc/partitions |wc -l" 873 status, output = qemu.run_serial(cmd) 874 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 875 self.assertEqual(output, '3') 876 877 @staticmethod 878 def _make_fixed_size_wks(size): 879 """ 880 Create a wks of an image with a single partition. Size of the partition is set 881 using --fixed-size flag. Returns a tuple: (path to wks file, wks image name) 882 """ 883 with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf: 884 wkspath = tempf.name 885 tempf.write("part " \ 886 "--source rootfs --ondisk hda --align 4 --fixed-size %d " 887 "--fstype=ext4\n" % size) 888 889 return wkspath 890 891 def _get_wic_partitions(self, wkspath, native_sysroot=None, ignore_status=False): 892 p = runCmd("wic create %s -e core-image-minimal -o %s" % (wkspath, self.resultdir), 893 ignore_status=ignore_status) 894 895 if p.status: 896 return (p, None) 897 898 wksname = os.path.splitext(os.path.basename(wkspath))[0] 899 900 wicout = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 901 902 if not wicout: 903 return (p, None) 904 905 wicimg = wicout[0] 906 907 if not native_sysroot: 908 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 909 910 # verify partition size with wic 911 res = runCmd("parted -m %s unit kib p 2>/dev/null" % wicimg, 912 native_sysroot=native_sysroot) 913 914 # parse parted output which looks like this: 915 # BYT;\n 916 # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n 917 # 1:0.00MiB:200MiB:200MiB:ext4::;\n 918 return (p, res.output.splitlines()[2:]) 919 920 def test_fixed_size(self): 921 """ 922 Test creation of a simple image with partition size controlled through 923 --fixed-size flag 924 """ 925 wkspath = Wic2._make_fixed_size_wks(200) 926 _, partlns = self._get_wic_partitions(wkspath) 927 os.remove(wkspath) 928 929 self.assertEqual(partlns, [ 930 "1:4.00kiB:204804kiB:204800kiB:ext4::;", 931 ]) 932 933 def test_fixed_size_error(self): 934 """ 935 Test creation of a simple image with partition size controlled through 936 --fixed-size flag. The size of partition is intentionally set to 1MiB 937 in order to trigger an error in wic. 938 """ 939 wkspath = Wic2._make_fixed_size_wks(1) 940 p, _ = self._get_wic_partitions(wkspath, ignore_status=True) 941 os.remove(wkspath) 942 943 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output) 944 945 def test_offset(self): 946 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 947 948 with NamedTemporaryFile("w", suffix=".wks") as tempf: 949 # Test that partitions are placed at the correct offsets, default KB 950 tempf.write("bootloader --ptable gpt\n" \ 951 "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \ 952 "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n") 953 tempf.flush() 954 955 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 956 self.assertEqual(partlns, [ 957 "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;", 958 "2:102432kiB:204832kiB:102400kiB:ext4:primary:;", 959 ]) 960 961 with NamedTemporaryFile("w", suffix=".wks") as tempf: 962 # Test that partitions are placed at the correct offsets, same with explicit KB 963 tempf.write("bootloader --ptable gpt\n" \ 964 "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \ 965 "part /bar --ondisk hda --offset 102432K --fixed-size 100M --fstype=ext4\n") 966 tempf.flush() 967 968 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 969 self.assertEqual(partlns, [ 970 "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;", 971 "2:102432kiB:204832kiB:102400kiB:ext4:primary:;", 972 ]) 973 974 with NamedTemporaryFile("w", suffix=".wks") as tempf: 975 # Test that partitions are placed at the correct offsets using MB 976 tempf.write("bootloader --ptable gpt\n" \ 977 "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \ 978 "part /bar --ondisk hda --offset 101M --fixed-size 100M --fstype=ext4\n") 979 tempf.flush() 980 981 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 982 self.assertEqual(partlns, [ 983 "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;", 984 "2:103424kiB:205824kiB:102400kiB:ext4:primary:;", 985 ]) 986 987 with NamedTemporaryFile("w", suffix=".wks") as tempf: 988 # Test that partitions can be placed on a 512 byte sector boundary 989 tempf.write("bootloader --ptable gpt\n" \ 990 "part / --source rootfs --ondisk hda --offset 65s --fixed-size 99M --fstype=ext4\n" \ 991 "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n") 992 tempf.flush() 993 994 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 995 self.assertEqual(partlns, [ 996 "1:32.5kiB:101408kiB:101376kiB:ext4:primary:;", 997 "2:102432kiB:204832kiB:102400kiB:ext4:primary:;", 998 ]) 999 1000 with NamedTemporaryFile("w", suffix=".wks") as tempf: 1001 # Test that a partition can be placed immediately after a MSDOS partition table 1002 tempf.write("bootloader --ptable msdos\n" \ 1003 "part / --source rootfs --ondisk hda --offset 1s --fixed-size 100M --fstype=ext4\n") 1004 tempf.flush() 1005 1006 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 1007 self.assertEqual(partlns, [ 1008 "1:0.50kiB:102400kiB:102400kiB:ext4::;", 1009 ]) 1010 1011 with NamedTemporaryFile("w", suffix=".wks") as tempf: 1012 # Test that image creation fails if the partitions would overlap 1013 tempf.write("bootloader --ptable gpt\n" \ 1014 "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \ 1015 "part /bar --ondisk hda --offset 102431 --fixed-size 100M --fstype=ext4\n") 1016 tempf.flush() 1017 1018 p, _ = self._get_wic_partitions(tempf.name, ignore_status=True) 1019 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output) 1020 1021 with NamedTemporaryFile("w", suffix=".wks") as tempf: 1022 # Test that partitions are not allowed to overlap with the booloader 1023 tempf.write("bootloader --ptable gpt\n" \ 1024 "part / --source rootfs --ondisk hda --offset 8 --fixed-size 100M --fstype=ext4\n") 1025 tempf.flush() 1026 1027 p, _ = self._get_wic_partitions(tempf.name, ignore_status=True) 1028 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output) 1029 1030 def test_extra_space(self): 1031 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 1032 1033 with NamedTemporaryFile("w", suffix=".wks") as tempf: 1034 tempf.write("bootloader --ptable gpt\n" \ 1035 "part / --source rootfs --ondisk hda --extra-space 200M --fstype=ext4\n") 1036 tempf.flush() 1037 1038 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 1039 self.assertEqual(len(partlns), 1) 1040 size = partlns[0].split(':')[3] 1041 self.assertRegex(size, r'^[0-9]+kiB$') 1042 size = int(size[:-3]) 1043 self.assertGreaterEqual(size, 204800) 1044 1045 # TODO this test could also work on aarch64 1046 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1047 @OETestTag("runqemu") 1048 def test_rawcopy_plugin_qemu(self): 1049 """Test rawcopy plugin in qemu""" 1050 # build ext4 and then use it for a wic image 1051 config = 'IMAGE_FSTYPES = "ext4"\n' 1052 self.append_config(config) 1053 bitbake('core-image-minimal') 1054 image_link_name = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal') 1055 self.remove_config(config) 1056 1057 config = 'IMAGE_FSTYPES = "wic"\n' \ 1058 'IMAGE_LINK_NAME_CORE_IMAGE_MINIMAL = "%s"\n'\ 1059 'WKS_FILE = "test_rawcopy_plugin.wks.in"\n'\ 1060 % image_link_name 1061 self.append_config(config) 1062 bitbake('core-image-minimal-mtdutils') 1063 self.remove_config(config) 1064 1065 with runqemu('core-image-minimal-mtdutils', ssh=False, 1066 runqemuparams='nographic', image_fstype='wic') as qemu: 1067 cmd = "grep sda. /proc/partitions |wc -l" 1068 status, output = qemu.run_serial(cmd) 1069 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1070 self.assertEqual(output, '2') 1071 1072 def _rawcopy_plugin(self, fstype): 1073 """Test rawcopy plugin""" 1074 image = 'core-image-minimal' 1075 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image) 1076 params = ',unpack' if fstype.endswith('.gz') else '' 1077 with NamedTemporaryFile("w", suffix=".wks") as wks: 1078 wks.write('part / --source rawcopy --sourceparams="file=%s.%s%s"\n'\ 1079 % (bb_vars['IMAGE_LINK_NAME'], fstype, params)) 1080 wks.flush() 1081 cmd = "wic create %s -e %s -o %s" % (wks.name, image, self.resultdir) 1082 runCmd(cmd) 1083 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1084 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1085 self.assertEqual(1, len(out)) 1086 1087 def test_rawcopy_plugin(self): 1088 self._rawcopy_plugin('ext4') 1089 1090 def test_rawcopy_plugin_unpack(self): 1091 fstype = 'ext4.gz' 1092 config = 'IMAGE_FSTYPES = "%s"\n' % fstype 1093 self.append_config(config) 1094 self.assertEqual(0, bitbake('core-image-minimal').status) 1095 self.remove_config(config) 1096 self._rawcopy_plugin(fstype) 1097 1098 def test_empty_plugin(self): 1099 """Test empty plugin""" 1100 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_empty_plugin.wks"\n' 1101 self.append_config(config) 1102 image = 'core-image-minimal' 1103 bitbake(image) 1104 self.remove_config(config) 1105 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image) 1106 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME']) 1107 self.assertTrue(os.path.exists(image_path), msg="Image file %s wasn't generated as expected" % image_path) 1108 1109 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1110 1111 # Fstype column from 'wic ls' should be empty for the second partition 1112 # as listed in test_empty_plugin.wks 1113 result = runCmd("wic ls %s -n %s | awk -F ' ' '{print $1 \" \" $5}' | grep '^2' | wc -w" % (image_path, sysroot)) 1114 self.assertEqual('1', result.output) 1115 1116 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1117 @OETestTag("runqemu") 1118 def test_biosplusefi_plugin_qemu(self): 1119 """Test biosplusefi plugin in qemu""" 1120 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n' 1121 self.append_config(config) 1122 bitbake('core-image-minimal') 1123 self.remove_config(config) 1124 1125 with runqemu('core-image-minimal', ssh=False, 1126 runqemuparams='nographic', image_fstype='wic') as qemu: 1127 # Check that we have ONLY two /dev/sda* partitions (/boot and /) 1128 cmd = "grep sda. /proc/partitions | wc -l" 1129 status, output = qemu.run_serial(cmd) 1130 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1131 self.assertEqual(output, '2') 1132 # Check that /dev/sda1 is /boot and that either /dev/root OR /dev/sda2 is / 1133 cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' -e '/dev/root /|/dev/sda2 /'" 1134 status, output = qemu.run_serial(cmd) 1135 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1136 self.assertEqual(output, '2') 1137 # Check that /boot has EFI bootx64.efi (required for EFI) 1138 cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l" 1139 status, output = qemu.run_serial(cmd) 1140 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1141 self.assertEqual(output, '1') 1142 # Check that "BOOTABLE" flag is set on boot partition (required for PC-Bios) 1143 # Trailing "cat" seems to be required; otherwise run_serial() sends back echo of the input command 1144 cmd = "fdisk -l /dev/sda | grep /dev/sda1 | awk {print'$2'} | cat" 1145 status, output = qemu.run_serial(cmd) 1146 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1147 self.assertEqual(output, '*') 1148 1149 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1150 def test_biosplusefi_plugin(self): 1151 """Test biosplusefi plugin""" 1152 # Wic generation below may fail depending on the order of the unittests 1153 # This is because bootimg-pcbios (that bootimg-biosplusefi uses) generate its MBR inside STAGING_DATADIR directory 1154 # which may or may not exists depending on what was built already 1155 # If an image hasn't been built yet, directory ${STAGING_DATADIR}/syslinux won't exists and _get_bootimg_dir() 1156 # will raise with "Couldn't find correct bootimg_dir" 1157 # The easiest way to work-around this issue is to make sure we already built an image here, hence the bitbake call 1158 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n' 1159 self.append_config(config) 1160 bitbake('core-image-minimal') 1161 self.remove_config(config) 1162 1163 img = 'core-image-minimal' 1164 with NamedTemporaryFile("w", suffix=".wks") as wks: 1165 wks.writelines(['part /boot --active --source bootimg-biosplusefi --sourceparams="loader=grub-efi"\n', 1166 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\ 1167 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n']) 1168 wks.flush() 1169 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1170 runCmd(cmd) 1171 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1172 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname)) 1173 self.assertEqual(1, len(out)) 1174 1175 @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64']) 1176 def test_uefi_kernel(self): 1177 """ Test uefi-kernel in wic """ 1178 config = 'IMAGE_EFI_BOOT_FILES="/etc/fstab;testfile"\nIMAGE_FSTYPES = "wic"\nWKS_FILE = "test_uefikernel.wks"\nMACHINE_FEATURES:append = " efi"\n' 1179 self.append_config(config) 1180 bitbake('core-image-minimal') 1181 self.remove_config(config) 1182 1183 img = 'core-image-minimal' 1184 with NamedTemporaryFile("w", suffix=".wks") as wks: 1185 wks.writelines(['part /boot --source bootimg-efi --sourceparams="loader=uefi-kernel"\n' 1186 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\ 1187 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n']) 1188 wks.flush() 1189 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1190 runCmd(cmd) 1191 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1192 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname)) 1193 self.assertEqual(1, len(out)) 1194 1195 # TODO this test could also work on aarch64 1196 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1197 @OETestTag("runqemu") 1198 def test_efi_plugin_unified_kernel_image_qemu(self): 1199 """Test efi plugin's Unified Kernel Image feature in qemu""" 1200 config = 'IMAGE_FSTYPES = "wic"\n'\ 1201 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\ 1202 'WKS_FILE = "test_efi_plugin.wks"\n'\ 1203 'MACHINE_FEATURES:append = " efi"\n' 1204 self.append_config(config) 1205 bitbake('core-image-minimal core-image-minimal-initramfs ovmf') 1206 self.remove_config(config) 1207 1208 with runqemu('core-image-minimal', ssh=False, 1209 runqemuparams='nographic ovmf', image_fstype='wic') as qemu: 1210 # Check that /boot has EFI bootx64.efi (required for EFI) 1211 cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l" 1212 status, output = qemu.run_serial(cmd) 1213 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1214 self.assertEqual(output, '1') 1215 # Check that /boot has EFI/Linux/linux.efi (required for Unified Kernel Images auto detection) 1216 cmd = "ls /boot/EFI/Linux/linux.efi | wc -l" 1217 status, output = qemu.run_serial(cmd) 1218 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1219 self.assertEqual(output, '1') 1220 # Check that /boot doesn't have loader/entries/boot.conf (Unified Kernel Images are auto detected by the bootloader) 1221 cmd = "ls /boot/loader/entries/boot.conf 2&>/dev/null | wc -l" 1222 status, output = qemu.run_serial(cmd) 1223 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1224 self.assertEqual(output, '0') 1225 1226 def test_fs_types(self): 1227 """Test filesystem types for empty and not empty partitions""" 1228 img = 'core-image-minimal' 1229 with NamedTemporaryFile("w", suffix=".wks") as wks: 1230 wks.writelines(['part ext2 --fstype ext2 --source rootfs\n', 1231 'part btrfs --fstype btrfs --source rootfs --size 40M\n', 1232 'part squash --fstype squashfs --source rootfs\n', 1233 'part swap --fstype swap --size 1M\n', 1234 'part emptyvfat --fstype vfat --size 1M\n', 1235 'part emptymsdos --fstype msdos --size 1M\n', 1236 'part emptyext2 --fstype ext2 --size 1M\n', 1237 'part emptybtrfs --fstype btrfs --size 150M\n']) 1238 wks.flush() 1239 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1240 runCmd(cmd) 1241 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1242 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1243 self.assertEqual(1, len(out)) 1244 1245 def test_kickstart_parser(self): 1246 """Test wks parser options""" 1247 with NamedTemporaryFile("w", suffix=".wks") as wks: 1248 wks.writelines(['part / --fstype ext3 --source rootfs --system-id 0xFF '\ 1249 '--overhead-factor 1.2 --size 100k\n']) 1250 wks.flush() 1251 cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir) 1252 runCmd(cmd) 1253 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1254 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1255 self.assertEqual(1, len(out)) 1256 1257 def test_image_bootpart_globbed(self): 1258 """Test globbed sources with image-bootpart plugin""" 1259 img = "core-image-minimal" 1260 cmd = "wic create sdimage-bootpart -e %s -o %s" % (img, self.resultdir) 1261 config = 'IMAGE_BOOT_FILES = "%s*"' % get_bb_var('KERNEL_IMAGETYPE', img) 1262 self.append_config(config) 1263 runCmd(cmd) 1264 self.remove_config(config) 1265 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct")))) 1266 1267 def test_sparse_copy(self): 1268 """Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs""" 1269 libpath = os.path.join(self.td['COREBASE'], 'scripts', 'lib', 'wic') 1270 sys.path.insert(0, libpath) 1271 from filemap import FilemapFiemap, FilemapSeek, sparse_copy, ErrorNotSupp 1272 with NamedTemporaryFile("w", suffix=".wic-sparse") as sparse: 1273 src_name = sparse.name 1274 src_size = 1024 * 10 1275 sparse.truncate(src_size) 1276 # write one byte to the file 1277 with open(src_name, 'r+b') as sfile: 1278 sfile.seek(1024 * 4) 1279 sfile.write(b'\x00') 1280 dest = sparse.name + '.out' 1281 # copy src file to dest using different filemap APIs 1282 for api in (FilemapFiemap, FilemapSeek, None): 1283 if os.path.exists(dest): 1284 os.unlink(dest) 1285 try: 1286 sparse_copy(sparse.name, dest, api=api) 1287 except ErrorNotSupp: 1288 continue # skip unsupported API 1289 dest_stat = os.stat(dest) 1290 self.assertEqual(dest_stat.st_size, src_size) 1291 # 8 blocks is 4K (physical sector size) 1292 self.assertEqual(dest_stat.st_blocks, 8) 1293 os.unlink(dest) 1294 1295 def test_mkfs_extraopts(self): 1296 """Test wks option --mkfs-extraopts for empty and not empty partitions""" 1297 img = 'core-image-minimal' 1298 with NamedTemporaryFile("w", suffix=".wks") as wks: 1299 wks.writelines( 1300 ['part ext2 --fstype ext2 --source rootfs --mkfs-extraopts "-D -F -i 8192"\n', 1301 "part btrfs --fstype btrfs --source rootfs --size 40M --mkfs-extraopts='--quiet'\n", 1302 'part squash --fstype squashfs --source rootfs --mkfs-extraopts "-no-sparse -b 4096"\n', 1303 'part emptyvfat --fstype vfat --size 1M --mkfs-extraopts "-S 1024 -s 64"\n', 1304 'part emptymsdos --fstype msdos --size 1M --mkfs-extraopts "-S 1024 -s 64"\n', 1305 'part emptyext2 --fstype ext2 --size 1M --mkfs-extraopts "-D -F -i 8192"\n', 1306 'part emptybtrfs --fstype btrfs --size 100M --mkfs-extraopts "--mixed -K"\n']) 1307 wks.flush() 1308 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1309 runCmd(cmd) 1310 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1311 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1312 self.assertEqual(1, len(out)) 1313 1314 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1315 @OETestTag("runqemu") 1316 def test_expand_mbr_image(self): 1317 """Test wic write --expand command for mbr image""" 1318 # build an image 1319 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "directdisk.wks"\n' 1320 self.append_config(config) 1321 image = 'core-image-minimal' 1322 bitbake(image) 1323 1324 # get path to the image 1325 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image) 1326 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME']) 1327 1328 self.remove_config(config) 1329 1330 try: 1331 # expand image to 1G 1332 new_image_path = None 1333 with NamedTemporaryFile(mode='wb', suffix='.wic.exp', 1334 dir=bb_vars['DEPLOY_DIR_IMAGE'], delete=False) as sparse: 1335 sparse.truncate(1024 ** 3) 1336 new_image_path = sparse.name 1337 1338 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1339 cmd = "wic write -n %s --expand 1:0 %s %s" % (sysroot, image_path, new_image_path) 1340 runCmd(cmd) 1341 1342 # check if partitions are expanded 1343 orig = runCmd("wic ls %s -n %s" % (image_path, sysroot)) 1344 exp = runCmd("wic ls %s -n %s" % (new_image_path, sysroot)) 1345 orig_sizes = [int(line.split()[3]) for line in orig.output.split('\n')[1:]] 1346 exp_sizes = [int(line.split()[3]) for line in exp.output.split('\n')[1:]] 1347 self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized 1348 self.assertTrue(orig_sizes[1] < exp_sizes[1], msg="Parition size wasn't enlarged (%s vs %s)" % (orig_sizes[1], exp_sizes[1])) 1349 1350 # Check if all free space is partitioned 1351 result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path)) 1352 self.assertIn("0 B, 0 bytes, 0 sectors", result.output) 1353 1354 os.rename(image_path, image_path + '.bak') 1355 os.rename(new_image_path, image_path) 1356 1357 # Check if it boots in qemu 1358 with runqemu('core-image-minimal', ssh=False, runqemuparams='nographic') as qemu: 1359 cmd = "ls /etc/" 1360 status, output = qemu.run_serial('true') 1361 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1362 finally: 1363 if os.path.exists(new_image_path): 1364 os.unlink(new_image_path) 1365 if os.path.exists(image_path + '.bak'): 1366 os.rename(image_path + '.bak', image_path) 1367 1368 def test_gpt_partition_name(self): 1369 """Test --part-name argument to set partition name in GPT table""" 1370 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "test_gpt_partition_name.wks"\n' 1371 self.append_config(config) 1372 image = 'core-image-minimal' 1373 bitbake(image) 1374 self.remove_config(config) 1375 deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') 1376 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image) 1377 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME']) 1378 1379 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1380 1381 # Image is created 1382 self.assertTrue(os.path.exists(image_path), "image file %s doesn't exist" % image_path) 1383 1384 # Check the names of the three partitions 1385 # as listed in test_gpt_partition_name.wks 1386 result = runCmd("%s/usr/sbin/sfdisk --part-label %s 1" % (sysroot, image_path)) 1387 self.assertEqual('boot-A', result.output) 1388 result = runCmd("%s/usr/sbin/sfdisk --part-label %s 2" % (sysroot, image_path)) 1389 self.assertEqual('root-A', result.output) 1390 # When the --part-name is not defined, the partition name is equal to the --label 1391 result = runCmd("%s/usr/sbin/sfdisk --part-label %s 3" % (sysroot, image_path)) 1392 self.assertEqual('ext-space', result.output) 1393 1394class ModifyTests(WicTestCase): 1395 def test_wic_ls(self): 1396 """Test listing image content using 'wic ls'""" 1397 runCmd("wic create wictestdisk " 1398 "--image-name=core-image-minimal " 1399 "-D -o %s" % self.resultdir) 1400 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1401 self.assertEqual(1, len(images)) 1402 1403 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1404 1405 # list partitions 1406 result = runCmd("wic ls %s -n %s" % (images[0], sysroot)) 1407 self.assertEqual(3, len(result.output.split('\n'))) 1408 1409 # list directory content of the first partition 1410 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1411 self.assertEqual(6, len(result.output.split('\n'))) 1412 1413 def test_wic_cp(self): 1414 """Test copy files and directories to the the wic image.""" 1415 runCmd("wic create wictestdisk " 1416 "--image-name=core-image-minimal " 1417 "-D -o %s" % self.resultdir) 1418 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1419 self.assertEqual(1, len(images)) 1420 1421 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1422 1423 # list directory content of the first partition 1424 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1425 self.assertEqual(6, len(result.output.split('\n'))) 1426 1427 with NamedTemporaryFile("w", suffix=".wic-cp") as testfile: 1428 testfile.write("test") 1429 1430 # copy file to the partition 1431 runCmd("wic cp %s %s:1/ -n %s" % (testfile.name, images[0], sysroot)) 1432 1433 # check if file is there 1434 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1435 self.assertEqual(7, len(result.output.split('\n'))) 1436 self.assertIn(os.path.basename(testfile.name), result.output) 1437 1438 # prepare directory 1439 testdir = os.path.join(self.resultdir, 'wic-test-cp-dir') 1440 testsubdir = os.path.join(testdir, 'subdir') 1441 os.makedirs(os.path.join(testsubdir)) 1442 copy(testfile.name, testdir) 1443 1444 # copy directory to the partition 1445 runCmd("wic cp %s %s:1/ -n %s" % (testdir, images[0], sysroot)) 1446 1447 # check if directory is there 1448 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1449 self.assertEqual(8, len(result.output.split('\n'))) 1450 self.assertIn(os.path.basename(testdir), result.output) 1451 1452 # copy the file from the partition and check if it success 1453 dest = '%s-cp' % testfile.name 1454 runCmd("wic cp %s:1/%s %s -n %s" % (images[0], 1455 os.path.basename(testfile.name), dest, sysroot)) 1456 self.assertTrue(os.path.exists(dest), msg="File %s wasn't generated as expected" % dest) 1457 1458 1459 def test_wic_rm(self): 1460 """Test removing files and directories from the the wic image.""" 1461 runCmd("wic create mkefidisk " 1462 "--image-name=core-image-minimal " 1463 "-D -o %s" % self.resultdir) 1464 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct")) 1465 self.assertEqual(1, len(images)) 1466 1467 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1468 # Not bulletproof but hopefully sufficient 1469 kerneltype = get_bb_var('KERNEL_IMAGETYPE', 'virtual/kernel') 1470 1471 # list directory content of the first partition 1472 result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot)) 1473 self.assertIn('\n%s ' % kerneltype.upper(), result.output) 1474 self.assertIn('\nEFI <DIR> ', result.output) 1475 1476 # remove file. EFI partitions are case-insensitive so exercise that too 1477 runCmd("wic rm %s:1/%s -n %s" % (images[0], kerneltype.lower(), sysroot)) 1478 1479 # remove directory 1480 runCmd("wic rm %s:1/efi -n %s" % (images[0], sysroot)) 1481 1482 # check if they're removed 1483 result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot)) 1484 self.assertNotIn('\n%s ' % kerneltype.upper(), result.output) 1485 self.assertNotIn('\nEFI <DIR> ', result.output) 1486 1487 def test_wic_ls_ext(self): 1488 """Test listing content of the ext partition using 'wic ls'""" 1489 runCmd("wic create wictestdisk " 1490 "--image-name=core-image-minimal " 1491 "-D -o %s" % self.resultdir) 1492 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1493 self.assertEqual(1, len(images)) 1494 1495 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1496 1497 # list directory content of the second ext4 partition 1498 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1499 self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset( 1500 set(line.split()[-1] for line in result.output.split('\n') if line)), msg="Expected directories not present %s" % result.output) 1501 1502 def test_wic_cp_ext(self): 1503 """Test copy files and directories to the ext partition.""" 1504 runCmd("wic create wictestdisk " 1505 "--image-name=core-image-minimal " 1506 "-D -o %s" % self.resultdir) 1507 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1508 self.assertEqual(1, len(images)) 1509 1510 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1511 1512 # list directory content of the ext4 partition 1513 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1514 dirs = set(line.split()[-1] for line in result.output.split('\n') if line) 1515 self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs), msg="Expected directories not present %s" % dirs) 1516 1517 with NamedTemporaryFile("w", suffix=".wic-cp") as testfile: 1518 testfile.write("test") 1519 1520 # copy file to the partition 1521 runCmd("wic cp %s %s:2/ -n %s" % (testfile.name, images[0], sysroot)) 1522 1523 # check if file is there 1524 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1525 newdirs = set(line.split()[-1] for line in result.output.split('\n') if line) 1526 self.assertEqual(newdirs.difference(dirs), set([os.path.basename(testfile.name)])) 1527 1528 # check if the file to copy is in the partition 1529 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot)) 1530 self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line]) 1531 1532 # copy file from the partition, replace the temporary file content with it and 1533 # check for the file size to validate the copy 1534 runCmd("wic cp %s:2/etc/fstab %s -n %s" % (images[0], testfile.name, sysroot)) 1535 self.assertTrue(os.stat(testfile.name).st_size > 0, msg="Filesize not as expected %s" % os.stat(testfile.name).st_size) 1536 1537 1538 def test_wic_rm_ext(self): 1539 """Test removing files from the ext partition.""" 1540 runCmd("wic create mkefidisk " 1541 "--image-name=core-image-minimal " 1542 "-D -o %s" % self.resultdir) 1543 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct")) 1544 self.assertEqual(1, len(images)) 1545 1546 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1547 1548 # list directory content of the /etc directory on ext4 partition 1549 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot)) 1550 self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line]) 1551 1552 # remove file 1553 runCmd("wic rm %s:2/etc/fstab -n %s" % (images[0], sysroot)) 1554 1555 # check if it's removed 1556 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot)) 1557 self.assertNotIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line]) 1558 1559 # remove non-empty directory 1560 runCmd("wic rm -r %s:2/etc/ -n %s" % (images[0], sysroot)) 1561 1562 # check if it's removed 1563 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1564 self.assertNotIn('etc', [line.split()[-1] for line in result.output.split('\n') if line]) 1565