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) 733 734class Wic2(WicTestCase): 735 736 def test_bmap_short(self): 737 """Test generation of .bmap file -m option""" 738 cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir 739 runCmd(cmd) 740 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 741 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap")))) 742 743 def test_bmap_long(self): 744 """Test generation of .bmap file --bmap option""" 745 cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir 746 runCmd(cmd) 747 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 748 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap")))) 749 750 def test_image_env(self): 751 """Test generation of <image>.env files.""" 752 image = 'core-image-minimal' 753 imgdatadir = self._get_image_env_path(image) 754 755 bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image) 756 basename = bb_vars['IMAGE_BASENAME'] 757 self.assertEqual(basename, image) 758 path = os.path.join(imgdatadir, basename) + '.env' 759 self.assertTrue(os.path.isfile(path)) 760 761 wicvars = set(bb_vars['WICVARS'].split()) 762 # filter out optional variables 763 wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES', 764 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE', 765 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME', 766 'APPEND', 'IMAGE_EFI_BOOT_FILES')) 767 with open(path) as envfile: 768 content = dict(line.split("=", 1) for line in envfile) 769 # test if variables used by wic present in the .env file 770 for var in wicvars: 771 self.assertTrue(var in content, "%s is not in .env file" % var) 772 self.assertTrue(content[var]) 773 774 def test_image_vars_dir_short(self): 775 """Test image vars directory selection -v option""" 776 image = 'core-image-minimal' 777 imgenvdir = self._get_image_env_path(image) 778 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 779 780 runCmd("wic create wictestdisk " 781 "--image-name=%s -v %s -n %s -o %s" 782 % (image, imgenvdir, native_sysroot, 783 self.resultdir)) 784 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 785 786 def test_image_vars_dir_long(self): 787 """Test image vars directory selection --vars option""" 788 image = 'core-image-minimal' 789 imgenvdir = self._get_image_env_path(image) 790 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 791 792 runCmd("wic create wictestdisk " 793 "--image-name=%s " 794 "--vars %s " 795 "--native-sysroot %s " 796 "--outdir %s" 797 % (image, imgenvdir, native_sysroot, 798 self.resultdir)) 799 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct")))) 800 801 # TODO this test could also work on aarch64 802 @skipIfNotArch(['i586', 'i686', 'x86_64']) 803 def test_wic_image_type(self): 804 """Test building wic images by bitbake""" 805 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ 806 'MACHINE_FEATURES:append = " efi"\n' 807 self.append_config(config) 808 bitbake('wic-image-minimal') 809 self.remove_config(config) 810 811 deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') 812 machine = self.td['MACHINE'] 813 prefix = os.path.join(deploy_dir, 'wic-image-minimal-%s.' % machine) 814 # check if we have result image and manifests symlinks 815 # pointing to existing files 816 for suffix in ('wic', 'manifest'): 817 path = prefix + suffix 818 self.assertTrue(os.path.islink(path)) 819 self.assertTrue(os.path.isfile(os.path.realpath(path))) 820 821 # TODO this should work on aarch64 822 @skipIfNotArch(['i586', 'i686', 'x86_64']) 823 @OETestTag("runqemu") 824 def test_qemu(self): 825 """Test wic-image-minimal under qemu""" 826 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ 827 'MACHINE_FEATURES:append = " efi"\n' 828 self.append_config(config) 829 bitbake('wic-image-minimal') 830 self.remove_config(config) 831 832 with runqemu('wic-image-minimal', ssh=False, runqemuparams='nographic') as qemu: 833 cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' " \ 834 "-e '/dev/root /|/dev/sda2 /' -e '/dev/sda3 /media' -e '/dev/sda4 /mnt'" 835 status, output = qemu.run_serial(cmd) 836 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 837 self.assertEqual(output, '4') 838 cmd = "grep UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba /etc/fstab" 839 status, output = qemu.run_serial(cmd) 840 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 841 self.assertEqual(output, 'UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba\t/media\text4\tdefaults\t0\t0') 842 843 @skipIfNotArch(['i586', 'i686', 'x86_64']) 844 @OETestTag("runqemu") 845 def test_qemu_efi(self): 846 """Test core-image-minimal efi image under qemu""" 847 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n' 848 self.append_config(config) 849 bitbake('core-image-minimal ovmf') 850 self.remove_config(config) 851 852 with runqemu('core-image-minimal', ssh=False, 853 runqemuparams='nographic ovmf', image_fstype='wic') as qemu: 854 cmd = "grep sda. /proc/partitions |wc -l" 855 status, output = qemu.run_serial(cmd) 856 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 857 self.assertEqual(output, '3') 858 859 @staticmethod 860 def _make_fixed_size_wks(size): 861 """ 862 Create a wks of an image with a single partition. Size of the partition is set 863 using --fixed-size flag. Returns a tuple: (path to wks file, wks image name) 864 """ 865 with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf: 866 wkspath = tempf.name 867 tempf.write("part " \ 868 "--source rootfs --ondisk hda --align 4 --fixed-size %d " 869 "--fstype=ext4\n" % size) 870 871 return wkspath 872 873 def _get_wic_partitions(self, wkspath, native_sysroot=None, ignore_status=False): 874 p = runCmd("wic create %s -e core-image-minimal -o %s" % (wkspath, self.resultdir), 875 ignore_status=ignore_status) 876 877 if p.status: 878 return (p, None) 879 880 wksname = os.path.splitext(os.path.basename(wkspath))[0] 881 882 wicout = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 883 884 if not wicout: 885 return (p, None) 886 887 wicimg = wicout[0] 888 889 if not native_sysroot: 890 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 891 892 # verify partition size with wic 893 res = runCmd("parted -m %s unit kib p 2>/dev/null" % wicimg, 894 native_sysroot=native_sysroot) 895 896 # parse parted output which looks like this: 897 # BYT;\n 898 # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n 899 # 1:0.00MiB:200MiB:200MiB:ext4::;\n 900 return (p, res.output.splitlines()[2:]) 901 902 def test_fixed_size(self): 903 """ 904 Test creation of a simple image with partition size controlled through 905 --fixed-size flag 906 """ 907 wkspath = Wic2._make_fixed_size_wks(200) 908 _, partlns = self._get_wic_partitions(wkspath) 909 os.remove(wkspath) 910 911 self.assertEqual(partlns, [ 912 "1:4.00kiB:204804kiB:204800kiB:ext4::;", 913 ]) 914 915 def test_fixed_size_error(self): 916 """ 917 Test creation of a simple image with partition size controlled through 918 --fixed-size flag. The size of partition is intentionally set to 1MiB 919 in order to trigger an error in wic. 920 """ 921 wkspath = Wic2._make_fixed_size_wks(1) 922 p, _ = self._get_wic_partitions(wkspath, ignore_status=True) 923 os.remove(wkspath) 924 925 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output) 926 927 def test_offset(self): 928 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 929 930 with NamedTemporaryFile("w", suffix=".wks") as tempf: 931 # Test that partitions are placed at the correct offsets, default KB 932 tempf.write("bootloader --ptable gpt\n" \ 933 "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \ 934 "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n") 935 tempf.flush() 936 937 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 938 self.assertEqual(partlns, [ 939 "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;", 940 "2:102432kiB:204832kiB:102400kiB:ext4:primary:;", 941 ]) 942 943 with NamedTemporaryFile("w", suffix=".wks") as tempf: 944 # Test that partitions are placed at the correct offsets, same with explicit KB 945 tempf.write("bootloader --ptable gpt\n" \ 946 "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \ 947 "part /bar --ondisk hda --offset 102432K --fixed-size 100M --fstype=ext4\n") 948 tempf.flush() 949 950 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 951 self.assertEqual(partlns, [ 952 "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;", 953 "2:102432kiB:204832kiB:102400kiB:ext4:primary:;", 954 ]) 955 956 with NamedTemporaryFile("w", suffix=".wks") as tempf: 957 # Test that partitions are placed at the correct offsets using MB 958 tempf.write("bootloader --ptable gpt\n" \ 959 "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \ 960 "part /bar --ondisk hda --offset 101M --fixed-size 100M --fstype=ext4\n") 961 tempf.flush() 962 963 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 964 self.assertEqual(partlns, [ 965 "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;", 966 "2:103424kiB:205824kiB:102400kiB:ext4:primary:;", 967 ]) 968 969 with NamedTemporaryFile("w", suffix=".wks") as tempf: 970 # Test that partitions can be placed on a 512 byte sector boundary 971 tempf.write("bootloader --ptable gpt\n" \ 972 "part / --source rootfs --ondisk hda --offset 65s --fixed-size 99M --fstype=ext4\n" \ 973 "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n") 974 tempf.flush() 975 976 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 977 self.assertEqual(partlns, [ 978 "1:32.5kiB:101408kiB:101376kiB:ext4:primary:;", 979 "2:102432kiB:204832kiB:102400kiB:ext4:primary:;", 980 ]) 981 982 with NamedTemporaryFile("w", suffix=".wks") as tempf: 983 # Test that a partition can be placed immediately after a MSDOS partition table 984 tempf.write("bootloader --ptable msdos\n" \ 985 "part / --source rootfs --ondisk hda --offset 1s --fixed-size 100M --fstype=ext4\n") 986 tempf.flush() 987 988 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 989 self.assertEqual(partlns, [ 990 "1:0.50kiB:102400kiB:102400kiB:ext4::;", 991 ]) 992 993 with NamedTemporaryFile("w", suffix=".wks") as tempf: 994 # Test that image creation fails if the partitions would overlap 995 tempf.write("bootloader --ptable gpt\n" \ 996 "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \ 997 "part /bar --ondisk hda --offset 102431 --fixed-size 100M --fstype=ext4\n") 998 tempf.flush() 999 1000 p, _ = self._get_wic_partitions(tempf.name, ignore_status=True) 1001 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output) 1002 1003 with NamedTemporaryFile("w", suffix=".wks") as tempf: 1004 # Test that partitions are not allowed to overlap with the booloader 1005 tempf.write("bootloader --ptable gpt\n" \ 1006 "part / --source rootfs --ondisk hda --offset 8 --fixed-size 100M --fstype=ext4\n") 1007 tempf.flush() 1008 1009 p, _ = self._get_wic_partitions(tempf.name, ignore_status=True) 1010 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output) 1011 1012 def test_extra_space(self): 1013 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 1014 1015 with NamedTemporaryFile("w", suffix=".wks") as tempf: 1016 tempf.write("bootloader --ptable gpt\n" \ 1017 "part / --source rootfs --ondisk hda --extra-space 200M --fstype=ext4\n") 1018 tempf.flush() 1019 1020 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot) 1021 self.assertEqual(len(partlns), 1) 1022 size = partlns[0].split(':')[3] 1023 self.assertRegex(size, r'^[0-9]+kiB$') 1024 size = int(size[:-3]) 1025 self.assertGreaterEqual(size, 204800) 1026 1027 # TODO this test could also work on aarch64 1028 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1029 @OETestTag("runqemu") 1030 def test_rawcopy_plugin_qemu(self): 1031 """Test rawcopy plugin in qemu""" 1032 # build ext4 and then use it for a wic image 1033 config = 'IMAGE_FSTYPES = "ext4"\n' 1034 self.append_config(config) 1035 bitbake('core-image-minimal') 1036 self.remove_config(config) 1037 1038 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' 1039 self.append_config(config) 1040 bitbake('core-image-minimal-mtdutils') 1041 self.remove_config(config) 1042 1043 with runqemu('core-image-minimal-mtdutils', ssh=False, 1044 runqemuparams='nographic', image_fstype='wic') as qemu: 1045 cmd = "grep sda. /proc/partitions |wc -l" 1046 status, output = qemu.run_serial(cmd) 1047 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1048 self.assertEqual(output, '2') 1049 1050 def _rawcopy_plugin(self, fstype): 1051 """Test rawcopy plugin""" 1052 img = 'core-image-minimal' 1053 machine = self.td["MACHINE"] 1054 params = ',unpack' if fstype.endswith('.gz') else '' 1055 with NamedTemporaryFile("w", suffix=".wks") as wks: 1056 wks.write('part / --source rawcopy --sourceparams="file=%s-%s.%s%s"\n'\ 1057 % (img, machine, fstype, params)) 1058 wks.flush() 1059 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1060 runCmd(cmd) 1061 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1062 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1063 self.assertEqual(1, len(out)) 1064 1065 def test_rawcopy_plugin(self): 1066 self._rawcopy_plugin('ext4') 1067 1068 def test_rawcopy_plugin_unpack(self): 1069 fstype = 'ext4.gz' 1070 config = 'IMAGE_FSTYPES = "%s"\n' % fstype 1071 self.append_config(config) 1072 self.assertEqual(0, bitbake('core-image-minimal').status) 1073 self.remove_config(config) 1074 self._rawcopy_plugin(fstype) 1075 1076 def test_empty_plugin(self): 1077 """Test empty plugin""" 1078 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_empty_plugin.wks"\n' 1079 self.append_config(config) 1080 bitbake('core-image-minimal') 1081 self.remove_config(config) 1082 deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') 1083 machine = self.td['MACHINE'] 1084 1085 image_path = os.path.join(deploy_dir, 'core-image-minimal-%s.wic' % machine) 1086 self.assertTrue(os.path.exists(image_path)) 1087 1088 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1089 1090 # Fstype column from 'wic ls' should be empty for the second partition 1091 # as listed in test_empty_plugin.wks 1092 result = runCmd("wic ls %s -n %s | awk -F ' ' '{print $1 \" \" $5}' | grep '^2' | wc -w" % (image_path, sysroot)) 1093 self.assertEqual('1', result.output) 1094 1095 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1096 @OETestTag("runqemu") 1097 def test_biosplusefi_plugin_qemu(self): 1098 """Test biosplusefi plugin in qemu""" 1099 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n' 1100 self.append_config(config) 1101 bitbake('core-image-minimal') 1102 self.remove_config(config) 1103 1104 with runqemu('core-image-minimal', ssh=False, 1105 runqemuparams='nographic', image_fstype='wic') as qemu: 1106 # Check that we have ONLY two /dev/sda* partitions (/boot and /) 1107 cmd = "grep sda. /proc/partitions | wc -l" 1108 status, output = qemu.run_serial(cmd) 1109 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1110 self.assertEqual(output, '2') 1111 # Check that /dev/sda1 is /boot and that either /dev/root OR /dev/sda2 is / 1112 cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' -e '/dev/root /|/dev/sda2 /'" 1113 status, output = qemu.run_serial(cmd) 1114 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1115 self.assertEqual(output, '2') 1116 # Check that /boot has EFI bootx64.efi (required for EFI) 1117 cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l" 1118 status, output = qemu.run_serial(cmd) 1119 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1120 self.assertEqual(output, '1') 1121 # Check that "BOOTABLE" flag is set on boot partition (required for PC-Bios) 1122 # Trailing "cat" seems to be required; otherwise run_serial() sends back echo of the input command 1123 cmd = "fdisk -l /dev/sda | grep /dev/sda1 | awk {print'$2'} | cat" 1124 status, output = qemu.run_serial(cmd) 1125 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1126 self.assertEqual(output, '*') 1127 1128 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1129 def test_biosplusefi_plugin(self): 1130 """Test biosplusefi plugin""" 1131 # Wic generation below may fail depending on the order of the unittests 1132 # This is because bootimg-pcbios (that bootimg-biosplusefi uses) generate its MBR inside STAGING_DATADIR directory 1133 # which may or may not exists depending on what was built already 1134 # If an image hasn't been built yet, directory ${STAGING_DATADIR}/syslinux won't exists and _get_bootimg_dir() 1135 # will raise with "Couldn't find correct bootimg_dir" 1136 # The easiest way to work-around this issue is to make sure we already built an image here, hence the bitbake call 1137 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n' 1138 self.append_config(config) 1139 bitbake('core-image-minimal') 1140 self.remove_config(config) 1141 1142 img = 'core-image-minimal' 1143 with NamedTemporaryFile("w", suffix=".wks") as wks: 1144 wks.writelines(['part /boot --active --source bootimg-biosplusefi --sourceparams="loader=grub-efi"\n', 1145 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\ 1146 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n']) 1147 wks.flush() 1148 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1149 runCmd(cmd) 1150 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1151 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname)) 1152 self.assertEqual(1, len(out)) 1153 1154 # TODO this test could also work on aarch64 1155 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1156 @OETestTag("runqemu") 1157 def test_efi_plugin_unified_kernel_image_qemu(self): 1158 """Test efi plugin's Unified Kernel Image feature in qemu""" 1159 config = 'IMAGE_FSTYPES = "wic"\n'\ 1160 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\ 1161 'WKS_FILE = "test_efi_plugin.wks"\n'\ 1162 'MACHINE_FEATURES:append = " efi"\n' 1163 self.append_config(config) 1164 bitbake('core-image-minimal core-image-minimal-initramfs ovmf') 1165 self.remove_config(config) 1166 1167 with runqemu('core-image-minimal', ssh=False, 1168 runqemuparams='nographic ovmf', image_fstype='wic') as qemu: 1169 # Check that /boot has EFI bootx64.efi (required for EFI) 1170 cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l" 1171 status, output = qemu.run_serial(cmd) 1172 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1173 self.assertEqual(output, '1') 1174 # Check that /boot has EFI/Linux/linux.efi (required for Unified Kernel Images auto detection) 1175 cmd = "ls /boot/EFI/Linux/linux.efi | wc -l" 1176 status, output = qemu.run_serial(cmd) 1177 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1178 self.assertEqual(output, '1') 1179 # Check that /boot doesn't have loader/entries/boot.conf (Unified Kernel Images are auto detected by the bootloader) 1180 cmd = "ls /boot/loader/entries/boot.conf 2&>/dev/null | wc -l" 1181 status, output = qemu.run_serial(cmd) 1182 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1183 self.assertEqual(output, '0') 1184 1185 def test_fs_types(self): 1186 """Test filesystem types for empty and not empty partitions""" 1187 img = 'core-image-minimal' 1188 with NamedTemporaryFile("w", suffix=".wks") as wks: 1189 wks.writelines(['part ext2 --fstype ext2 --source rootfs\n', 1190 'part btrfs --fstype btrfs --source rootfs --size 40M\n', 1191 'part squash --fstype squashfs --source rootfs\n', 1192 'part swap --fstype swap --size 1M\n', 1193 'part emptyvfat --fstype vfat --size 1M\n', 1194 'part emptymsdos --fstype msdos --size 1M\n', 1195 'part emptyext2 --fstype ext2 --size 1M\n', 1196 'part emptybtrfs --fstype btrfs --size 150M\n']) 1197 wks.flush() 1198 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1199 runCmd(cmd) 1200 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1201 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1202 self.assertEqual(1, len(out)) 1203 1204 def test_kickstart_parser(self): 1205 """Test wks parser options""" 1206 with NamedTemporaryFile("w", suffix=".wks") as wks: 1207 wks.writelines(['part / --fstype ext3 --source rootfs --system-id 0xFF '\ 1208 '--overhead-factor 1.2 --size 100k\n']) 1209 wks.flush() 1210 cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir) 1211 runCmd(cmd) 1212 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1213 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1214 self.assertEqual(1, len(out)) 1215 1216 def test_image_bootpart_globbed(self): 1217 """Test globbed sources with image-bootpart plugin""" 1218 img = "core-image-minimal" 1219 cmd = "wic create sdimage-bootpart -e %s -o %s" % (img, self.resultdir) 1220 config = 'IMAGE_BOOT_FILES = "%s*"' % get_bb_var('KERNEL_IMAGETYPE', img) 1221 self.append_config(config) 1222 runCmd(cmd) 1223 self.remove_config(config) 1224 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct")))) 1225 1226 def test_sparse_copy(self): 1227 """Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs""" 1228 libpath = os.path.join(self.td['COREBASE'], 'scripts', 'lib', 'wic') 1229 sys.path.insert(0, libpath) 1230 from filemap import FilemapFiemap, FilemapSeek, sparse_copy, ErrorNotSupp 1231 with NamedTemporaryFile("w", suffix=".wic-sparse") as sparse: 1232 src_name = sparse.name 1233 src_size = 1024 * 10 1234 sparse.truncate(src_size) 1235 # write one byte to the file 1236 with open(src_name, 'r+b') as sfile: 1237 sfile.seek(1024 * 4) 1238 sfile.write(b'\x00') 1239 dest = sparse.name + '.out' 1240 # copy src file to dest using different filemap APIs 1241 for api in (FilemapFiemap, FilemapSeek, None): 1242 if os.path.exists(dest): 1243 os.unlink(dest) 1244 try: 1245 sparse_copy(sparse.name, dest, api=api) 1246 except ErrorNotSupp: 1247 continue # skip unsupported API 1248 dest_stat = os.stat(dest) 1249 self.assertEqual(dest_stat.st_size, src_size) 1250 # 8 blocks is 4K (physical sector size) 1251 self.assertEqual(dest_stat.st_blocks, 8) 1252 os.unlink(dest) 1253 1254 def test_mkfs_extraopts(self): 1255 """Test wks option --mkfs-extraopts for empty and not empty partitions""" 1256 img = 'core-image-minimal' 1257 with NamedTemporaryFile("w", suffix=".wks") as wks: 1258 wks.writelines( 1259 ['part ext2 --fstype ext2 --source rootfs --mkfs-extraopts "-D -F -i 8192"\n', 1260 "part btrfs --fstype btrfs --source rootfs --size 40M --mkfs-extraopts='--quiet'\n", 1261 'part squash --fstype squashfs --source rootfs --mkfs-extraopts "-no-sparse -b 4096"\n', 1262 'part emptyvfat --fstype vfat --size 1M --mkfs-extraopts "-S 1024 -s 64"\n', 1263 'part emptymsdos --fstype msdos --size 1M --mkfs-extraopts "-S 1024 -s 64"\n', 1264 'part emptyext2 --fstype ext2 --size 1M --mkfs-extraopts "-D -F -i 8192"\n', 1265 'part emptybtrfs --fstype btrfs --size 100M --mkfs-extraopts "--mixed -K"\n']) 1266 wks.flush() 1267 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) 1268 runCmd(cmd) 1269 wksname = os.path.splitext(os.path.basename(wks.name))[0] 1270 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname)) 1271 self.assertEqual(1, len(out)) 1272 1273 @skipIfNotArch(['i586', 'i686', 'x86_64']) 1274 @OETestTag("runqemu") 1275 def test_expand_mbr_image(self): 1276 """Test wic write --expand command for mbr image""" 1277 # build an image 1278 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "directdisk.wks"\n' 1279 self.append_config(config) 1280 bitbake('core-image-minimal') 1281 1282 # get path to the image 1283 deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') 1284 machine = self.td['MACHINE'] 1285 image_path = os.path.join(deploy_dir, 'core-image-minimal-%s.wic' % machine) 1286 1287 self.remove_config(config) 1288 1289 try: 1290 # expand image to 1G 1291 new_image_path = None 1292 with NamedTemporaryFile(mode='wb', suffix='.wic.exp', 1293 dir=deploy_dir, delete=False) as sparse: 1294 sparse.truncate(1024 ** 3) 1295 new_image_path = sparse.name 1296 1297 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1298 cmd = "wic write -n %s --expand 1:0 %s %s" % (sysroot, image_path, new_image_path) 1299 runCmd(cmd) 1300 1301 # check if partitions are expanded 1302 orig = runCmd("wic ls %s -n %s" % (image_path, sysroot)) 1303 exp = runCmd("wic ls %s -n %s" % (new_image_path, sysroot)) 1304 orig_sizes = [int(line.split()[3]) for line in orig.output.split('\n')[1:]] 1305 exp_sizes = [int(line.split()[3]) for line in exp.output.split('\n')[1:]] 1306 self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized 1307 self.assertTrue(orig_sizes[1] < exp_sizes[1]) 1308 1309 # Check if all free space is partitioned 1310 result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path)) 1311 self.assertTrue("0 B, 0 bytes, 0 sectors" in result.output) 1312 1313 os.rename(image_path, image_path + '.bak') 1314 os.rename(new_image_path, image_path) 1315 1316 # Check if it boots in qemu 1317 with runqemu('core-image-minimal', ssh=False, runqemuparams='nographic') as qemu: 1318 cmd = "ls /etc/" 1319 status, output = qemu.run_serial('true') 1320 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 1321 finally: 1322 if os.path.exists(new_image_path): 1323 os.unlink(new_image_path) 1324 if os.path.exists(image_path + '.bak'): 1325 os.rename(image_path + '.bak', image_path) 1326 1327class ModifyTests(WicTestCase): 1328 def test_wic_ls(self): 1329 """Test listing image content using 'wic ls'""" 1330 runCmd("wic create wictestdisk " 1331 "--image-name=core-image-minimal " 1332 "-D -o %s" % self.resultdir) 1333 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1334 self.assertEqual(1, len(images)) 1335 1336 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1337 1338 # list partitions 1339 result = runCmd("wic ls %s -n %s" % (images[0], sysroot)) 1340 self.assertEqual(3, len(result.output.split('\n'))) 1341 1342 # list directory content of the first partition 1343 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1344 self.assertEqual(6, len(result.output.split('\n'))) 1345 1346 def test_wic_cp(self): 1347 """Test copy files and directories to the the wic image.""" 1348 runCmd("wic create wictestdisk " 1349 "--image-name=core-image-minimal " 1350 "-D -o %s" % self.resultdir) 1351 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1352 self.assertEqual(1, len(images)) 1353 1354 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1355 1356 # list directory content of the first partition 1357 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1358 self.assertEqual(6, len(result.output.split('\n'))) 1359 1360 with NamedTemporaryFile("w", suffix=".wic-cp") as testfile: 1361 testfile.write("test") 1362 1363 # copy file to the partition 1364 runCmd("wic cp %s %s:1/ -n %s" % (testfile.name, images[0], sysroot)) 1365 1366 # check if file is there 1367 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1368 self.assertEqual(7, len(result.output.split('\n'))) 1369 self.assertTrue(os.path.basename(testfile.name) in result.output) 1370 1371 # prepare directory 1372 testdir = os.path.join(self.resultdir, 'wic-test-cp-dir') 1373 testsubdir = os.path.join(testdir, 'subdir') 1374 os.makedirs(os.path.join(testsubdir)) 1375 copy(testfile.name, testdir) 1376 1377 # copy directory to the partition 1378 runCmd("wic cp %s %s:1/ -n %s" % (testdir, images[0], sysroot)) 1379 1380 # check if directory is there 1381 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot)) 1382 self.assertEqual(8, len(result.output.split('\n'))) 1383 self.assertTrue(os.path.basename(testdir) in result.output) 1384 1385 # copy the file from the partition and check if it success 1386 dest = '%s-cp' % testfile.name 1387 runCmd("wic cp %s:1/%s %s -n %s" % (images[0], 1388 os.path.basename(testfile.name), dest, sysroot)) 1389 self.assertTrue(os.path.exists(dest)) 1390 1391 1392 def test_wic_rm(self): 1393 """Test removing files and directories from the the wic image.""" 1394 runCmd("wic create mkefidisk " 1395 "--image-name=core-image-minimal " 1396 "-D -o %s" % self.resultdir) 1397 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct")) 1398 self.assertEqual(1, len(images)) 1399 1400 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1401 # Not bulletproof but hopefully sufficient 1402 kerneltype = get_bb_var('KERNEL_IMAGETYPE', 'virtual/kernel') 1403 1404 # list directory content of the first partition 1405 result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot)) 1406 self.assertIn('\n%s ' % kerneltype.upper(), result.output) 1407 self.assertIn('\nEFI <DIR> ', result.output) 1408 1409 # remove file. EFI partitions are case-insensitive so exercise that too 1410 runCmd("wic rm %s:1/%s -n %s" % (images[0], kerneltype.lower(), sysroot)) 1411 1412 # remove directory 1413 runCmd("wic rm %s:1/efi -n %s" % (images[0], sysroot)) 1414 1415 # check if they're removed 1416 result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot)) 1417 self.assertNotIn('\n%s ' % kerneltype.upper(), result.output) 1418 self.assertNotIn('\nEFI <DIR> ', result.output) 1419 1420 def test_wic_ls_ext(self): 1421 """Test listing content of the ext partition using 'wic ls'""" 1422 runCmd("wic create wictestdisk " 1423 "--image-name=core-image-minimal " 1424 "-D -o %s" % self.resultdir) 1425 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1426 self.assertEqual(1, len(images)) 1427 1428 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1429 1430 # list directory content of the second ext4 partition 1431 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1432 self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset( 1433 set(line.split()[-1] for line in result.output.split('\n') if line))) 1434 1435 def test_wic_cp_ext(self): 1436 """Test copy files and directories to the ext partition.""" 1437 runCmd("wic create wictestdisk " 1438 "--image-name=core-image-minimal " 1439 "-D -o %s" % self.resultdir) 1440 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct")) 1441 self.assertEqual(1, len(images)) 1442 1443 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1444 1445 # list directory content of the ext4 partition 1446 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1447 dirs = set(line.split()[-1] for line in result.output.split('\n') if line) 1448 self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs)) 1449 1450 with NamedTemporaryFile("w", suffix=".wic-cp") as testfile: 1451 testfile.write("test") 1452 1453 # copy file to the partition 1454 runCmd("wic cp %s %s:2/ -n %s" % (testfile.name, images[0], sysroot)) 1455 1456 # check if file is there 1457 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1458 newdirs = set(line.split()[-1] for line in result.output.split('\n') if line) 1459 self.assertEqual(newdirs.difference(dirs), set([os.path.basename(testfile.name)])) 1460 1461 # check if the file to copy is in the partition 1462 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot)) 1463 self.assertTrue('fstab' in [line.split()[-1] for line in result.output.split('\n') if line]) 1464 1465 # copy file from the partition, replace the temporary file content with it and 1466 # check for the file size to validate the copy 1467 runCmd("wic cp %s:2/etc/fstab %s -n %s" % (images[0], testfile.name, sysroot)) 1468 self.assertTrue(os.stat(testfile.name).st_size > 0) 1469 1470 1471 def test_wic_rm_ext(self): 1472 """Test removing files from the ext partition.""" 1473 runCmd("wic create mkefidisk " 1474 "--image-name=core-image-minimal " 1475 "-D -o %s" % self.resultdir) 1476 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct")) 1477 self.assertEqual(1, len(images)) 1478 1479 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools') 1480 1481 # list directory content of the /etc directory on ext4 partition 1482 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot)) 1483 self.assertTrue('fstab' in [line.split()[-1] for line in result.output.split('\n') if line]) 1484 1485 # remove file 1486 runCmd("wic rm %s:2/etc/fstab -n %s" % (images[0], sysroot)) 1487 1488 # check if it's removed 1489 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot)) 1490 self.assertTrue('fstab' not in [line.split()[-1] for line in result.output.split('\n') if line]) 1491 1492 # remove non-empty directory 1493 runCmd("wic rm -r %s:2/etc/ -n %s" % (images[0], sysroot)) 1494 1495 # check if it's removed 1496 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot)) 1497 self.assertTrue('etc' not in [line.split()[-1] for line in result.output.split('\n') if line]) 1498