wic.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. #!/usr/bin/env python
  2. # ex:ts=4:sw=4:sts=4:et
  3. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  4. #
  5. # Copyright (c) 2015, Intel Corporation.
  6. # All rights reserved.
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License version 2 as
  10. # published by the Free Software Foundation.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. # AUTHORS
  22. # Ed Bartosh <ed.bartosh@linux.intel.com>
  23. """Test cases for wic."""
  24. import os
  25. import unittest
  26. from glob import glob
  27. from shutil import rmtree
  28. from functools import wraps, lru_cache
  29. from tempfile import NamedTemporaryFile
  30. from oeqa.selftest.base import oeSelfTest
  31. from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu
  32. from oeqa.utils.decorators import testcase
  33. @lru_cache(maxsize=32)
  34. def get_host_arch(recipe):
  35. """A cached call to get_bb_var('HOST_ARCH', <recipe>)"""
  36. return get_bb_var('HOST_ARCH', recipe)
  37. def only_for_arch(archs, image='core-image-minimal'):
  38. """Decorator for wrapping test cases that can be run only for specific target
  39. architectures. A list of compatible architectures is passed in `archs`.
  40. Current architecture will be determined by parsing bitbake output for
  41. `image` recipe.
  42. """
  43. def wrapper(func):
  44. @wraps(func)
  45. def wrapped_f(*args, **kwargs):
  46. arch = get_host_arch(image)
  47. if archs and arch not in archs:
  48. raise unittest.SkipTest("Testcase arch dependency not met: %s" % arch)
  49. return func(*args, **kwargs)
  50. wrapped_f.__name__ = func.__name__
  51. return wrapped_f
  52. return wrapper
  53. class Wic(oeSelfTest):
  54. """Wic test class."""
  55. resultdir = "/var/tmp/wic.oe-selftest/"
  56. image_is_ready = False
  57. native_sysroot = None
  58. wicenv_cache = {}
  59. def setUpLocal(self):
  60. """This code is executed before each test method."""
  61. if not self.native_sysroot:
  62. Wic.native_sysroot = get_bb_var('STAGING_DIR_NATIVE', 'wic-tools')
  63. # Do this here instead of in setUpClass as the base setUp does some
  64. # clean up which can result in the native tools built earlier in
  65. # setUpClass being unavailable.
  66. if not Wic.image_is_ready:
  67. bitbake('wic-tools')
  68. bitbake('core-image-minimal')
  69. Wic.image_is_ready = True
  70. rmtree(self.resultdir, ignore_errors=True)
  71. def tearDownLocal(self):
  72. """Remove resultdir as it may contain images."""
  73. rmtree(self.resultdir, ignore_errors=True)
  74. @testcase(1552)
  75. def test_version(self):
  76. """Test wic --version"""
  77. self.assertEqual(0, runCmd('wic --version').status)
  78. @testcase(1208)
  79. def test_help(self):
  80. """Test wic --help and wic -h"""
  81. self.assertEqual(0, runCmd('wic --help').status)
  82. self.assertEqual(0, runCmd('wic -h').status)
  83. @testcase(1209)
  84. def test_createhelp(self):
  85. """Test wic create --help"""
  86. self.assertEqual(0, runCmd('wic create --help').status)
  87. @testcase(1210)
  88. def test_listhelp(self):
  89. """Test wic list --help"""
  90. self.assertEqual(0, runCmd('wic list --help').status)
  91. @testcase(1553)
  92. def test_help_create(self):
  93. """Test wic help create"""
  94. self.assertEqual(0, runCmd('wic help create').status)
  95. @testcase(1554)
  96. def test_help_list(self):
  97. """Test wic help list"""
  98. self.assertEqual(0, runCmd('wic help list').status)
  99. @testcase(1215)
  100. def test_help_overview(self):
  101. """Test wic help overview"""
  102. self.assertEqual(0, runCmd('wic help overview').status)
  103. @testcase(1216)
  104. def test_help_plugins(self):
  105. """Test wic help plugins"""
  106. self.assertEqual(0, runCmd('wic help plugins').status)
  107. @testcase(1217)
  108. def test_help_kickstart(self):
  109. """Test wic help kickstart"""
  110. self.assertEqual(0, runCmd('wic help kickstart').status)
  111. @testcase(1555)
  112. def test_list_images(self):
  113. """Test wic list images"""
  114. self.assertEqual(0, runCmd('wic list images').status)
  115. @testcase(1556)
  116. def test_list_source_plugins(self):
  117. """Test wic list source-plugins"""
  118. self.assertEqual(0, runCmd('wic list source-plugins').status)
  119. @testcase(1557)
  120. def test_listed_images_help(self):
  121. """Test wic listed images help"""
  122. output = runCmd('wic list images').output
  123. imagelist = [line.split()[0] for line in output.splitlines()]
  124. for image in imagelist:
  125. self.assertEqual(0, runCmd('wic list %s help' % image).status)
  126. @testcase(1213)
  127. def test_unsupported_subcommand(self):
  128. """Test unsupported subcommand"""
  129. self.assertEqual(1, runCmd('wic unsupported',
  130. ignore_status=True).status)
  131. @testcase(1214)
  132. def test_no_command(self):
  133. """Test wic without command"""
  134. self.assertEqual(1, runCmd('wic', ignore_status=True).status)
  135. @testcase(1211)
  136. def test_build_image_name(self):
  137. """Test wic create wictestdisk --image-name=core-image-minimal"""
  138. cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir
  139. self.assertEqual(0, runCmd(cmd).status)
  140. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  141. @testcase(1157)
  142. @only_for_arch(['i586', 'i686', 'x86_64'])
  143. def test_gpt_image(self):
  144. """Test creation of core-image-minimal with gpt table and UUID boot"""
  145. cmd = "wic create directdisk-gpt --image-name core-image-minimal -o %s" % self.resultdir
  146. self.assertEqual(0, runCmd(cmd).status)
  147. self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
  148. @testcase(1346)
  149. @only_for_arch(['i586', 'i686', 'x86_64'])
  150. def test_iso_image(self):
  151. """Test creation of hybrid iso image with legacy and EFI boot"""
  152. config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\
  153. 'MACHINE_FEATURES_append = " efi"\n'
  154. self.append_config(config)
  155. bitbake('core-image-minimal')
  156. self.remove_config(config)
  157. cmd = "wic create mkhybridiso --image-name core-image-minimal -o %s" % self.resultdir
  158. self.assertEqual(0, runCmd(cmd).status)
  159. self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.direct")))
  160. self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.iso")))
  161. @testcase(1348)
  162. @only_for_arch(['i586', 'i686', 'x86_64'])
  163. def test_qemux86_directdisk(self):
  164. """Test creation of qemux-86-directdisk image"""
  165. cmd = "wic create qemux86-directdisk -e core-image-minimal -o %s" % self.resultdir
  166. self.assertEqual(0, runCmd(cmd).status)
  167. self.assertEqual(1, len(glob(self.resultdir + "qemux86-directdisk-*direct")))
  168. @testcase(1350)
  169. @only_for_arch(['i586', 'i686', 'x86_64'])
  170. def test_mkefidisk(self):
  171. """Test creation of mkefidisk image"""
  172. cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
  173. self.assertEqual(0, runCmd(cmd).status)
  174. self.assertEqual(1, len(glob(self.resultdir + "mkefidisk-*direct")))
  175. @testcase(1385)
  176. @only_for_arch(['i586', 'i686', 'x86_64'])
  177. def test_directdisk_bootloader_config(self):
  178. """Test creation of directdisk-bootloader-config image"""
  179. cmd = "wic create directdisk-bootloader-config -e core-image-minimal -o %s" % self.resultdir
  180. self.assertEqual(0, runCmd(cmd).status)
  181. self.assertEqual(1, len(glob(self.resultdir + "directdisk-bootloader-config-*direct")))
  182. @testcase(1560)
  183. @only_for_arch(['i586', 'i686', 'x86_64'])
  184. def test_systemd_bootdisk(self):
  185. """Test creation of systemd-bootdisk image"""
  186. config = 'MACHINE_FEATURES_append = " efi"\n'
  187. self.append_config(config)
  188. bitbake('core-image-minimal')
  189. self.remove_config(config)
  190. cmd = "wic create systemd-bootdisk -e core-image-minimal -o %s" % self.resultdir
  191. self.assertEqual(0, runCmd(cmd).status)
  192. self.assertEqual(1, len(glob(self.resultdir + "systemd-bootdisk-*direct")))
  193. @testcase(1561)
  194. def test_sdimage_bootpart(self):
  195. """Test creation of sdimage-bootpart image"""
  196. cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir
  197. kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
  198. self.write_config('IMAGE_BOOT_FILES = "%s"\n' % kimgtype)
  199. self.assertEqual(0, runCmd(cmd).status)
  200. self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct")))
  201. @testcase(1562)
  202. @only_for_arch(['i586', 'i686', 'x86_64'])
  203. def test_default_output_dir(self):
  204. """Test default output location"""
  205. for fname in glob("directdisk-*.direct"):
  206. os.remove(fname)
  207. cmd = "wic create directdisk -e core-image-minimal"
  208. self.assertEqual(0, runCmd(cmd).status)
  209. self.assertEqual(1, len(glob("directdisk-*.direct")))
  210. @testcase(1212)
  211. @only_for_arch(['i586', 'i686', 'x86_64'])
  212. def test_build_artifacts(self):
  213. """Test wic create directdisk providing all artifacts."""
  214. bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
  215. 'wic-tools')
  216. bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
  217. 'core-image-minimal'))
  218. bbvars = {key.lower(): value for key, value in bb_vars.items()}
  219. bbvars['resultdir'] = self.resultdir
  220. status = runCmd("wic create directdisk "
  221. "-b %(staging_datadir)s "
  222. "-k %(deploy_dir_image)s "
  223. "-n %(recipe_sysroot_native)s "
  224. "-r %(image_rootfs)s "
  225. "-o %(resultdir)s" % bbvars).status
  226. self.assertEqual(0, status)
  227. self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
  228. @testcase(1264)
  229. def test_compress_gzip(self):
  230. """Test compressing an image with gzip"""
  231. self.assertEqual(0, runCmd("wic create wictestdisk "
  232. "--image-name core-image-minimal "
  233. "-c gzip -o %s" % self.resultdir).status)
  234. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.gz")))
  235. @testcase(1265)
  236. def test_compress_bzip2(self):
  237. """Test compressing an image with bzip2"""
  238. self.assertEqual(0, runCmd("wic create wictestdisk "
  239. "--image-name=core-image-minimal "
  240. "-c bzip2 -o %s" % self.resultdir).status)
  241. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.bz2")))
  242. @testcase(1266)
  243. def test_compress_xz(self):
  244. """Test compressing an image with xz"""
  245. self.assertEqual(0, runCmd("wic create wictestdisk "
  246. "--image-name=core-image-minimal "
  247. "--compress-with=xz -o %s" % self.resultdir).status)
  248. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.xz")))
  249. @testcase(1267)
  250. def test_wrong_compressor(self):
  251. """Test how wic breaks if wrong compressor is provided"""
  252. self.assertEqual(2, runCmd("wic create wictestdisk "
  253. "--image-name=core-image-minimal "
  254. "-c wrong -o %s" % self.resultdir,
  255. ignore_status=True).status)
  256. @testcase(1558)
  257. def test_debug_short(self):
  258. """Test -D option"""
  259. self.assertEqual(0, runCmd("wic create wictestdisk "
  260. "--image-name=core-image-minimal "
  261. "-D -o %s" % self.resultdir).status)
  262. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  263. def test_debug_long(self):
  264. """Test --debug option"""
  265. self.assertEqual(0, runCmd("wic create wictestdisk "
  266. "--image-name=core-image-minimal "
  267. "--debug -o %s" % self.resultdir).status)
  268. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  269. @testcase(1563)
  270. def test_skip_build_check_short(self):
  271. """Test -s option"""
  272. self.assertEqual(0, runCmd("wic create wictestdisk "
  273. "--image-name=core-image-minimal "
  274. "-s -o %s" % self.resultdir).status)
  275. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  276. def test_skip_build_check_long(self):
  277. """Test --skip-build-check option"""
  278. self.assertEqual(0, runCmd("wic create wictestdisk "
  279. "--image-name=core-image-minimal "
  280. "--skip-build-check "
  281. "--outdir %s" % self.resultdir).status)
  282. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  283. @testcase(1564)
  284. def test_build_rootfs_short(self):
  285. """Test -f option"""
  286. self.assertEqual(0, runCmd("wic create wictestdisk "
  287. "--image-name=core-image-minimal "
  288. "-f -o %s" % self.resultdir).status)
  289. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  290. def test_build_rootfs_long(self):
  291. """Test --build-rootfs option"""
  292. self.assertEqual(0, runCmd("wic create wictestdisk "
  293. "--image-name=core-image-minimal "
  294. "--build-rootfs "
  295. "--outdir %s" % self.resultdir).status)
  296. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  297. @testcase(1268)
  298. @only_for_arch(['i586', 'i686', 'x86_64'])
  299. def test_rootfs_indirect_recipes(self):
  300. """Test usage of rootfs plugin with rootfs recipes"""
  301. status = runCmd("wic create directdisk-multi-rootfs "
  302. "--image-name=core-image-minimal "
  303. "--rootfs rootfs1=core-image-minimal "
  304. "--rootfs rootfs2=core-image-minimal "
  305. "--outdir %s" % self.resultdir).status
  306. self.assertEqual(0, status)
  307. self.assertEqual(1, len(glob(self.resultdir + "directdisk-multi-rootfs*.direct")))
  308. @testcase(1269)
  309. @only_for_arch(['i586', 'i686', 'x86_64'])
  310. def test_rootfs_artifacts(self):
  311. """Test usage of rootfs plugin with rootfs paths"""
  312. bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
  313. 'wic-tools')
  314. bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
  315. 'core-image-minimal'))
  316. bbvars = {key.lower(): value for key, value in bb_vars.items()}
  317. bbvars['wks'] = "directdisk-multi-rootfs"
  318. bbvars['resultdir'] = self.resultdir
  319. status = runCmd("wic create %(wks)s "
  320. "--bootimg-dir=%(staging_datadir)s "
  321. "--kernel-dir=%(deploy_dir_image)s "
  322. "--native-sysroot=%(recipe_sysroot_native)s "
  323. "--rootfs-dir rootfs1=%(image_rootfs)s "
  324. "--rootfs-dir rootfs2=%(image_rootfs)s "
  325. "--outdir %(resultdir)s" % bbvars).status
  326. self.assertEqual(0, status)
  327. self.assertEqual(1, len(glob(self.resultdir + "%(wks)s-*.direct" % bbvars)))
  328. def test_exclude_path(self):
  329. """Test --exclude-path wks option."""
  330. oldpath = os.environ['PATH']
  331. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  332. try:
  333. wks_file = 'temp.wks'
  334. with open(wks_file, 'w') as wks:
  335. rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
  336. wks.write("""part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr
  337. part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr
  338. part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr"""
  339. % (rootfs_dir, rootfs_dir))
  340. self.assertEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  341. % (wks_file, self.resultdir)).status)
  342. os.remove(wks_file)
  343. wicout = glob(self.resultdir + "%s-*direct" % 'temp')
  344. self.assertEqual(1, len(wicout))
  345. wicimg = wicout[0]
  346. # verify partition size with wic
  347. res = runCmd("parted -m %s unit b p 2>/dev/null" % wicimg)
  348. self.assertEqual(0, res.status)
  349. # parse parted output which looks like this:
  350. # BYT;\n
  351. # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
  352. # 1:0.00MiB:200MiB:200MiB:ext4::;\n
  353. partlns = res.output.splitlines()[2:]
  354. self.assertEqual(3, len(partlns))
  355. for part in [1, 2, 3]:
  356. part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
  357. partln = partlns[part-1].split(":")
  358. self.assertEqual(7, len(partln))
  359. start = int(partln[1].rstrip("B")) / 512
  360. length = int(partln[3].rstrip("B")) / 512
  361. self.assertEqual(0, runCmd("dd if=%s of=%s skip=%d count=%d" %
  362. (wicimg, part_file, start, length)).status)
  363. def extract_files(debugfs_output):
  364. # extract file names from the output of debugfs -R 'ls -p',
  365. # which looks like this:
  366. #
  367. # /2/040755/0/0/.//\n
  368. # /2/040755/0/0/..//\n
  369. # /11/040700/0/0/lost+found^M//\n
  370. # /12/040755/1002/1002/run//\n
  371. # /13/040755/1002/1002/sys//\n
  372. # /14/040755/1002/1002/bin//\n
  373. # /80/040755/1002/1002/var//\n
  374. # /92/040755/1002/1002/tmp//\n
  375. #
  376. # NOTE the occasional ^M in file names
  377. return [line.split('/')[5].strip() for line in \
  378. debugfs_output.strip().split('/\n')]
  379. # Test partition 1, should contain the normal root directories, except
  380. # /usr.
  381. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % os.path.join(self.resultdir, "selftest_img.part1"))
  382. self.assertEqual(0, res.status)
  383. files = extract_files(res.output)
  384. self.assertIn("etc", files)
  385. self.assertNotIn("usr", files)
  386. # Partition 2, should contain common directories for /usr, not root
  387. # directories.
  388. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % os.path.join(self.resultdir, "selftest_img.part2"))
  389. self.assertEqual(0, res.status)
  390. files = extract_files(res.output)
  391. self.assertNotIn("etc", files)
  392. self.assertNotIn("usr", files)
  393. self.assertIn("share", files)
  394. # Partition 3, should contain the same as partition 2, including the bin
  395. # directory, but not the files inside it.
  396. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % os.path.join(self.resultdir, "selftest_img.part3"))
  397. self.assertEqual(0, res.status)
  398. files = extract_files(res.output)
  399. self.assertNotIn("etc", files)
  400. self.assertNotIn("usr", files)
  401. self.assertIn("share", files)
  402. self.assertIn("bin", files)
  403. res = runCmd("debugfs -R 'ls -p bin' %s 2>/dev/null" % os.path.join(self.resultdir, "selftest_img.part3"))
  404. self.assertEqual(0, res.status)
  405. files = extract_files(res.output)
  406. self.assertIn(".", files)
  407. self.assertIn("..", files)
  408. self.assertEqual(2, len(files))
  409. for part in [1, 2, 3]:
  410. part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
  411. os.remove(part_file)
  412. finally:
  413. os.environ['PATH'] = oldpath
  414. def test_exclude_path_errors(self):
  415. """Test --exclude-path wks option error handling."""
  416. wks_file = 'temp.wks'
  417. rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
  418. # Absolute argument.
  419. with open(wks_file, 'w') as wks:
  420. wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path /usr")
  421. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  422. % (wks_file, self.resultdir), ignore_status=True).status)
  423. os.remove(wks_file)
  424. # Argument pointing to parent directory.
  425. with open(wks_file, 'w') as wks:
  426. wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path ././..")
  427. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  428. % (wks_file, self.resultdir), ignore_status=True).status)
  429. os.remove(wks_file)
  430. @testcase(1496)
  431. def test_bmap_short(self):
  432. """Test generation of .bmap file -m option"""
  433. cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir
  434. status = runCmd(cmd).status
  435. self.assertEqual(0, status)
  436. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  437. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap")))
  438. def test_bmap_long(self):
  439. """Test generation of .bmap file --bmap option"""
  440. cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir
  441. status = runCmd(cmd).status
  442. self.assertEqual(0, status)
  443. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  444. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap")))
  445. def _get_image_env_path(self, image):
  446. """Generate and obtain the path to <image>.env"""
  447. if image not in self.wicenv_cache:
  448. self.assertEqual(0, bitbake('%s -c do_rootfs_wicenv' % image).status)
  449. bb_vars = get_bb_vars(['STAGING_DIR', 'MACHINE'], image)
  450. stdir = bb_vars['STAGING_DIR']
  451. machine = bb_vars['MACHINE']
  452. self.wicenv_cache[image] = os.path.join(stdir, machine, 'imgdata')
  453. return self.wicenv_cache[image]
  454. @testcase(1347)
  455. def test_image_env(self):
  456. """Test generation of <image>.env files."""
  457. image = 'core-image-minimal'
  458. imgdatadir = self._get_image_env_path(image)
  459. bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image)
  460. basename = bb_vars['IMAGE_BASENAME']
  461. self.assertEqual(basename, image)
  462. path = os.path.join(imgdatadir, basename) + '.env'
  463. self.assertTrue(os.path.isfile(path))
  464. wicvars = set(bb_vars['WICVARS'].split())
  465. # filter out optional variables
  466. wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES',
  467. 'INITRD', 'INITRD_LIVE', 'ISODIR'))
  468. with open(path) as envfile:
  469. content = dict(line.split("=", 1) for line in envfile)
  470. # test if variables used by wic present in the .env file
  471. for var in wicvars:
  472. self.assertTrue(var in content, "%s is not in .env file" % var)
  473. self.assertTrue(content[var])
  474. @testcase(1559)
  475. def test_image_vars_dir_short(self):
  476. """Test image vars directory selection -v option"""
  477. image = 'core-image-minimal'
  478. imgenvdir = self._get_image_env_path(image)
  479. self.assertEqual(0, runCmd("wic create wictestdisk "
  480. "--image-name=%s -v %s -o %s"
  481. % (image, imgenvdir, self.resultdir)).status)
  482. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  483. def test_image_vars_dir_long(self):
  484. """Test image vars directory selection --vars option"""
  485. image = 'core-image-minimal'
  486. imgenvdir = self._get_image_env_path(image)
  487. self.assertEqual(0, runCmd("wic create wictestdisk "
  488. "--image-name=%s "
  489. "--vars %s "
  490. "--outdir %s"
  491. % (image, imgenvdir, self.resultdir)).status)
  492. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  493. @testcase(1351)
  494. @only_for_arch(['i586', 'i686', 'x86_64'])
  495. def test_wic_image_type(self):
  496. """Test building wic images by bitbake"""
  497. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
  498. 'MACHINE_FEATURES_append = " efi"\n'
  499. self.append_config(config)
  500. self.assertEqual(0, bitbake('wic-image-minimal').status)
  501. self.remove_config(config)
  502. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'])
  503. deploy_dir = bb_vars['DEPLOY_DIR_IMAGE']
  504. machine = bb_vars['MACHINE']
  505. prefix = os.path.join(deploy_dir, 'wic-image-minimal-%s.' % machine)
  506. # check if we have result image and manifests symlinks
  507. # pointing to existing files
  508. for suffix in ('wic', 'manifest'):
  509. path = prefix + suffix
  510. self.assertTrue(os.path.islink(path))
  511. self.assertTrue(os.path.isfile(os.path.realpath(path)))
  512. @testcase(1422)
  513. @only_for_arch(['i586', 'i686', 'x86_64'])
  514. def test_qemu(self):
  515. """Test wic-image-minimal under qemu"""
  516. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
  517. 'MACHINE_FEATURES_append = " efi"\n'
  518. self.append_config(config)
  519. self.assertEqual(0, bitbake('wic-image-minimal').status)
  520. self.remove_config(config)
  521. with runqemu('wic-image-minimal', ssh=False) as qemu:
  522. cmd = "mount |grep '^/dev/' | cut -f1,3 -d ' '"
  523. status, output = qemu.run_serial(cmd)
  524. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  525. self.assertEqual(output, '/dev/root /\r\n/dev/vda3 /mnt')
  526. @only_for_arch(['i586', 'i686', 'x86_64'])
  527. def test_qemu_efi(self):
  528. """Test core-image-minimal efi image under qemu"""
  529. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n'
  530. self.append_config(config)
  531. self.assertEqual(0, bitbake('core-image-minimal ovmf').status)
  532. self.remove_config(config)
  533. with runqemu('core-image-minimal', ssh=False,
  534. runqemuparams='ovmf', image_fstype='wic') as qemu:
  535. cmd = "grep vda. /proc/partitions |wc -l"
  536. status, output = qemu.run_serial(cmd)
  537. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  538. self.assertEqual(output, '3')
  539. @staticmethod
  540. def _make_fixed_size_wks(size):
  541. """
  542. Create a wks of an image with a single partition. Size of the partition is set
  543. using --fixed-size flag. Returns a tuple: (path to wks file, wks image name)
  544. """
  545. with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf:
  546. wkspath = tempf.name
  547. tempf.write("part " \
  548. "--source rootfs --ondisk hda --align 4 --fixed-size %d "
  549. "--fstype=ext4\n" % size)
  550. wksname = os.path.splitext(os.path.basename(wkspath))[0]
  551. return wkspath, wksname
  552. def test_fixed_size(self):
  553. """
  554. Test creation of a simple image with partition size controlled through
  555. --fixed-size flag
  556. """
  557. wkspath, wksname = Wic._make_fixed_size_wks(200)
  558. self.assertEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  559. % (wkspath, self.resultdir)).status)
  560. os.remove(wkspath)
  561. wicout = glob(self.resultdir + "%s-*direct" % wksname)
  562. self.assertEqual(1, len(wicout))
  563. wicimg = wicout[0]
  564. # verify partition size with wic
  565. res = runCmd("parted -m %s unit mib p 2>/dev/null" % wicimg,
  566. ignore_status=True,
  567. native_sysroot=self.native_sysroot)
  568. self.assertEqual(0, res.status)
  569. # parse parted output which looks like this:
  570. # BYT;\n
  571. # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
  572. # 1:0.00MiB:200MiB:200MiB:ext4::;\n
  573. partlns = res.output.splitlines()[2:]
  574. self.assertEqual(1, len(partlns))
  575. self.assertEqual("1:0.00MiB:200MiB:200MiB:ext4::;", partlns[0])
  576. def test_fixed_size_error(self):
  577. """
  578. Test creation of a simple image with partition size controlled through
  579. --fixed-size flag. The size of partition is intentionally set to 1MiB
  580. in order to trigger an error in wic.
  581. """
  582. wkspath, wksname = Wic._make_fixed_size_wks(1)
  583. self.assertEqual(1, runCmd("wic create %s -e core-image-minimal -o %s" \
  584. % (wkspath, self.resultdir), ignore_status=True).status)
  585. os.remove(wkspath)
  586. wicout = glob(self.resultdir + "%s-*direct" % wksname)
  587. self.assertEqual(0, len(wicout))
  588. @only_for_arch(['i586', 'i686', 'x86_64'])
  589. def test_rawcopy_plugin_qemu(self):
  590. """Test rawcopy plugin in qemu"""
  591. # build ext4 and wic images
  592. for fstype in ("ext4", "wic"):
  593. config = 'IMAGE_FSTYPES = "%s"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' % fstype
  594. self.append_config(config)
  595. self.assertEqual(0, bitbake('core-image-minimal').status)
  596. self.remove_config(config)
  597. with runqemu('core-image-minimal', ssh=False, image_fstype='wic') as qemu:
  598. cmd = "grep vda. /proc/partitions |wc -l"
  599. status, output = qemu.run_serial(cmd)
  600. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  601. self.assertEqual(output, '2')