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