]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core.git/blob
b1c318bd4e
[thirdparty/openembedded/openembedded-core.git] /
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
11 import os
12 import sys
13 import unittest
14 import hashlib
15 import subprocess
16
17 from glob import glob
18 from shutil import rmtree, copy
19 from tempfile import NamedTemporaryFile
20 from tempfile import TemporaryDirectory
21
22 from oeqa.selftest.case import OESelftestTestCase
23 from oeqa.core.decorator import OETestTag
24 from oeqa.core.decorator.data import skipIfNotArch
25 from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu
26
27
28 def extract_files(debugfs_output):
29 """
30 extract file names from the output of debugfs -R 'ls -p',
31 which looks like this:
32
33 /2/040755/0/0/.//\n
34 /2/040755/0/0/..//\n
35 /11/040700/0/0/lost+found^M//\n
36 /12/040755/1002/1002/run//\n
37 /13/040755/1002/1002/sys//\n
38 /14/040755/1002/1002/bin//\n
39 /80/040755/1002/1002/var//\n
40 /92/040755/1002/1002/tmp//\n
41 """
42 # NOTE the occasional ^M in file names
43 return [line.split('/')[5].strip() for line in \
44 debugfs_output.strip().split('/\n')]
45
46 def files_own_by_root(debugfs_output):
47 for line in debugfs_output.strip().split('/\n'):
48 if line.split('/')[3:5] != ['0', '0']:
49 print(debugfs_output)
50 return False
51 return True
52
53 class WicTestCase(OESelftestTestCase):
54 """Wic test class."""
55
56 image_is_ready = False
57 wicenv_cache = {}
58
59 def setUpLocal(self):
60 """This code is executed before each test method."""
61 self.resultdir = os.path.join(self.builddir, "wic-tmp")
62 super(WicTestCase, self).setUpLocal()
63
64 # Do this here instead of in setUpClass as the base setUp does some
65 # clean up which can result in the native tools built earlier in
66 # setUpClass being unavailable.
67 if not WicTestCase.image_is_ready:
68 if self.td['USE_NLS'] != 'yes':
69 self.skipTest('wic-tools needs USE_NLS=yes')
70
71 bitbake('wic-tools core-image-minimal core-image-minimal-mtdutils')
72 WicTestCase.image_is_ready = True
73 rmtree(self.resultdir, ignore_errors=True)
74
75 def tearDownLocal(self):
76 """Remove resultdir as it may contain images."""
77 rmtree(self.resultdir, ignore_errors=True)
78 super(WicTestCase, self).tearDownLocal()
79
80 def _get_image_env_path(self, image):
81 """Generate and obtain the path to <image>.env"""
82 if image not in WicTestCase.wicenv_cache:
83 bitbake('%s -c do_rootfs_wicenv' % image)
84 stdir = get_bb_var('STAGING_DIR', image)
85 machine = self.td["MACHINE"]
86 WicTestCase.wicenv_cache[image] = os.path.join(stdir, machine, 'imgdata')
87 return WicTestCase.wicenv_cache[image]
88
89 class CLITests(OESelftestTestCase):
90 def test_version(self):
91 """Test wic --version"""
92 runCmd('wic --version')
93
94 def test_help(self):
95 """Test wic --help and wic -h"""
96 runCmd('wic --help')
97 runCmd('wic -h')
98
99 def test_createhelp(self):
100 """Test wic create --help"""
101 runCmd('wic create --help')
102
103 def test_listhelp(self):
104 """Test wic list --help"""
105 runCmd('wic list --help')
106
107 def test_help_create(self):
108 """Test wic help create"""
109 runCmd('wic help create')
110
111 def test_help_list(self):
112 """Test wic help list"""
113 runCmd('wic help list')
114
115 def test_help_overview(self):
116 """Test wic help overview"""
117 runCmd('wic help overview')
118
119 def test_help_plugins(self):
120 """Test wic help plugins"""
121 runCmd('wic help plugins')
122
123 def test_help_kickstart(self):
124 """Test wic help kickstart"""
125 runCmd('wic help kickstart')
126
127 def test_list_images(self):
128 """Test wic list images"""
129 runCmd('wic list images')
130
131 def test_list_source_plugins(self):
132 """Test wic list source-plugins"""
133 runCmd('wic list source-plugins')
134
135 def test_listed_images_help(self):
136 """Test wic listed images help"""
137 output = runCmd('wic list images').output
138 imagelist = [line.split()[0] for line in output.splitlines()]
139 for image in imagelist:
140 runCmd('wic list %s help' % image)
141
142 def test_unsupported_subcommand(self):
143 """Test unsupported subcommand"""
144 self.assertNotEqual(0, runCmd('wic unsupported', ignore_status=True).status)
145
146 def test_no_command(self):
147 """Test wic without command"""
148 self.assertEqual(1, runCmd('wic', ignore_status=True).status)
149
150 class Wic(WicTestCase):
151 def test_skip_kernel_install(self):
152 """Test the functionality of not installing the kernel in the boot directory using the wic plugin"""
153 # create a temporary file for the WKS content
154 with NamedTemporaryFile("w", suffix=".wks") as wks:
155 wks.write(
156 'part --source bootimg_efi '
157 '--sourceparams="loader=grub-efi,install-kernel-into-boot-dir=false" '
158 '--label boot --active\n'
159 )
160 wks.flush()
161 # create a temporary directory to extract the disk image to
162 with TemporaryDirectory() as tmpdir:
163 img = 'core-image-minimal'
164 # build the image using the WKS file
165 cmd = "wic create %s -e %s -o %s" % (
166 wks.name, img, self.resultdir)
167 runCmd(cmd)
168 wksname = os.path.splitext(os.path.basename(wks.name))[0]
169 out = glob(os.path.join(
170 self.resultdir, "%s-*.direct" % wksname))
171 self.assertEqual(1, len(out))
172 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
173 # extract the content of the disk image to the temporary directory
174 cmd = "wic cp %s:1 %s -n %s" % (out[0], tmpdir, sysroot)
175 runCmd(cmd)
176 # check if the kernel is installed or not
177 kimgtype = get_bb_var('KERNEL_IMAGETYPE', img)
178 for file in os.listdir(tmpdir):
179 if file == kimgtype:
180 raise AssertionError(
181 "The kernel image '{}' was found in the partition".format(kimgtype)
182 )
183
184 def test_kernel_install(self):
185 """Test the installation of the kernel to the boot directory in the wic plugin"""
186 # create a temporary file for the WKS content
187 with NamedTemporaryFile("w", suffix=".wks") as wks:
188 wks.write(
189 'part --source bootimg_efi '
190 '--sourceparams="loader=grub-efi,install-kernel-into-boot-dir=true" '
191 '--label boot --active\n'
192 )
193 wks.flush()
194 # create a temporary directory to extract the disk image to
195 with TemporaryDirectory() as tmpdir:
196 img = 'core-image-minimal'
197 # build the image using the WKS file
198 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
199 runCmd(cmd)
200 wksname = os.path.splitext(os.path.basename(wks.name))[0]
201 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
202 self.assertEqual(1, len(out))
203 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
204 # extract the content of the disk image to the temporary directory
205 cmd = "wic cp %s:1 %s -n %s" % (out[0], tmpdir, sysroot)
206 runCmd(cmd)
207 # check if the kernel is installed or not
208 kimgtype = get_bb_var('KERNEL_IMAGETYPE', img)
209 found = False
210 for file in os.listdir(tmpdir):
211 if file == kimgtype:
212 found = True
213 break
214 self.assertTrue(
215 found, "The kernel image '{}' was not found in the boot partition".format(kimgtype)
216 )
217
218 @skipIfNotArch(['x86_64'])
219 def test_grub_install_pcbios(self):
220 """
221 Test the installation of the grub modules + config
222 into the boot directory in the resulting wic image.
223 """
224
225 # create a temporary file for the WKS content
226 with NamedTemporaryFile("w", suffix=".wks") as wks:
227 wks.write(
228 'part --source bootimg_pcbios --sourceparams="loader-bios=grub" '
229 '--offset 1024 --fixed-size 78M --label boot --active\n'
230 'bootloader --ptable msdos --source bootimg_pcbios\n'
231 )
232 wks.flush()
233 # create a temporary directory to extract the disk image to
234 with TemporaryDirectory() as tmpdir:
235 img = "core-image-minimal"
236 config = 'DEPENDS:pn-%s += "grub-native grub"' % (img)
237
238 self.append_config(config)
239 bitbake(img)
240 self.remove_config(config)
241
242 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
243 runCmd(cmd)
244
245 wksname = os.path.splitext(os.path.basename(wks.name))[0]
246 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
247 self.assertEqual(1, len(out))
248
249 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
250
251 # Check if grub.cfg is installed
252 result = runCmd("wic ls %s:1/boot/grub -n %s" % (out[0], sysroot))
253 self.assertIn('grub', result.output)
254
255 # Check if normal.mod is installed
256 result = runCmd("wic ls %s:1/boot/grub/i386-pc -n %s" % (out[0], sysroot))
257 self.assertIn('normal', result.output)
258
259 def test_build_image_name(self):
260 """Test wic create wictestdisk --image-name=core-image-minimal"""
261 cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir
262 runCmd(cmd)
263 self.assertEqual(1, len(glob(os.path.join (self.resultdir, "wictestdisk-*.direct"))))
264
265 @skipIfNotArch(['i586', 'i686', 'x86_64'])
266 def test_gpt_image(self):
267 """Test creation of core-image-minimal with gpt table and UUID boot"""
268 cmd = "wic create directdisk-gpt --image-name core-image-minimal -o %s" % self.resultdir
269 runCmd(cmd)
270 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-*.direct"))))
271
272 @skipIfNotArch(['i586', 'i686', 'x86_64'])
273 def test_iso_image(self):
274 """Test creation of hybrid iso image with legacy and EFI boot"""
275 config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\
276 'MACHINE_FEATURES:append = " efi"\n'\
277 'DEPENDS:pn-core-image-minimal += "syslinux"\n'
278 self.append_config(config)
279 bitbake('core-image-minimal core-image-minimal-initramfs')
280 self.remove_config(config)
281 cmd = "wic create mkhybridiso --image-name core-image-minimal -o %s" % self.resultdir
282 runCmd(cmd)
283 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "HYBRID_ISO_IMG-*.direct"))))
284 self.assertEqual(1, len(glob(os.path.join (self.resultdir, "HYBRID_ISO_IMG-*.iso"))))
285
286 @skipIfNotArch(['i586', 'i686', 'x86_64'])
287 def test_qemux86_directdisk(self):
288 """Test creation of qemux-86-directdisk image"""
289 cmd = "wic create qemux86-directdisk -e core-image-minimal -o %s" % self.resultdir
290 runCmd(cmd)
291 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "qemux86-directdisk-*direct"))))
292
293 @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64'])
294 def test_mkefidisk(self):
295 """Test creation of mkefidisk image"""
296 cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
297 runCmd(cmd)
298 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "mkefidisk-*direct"))))
299
300 @skipIfNotArch(['i586', 'i686', 'x86_64'])
301 def test_bootloader_config(self):
302 """Test creation of directdisk-bootloader-config image"""
303 config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n'
304 self.append_config(config)
305 bitbake('core-image-minimal')
306 self.remove_config(config)
307 cmd = "wic create directdisk-bootloader-config -e core-image-minimal -o %s" % self.resultdir
308 runCmd(cmd)
309 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-bootloader-config-*direct"))))
310
311 @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64'])
312 def test_systemd_bootdisk(self):
313 """Test creation of systemd-bootdisk image"""
314 config = 'MACHINE_FEATURES:append = " efi"\n'
315 self.append_config(config)
316 bitbake('core-image-minimal')
317 self.remove_config(config)
318 cmd = "wic create systemd-bootdisk -e core-image-minimal -o %s" % self.resultdir
319 runCmd(cmd)
320 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "systemd-bootdisk-*direct"))))
321
322 def test_efi_bootpart(self):
323 """Test creation of efi-bootpart image"""
324 cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
325 kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
326 self.append_config('IMAGE_EFI_BOOT_FILES = "%s;kernel"\n' % kimgtype)
327 runCmd(cmd)
328 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
329 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct"))
330 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
331 self.assertIn("kernel",result.output)
332
333 def test_sdimage_bootpart(self):
334 """Test creation of sdimage-bootpart image"""
335 cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir
336 kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
337 self.write_config('IMAGE_BOOT_FILES = "%s"\n' % kimgtype)
338 runCmd(cmd)
339 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct"))))
340
341 # TODO this doesn't have to be x86-specific
342 @skipIfNotArch(['i586', 'i686', 'x86_64'])
343 def test_default_output_dir(self):
344 """Test default output location"""
345 for fname in glob("directdisk-*.direct"):
346 os.remove(fname)
347 config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n'
348 self.append_config(config)
349 bitbake('core-image-minimal')
350 self.remove_config(config)
351 cmd = "wic create directdisk -e core-image-minimal"
352 runCmd(cmd)
353 self.assertEqual(1, len(glob("directdisk-*.direct")))
354
355 @skipIfNotArch(['i586', 'i686', 'x86_64'])
356 def test_build_artifacts(self):
357 """Test wic create directdisk providing all artifacts."""
358 bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
359 'wic-tools')
360 bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
361 'core-image-minimal'))
362 bbvars = {key.lower(): value for key, value in bb_vars.items()}
363 bbvars['resultdir'] = self.resultdir
364 runCmd("wic create directdisk "
365 "-b %(staging_datadir)s "
366 "-k %(deploy_dir_image)s "
367 "-n %(recipe_sysroot_native)s "
368 "-r %(image_rootfs)s "
369 "-o %(resultdir)s" % bbvars)
370 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-*.direct"))))
371
372 def test_compress_gzip(self):
373 """Test compressing an image with gzip"""
374 runCmd("wic create wictestdisk "
375 "--image-name core-image-minimal "
376 "-c gzip -o %s" % self.resultdir)
377 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.gz"))))
378
379 def test_compress_bzip2(self):
380 """Test compressing an image with bzip2"""
381 runCmd("wic create wictestdisk "
382 "--image-name=core-image-minimal "
383 "-c bzip2 -o %s" % self.resultdir)
384 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.bz2"))))
385
386 def test_compress_xz(self):
387 """Test compressing an image with xz"""
388 runCmd("wic create wictestdisk "
389 "--image-name=core-image-minimal "
390 "--compress-with=xz -o %s" % self.resultdir)
391 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.xz"))))
392
393 def test_wrong_compressor(self):
394 """Test how wic breaks if wrong compressor is provided"""
395 self.assertEqual(2, runCmd("wic create wictestdisk "
396 "--image-name=core-image-minimal "
397 "-c wrong -o %s" % self.resultdir,
398 ignore_status=True).status)
399
400 def test_debug_short(self):
401 """Test -D option"""
402 runCmd("wic create wictestdisk "
403 "--image-name=core-image-minimal "
404 "-D -o %s" % self.resultdir)
405 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
406 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "tmp.wic*"))))
407
408 def test_debug_long(self):
409 """Test --debug option"""
410 runCmd("wic create wictestdisk "
411 "--image-name=core-image-minimal "
412 "--debug -o %s" % self.resultdir)
413 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
414 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "tmp.wic*"))))
415
416 def test_skip_build_check_short(self):
417 """Test -s option"""
418 runCmd("wic create wictestdisk "
419 "--image-name=core-image-minimal "
420 "-s -o %s" % self.resultdir)
421 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
422
423 def test_skip_build_check_long(self):
424 """Test --skip-build-check option"""
425 runCmd("wic create wictestdisk "
426 "--image-name=core-image-minimal "
427 "--skip-build-check "
428 "--outdir %s" % self.resultdir)
429 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
430
431 def test_build_rootfs_short(self):
432 """Test -f option"""
433 runCmd("wic create wictestdisk "
434 "--image-name=core-image-minimal "
435 "-f -o %s" % self.resultdir)
436 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
437
438 def test_build_rootfs_long(self):
439 """Test --build-rootfs option"""
440 runCmd("wic create wictestdisk "
441 "--image-name=core-image-minimal "
442 "--build-rootfs "
443 "--outdir %s" % self.resultdir)
444 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
445
446 # TODO this doesn't have to be x86-specific
447 @skipIfNotArch(['i586', 'i686', 'x86_64'])
448 def test_rootfs_indirect_recipes(self):
449 """Test usage of rootfs plugin with rootfs recipes"""
450 runCmd("wic create directdisk-multi-rootfs "
451 "--image-name=core-image-minimal "
452 "--rootfs rootfs1=core-image-minimal "
453 "--rootfs rootfs2=core-image-minimal "
454 "--outdir %s" % self.resultdir)
455 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-multi-rootfs*.direct"))))
456
457 # TODO this doesn't have to be x86-specific
458 @skipIfNotArch(['i586', 'i686', 'x86_64'])
459 def test_rootfs_artifacts(self):
460 """Test usage of rootfs plugin with rootfs paths"""
461 bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
462 'wic-tools')
463 bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
464 'core-image-minimal'))
465 bbvars = {key.lower(): value for key, value in bb_vars.items()}
466 bbvars['wks'] = "directdisk-multi-rootfs"
467 bbvars['resultdir'] = self.resultdir
468 runCmd("wic create %(wks)s "
469 "--bootimg-dir=%(staging_datadir)s "
470 "--kernel-dir=%(deploy_dir_image)s "
471 "--native-sysroot=%(recipe_sysroot_native)s "
472 "--rootfs-dir rootfs1=%(image_rootfs)s "
473 "--rootfs-dir rootfs2=%(image_rootfs)s "
474 "--outdir %(resultdir)s" % bbvars)
475 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "%(wks)s-*.direct" % bbvars))))
476
477 def test_exclude_path(self):
478 """Test --exclude-path wks option."""
479
480 oldpath = os.environ['PATH']
481 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
482
483 try:
484 wks_file = 'temp.wks'
485 with open(wks_file, 'w') as wks:
486 rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
487 wks.write("""
488 part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr
489 part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr
490 part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr
491 part /mnt --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/whoami --rootfs-dir %s/usr"""
492 % (rootfs_dir, rootfs_dir, rootfs_dir))
493 runCmd("wic create %s -e core-image-minimal -o %s" \
494 % (wks_file, self.resultdir))
495
496 os.remove(wks_file)
497 wicout = glob(os.path.join(self.resultdir, "%s-*direct" % 'temp'))
498 self.assertEqual(1, len(wicout))
499
500 wicimg = wicout[0]
501
502 # verify partition size with wic
503 res = runCmd("parted -m %s unit b p" % wicimg, stderr=subprocess.PIPE)
504
505 # parse parted output which looks like this:
506 # BYT;\n
507 # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
508 # 1:0.00MiB:200MiB:200MiB:ext4::;\n
509 partlns = res.output.splitlines()[2:]
510
511 self.assertEqual(4, len(partlns))
512
513 for part in [1, 2, 3, 4]:
514 part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
515 partln = partlns[part-1].split(":")
516 self.assertEqual(7, len(partln))
517 start = int(partln[1].rstrip("B")) / 512
518 length = int(partln[3].rstrip("B")) / 512
519 runCmd("dd if=%s of=%s skip=%d count=%d" %
520 (wicimg, part_file, start, length))
521
522 # Test partition 1, should contain the normal root directories, except
523 # /usr.
524 res = runCmd("debugfs -R 'ls -p' %s" % \
525 os.path.join(self.resultdir, "selftest_img.part1"), stderr=subprocess.PIPE)
526 files = extract_files(res.output)
527 self.assertIn("etc", files)
528 self.assertNotIn("usr", files)
529
530 # Partition 2, should contain common directories for /usr, not root
531 # directories.
532 res = runCmd("debugfs -R 'ls -p' %s" % \
533 os.path.join(self.resultdir, "selftest_img.part2"), stderr=subprocess.PIPE)
534 files = extract_files(res.output)
535 self.assertNotIn("etc", files)
536 self.assertNotIn("usr", files)
537 self.assertIn("share", files)
538
539 # Partition 3, should contain the same as partition 2, including the bin
540 # directory, but not the files inside it.
541 res = runCmd("debugfs -R 'ls -p' %s" % \
542 os.path.join(self.resultdir, "selftest_img.part3"), stderr=subprocess.PIPE)
543 files = extract_files(res.output)
544 self.assertNotIn("etc", files)
545 self.assertNotIn("usr", files)
546 self.assertIn("share", files)
547 self.assertIn("bin", files)
548 res = runCmd("debugfs -R 'ls -p bin' %s" % \
549 os.path.join(self.resultdir, "selftest_img.part3"), stderr=subprocess.PIPE)
550 files = extract_files(res.output)
551 self.assertIn(".", files)
552 self.assertIn("..", files)
553 self.assertEqual(2, len(files))
554
555 # Partition 4, should contain the same as partition 2, including the bin
556 # directory, but not whoami (a symlink to busybox.nosuid) inside it.
557 res = runCmd("debugfs -R 'ls -p' %s" % \
558 os.path.join(self.resultdir, "selftest_img.part4"), stderr=subprocess.PIPE)
559 files = extract_files(res.output)
560 self.assertNotIn("etc", files)
561 self.assertNotIn("usr", files)
562 self.assertIn("share", files)
563 self.assertIn("bin", files)
564 res = runCmd("debugfs -R 'ls -p bin' %s" % \
565 os.path.join(self.resultdir, "selftest_img.part4"), stderr=subprocess.PIPE)
566 files = extract_files(res.output)
567 self.assertIn(".", files)
568 self.assertIn("..", files)
569 self.assertIn("who", files)
570 self.assertNotIn("whoami", files)
571
572 for part in [1, 2, 3, 4]:
573 part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
574 os.remove(part_file)
575
576 finally:
577 os.environ['PATH'] = oldpath
578
579 def test_exclude_path_with_extra_space(self):
580 """Test having --exclude-path with IMAGE_ROOTFS_EXTRA_SPACE. [Yocto #15555]"""
581
582 with NamedTemporaryFile("w", suffix=".wks") as wks:
583 wks.writelines(
584 ['bootloader --ptable gpt\n',
585 'part /boot --size=100M --active --fstype=ext4 --label boot\n',
586 'part / --source rootfs --fstype=ext4 --label root --exclude-path boot/\n'])
587 wks.flush()
588 config = 'IMAGE_ROOTFS_EXTRA_SPACE = "500000"\n'\
589 'DEPENDS:pn-core-image-minimal += "wic-tools"\n'\
590 'IMAGE_FSTYPES += "wic ext4"\n'\
591 'WKS_FILE = "%s"\n' % wks.name
592 self.append_config(config)
593 bitbake('core-image-minimal')
594
595 """
596 the output of "wic ls <image>.wic" will look something like:
597 Num Start End Size Fstype
598 1 17408 136332287 136314880 ext4
599 2 136332288 171464703 35132416 ext4
600 we are looking for the size of partition 2
601 i.e. in this case the number 35,132,416
602 without the fix the size will be around 85,403,648
603 with the fix the size should be around 799,960,064
604 """
605 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'], 'core-image-minimal')
606 deploy_dir = bb_vars['DEPLOY_DIR_IMAGE']
607 machine = bb_vars['MACHINE']
608 nativesysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
609 wicout = glob(os.path.join(deploy_dir, "core-image-minimal-%s.rootfs-*.wic" % machine))[0]
610 size_of_root_partition = int(runCmd("wic ls %s --native-sysroot %s" % (wicout, nativesysroot)).output.split('\n')[2].split()[3])
611 self.assertGreater(size_of_root_partition, 500000000)
612
613 def test_include_path(self):
614 """Test --include-path wks option."""
615
616 oldpath = os.environ['PATH']
617 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
618
619 try:
620 include_path = os.path.join(self.resultdir, 'test-include')
621 os.makedirs(include_path)
622 with open(os.path.join(include_path, 'test-file'), 'w') as t:
623 t.write("test\n")
624 wks_file = os.path.join(include_path, 'temp.wks')
625 with open(wks_file, 'w') as wks:
626 rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
627 wks.write("""
628 part /part1 --source rootfs --ondisk mmcblk0 --fstype=ext4
629 part /part2 --source rootfs --ondisk mmcblk0 --fstype=ext4 --include-path %s"""
630 % (include_path))
631 runCmd("wic create %s -e core-image-minimal -o %s" \
632 % (wks_file, self.resultdir))
633
634 part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
635 part2 = glob(os.path.join(self.resultdir, 'temp-*.direct.p2'))[0]
636
637 # Test partition 1, should not contain 'test-file'
638 res = runCmd("debugfs -R 'ls -p' %s" % (part1), stderr=subprocess.PIPE)
639 files = extract_files(res.output)
640 self.assertNotIn('test-file', files)
641 self.assertEqual(True, files_own_by_root(res.output))
642
643 # Test partition 2, should contain 'test-file'
644 res = runCmd("debugfs -R 'ls -p' %s" % (part2), stderr=subprocess.PIPE)
645 files = extract_files(res.output)
646 self.assertIn('test-file', files)
647 self.assertEqual(True, files_own_by_root(res.output))
648
649 finally:
650 os.environ['PATH'] = oldpath
651
652 def test_include_path_embeded(self):
653 """Test --include-path wks option."""
654
655 oldpath = os.environ['PATH']
656 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
657
658 try:
659 include_path = os.path.join(self.resultdir, 'test-include')
660 os.makedirs(include_path)
661 with open(os.path.join(include_path, 'test-file'), 'w') as t:
662 t.write("test\n")
663 wks_file = os.path.join(include_path, 'temp.wks')
664 with open(wks_file, 'w') as wks:
665 wks.write("""
666 part / --source rootfs --fstype=ext4 --include-path %s --include-path core-image-minimal-mtdutils export/"""
667 % (include_path))
668 runCmd("wic create %s -e core-image-minimal -o %s" \
669 % (wks_file, self.resultdir))
670
671 part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
672
673 res = runCmd("debugfs -R 'ls -p' %s" % (part1), stderr=subprocess.PIPE)
674 files = extract_files(res.output)
675 self.assertIn('test-file', files)
676 self.assertEqual(True, files_own_by_root(res.output))
677
678 res = runCmd("debugfs -R 'ls -p /export/etc/' %s" % (part1), stderr=subprocess.PIPE)
679 files = extract_files(res.output)
680 self.assertIn('passwd', files)
681 self.assertEqual(True, files_own_by_root(res.output))
682
683 finally:
684 os.environ['PATH'] = oldpath
685
686 def test_include_path_errors(self):
687 """Test --include-path wks option error handling."""
688 wks_file = 'temp.wks'
689
690 # Absolute argument.
691 with open(wks_file, 'w') as wks:
692 wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils /export")
693 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
694 % (wks_file, self.resultdir), ignore_status=True).status)
695 os.remove(wks_file)
696
697 # Argument pointing to parent directory.
698 with open(wks_file, 'w') as wks:
699 wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils ././..")
700 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
701 % (wks_file, self.resultdir), ignore_status=True).status)
702 os.remove(wks_file)
703
704 # 3 Argument pointing to parent directory.
705 with open(wks_file, 'w') as wks:
706 wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils export/ dummy")
707 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
708 % (wks_file, self.resultdir), ignore_status=True).status)
709 os.remove(wks_file)
710
711 def test_exclude_path_errors(self):
712 """Test --exclude-path wks option error handling."""
713 wks_file = 'temp.wks'
714
715 # Absolute argument.
716 with open(wks_file, 'w') as wks:
717 wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path /usr")
718 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
719 % (wks_file, self.resultdir), ignore_status=True).status)
720 os.remove(wks_file)
721
722 # Argument pointing to parent directory.
723 with open(wks_file, 'w') as wks:
724 wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path ././..")
725 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
726 % (wks_file, self.resultdir), ignore_status=True).status)
727 os.remove(wks_file)
728
729 def test_permissions(self):
730 """Test permissions are respected"""
731
732 # prepare wicenv and rootfs
733 bitbake('core-image-minimal core-image-minimal-mtdutils -c do_rootfs_wicenv')
734
735 oldpath = os.environ['PATH']
736 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
737
738 t_normal = """
739 part / --source rootfs --fstype=ext4
740 """
741 t_exclude = """
742 part / --source rootfs --fstype=ext4 --exclude-path=home
743 """
744 t_multi = """
745 part / --source rootfs --ondisk sda --fstype=ext4
746 part /export --source rootfs --rootfs=core-image-minimal-mtdutils --fstype=ext4
747 """
748 t_change = """
749 part / --source rootfs --ondisk sda --fstype=ext4 --exclude-path=etc/   
750 part /etc --source rootfs --fstype=ext4 --change-directory=etc
751 """
752 tests = [t_normal, t_exclude, t_multi, t_change]
753
754 try:
755 for test in tests:
756 include_path = os.path.join(self.resultdir, 'test-include')
757 os.makedirs(include_path)
758 wks_file = os.path.join(include_path, 'temp.wks')
759 with open(wks_file, 'w') as wks:
760 wks.write(test)
761 runCmd("wic create %s -e core-image-minimal -o %s" \
762 % (wks_file, self.resultdir))
763
764 for part in glob(os.path.join(self.resultdir, 'temp-*.direct.p*')):
765 res = runCmd("debugfs -R 'ls -p' %s" % (part), stderr=subprocess.PIPE)
766 self.assertEqual(True, files_own_by_root(res.output))
767
768 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "%s"\n' % wks_file
769 self.append_config(config)
770 bitbake('core-image-minimal')
771 tmpdir = os.path.join(get_bb_var('WORKDIR', 'core-image-minimal'),'build-wic')
772
773 # check each partition for permission
774 for part in glob(os.path.join(tmpdir, 'temp-*.direct.p*')):
775 res = runCmd("debugfs -R 'ls -p' %s" % (part), stderr=subprocess.PIPE)
776 self.assertTrue(files_own_by_root(res.output)
777 ,msg='Files permission incorrect using wks set "%s"' % test)
778
779 # clean config and result directory for next cases
780 self.remove_config(config)
781 rmtree(self.resultdir, ignore_errors=True)
782
783 finally:
784 os.environ['PATH'] = oldpath
785
786 def test_change_directory(self):
787 """Test --change-directory wks option."""
788
789 oldpath = os.environ['PATH']
790 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
791
792 try:
793 include_path = os.path.join(self.resultdir, 'test-include')
794 os.makedirs(include_path)
795 wks_file = os.path.join(include_path, 'temp.wks')
796 with open(wks_file, 'w') as wks:
797 wks.write("part /etc --source rootfs --fstype=ext4 --change-directory=etc")
798 runCmd("wic create %s -e core-image-minimal -o %s" \
799 % (wks_file, self.resultdir))
800
801 part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
802
803 res = runCmd("debugfs -R 'ls -p' %s" % (part1), stderr=subprocess.PIPE)
804 files = extract_files(res.output)
805 self.assertIn('passwd', files)
806
807 finally:
808 os.environ['PATH'] = oldpath
809
810 def test_change_directory_errors(self):
811 """Test --change-directory wks option error handling."""
812 wks_file = 'temp.wks'
813
814 # Absolute argument.
815 with open(wks_file, 'w') as wks:
816 wks.write("part / --source rootfs --fstype=ext4 --change-directory /usr")
817 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
818 % (wks_file, self.resultdir), ignore_status=True).status)
819 os.remove(wks_file)
820
821 # Argument pointing to parent directory.
822 with open(wks_file, 'w') as wks:
823 wks.write("part / --source rootfs --fstype=ext4 --change-directory ././..")
824 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
825 % (wks_file, self.resultdir), ignore_status=True).status)
826 os.remove(wks_file)
827
828 def test_no_fstab_update(self):
829 """Test --no-fstab-update wks option."""
830
831 oldpath = os.environ['PATH']
832 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
833
834 # Get stock fstab from base-files recipe
835 bitbake('base-files -c do_install')
836 bf_fstab = os.path.join(get_bb_var('D', 'base-files'), 'etc', 'fstab')
837 self.assertEqual(True, os.path.exists(bf_fstab))
838 bf_fstab_md5sum = runCmd('md5sum %s ' % bf_fstab).output.split(" ")[0]
839
840 try:
841 no_fstab_update_path = os.path.join(self.resultdir, 'test-no-fstab-update')
842 os.makedirs(no_fstab_update_path)
843 wks_file = os.path.join(no_fstab_update_path, 'temp.wks')
844 with open(wks_file, 'w') as wks:
845 wks.writelines(['part / --source rootfs --fstype=ext4 --label rootfs\n',
846 'part /mnt/p2 --source rootfs --rootfs-dir=core-image-minimal ',
847 '--fstype=ext4 --label p2 --no-fstab-update\n'])
848 runCmd("wic create %s -e core-image-minimal -o %s" \
849 % (wks_file, self.resultdir))
850
851 part_fstab_md5sum = []
852 for i in range(1, 3):
853 part = glob(os.path.join(self.resultdir, 'temp-*.direct.p') + str(i))[0]
854 part_fstab = runCmd("debugfs -R 'cat etc/fstab' %s" % (part), stderr=subprocess.PIPE)
855 part_fstab_md5sum.append(hashlib.md5((part_fstab.output + "\n\n").encode('utf-8')).hexdigest())
856
857 # '/etc/fstab' in partition 2 should contain the same stock fstab file
858 # as the one installed by the base-file recipe.
859 self.assertEqual(bf_fstab_md5sum, part_fstab_md5sum[1])
860
861 # '/etc/fstab' in partition 1 should contain an updated fstab file.
862 self.assertNotEqual(bf_fstab_md5sum, part_fstab_md5sum[0])
863
864 finally:
865 os.environ['PATH'] = oldpath
866
867 def test_no_fstab_update_errors(self):
868 """Test --no-fstab-update wks option error handling."""
869 wks_file = 'temp.wks'
870
871 # Absolute argument.
872 with open(wks_file, 'w') as wks:
873 wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update /etc")
874 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
875 % (wks_file, self.resultdir), ignore_status=True).status)
876 os.remove(wks_file)
877
878 # Argument pointing to parent directory.
879 with open(wks_file, 'w') as wks:
880 wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update ././..")
881 self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
882 % (wks_file, self.resultdir), ignore_status=True).status)
883 os.remove(wks_file)
884
885 def test_extra_space(self):
886 """Test --extra-space wks option."""
887 extraspace = 1024**3
888 runCmd("wic create wictestdisk "
889 "--image-name core-image-minimal "
890 "--extra-space %i -o %s" % (extraspace ,self.resultdir))
891 wicout = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
892 self.assertEqual(1, len(wicout))
893 size = os.path.getsize(wicout[0])
894 self.assertTrue(size > extraspace, msg="Extra space not present (%s vs %s)" % (size, extraspace))
895
896 def test_no_table(self):
897 """Test --no-table wks option."""
898 wks_file = 'temp.wks'
899
900 # Absolute argument.
901 with open(wks_file, 'w') as wks:
902 wks.write("part testspace --no-table --fixed-size 16k --offset 4080k")
903 runCmd("wic create %s --image-name core-image-minimal -o %s" % (wks_file, self.resultdir))
904
905 wicout = glob(os.path.join(self.resultdir, "*.*"))
906
907 self.assertEqual(1, len(wicout))
908 size = os.path.getsize(wicout[0])
909 self.assertEqual(size, 4 * 1024 * 1024)
910
911 os.remove(wks_file)
912
913 def test_partition_hidden_attributes(self):
914 """Test --hidden wks option."""
915 wks_file = 'temp.wks'
916 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
917 try:
918 with open(wks_file, 'w') as wks:
919 wks.write("""
920 part / --source rootfs --fstype=ext4
921 part / --source rootfs --fstype=ext4 --hidden
922 bootloader --ptable gpt""")
923
924 runCmd("wic create %s -e core-image-minimal -o %s" \
925 % (wks_file, self.resultdir))
926 wicout = os.path.join(self.resultdir, "*.direct")
927
928 result = runCmd("%s/usr/sbin/sfdisk --part-attrs %s 1" % (sysroot, wicout))
929 self.assertEqual('', result.output)
930 result = runCmd("%s/usr/sbin/sfdisk --part-attrs %s 2" % (sysroot, wicout))
931 self.assertEqual('RequiredPartition', result.output)
932
933 finally:
934 os.remove(wks_file)
935
936 def test_wic_sector_size(self):
937 """Test generation image sector size"""
938
939 oldpath = os.environ['PATH']
940 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
941
942 try:
943 # Add WIC_SECTOR_SIZE into config
944 config = 'WIC_SECTOR_SIZE = "4096"\n'\
945 'WICVARS:append = " WIC_SECTOR_SIZE"\n'
946 self.append_config(config)
947 bitbake('core-image-minimal')
948
949 # Check WIC_SECTOR_SIZE apply to bitbake variable
950 wic_sector_size_str = get_bb_var('WIC_SECTOR_SIZE', 'core-image-minimal')
951 wic_sector_size = int(wic_sector_size_str)
952 self.assertEqual(4096, wic_sector_size)
953
954 self.logger.info("Test wic_sector_size: %d \n" % wic_sector_size)
955
956 with NamedTemporaryFile("w", suffix=".wks") as wks:
957 wks.writelines(
958 ['bootloader --ptable gpt\n',
959 'part --fstype ext4 --source rootfs --label rofs-a --mkfs-extraopts "-b 4096"\n',
960 'part --fstype ext4 --source rootfs --use-uuid --mkfs-extraopts "-b 4096"\n'])
961 wks.flush()
962 cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir)
963 runCmd(cmd)
964 wksname = os.path.splitext(os.path.basename(wks.name))[0]
965 images = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
966 self.assertEqual(1, len(images))
967
968 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
969 # list partitions
970 result = runCmd("wic ls %s -n %s" % (images[0], sysroot))
971 self.assertEqual(3, len(result.output.split('\n')))
972
973 # verify partition size with wic
974 res = runCmd("export PARTED_SECTOR_SIZE=%d; parted -m %s unit b p" % (wic_sector_size, images[0]),
975 stderr=subprocess.PIPE)
976
977 # parse parted output which looks like this:
978 # BYT;\n
979 # /var/tmp/wic/build/tmpgjzzefdd-202410281021-sda.direct:78569472B:file:4096:4096:gpt::;\n
980 # 1:139264B:39284735B:39145472B:ext4:rofs-a:;\n
981 # 2:39284736B:78430207B:39145472B:ext4:primary:;\n
982 disk_info = res.output.splitlines()[1]
983 # Check sector sizes
984 sector_size_logical = int(disk_info.split(":")[3])
985 sector_size_physical = int(disk_info.split(":")[4])
986 self.assertEqual(wic_sector_size, sector_size_logical, "Logical sector size is not %d." % wic_sector_size)
987 self.assertEqual(wic_sector_size, sector_size_physical, "Physical sector size is not %d." % wic_sector_size)
988
989 finally:
990 os.environ['PATH'] = oldpath
991
992 class Wic2(WicTestCase):
993
994 def test_bmap_short(self):
995 """Test generation of .bmap file -m option"""
996 cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir
997 runCmd(cmd)
998 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
999 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap"))))
1000
1001 def test_bmap_long(self):
1002 """Test generation of .bmap file --bmap option"""
1003 cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir
1004 runCmd(cmd)
1005 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
1006 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap"))))
1007
1008 def test_image_env(self):
1009 """Test generation of <image>.env files."""
1010 image = 'core-image-minimal'
1011 imgdatadir = self._get_image_env_path(image)
1012
1013 bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image)
1014 basename = bb_vars['IMAGE_BASENAME']
1015 self.assertEqual(basename, image)
1016 path = os.path.join(imgdatadir, basename) + '.env'
1017 self.assertTrue(os.path.isfile(path), msg="File %s wasn't generated as expected" % path)
1018
1019 wicvars = set(bb_vars['WICVARS'].split())
1020 # filter out optional variables
1021 wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES',
1022 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE',
1023 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME',
1024 'APPEND', 'IMAGE_EFI_BOOT_FILES'))
1025 with open(path) as envfile:
1026 content = dict(line.split("=", 1) for line in envfile)
1027 # test if variables used by wic present in the .env file
1028 for var in wicvars:
1029 self.assertTrue(var in content, "%s is not in .env file" % var)
1030 self.assertTrue(content[var], "%s doesn't have a value (%s)" % (var, content[var]))
1031
1032 def test_image_vars_dir_short(self):
1033 """Test image vars directory selection -v option"""
1034 image = 'core-image-minimal'
1035 imgenvdir = self._get_image_env_path(image)
1036 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
1037
1038 runCmd("wic create wictestdisk "
1039 "--image-name=%s -v %s -n %s -o %s"
1040 % (image, imgenvdir, native_sysroot,
1041 self.resultdir))
1042 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
1043
1044 def test_image_vars_dir_long(self):
1045 """Test image vars directory selection --vars option"""
1046 image = 'core-image-minimal'
1047 imgenvdir = self._get_image_env_path(image)
1048 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
1049
1050 runCmd("wic create wictestdisk "
1051 "--image-name=%s "
1052 "--vars %s "
1053 "--native-sysroot %s "
1054 "--outdir %s"
1055 % (image, imgenvdir, native_sysroot,
1056 self.resultdir))
1057 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
1058
1059 # TODO this test could also work on aarch64
1060 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1061 def test_wic_image_type(self):
1062 """Test building wic images by bitbake"""
1063 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
1064 'MACHINE_FEATURES:append = " efi"\n'
1065 image_recipe_append = """
1066 do_image_wic[postfuncs] += "run_wic_cmd"
1067 run_wic_cmd() {
1068 echo "test" >> ${WORKDIR}/test.wic-cp
1069 wic cp --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${WORKDIR}/test.wic-cp ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/
1070 wic ls --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/
1071 wic rm --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/test.wic-cp
1072 wic cp --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${WORKDIR}/test.wic-cp ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/
1073 }
1074 """
1075 self.write_recipeinc('images', image_recipe_append)
1076
1077 self.append_config(config)
1078 image = 'wic-image-minimal'
1079 bitbake(image)
1080 self.remove_config(config)
1081
1082 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
1083 prefix = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.' % bb_vars['IMAGE_LINK_NAME'])
1084
1085 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1086 # check if file is there
1087 result = runCmd("wic ls %s:1/ -n %s" % (prefix+"wic", sysroot))
1088 self.assertIn("test.wic-cp", result.output)
1089
1090 # check if we have result image and manifests symlinks
1091 # pointing to existing files
1092 for suffix in ('wic', 'manifest'):
1093 path = prefix + suffix
1094 self.assertTrue(os.path.islink(path), msg="Link %s wasn't generated as expected" % path)
1095 self.assertTrue(os.path.isfile(os.path.realpath(path)), msg="File linked to by %s wasn't generated as expected" % path)
1096
1097 # TODO this should work on aarch64
1098 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1099 @OETestTag("runqemu")
1100 def test_qemu(self):
1101 """Test wic-image-minimal under qemu"""
1102 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
1103 'MACHINE_FEATURES:append = " efi"\n'
1104 self.append_config(config)
1105 image_recipe_append = """
1106 do_image_wic[postfuncs] += "run_wic_cmd"
1107 run_wic_cmd() {
1108 echo "test" >> ${WORKDIR}/test.wic-cp
1109 wic cp --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${WORKDIR}/test.wic-cp ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/
1110 wic ls --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/
1111 wic rm --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/test.wic-cp
1112 wic cp --vars "${STAGING_DIR}/${MACHINE}/imgdata/" -e "${IMAGE_BASENAME}" ${WORKDIR}/test.wic-cp ${IMGDEPLOYDIR}/${IMAGE_NAME}.wic:1/
1113 }
1114 """
1115 self.write_recipeinc('images', image_recipe_append)
1116 bitbake('wic-image-minimal')
1117
1118 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1119 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], "wic-image-minimal")
1120 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], bb_vars['IMAGE_LINK_NAME'])
1121 # check if file is there
1122 result = runCmd("wic ls %s:1/ -n %s" % (image_path+".wic", sysroot))
1123 self.assertIn("test.wic-cp", result.output)
1124 self.remove_config(config)
1125
1126 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'wic-image-minimal') or ""
1127 with runqemu('wic-image-minimal', ssh=False, runqemuparams='%s nographic' % (runqemu_params)) as qemu:
1128 cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' " \
1129 "-e '/dev/root /|/dev/sda2 /' -e '/dev/sda3 /media' -e '/dev/sda4 /mnt'"
1130 status, output = qemu.run_serial(cmd)
1131 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1132 self.assertEqual(output, '4')
1133 cmd = "grep UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba /etc/fstab"
1134 status, output = qemu.run_serial(cmd)
1135 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1136 self.assertEqual(output, 'UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba\t/media\text4\tdefaults\t0\t0')
1137
1138 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1139 @OETestTag("runqemu")
1140 def test_qemu_efi(self):
1141 """Test core-image-minimal efi image under qemu"""
1142 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n'
1143 self.append_config(config)
1144 bitbake('core-image-minimal ovmf')
1145 self.remove_config(config)
1146
1147 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal') or ""
1148 with runqemu('core-image-minimal', ssh=False,
1149 runqemuparams='%s nographic ovmf' % (runqemu_params), image_fstype='wic') as qemu:
1150 cmd = "grep sda. /proc/partitions |wc -l"
1151 status, output = qemu.run_serial(cmd)
1152 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1153 self.assertEqual(output, '3')
1154
1155 @staticmethod
1156 def _make_fixed_size_wks(size):
1157 """
1158 Create a wks of an image with a single partition. Size of the partition is set
1159 using --fixed-size flag. Returns a tuple: (path to wks file, wks image name)
1160 """
1161 with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf:
1162 wkspath = tempf.name
1163 tempf.write("part " \
1164 "--source rootfs --ondisk hda --align 4 --fixed-size %d "
1165 "--fstype=ext4\n" % size)
1166
1167 return wkspath
1168
1169 def _get_wic(self, wkspath, ignore_status=False):
1170 p = runCmd("wic create %s -e core-image-minimal -o %s" % (wkspath, self.resultdir),
1171 ignore_status=ignore_status)
1172
1173 if p.status:
1174 return (p, None)
1175
1176 wksname = os.path.splitext(os.path.basename(wkspath))[0]
1177
1178 wicout = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
1179
1180 if not wicout:
1181 return (p, None)
1182
1183 return (p, wicout[0])
1184
1185 def _get_wic_partitions(self, wkspath, native_sysroot=None, ignore_status=False):
1186 p, wicimg = self._get_wic(wkspath, ignore_status)
1187
1188 if wicimg is None:
1189 return (p, None)
1190
1191 if not native_sysroot:
1192 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
1193
1194 # verify partition size with wic
1195 res = runCmd("parted -m %s unit kib p" % wicimg,
1196 native_sysroot=native_sysroot, stderr=subprocess.PIPE)
1197
1198 # parse parted output which looks like this:
1199 # BYT;\n
1200 # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
1201 # 1:0.00MiB:200MiB:200MiB:ext4::;\n
1202 return (p, res.output.splitlines()[2:])
1203
1204 def test_fixed_size(self):
1205 """
1206 Test creation of a simple image with partition size controlled through
1207 --fixed-size flag
1208 """
1209 wkspath = Wic2._make_fixed_size_wks(200)
1210 _, partlns = self._get_wic_partitions(wkspath)
1211 os.remove(wkspath)
1212
1213 self.assertEqual(partlns, [
1214 "1:4.00kiB:204804kiB:204800kiB:ext4::;",
1215 ])
1216
1217 def test_fixed_size_error(self):
1218 """
1219 Test creation of a simple image with partition size controlled through
1220 --fixed-size flag. The size of partition is intentionally set to 1MiB
1221 in order to trigger an error in wic.
1222 """
1223 wkspath = Wic2._make_fixed_size_wks(1)
1224 p, _ = self._get_wic_partitions(wkspath, ignore_status=True)
1225 os.remove(wkspath)
1226
1227 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
1228
1229 def test_offset(self):
1230 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
1231
1232 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1233 # Test that partitions are placed at the correct offsets, default KB
1234 tempf.write("bootloader --ptable gpt\n" \
1235 "part / --source rootfs --ondisk hda --offset 32 --fixed-size 200M --fstype=ext4\n" \
1236 "part /bar --ondisk hda --offset 204832 --fixed-size 100M --fstype=ext4\n")
1237 tempf.flush()
1238
1239 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
1240 self.assertEqual(partlns, [
1241 "1:32.0kiB:204832kiB:204800kiB:ext4:primary:;",
1242 "2:204832kiB:307232kiB:102400kiB:ext4:primary:;",
1243 ])
1244
1245 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1246 # Test that partitions are placed at the correct offsets, same with explicit KB
1247 tempf.write("bootloader --ptable gpt\n" \
1248 "part / --source rootfs --ondisk hda --offset 32K --fixed-size 200M --fstype=ext4\n" \
1249 "part /bar --ondisk hda --offset 204832K --fixed-size 100M --fstype=ext4\n")
1250 tempf.flush()
1251
1252 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
1253 self.assertEqual(partlns, [
1254 "1:32.0kiB:204832kiB:204800kiB:ext4:primary:;",
1255 "2:204832kiB:307232kiB:102400kiB:ext4:primary:;",
1256 ])
1257
1258 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1259 # Test that partitions are placed at the correct offsets using MB
1260 tempf.write("bootloader --ptable gpt\n" \
1261 "part / --source rootfs --ondisk hda --offset 32K --fixed-size 200M --fstype=ext4\n" \
1262 "part /bar --ondisk hda --offset 201M --fixed-size 100M --fstype=ext4\n")
1263 tempf.flush()
1264
1265 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
1266 self.assertEqual(partlns, [
1267 "1:32.0kiB:204832kiB:204800kiB:ext4:primary:;",
1268 "2:205824kiB:308224kiB:102400kiB:ext4:primary:;",
1269 ])
1270
1271 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1272 # Test that partitions can be placed on a 512 byte sector boundary
1273 tempf.write("bootloader --ptable gpt\n" \
1274 "part / --source rootfs --ondisk hda --offset 65s --fixed-size 199M --fstype=ext4\n" \
1275 "part /bar --ondisk hda --offset 204832 --fixed-size 100M --fstype=ext4\n")
1276 tempf.flush()
1277
1278 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
1279 self.assertEqual(partlns, [
1280 "1:32.5kiB:203808kiB:203776kiB:ext4:primary:;",
1281 "2:204832kiB:307232kiB:102400kiB:ext4:primary:;",
1282 ])
1283
1284 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1285 # Test that a partition can be placed immediately after a MSDOS partition table
1286 tempf.write("bootloader --ptable msdos\n" \
1287 "part / --source rootfs --ondisk hda --offset 1s --fixed-size 200M --fstype=ext4\n")
1288 tempf.flush()
1289
1290 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
1291 self.assertEqual(partlns, [
1292 "1:0.50kiB:204800kiB:204800kiB:ext4::;",
1293 ])
1294
1295 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1296 # Test that image creation fails if the partitions would overlap
1297 tempf.write("bootloader --ptable gpt\n" \
1298 "part / --source rootfs --ondisk hda --offset 32 --fixed-size 200M --fstype=ext4\n" \
1299 "part /bar --ondisk hda --offset 204831 --fixed-size 100M --fstype=ext4\n")
1300 tempf.flush()
1301
1302 p, _ = self._get_wic_partitions(tempf.name, ignore_status=True)
1303 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
1304
1305 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1306 # Test that partitions are not allowed to overlap with the booloader
1307 tempf.write("bootloader --ptable gpt\n" \
1308 "part / --source rootfs --ondisk hda --offset 8 --fixed-size 200M --fstype=ext4\n")
1309 tempf.flush()
1310
1311 p, _ = self._get_wic_partitions(tempf.name, ignore_status=True)
1312 self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
1313
1314 def test_extra_filesystem_space(self):
1315 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
1316
1317 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1318 tempf.write("bootloader --ptable gpt\n" \
1319 "part / --source rootfs --ondisk hda --extra-filesystem-space 200M --fstype=ext4\n")
1320 tempf.flush()
1321
1322 _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
1323 self.assertEqual(len(partlns), 1)
1324 size = partlns[0].split(':')[3]
1325 self.assertRegex(size, r'^[0-9]+kiB$')
1326 size = int(size[:-3])
1327 self.assertGreaterEqual(size, 204800)
1328
1329 def test_extra_partition_space(self):
1330 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
1331
1332 with NamedTemporaryFile("w", suffix=".wks") as tempf:
1333 tempf.write("bootloader --ptable gpt\n" \
1334 "part --ondisk hda --size 10M --extra-partition-space 10M --fstype=ext4\n" \
1335 "part --ondisk hda --fixed-size 20M --extra-partition-space 10M --fstype=ext4\n" \
1336 "part --source rootfs --ondisk hda --extra-partition-space 10M --fstype=ext4\n" \
1337 "part --source rootfs --ondisk hda --fixed-size 200M --extra-partition-space 10M --fstype=ext4\n")
1338 tempf.flush()
1339
1340 _, wicimg = self._get_wic(tempf.name)
1341
1342 res = runCmd("parted -m %s unit b p" % wicimg,
1343 native_sysroot=native_sysroot, stderr=subprocess.PIPE)
1344
1345 # parse parted output which looks like this:
1346 # BYT;\n
1347 # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
1348 # 1:0.00MiB:200MiB:200MiB:ext4::;\n
1349 partlns = res.output.splitlines()[2:]
1350
1351 self.assertEqual(4, len(partlns))
1352
1353 # Test for each partitions that the extra part space exists
1354 for part in range(0, len(partlns)):
1355 part_file = os.path.join(self.resultdir, "selftest_img.part%d" % (part + 1))
1356 partln = partlns[part].split(":")
1357 self.assertEqual(7, len(partln))
1358 self.assertRegex(partln[3], r'^[0-9]+B$')
1359 part_size = int(partln[3].rstrip("B"))
1360 start = int(partln[1].rstrip("B")) / 512
1361 length = part_size / 512
1362 runCmd("dd if=%s of=%s skip=%d count=%d" %
1363 (wicimg, part_file, start, length))
1364 res = runCmd("dumpe2fs %s -h | grep \"^Block count\"" % part_file)
1365 fs_size = int(res.output.split(":")[1].strip()) * 1024
1366 self.assertLessEqual(fs_size + 10485760, part_size, "part file: %s" % part_file)
1367
1368 # TODO this test could also work on aarch64
1369 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1370 @OETestTag("runqemu")
1371 def test_rawcopy_plugin_qemu(self):
1372 """Test rawcopy plugin in qemu"""
1373 # build ext4 and then use it for a wic image
1374 config = 'IMAGE_FSTYPES = "ext4"\n'
1375 self.append_config(config)
1376 bitbake('core-image-minimal')
1377 image_link_name = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal')
1378 self.remove_config(config)
1379
1380 config = 'IMAGE_FSTYPES = "wic"\n' \
1381 'IMAGE_LINK_NAME_CORE_IMAGE_MINIMAL = "%s"\n'\
1382 'WKS_FILE = "test_rawcopy_plugin.wks.in"\n'\
1383 % image_link_name
1384 self.append_config(config)
1385 bitbake('core-image-minimal-mtdutils')
1386 self.remove_config(config)
1387
1388 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal-mtdutils') or ""
1389 with runqemu('core-image-minimal-mtdutils', ssh=False,
1390 runqemuparams='%s nographic' % (runqemu_params), image_fstype='wic') as qemu:
1391 cmd = "grep sda. /proc/partitions |wc -l"
1392 status, output = qemu.run_serial(cmd)
1393 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1394 self.assertEqual(output, '2')
1395
1396 def _rawcopy_plugin(self, fstype):
1397 """Test rawcopy plugin"""
1398 image = 'core-image-minimal'
1399 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
1400 params = ',unpack' if fstype.endswith('.gz') else ''
1401 with NamedTemporaryFile("w", suffix=".wks") as wks:
1402 wks.write('part / --source rawcopy --sourceparams="file=%s.%s%s"\n'\
1403 % (bb_vars['IMAGE_LINK_NAME'], fstype, params))
1404 wks.flush()
1405 cmd = "wic create %s -e %s -o %s" % (wks.name, image, self.resultdir)
1406 runCmd(cmd)
1407 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1408 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
1409 self.assertEqual(1, len(out))
1410
1411 def test_rawcopy_plugin(self):
1412 config = 'IMAGE_FSTYPES = "ext4"\n'
1413 self.append_config(config)
1414 self.assertEqual(0, bitbake('core-image-minimal').status)
1415 self.remove_config(config)
1416 self._rawcopy_plugin('ext4')
1417
1418 def test_rawcopy_plugin_unpack(self):
1419 fstype = 'ext4.gz'
1420 config = 'IMAGE_FSTYPES = "%s"\n' % fstype
1421 self.append_config(config)
1422 self.assertEqual(0, bitbake('core-image-minimal').status)
1423 self.remove_config(config)
1424 self._rawcopy_plugin(fstype)
1425
1426 def test_empty_plugin(self):
1427 """Test empty plugin"""
1428 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_empty_plugin.wks"\n'
1429 self.append_config(config)
1430 image = 'core-image-minimal'
1431 bitbake(image)
1432 self.remove_config(config)
1433 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
1434 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
1435 self.assertTrue(os.path.exists(image_path), msg="Image file %s wasn't generated as expected" % image_path)
1436
1437 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1438
1439 # Fstype column from 'wic ls' should be empty for the second partition
1440 # as listed in test_empty_plugin.wks
1441 result = runCmd("wic ls %s -n %s | awk -F ' ' '{print $1 \" \" $5}' | grep '^2' | wc -w" % (image_path, sysroot))
1442 self.assertEqual('1', result.output)
1443
1444 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1445 @OETestTag("runqemu")
1446 def test_biosplusefi_plugin_qemu(self):
1447 """Test biosplusefi plugin in qemu"""
1448 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n'
1449 self.append_config(config)
1450 bitbake('core-image-minimal')
1451 self.remove_config(config)
1452
1453 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal') or ""
1454 with runqemu('core-image-minimal', ssh=False,
1455 runqemuparams='%s nographic' % (runqemu_params), image_fstype='wic') as qemu:
1456 # Check that we have ONLY two /dev/sda* partitions (/boot and /)
1457 cmd = "grep sda. /proc/partitions | wc -l"
1458 status, output = qemu.run_serial(cmd)
1459 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1460 self.assertEqual(output, '2')
1461 # Check that /dev/sda1 is /boot and that either /dev/root OR /dev/sda2 is /
1462 cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' -e '/dev/root /|/dev/sda2 /'"
1463 status, output = qemu.run_serial(cmd)
1464 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1465 self.assertEqual(output, '2')
1466 # Check that /boot has EFI bootx64.efi (required for EFI)
1467 cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l"
1468 status, output = qemu.run_serial(cmd)
1469 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1470 self.assertEqual(output, '1')
1471 # Check that "BOOTABLE" flag is set on boot partition (required for PC-Bios)
1472 # Trailing "cat" seems to be required; otherwise run_serial() sends back echo of the input command
1473 cmd = "fdisk -l /dev/sda | grep /dev/sda1 | awk {print'$2'} | cat"
1474 status, output = qemu.run_serial(cmd)
1475 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1476 self.assertEqual(output, '*')
1477
1478 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1479 def test_biosplusefi_plugin(self):
1480 """Test biosplusefi plugin"""
1481 # Wic generation below may fail depending on the order of the unittests
1482 # This is because bootimg_pcbios (that bootimg_biosplusefi uses) generate its MBR inside STAGING_DATADIR directory
1483 # which may or may not exists depending on what was built already
1484 # If an image hasn't been built yet, directory ${STAGING_DATADIR}/syslinux won't exists and _get_bootimg_dir()
1485 # will raise with "Couldn't find correct bootimg_dir"
1486 # The easiest way to work-around this issue is to make sure we already built an image here, hence the bitbake call
1487 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n'
1488 self.append_config(config)
1489 bitbake('core-image-minimal')
1490 self.remove_config(config)
1491
1492 img = 'core-image-minimal'
1493 with NamedTemporaryFile("w", suffix=".wks") as wks:
1494 wks.writelines(['part /boot --active --source bootimg_biosplusefi --sourceparams="loader=grub-efi"\n',
1495 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\
1496 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n'])
1497 wks.flush()
1498 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
1499 runCmd(cmd)
1500 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1501 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
1502 self.assertEqual(1, len(out))
1503
1504 @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64'])
1505 def test_uefi_kernel(self):
1506 """ Test uefi-kernel in wic """
1507 config = 'IMAGE_EFI_BOOT_FILES="/etc/fstab;testfile"\nIMAGE_FSTYPES = "wic"\nWKS_FILE = "test_uefikernel.wks"\nMACHINE_FEATURES:append = " efi"\n'
1508 self.append_config(config)
1509 bitbake('core-image-minimal')
1510 self.remove_config(config)
1511
1512 img = 'core-image-minimal'
1513 with NamedTemporaryFile("w", suffix=".wks") as wks:
1514 wks.writelines(['part /boot --source bootimg_efi --sourceparams="loader=uefi-kernel"\n'
1515 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\
1516 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n'])
1517 wks.flush()
1518 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
1519 runCmd(cmd)
1520 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1521 out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
1522 self.assertEqual(1, len(out))
1523
1524 # TODO this test could also work on aarch64
1525 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1526 @OETestTag("runqemu")
1527 def test_efi_plugin_unified_kernel_image_qemu(self):
1528 """Test Unified Kernel Image feature in qemu without systemd in initramfs or rootfs"""
1529 config = """
1530 # efi firmware must load systemd-boot, not grub
1531 EFI_PROVIDER = "systemd-boot"
1532
1533 # image format must be wic, needs esp partition for firmware etc
1534 IMAGE_FSTYPES:pn-core-image-base:append = " wic"
1535 WKS_FILE = "test_efi_plugin.wks"
1536
1537 # efi, uki and systemd features must be enabled
1538 MACHINE_FEATURES:append = " efi"
1539 IMAGE_CLASSES:append:pn-core-image-base = " uki"
1540
1541 # uki embeds also an initrd, no systemd or udev
1542 INITRAMFS_IMAGE = "core-image-initramfs-boot"
1543
1544 # runqemu must not load kernel separately, it's in the uki
1545 QB_KERNEL_ROOT = ""
1546 QB_DEFAULT_KERNEL = "none"
1547
1548 # boot command line provided via uki, not via bootloader
1549 UKI_CMDLINE = "rootwait root=LABEL=root console=${KERNEL_CONSOLE}"
1550
1551 """
1552 self.append_config(config)
1553 bitbake('core-image-base ovmf')
1554 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-base') or ""
1555 uki_filename = get_bb_var('UKI_FILENAME', 'core-image-base')
1556 self.remove_config(config)
1557
1558 with runqemu('core-image-base', ssh=False,
1559 runqemuparams='%s nographic ovmf' % (runqemu_params), image_fstype='wic') as qemu:
1560 # Check that /boot has EFI boot*.efi (required for EFI)
1561 cmd = "ls /boot/EFI/BOOT/boot*.efi | wc -l"
1562 status, output = qemu.run_serial(cmd)
1563 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1564 self.assertEqual(output, '1')
1565 # Check that /boot has EFI/Linux/${UKI_FILENAME} (required for Unified Kernel Images auto detection)
1566 cmd = "ls /boot/EFI/Linux/%s | wc -l" % (uki_filename)
1567 status, output = qemu.run_serial(cmd)
1568 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1569 self.assertEqual(output, '1')
1570 # Check that /boot doesn't have loader/entries/boot.conf (Unified Kernel Images are auto detected by the bootloader)
1571 cmd = "ls /boot/loader/entries/boot.conf 2&>/dev/null | wc -l"
1572 status, output = qemu.run_serial(cmd)
1573 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1574 self.assertEqual(output, '0')
1575
1576 @skipIfNotArch(['aarch64'])
1577 @OETestTag("runqemu")
1578 def test_efi_plugin_plain_systemd_boot_qemu_aarch64(self):
1579 """Test plain systemd-boot in qemu with systemd"""
1580 config = """
1581 INIT_MANAGER = "systemd"
1582 EFI_PROVIDER = "systemd-boot"
1583
1584 # image format must be wic, needs esp partition for firmware etc
1585 IMAGE_FSTYPES:pn-core-image-base:append = " wic"
1586 WKS_FILE = "test_efi_plugin_plain_systemd-boot.wks"
1587
1588 INITRAMFS_IMAGE = "core-image-initramfs-boot"
1589
1590 # to configure runqemu
1591 IMAGE_CLASSES += "qemuboot"
1592 # u-boot efi firmware
1593 QB_DEFAULT_BIOS = "u-boot.bin"
1594 # need to use virtio, scsi not supported by u-boot by default
1595 QB_DRIVE_TYPE = "/dev/vd"
1596
1597 # disable kvm, breaks boot
1598 QEMU_USE_KVM = ""
1599
1600 IMAGE_CLASSES:remove = 'testimage'
1601 """
1602 self.append_config(config)
1603 bitbake('core-image-base u-boot')
1604 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-base') or ""
1605
1606 with runqemu('core-image-base', ssh=False,
1607 runqemuparams='%s nographic' % (runqemu_params), image_fstype='wic') as qemu:
1608 # Check that /boot has EFI boot*.efi (required for EFI)
1609 cmd = "ls /boot/EFI/BOOT/boot*.efi | wc -l"
1610 status, output = qemu.run_serial(cmd)
1611 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1612 self.assertEqual(output, '1')
1613 # Check that boot.conf exists
1614 cmd = "cat /boot/loader/entries/boot.conf"
1615 status, output = qemu.run_serial(cmd)
1616 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1617 self.remove_config(config)
1618
1619 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1620 @OETestTag("runqemu")
1621 def test_efi_plugin_plain_systemd_boot_qemu_x86(self):
1622 """Test plain systemd-boot to systemd in qemu"""
1623 config = """
1624 INIT_MANAGER = "systemd"
1625 EFI_PROVIDER = "systemd-boot"
1626
1627 # image format must be wic, needs esp partition for firmware etc
1628 IMAGE_FSTYPES:pn-core-image-base:append = " wic"
1629 WKS_FILE = "test_efi_plugin_plain_systemd-boot.wks"
1630
1631 INITRAMFS_IMAGE = "core-image-initramfs-boot"
1632 """
1633 self.append_config(config)
1634 bitbake('core-image-base ovmf')
1635 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-base') or ""
1636 self.remove_config(config)
1637
1638 with runqemu('core-image-base', ssh=False,
1639 runqemuparams='%s nographic ovmf' % (runqemu_params), image_fstype='wic') as qemu:
1640 # Check that /boot has EFI boot*.efi (required for EFI)
1641 cmd = "ls /boot/EFI/BOOT/boot*.efi | wc -l"
1642 status, output = qemu.run_serial(cmd)
1643 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1644 self.assertEqual(output, '1')
1645 # Check that boot.conf exists
1646 cmd = "cat /boot/loader/entries/boot.conf"
1647 status, output = qemu.run_serial(cmd)
1648 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1649
1650 def test_fs_types(self):
1651 """Test filesystem types for empty and not empty partitions"""
1652 img = 'core-image-minimal'
1653 with NamedTemporaryFile("w", suffix=".wks") as wks:
1654 wks.writelines(['part ext2 --fstype ext2 --source rootfs\n',
1655 'part btrfs --fstype btrfs --source rootfs --size 40M\n',
1656 'part squash --fstype squashfs --source rootfs\n',
1657 'part swap --fstype swap --size 1M\n',
1658 'part emptyvfat --fstype vfat --size 1M\n',
1659 'part emptymsdos --fstype msdos --size 1M\n',
1660 'part emptyext2 --fstype ext2 --size 1M\n',
1661 'part emptybtrfs --fstype btrfs --size 150M\n'])
1662 wks.flush()
1663 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
1664 runCmd(cmd)
1665 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1666 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
1667 self.assertEqual(1, len(out))
1668
1669 def test_kickstart_parser(self):
1670 """Test wks parser options"""
1671 with NamedTemporaryFile("w", suffix=".wks") as wks:
1672 wks.writelines(['part / --fstype ext3 --source rootfs --system-id 0xFF '\
1673 '--overhead-factor 1.2 --size 100k\n'])
1674 wks.flush()
1675 cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir)
1676 runCmd(cmd)
1677 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1678 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
1679 self.assertEqual(1, len(out))
1680
1681 def test_image_bootpart_globbed(self):
1682 """Test globbed sources with image-bootpart plugin"""
1683 img = "core-image-minimal"
1684 cmd = "wic create sdimage-bootpart -e %s -o %s" % (img, self.resultdir)
1685 config = 'IMAGE_BOOT_FILES = "%s*"' % get_bb_var('KERNEL_IMAGETYPE', img)
1686 self.append_config(config)
1687 runCmd(cmd)
1688 self.remove_config(config)
1689 self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct"))))
1690
1691 def test_sparse_copy(self):
1692 """Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs"""
1693 libpath = os.path.join(self.td['COREBASE'], 'scripts', 'lib', 'wic')
1694 sys.path.insert(0, libpath)
1695 from filemap import FilemapFiemap, FilemapSeek, sparse_copy, ErrorNotSupp
1696 with NamedTemporaryFile("w", suffix=".wic-sparse") as sparse:
1697 src_name = sparse.name
1698 src_size = 1024 * 10
1699 sparse.truncate(src_size)
1700 # write one byte to the file
1701 with open(src_name, 'r+b') as sfile:
1702 sfile.seek(1024 * 4)
1703 sfile.write(b'\x00')
1704 dest = sparse.name + '.out'
1705 # copy src file to dest using different filemap APIs
1706 for api in (FilemapFiemap, FilemapSeek, None):
1707 if os.path.exists(dest):
1708 os.unlink(dest)
1709 try:
1710 sparse_copy(sparse.name, dest, api=api)
1711 except ErrorNotSupp:
1712 continue # skip unsupported API
1713 dest_stat = os.stat(dest)
1714 self.assertEqual(dest_stat.st_size, src_size)
1715 # 8 blocks is 4K (physical sector size)
1716 self.assertEqual(dest_stat.st_blocks, 8)
1717 os.unlink(dest)
1718
1719 def test_mkfs_extraopts(self):
1720 """Test wks option --mkfs-extraopts for empty and not empty partitions"""
1721 img = 'core-image-minimal'
1722 with NamedTemporaryFile("w", suffix=".wks") as wks:
1723 wks.writelines(
1724 ['part ext2 --fstype ext2 --source rootfs --mkfs-extraopts "-D -F -i 8192"\n',
1725 "part btrfs --fstype btrfs --source rootfs --size 40M --mkfs-extraopts='--quiet'\n",
1726 'part squash --fstype squashfs --source rootfs --mkfs-extraopts "-no-sparse -b 4096"\n',
1727 'part emptyvfat --fstype vfat --size 1M --mkfs-extraopts "-S 1024 -s 64"\n',
1728 'part emptymsdos --fstype msdos --size 1M --mkfs-extraopts "-S 1024 -s 64"\n',
1729 'part emptyext2 --fstype ext2 --size 1M --mkfs-extraopts "-D -F -i 8192"\n',
1730 'part emptybtrfs --fstype btrfs --size 100M --mkfs-extraopts "--mixed -K"\n'])
1731 wks.flush()
1732 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
1733 runCmd(cmd)
1734 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1735 out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
1736 self.assertEqual(1, len(out))
1737
1738 @skipIfNotArch(['i586', 'i686', 'x86_64'])
1739 @OETestTag("runqemu")
1740 def test_expand_mbr_image(self):
1741 """Test wic write --expand command for mbr image"""
1742 # build an image
1743 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "directdisk.wks"\n'
1744 self.append_config(config)
1745 image = 'core-image-minimal'
1746 bitbake(image)
1747
1748 # get path to the image
1749 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
1750 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
1751
1752 self.remove_config(config)
1753
1754 try:
1755 # expand image to 1G
1756 new_image_path = None
1757 with NamedTemporaryFile(mode='wb', suffix='.wic.exp',
1758 dir=bb_vars['DEPLOY_DIR_IMAGE'], delete=False) as sparse:
1759 sparse.truncate(1024 ** 3)
1760 new_image_path = sparse.name
1761
1762 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1763 cmd = "wic write -n %s --expand 1:0 %s %s" % (sysroot, image_path, new_image_path)
1764 runCmd(cmd)
1765
1766 # check if partitions are expanded
1767 orig = runCmd("wic ls %s -n %s" % (image_path, sysroot))
1768 exp = runCmd("wic ls %s -n %s" % (new_image_path, sysroot))
1769 orig_sizes = [int(line.split()[3]) for line in orig.output.split('\n')[1:]]
1770 exp_sizes = [int(line.split()[3]) for line in exp.output.split('\n')[1:]]
1771 self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized
1772 self.assertTrue(orig_sizes[1] < exp_sizes[1], msg="Parition size wasn't enlarged (%s vs %s)" % (orig_sizes[1], exp_sizes[1]))
1773
1774 # Check if all free space is partitioned
1775 result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path))
1776 self.assertIn("0 B, 0 bytes, 0 sectors", result.output)
1777
1778 os.rename(image_path, image_path + '.bak')
1779 os.rename(new_image_path, image_path)
1780
1781 runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal') or ""
1782 with runqemu('core-image-minimal', ssh=False, runqemuparams='%s nographic' % (runqemu_params)) as qemu:
1783 cmd = "ls /etc/"
1784 status, output = qemu.run_serial('true')
1785 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1786 finally:
1787 if os.path.exists(new_image_path):
1788 os.unlink(new_image_path)
1789 if os.path.exists(image_path + '.bak'):
1790 os.rename(image_path + '.bak', image_path)
1791
1792 def test_gpt_partition_name(self):
1793 """Test --part-name argument to set partition name in GPT table"""
1794 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "test_gpt_partition_name.wks"\n'
1795 self.append_config(config)
1796 image = 'core-image-minimal'
1797 bitbake(image)
1798 self.remove_config(config)
1799 deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE')
1800 bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
1801 image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
1802
1803 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1804
1805 # Image is created
1806 self.assertTrue(os.path.exists(image_path), "image file %s doesn't exist" % image_path)
1807
1808 # Check the names of the three partitions
1809 # as listed in test_gpt_partition_name.wks
1810 result = runCmd("%s/usr/sbin/sfdisk --part-label %s 1" % (sysroot, image_path))
1811 self.assertEqual('boot-A', result.output)
1812 result = runCmd("%s/usr/sbin/sfdisk --part-label %s 2" % (sysroot, image_path))
1813 self.assertEqual('root-A', result.output)
1814 # When the --part-name is not defined, the partition name is equal to the --label
1815 result = runCmd("%s/usr/sbin/sfdisk --part-label %s 3" % (sysroot, image_path))
1816 self.assertEqual('ext-space', result.output)
1817
1818 def test_empty_zeroize_plugin(self):
1819 img = 'core-image-minimal'
1820 expected_size = [ 1024*1024, # 1M
1821 512*1024, # 512K
1822 2*1024*1024] # 2M
1823 # Check combination of sourceparams
1824 with NamedTemporaryFile("w", suffix=".wks") as wks:
1825 wks.writelines(
1826 ['part empty --source empty --sourceparams="fill" --ondisk sda --fixed-size 1M\n',
1827 'part empty --source empty --sourceparams="size=512K" --ondisk sda --size 1M --align 1024\n',
1828 'part empty --source empty --sourceparams="size=2048k,bs=512K" --ondisk sda --size 4M --align 1024\n'
1829 ])
1830 wks.flush()
1831 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
1832 runCmd(cmd)
1833 wksname = os.path.splitext(os.path.basename(wks.name))[0]
1834 wicout = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
1835 # Skip the complete image and just look at the single partitions
1836 for idx, value in enumerate(wicout[1:]):
1837 self.logger.info(wicout[idx])
1838 # Check if partitions are actually zeroized
1839 with open(wicout[idx], mode="rb") as fd:
1840 ba = bytearray(fd.read())
1841 for b in ba:
1842 self.assertEqual(b, 0)
1843 self.assertEqual(expected_size[idx], os.path.getsize(wicout[idx]))
1844
1845 # Check inconsistancy check between "fill" and "--size" parameter
1846 with NamedTemporaryFile("w", suffix=".wks") as wks:
1847 wks.writelines(['part empty --source empty --sourceparams="fill" --ondisk sda --size 1M\n'])
1848 wks.flush()
1849 cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
1850 result = runCmd(cmd, ignore_status=True)
1851 self.assertIn("Source parameter 'fill' only works with the '--fixed-size' option, exiting.", result.output)
1852 self.assertNotEqual(0, result.status)
1853
1854 class ModifyTests(WicTestCase):
1855 def test_wic_ls(self):
1856 """Test listing image content using 'wic ls'"""
1857 runCmd("wic create wictestdisk "
1858 "--image-name=core-image-minimal "
1859 "-D -o %s" % self.resultdir)
1860 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
1861 self.assertEqual(1, len(images))
1862
1863 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1864
1865 # list partitions
1866 result = runCmd("wic ls %s -n %s" % (images[0], sysroot))
1867 self.assertEqual(3, len(result.output.split('\n')))
1868
1869 # list directory content of the first partition
1870 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
1871 self.assertEqual(6, len(result.output.split('\n')))
1872
1873 def test_wic_cp(self):
1874 """Test copy files and directories to the the wic image."""
1875 runCmd("wic create wictestdisk "
1876 "--image-name=core-image-minimal "
1877 "-D -o %s" % self.resultdir)
1878 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
1879 self.assertEqual(1, len(images))
1880
1881 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1882
1883 # list directory content of the first partition
1884 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
1885 self.assertEqual(6, len(result.output.split('\n')))
1886
1887 with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
1888 testfile.write("test")
1889
1890 # copy file to the partition
1891 runCmd("wic cp %s %s:1/ -n %s" % (testfile.name, images[0], sysroot))
1892
1893 # check if file is there
1894 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
1895 self.assertEqual(7, len(result.output.split('\n')))
1896 self.assertIn(os.path.basename(testfile.name), result.output)
1897
1898 # prepare directory
1899 testdir = os.path.join(self.resultdir, 'wic-test-cp-dir')
1900 testsubdir = os.path.join(testdir, 'subdir')
1901 os.makedirs(os.path.join(testsubdir))
1902 copy(testfile.name, testdir)
1903
1904 # copy directory to the partition
1905 runCmd("wic cp %s %s:1/ -n %s" % (testdir, images[0], sysroot))
1906
1907 # check if directory is there
1908 result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
1909 self.assertEqual(8, len(result.output.split('\n')))
1910 self.assertIn(os.path.basename(testdir), result.output)
1911
1912 # copy the file from the partition and check if it success
1913 dest = '%s-cp' % testfile.name
1914 runCmd("wic cp %s:1/%s %s -n %s" % (images[0],
1915 os.path.basename(testfile.name), dest, sysroot))
1916 self.assertTrue(os.path.exists(dest), msg="File %s wasn't generated as expected" % dest)
1917
1918
1919 def test_wic_rm(self):
1920 """Test removing files and directories from the the wic image."""
1921 runCmd("wic create mkefidisk "
1922 "--image-name=core-image-minimal "
1923 "-D -o %s" % self.resultdir)
1924 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct"))
1925 self.assertEqual(1, len(images))
1926
1927 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1928 # Not bulletproof but hopefully sufficient
1929 kerneltype = get_bb_var('KERNEL_IMAGETYPE', 'virtual/kernel')
1930
1931 # list directory content of the first partition
1932 result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot))
1933 self.assertIn('\n%s ' % kerneltype.upper(), result.output)
1934 self.assertIn('\nEFI <DIR> ', result.output)
1935
1936 # remove file. EFI partitions are case-insensitive so exercise that too
1937 runCmd("wic rm %s:1/%s -n %s" % (images[0], kerneltype.lower(), sysroot))
1938
1939 # remove directory
1940 runCmd("wic rm %s:1/efi -n %s" % (images[0], sysroot))
1941
1942 # check if they're removed
1943 result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot))
1944 self.assertNotIn('\n%s ' % kerneltype.upper(), result.output)
1945 self.assertNotIn('\nEFI <DIR> ', result.output)
1946
1947 def test_wic_ls_ext(self):
1948 """Test listing content of the ext partition using 'wic ls'"""
1949 runCmd("wic create wictestdisk "
1950 "--image-name=core-image-minimal "
1951 "-D -o %s" % self.resultdir)
1952 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
1953 self.assertEqual(1, len(images))
1954
1955 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1956
1957 # list directory content of the second ext4 partition
1958 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
1959 self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(
1960 set(line.split()[-1] for line in result.output.split('\n') if line)), msg="Expected directories not present %s" % result.output)
1961
1962 def test_wic_cp_ext(self):
1963 """Test copy files and directories to the ext partition."""
1964 runCmd("wic create wictestdisk "
1965 "--image-name=core-image-minimal "
1966 "-D -o %s" % self.resultdir)
1967 images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
1968 self.assertEqual(1, len(images))
1969
1970 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
1971
1972 # list directory content of the ext4 partition
1973 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
1974 dirs = set(line.split()[-1] for line in result.output.split('\n') if line)
1975 self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs), msg="Expected directories not present %s" % dirs)
1976
1977 with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
1978 testfile.write("test")
1979
1980 # copy file to the partition
1981 runCmd("wic cp %s %s:2/ -n %s" % (testfile.name, images[0], sysroot))
1982
1983 # check if file is there
1984 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
1985 newdirs = set(line.split()[-1] for line in result.output.split('\n') if line)
1986 self.assertEqual(newdirs.difference(dirs), set([os.path.basename(testfile.name)]))
1987
1988 # check if the file to copy is in the partition
1989 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
1990 self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
1991
1992 # copy file from the partition, replace the temporary file content with it and
1993 # check for the file size to validate the copy
1994 runCmd("wic cp %s:2/etc/fstab %s -n %s" % (images[0], testfile.name, sysroot))
1995 self.assertTrue(os.stat(testfile.name).st_size > 0, msg="Filesize not as expected %s" % os.stat(testfile.name).st_size)
1996
1997
1998 def test_wic_rm_ext(self):
1999 """Test removing files from the ext partition."""
2000 runCmd("wic create mkefidisk "
2001 "--image-name=core-image-minimal "
2002 "-D -o %s" % self.resultdir)
2003 images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct"))
2004 self.assertEqual(1, len(images))
2005
2006 sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
2007
2008 # list directory content of the /etc directory on ext4 partition
2009 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
2010 self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
2011
2012 # remove file
2013 runCmd("wic rm %s:2/etc/fstab -n %s" % (images[0], sysroot))
2014
2015 # check if it's removed
2016 result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
2017 self.assertNotIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
2018
2019 # remove non-empty directory
2020 runCmd("wic rm -r %s:2/etc/ -n %s" % (images[0], sysroot))
2021
2022 # check if it's removed
2023 result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
2024 self.assertNotIn('etc', [line.split()[-1] for line in result.output.split('\n') if line])