blob: 904ff6988b5285ce07f9efadc8d7ad2c0f4c4a50 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
2# SPDX-License-Identifier: MIT
3#
4
Brad Bishopd7bf8c12018-02-25 22:55:05 -05005import os
6import re
7import shutil
8import tempfile
9import glob
10import fnmatch
11
12import oeqa.utils.ftools as ftools
13from oeqa.selftest.case import OESelftestTestCase
14from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
15from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Brad Bishopd7bf8c12018-02-25 22:55:05 -050016
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080017oldmetapath = None
18
19def setUpModule():
20 import bb.utils
21
22 global templayerdir
23 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
24 corecopydir = os.path.join(templayerdir, 'core-copy')
25 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
26 edited_layers = []
27
28 # We need to take a copy of the meta layer so we can modify it and not
29 # have any races against other tests that might be running in parallel
30 # however things like COREBASE mean that you can't just copy meta, you
31 # need the whole repository.
32 def bblayers_edit_cb(layerpath, canonical_layerpath):
33 global oldmetapath
34 if not canonical_layerpath.endswith('/'):
35 # This helps us match exactly when we're using this path later
36 canonical_layerpath += '/'
37 if not edited_layers and canonical_layerpath.endswith('/meta/'):
38 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
39 edited_layers.append(layerpath)
40 oldmetapath = os.path.realpath(layerpath)
41 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
42 oldreporoot = result.output.rstrip()
43 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
44 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
45 # Now we need to copy any modified files
46 # You might ask "why not just copy the entire tree instead of
47 # cloning and doing this?" - well, the problem with that is
48 # TMPDIR or an equally large subdirectory might exist
49 # under COREBASE and we don't want to copy that, so we have
50 # to be selective.
51 result = runCmd('git status --porcelain', cwd=oldreporoot)
52 for line in result.output.splitlines():
53 if line.startswith(' M ') or line.startswith('?? '):
54 relpth = line.split()[1]
55 pth = os.path.join(oldreporoot, relpth)
56 if pth.startswith(canonical_layerpath):
57 if relpth.endswith('/'):
58 destdir = os.path.join(corecopydir, relpth)
59 shutil.copytree(pth, destdir)
60 else:
61 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
62 bb.utils.mkdirhier(destdir)
63 shutil.copy2(pth, destdir)
64 return newmetapath
65 else:
66 return layerpath
67 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
68
69def tearDownModule():
70 if oldmetapath:
71 edited_layers = []
72 def bblayers_edit_cb(layerpath, canonical_layerpath):
73 if not edited_layers and canonical_layerpath.endswith('/meta'):
74 edited_layers.append(layerpath)
75 return oldmetapath
76 else:
77 return layerpath
78 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
79 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
80 shutil.rmtree(templayerdir)
81
Brad Bishopd7bf8c12018-02-25 22:55:05 -050082class DevtoolBase(OESelftestTestCase):
83
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080084 @classmethod
85 def setUpClass(cls):
86 super(DevtoolBase, cls).setUpClass()
87 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
88 cls.original_sstate = bb_vars['SSTATE_DIR']
89 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
90 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
91 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
92 % cls.original_sstate)
93
94 @classmethod
95 def tearDownClass(cls):
96 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
97 runCmd('rm -rf %s' % cls.devtool_sstate)
98 super(DevtoolBase, cls).tearDownClass()
99
100 def setUp(self):
101 """Test case setup function"""
102 super(DevtoolBase, self).setUp()
103 self.workspacedir = os.path.join(self.builddir, 'workspace')
104 self.assertTrue(not os.path.exists(self.workspacedir),
105 'This test cannot be run with a workspace directory '
106 'under the build directory')
107 self.append_config(self.sstate_conf)
108
109 def _check_src_repo(self, repo_dir):
110 """Check srctree git repository"""
111 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
112 'git repository for external source tree not found')
113 result = runCmd('git status --porcelain', cwd=repo_dir)
114 self.assertEqual(result.output.strip(), "",
115 'Created git repo is not clean')
116 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
117 self.assertEqual(result.output.strip(), "refs/heads/devtool",
118 'Wrong branch in git repo')
119
120 def _check_repo_status(self, repo_dir, expected_status):
121 """Check the worktree status of a repository"""
122 result = runCmd('git status . --porcelain',
123 cwd=repo_dir)
124 for line in result.output.splitlines():
125 for ind, (f_status, fn_re) in enumerate(expected_status):
126 if re.match(fn_re, line[3:]):
127 if f_status != line[:2]:
128 self.fail('Unexpected status in line: %s' % line)
129 expected_status.pop(ind)
130 break
131 else:
132 self.fail('Unexpected modified file in line: %s' % line)
133 if expected_status:
134 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500135
136 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
137 with open(recipefile, 'r') as f:
138 invar = None
139 invalue = None
140 for line in f:
141 var = None
142 if invar:
143 value = line.strip().strip('"')
144 if value.endswith('\\'):
145 invalue += ' ' + value[:-1].strip()
146 continue
147 else:
148 invalue += ' ' + value.strip()
149 var = invar
150 value = invalue
151 invar = None
152 elif '=' in line:
153 splitline = line.split('=', 1)
154 var = splitline[0].rstrip()
155 value = splitline[1].strip().strip('"')
156 if value.endswith('\\'):
157 invalue = value[:-1].strip()
158 invar = var
159 continue
160 elif line.startswith('inherit '):
161 inherits = line.split()[1:]
162
163 if var and var in checkvars:
164 needvalue = checkvars.pop(var)
165 if needvalue is None:
166 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
167 if isinstance(needvalue, set):
168 if var == 'LICENSE':
169 value = set(value.split(' & '))
170 else:
171 value = set(value.split())
172 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
173
174
175 missingvars = {}
176 for var, value in checkvars.items():
177 if value is not None:
178 missingvars[var] = value
179 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
180
181 for inherit in checkinherits:
182 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
183
184 def _check_bbappend(self, testrecipe, recipefile, appenddir):
185 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
186 resultlines = result.output.splitlines()
187 inrecipe = False
188 bbappends = []
189 bbappendfile = None
190 for line in resultlines:
191 if inrecipe:
192 if line.startswith(' '):
193 bbappends.append(line.strip())
194 else:
195 break
196 elif line == '%s:' % os.path.basename(recipefile):
197 inrecipe = True
198 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
199 for bbappend in bbappends:
200 if bbappend.startswith(appenddir):
201 bbappendfile = bbappend
202 break
203 else:
204 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
205 return bbappendfile
206
207 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
208 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
209 if addlayer:
210 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
211 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
212
213 def _process_ls_output(self, output):
214 """
215 Convert ls -l output to a format we can reasonably compare from one context
216 to another (e.g. from host to target)
217 """
218 filelist = []
219 for line in output.splitlines():
220 splitline = line.split()
221 if len(splitline) < 8:
222 self.fail('_process_ls_output: invalid output line: %s' % line)
223 # Remove trailing . on perms
224 splitline[0] = splitline[0].rstrip('.')
225 # Remove leading . on paths
226 splitline[-1] = splitline[-1].lstrip('.')
227 # Drop fields we don't want to compare
228 del splitline[7]
229 del splitline[6]
230 del splitline[5]
231 del splitline[4]
232 del splitline[1]
233 filelist.append(' '.join(splitline))
234 return filelist
235
236
237class DevtoolTests(DevtoolBase):
238
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500239 def test_create_workspace(self):
240 # Check preconditions
241 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400242 self.assertTrue('\nworkspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500243 # Try creating a workspace layer with a specific path
244 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
245 self.track_for_cleanup(tempdir)
246 result = runCmd('devtool create-workspace %s' % tempdir)
247 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
248 result = runCmd('bitbake-layers show-layers')
249 self.assertIn(tempdir, result.output)
250 # Try creating a workspace layer with the default path
251 self.track_for_cleanup(self.workspacedir)
252 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
253 result = runCmd('devtool create-workspace')
254 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
255 result = runCmd('bitbake-layers show-layers')
256 self.assertNotIn(tempdir, result.output)
257 self.assertIn(self.workspacedir, result.output)
258
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800259class DevtoolAddTests(DevtoolBase):
260
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500261 def test_devtool_add(self):
262 # Fetch source
263 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
264 self.track_for_cleanup(tempdir)
265 pn = 'pv'
266 pv = '1.5.3'
267 url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2'
268 result = runCmd('wget %s' % url, cwd=tempdir)
269 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
270 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
271 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
272 # Test devtool add
273 self.track_for_cleanup(self.workspacedir)
274 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
275 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
276 result = runCmd('devtool add %s %s' % (pn, srcdir))
277 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
278 # Test devtool status
279 result = runCmd('devtool status')
280 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
281 self.assertIn(recipepath, result.output)
282 self.assertIn(srcdir, result.output)
283 # Test devtool find-recipe
284 result = runCmd('devtool -q find-recipe %s' % pn)
285 self.assertEqual(recipepath, result.output.strip())
286 # Test devtool edit-recipe
287 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
288 self.assertEqual('123 %s' % recipepath, result.output.strip())
289 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
290 bitbake('%s -c cleansstate' % pn)
291 # Test devtool build
292 result = runCmd('devtool build %s' % pn)
293 bb_vars = get_bb_vars(['D', 'bindir'], pn)
294 installdir = bb_vars['D']
295 self.assertTrue(installdir, 'Could not query installdir variable')
296 bindir = bb_vars['bindir']
297 self.assertTrue(bindir, 'Could not query bindir variable')
298 if bindir[0] == '/':
299 bindir = bindir[1:]
300 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
301
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800303 # We need dbus built so that DEPENDS recognition works
304 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500305 # Fetch source from a remote URL, but do it outside of devtool
306 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
307 self.track_for_cleanup(tempdir)
308 pn = 'dbus-wait'
309 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
310 # We choose an https:// git URL here to check rewriting the URL works
311 url = 'https://git.yoctoproject.org/git/dbus-wait'
312 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
313 # instead of the directory name
314 result = runCmd('git clone %s noname' % url, cwd=tempdir)
315 srcdir = os.path.join(tempdir, 'noname')
316 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
317 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
318 # Test devtool add
319 self.track_for_cleanup(self.workspacedir)
320 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
321 # Don't specify a name since we should be able to auto-detect it
322 result = runCmd('devtool add %s' % srcdir)
323 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
324 # Check the recipe name is correct
325 recipefile = get_bb_var('FILE', pn)
326 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
327 self.assertIn(recipefile, result.output)
328 # Test devtool status
329 result = runCmd('devtool status')
330 self.assertIn(pn, result.output)
331 self.assertIn(srcdir, result.output)
332 self.assertIn(recipefile, result.output)
333 checkvars = {}
334 checkvars['LICENSE'] = 'GPLv2'
335 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
336 checkvars['S'] = '${WORKDIR}/git'
337 checkvars['PV'] = '0.1+git${SRCPV}'
338 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https'
339 checkvars['SRCREV'] = srcrev
340 checkvars['DEPENDS'] = set(['dbus'])
341 self._test_recipe_contents(recipefile, checkvars, [])
342
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500343 def test_devtool_add_library(self):
344 # Fetch source
345 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
346 self.track_for_cleanup(tempdir)
347 version = '1.1'
348 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
349 result = runCmd('wget %s' % url, cwd=tempdir)
350 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
351 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
352 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
353 # Test devtool add (and use -V so we test that too)
354 self.track_for_cleanup(self.workspacedir)
355 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
356 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
357 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
358 # Test devtool status
359 result = runCmd('devtool status')
360 self.assertIn('libftdi', result.output)
361 self.assertIn(srcdir, result.output)
362 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
363 bitbake('libftdi -c cleansstate')
364 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
365 # There's also the matter of it installing cmake files to a path we don't
366 # normally cover, which triggers the installed-vs-shipped QA test we have
367 # within do_package
368 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
369 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
370 with open(recipefile, 'a') as f:
371 f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n')
372 # We don't have the ability to pick up this dependency automatically yet...
373 f.write('\nDEPENDS += "libusb1"\n')
374 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
375 # Test devtool build
376 result = runCmd('devtool build libftdi')
377 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
378 staging_libdir = bb_vars['TESTLIBOUTPUT']
379 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
380 self.assertTrue(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), "libftdi binary not found in STAGING_LIBDIR. Output of devtool build libftdi %s" % result.output)
381 # Test devtool reset
382 stampprefix = bb_vars['STAMP']
383 result = runCmd('devtool reset libftdi')
384 result = runCmd('devtool status')
385 self.assertNotIn('libftdi', result.output)
386 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
387 matches = glob.glob(stampprefix + '*')
388 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
389 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
390
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500391 def test_devtool_add_fetch(self):
392 # Fetch source
393 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
394 self.track_for_cleanup(tempdir)
395 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400396 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500397 testrecipe = 'python-markupsafe'
398 srcdir = os.path.join(tempdir, testrecipe)
399 # Test devtool add
400 self.track_for_cleanup(self.workspacedir)
401 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
402 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
403 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
404 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
405 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
406 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
407 # Test devtool status
408 result = runCmd('devtool status')
409 self.assertIn(testrecipe, result.output)
410 self.assertIn(srcdir, result.output)
411 # Check recipe
412 recipefile = get_bb_var('FILE', testrecipe)
413 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
414 checkvars = {}
415 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
416 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
417 self._test_recipe_contents(recipefile, checkvars, [])
418 # Try with version specified
419 result = runCmd('devtool reset -n %s' % testrecipe)
420 shutil.rmtree(srcdir)
421 fakever = '1.9'
422 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
423 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
424 # Test devtool status
425 result = runCmd('devtool status')
426 self.assertIn(testrecipe, result.output)
427 self.assertIn(srcdir, result.output)
428 # Check recipe
429 recipefile = get_bb_var('FILE', testrecipe)
430 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
431 checkvars = {}
432 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
433 checkvars['SRC_URI'] = url
434 self._test_recipe_contents(recipefile, checkvars, [])
435
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500436 def test_devtool_add_fetch_git(self):
437 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
438 self.track_for_cleanup(tempdir)
439 url = 'gitsm://git.yoctoproject.org/mraa'
440 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
441 testrecipe = 'mraa'
442 srcdir = os.path.join(tempdir, testrecipe)
443 # Test devtool add
444 self.track_for_cleanup(self.workspacedir)
445 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
446 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
447 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
448 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
449 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
450 # Test devtool status
451 result = runCmd('devtool status')
452 self.assertIn(testrecipe, result.output)
453 self.assertIn(srcdir, result.output)
454 # Check recipe
455 recipefile = get_bb_var('FILE', testrecipe)
456 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
457 checkvars = {}
458 checkvars['S'] = '${WORKDIR}/git'
459 checkvars['PV'] = '1.0+git${SRCPV}'
460 checkvars['SRC_URI'] = url
461 checkvars['SRCREV'] = '${AUTOREV}'
462 self._test_recipe_contents(recipefile, checkvars, [])
463 # Try with revision and version specified
464 result = runCmd('devtool reset -n %s' % testrecipe)
465 shutil.rmtree(srcdir)
466 url_rev = '%s;rev=%s' % (url, checkrev)
467 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
468 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
469 # Test devtool status
470 result = runCmd('devtool status')
471 self.assertIn(testrecipe, result.output)
472 self.assertIn(srcdir, result.output)
473 # Check recipe
474 recipefile = get_bb_var('FILE', testrecipe)
475 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
476 checkvars = {}
477 checkvars['S'] = '${WORKDIR}/git'
478 checkvars['PV'] = '1.5+git${SRCPV}'
479 checkvars['SRC_URI'] = url
480 checkvars['SRCREV'] = checkrev
481 self._test_recipe_contents(recipefile, checkvars, [])
482
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500483 def test_devtool_add_fetch_simple(self):
484 # Fetch source from a remote URL, auto-detecting name
485 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
486 self.track_for_cleanup(tempdir)
487 testver = '1.6.0'
488 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
489 testrecipe = 'pv'
490 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
491 # Test devtool add
492 self.track_for_cleanup(self.workspacedir)
493 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
494 result = runCmd('devtool add %s' % url)
495 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
496 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
497 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
498 # Test devtool status
499 result = runCmd('devtool status')
500 self.assertIn(testrecipe, result.output)
501 self.assertIn(srcdir, result.output)
502 # Check recipe
503 recipefile = get_bb_var('FILE', testrecipe)
504 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
505 checkvars = {}
506 checkvars['S'] = None
507 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
508 self._test_recipe_contents(recipefile, checkvars, [])
509
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800510class DevtoolModifyTests(DevtoolBase):
511
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500512 def test_devtool_modify(self):
513 import oe.path
514
515 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
516 self.track_for_cleanup(tempdir)
517 self.track_for_cleanup(self.workspacedir)
518 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
519 self.add_command_to_tearDown('bitbake -c clean mdadm')
520 result = runCmd('devtool modify mdadm -x %s' % tempdir)
521 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
522 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
523 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
524 self.assertTrue(matches, 'bbappend not created %s' % result.output)
525
526 # Test devtool status
527 result = runCmd('devtool status')
528 self.assertIn('mdadm', result.output)
529 self.assertIn(tempdir, result.output)
530 self._check_src_repo(tempdir)
531
532 bitbake('mdadm -C unpack')
533
534 def check_line(checkfile, expected, message, present=True):
535 # Check for $expected, on a line on its own, in checkfile.
536 with open(checkfile, 'r') as f:
537 if present:
538 self.assertIn(expected + '\n', f, message)
539 else:
540 self.assertNotIn(expected + '\n', f, message)
541
542 modfile = os.path.join(tempdir, 'mdadm.8.in')
543 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
544 pkgd = bb_vars['PKGD']
545 self.assertTrue(pkgd, 'Could not query PKGD variable')
546 mandir = bb_vars['mandir']
547 self.assertTrue(mandir, 'Could not query mandir variable')
548 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
549
550 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
551 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
552
553 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
554 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
555
556 bitbake('mdadm -c package')
557 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
558
559 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
560 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
561
562 bitbake('mdadm -c package')
563 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
564
565 result = runCmd('devtool reset mdadm')
566 result = runCmd('devtool status')
567 self.assertNotIn('mdadm', result.output)
568
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500569 def test_devtool_buildclean(self):
570 def assertFile(path, *paths):
571 f = os.path.join(path, *paths)
572 self.assertExists(f)
573 def assertNoFile(path, *paths):
574 f = os.path.join(path, *paths)
575 self.assertNotExists(f)
576
577 # Clean up anything in the workdir/sysroot/sstate cache
578 bitbake('mdadm m4 -c cleansstate')
579 # Try modifying a recipe
580 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
581 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
582 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
583 self.track_for_cleanup(tempdir_mdadm)
584 self.track_for_cleanup(tempdir_m4)
585 self.track_for_cleanup(builddir_m4)
586 self.track_for_cleanup(self.workspacedir)
587 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
588 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
589 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
590 try:
591 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
592 runCmd('devtool modify m4 -x %s' % tempdir_m4)
593 assertNoFile(tempdir_mdadm, 'mdadm')
594 assertNoFile(builddir_m4, 'src/m4')
595 result = bitbake('m4 -e')
596 result = bitbake('mdadm m4 -c compile')
597 self.assertEqual(result.status, 0)
598 assertFile(tempdir_mdadm, 'mdadm')
599 assertFile(builddir_m4, 'src/m4')
600 # Check that buildclean task exists and does call make clean
601 bitbake('mdadm m4 -c buildclean')
602 assertNoFile(tempdir_mdadm, 'mdadm')
603 assertNoFile(builddir_m4, 'src/m4')
604 bitbake('mdadm m4 -c compile')
605 assertFile(tempdir_mdadm, 'mdadm')
606 assertFile(builddir_m4, 'src/m4')
607 bitbake('mdadm m4 -c clean')
608 # Check that buildclean task is run before clean for B == S
609 assertNoFile(tempdir_mdadm, 'mdadm')
610 # Check that buildclean task is not run before clean for B != S
611 assertFile(builddir_m4, 'src/m4')
612 finally:
613 self.delete_recipeinc('m4')
614
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500615 def test_devtool_modify_invalid(self):
616 # Try modifying some recipes
617 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
618 self.track_for_cleanup(tempdir)
619 self.track_for_cleanup(self.workspacedir)
620 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
621
622 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split()
623 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
624 result = runCmd('bitbake-layers show-recipes gcc-source*')
625 for line in result.output.splitlines():
626 # just match those lines that contain a real target
627 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
628 if m:
629 testrecipes.append(m.group('recipe'))
630 for testrecipe in testrecipes:
631 # Check it's a valid recipe
632 bitbake('%s -e' % testrecipe)
633 # devtool extract should fail
634 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
635 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
636 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
637 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
638 # devtool modify should fail
639 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
640 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
641 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
642
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500643 def test_devtool_modify_native(self):
644 # Check preconditions
645 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
646 # Try modifying some recipes
647 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
648 self.track_for_cleanup(tempdir)
649 self.track_for_cleanup(self.workspacedir)
650 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
651
652 bbclassextended = False
653 inheritnative = False
654 testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split()
655 for testrecipe in testrecipes:
656 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
657 if not bbclassextended:
658 bbclassextended = checkextend
659 if not inheritnative:
660 inheritnative = not checkextend
661 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
662 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
663 result = runCmd('devtool build %s' % testrecipe)
664 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
665 result = runCmd('devtool reset %s' % testrecipe)
666 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
667
668 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
669 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
670
671
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500672 def test_devtool_modify_git(self):
673 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400674 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500675 src_uri = get_bb_var('SRC_URI', testrecipe)
676 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
677 # Clean up anything in the workdir/sysroot/sstate cache
678 bitbake('%s -c cleansstate' % testrecipe)
679 # Try modifying a recipe
680 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
681 self.track_for_cleanup(tempdir)
682 self.track_for_cleanup(self.workspacedir)
683 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
684 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
685 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400686 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500687 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400688 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500689 self.assertTrue(matches, 'bbappend not created')
690 # Test devtool status
691 result = runCmd('devtool status')
692 self.assertIn(testrecipe, result.output)
693 self.assertIn(tempdir, result.output)
694 # Check git repo
695 self._check_src_repo(tempdir)
696 # Try building
697 bitbake(testrecipe)
698
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500699 def test_devtool_modify_localfiles(self):
700 # Check preconditions
701 testrecipe = 'lighttpd'
702 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
703 foundlocal = False
704 for item in src_uri:
705 if item.startswith('file://') and '.patch' not in item:
706 foundlocal = True
707 break
708 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
709 # Clean up anything in the workdir/sysroot/sstate cache
710 bitbake('%s -c cleansstate' % testrecipe)
711 # Try modifying a recipe
712 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
713 self.track_for_cleanup(tempdir)
714 self.track_for_cleanup(self.workspacedir)
715 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
716 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
717 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
718 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
719 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
720 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
721 self.assertTrue(matches, 'bbappend not created')
722 # Test devtool status
723 result = runCmd('devtool status')
724 self.assertIn(testrecipe, result.output)
725 self.assertIn(tempdir, result.output)
726 # Try building
727 bitbake(testrecipe)
728
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500729 def test_devtool_modify_virtual(self):
730 # Try modifying a virtual recipe
731 virtrecipe = 'virtual/make'
732 realrecipe = 'make'
733 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
734 self.track_for_cleanup(tempdir)
735 self.track_for_cleanup(self.workspacedir)
736 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
737 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
738 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
739 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
740 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
741 self.assertTrue(matches, 'bbappend not created %s' % result.output)
742 # Test devtool status
743 result = runCmd('devtool status')
744 self.assertNotIn(virtrecipe, result.output)
745 self.assertIn(realrecipe, result.output)
746 # Check git repo
747 self._check_src_repo(tempdir)
748 # This is probably sufficient
749
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800750class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500751
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500752 def test_devtool_update_recipe(self):
753 # Check preconditions
754 testrecipe = 'minicom'
755 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
756 recipefile = bb_vars['FILE']
757 src_uri = bb_vars['SRC_URI']
758 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
759 self._check_repo_status(os.path.dirname(recipefile), [])
760 # First, modify a recipe
761 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
762 self.track_for_cleanup(tempdir)
763 self.track_for_cleanup(self.workspacedir)
764 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
765 # (don't bother with cleaning the recipe on teardown, we won't be building it)
766 # We don't use -x here so that we test the behaviour of devtool modify without it
767 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
768 # Check git repo
769 self._check_src_repo(tempdir)
770 # Add a couple of commits
771 # FIXME: this only tests adding, need to also test update and remove
772 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
773 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
774 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
775 result = runCmd('git add devtool-new-file', cwd=tempdir)
776 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
777 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
778 result = runCmd('devtool update-recipe %s' % testrecipe)
779 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
780 ('??', '.*/0001-Change-the-README.patch$'),
781 ('??', '.*/0002-Add-a-new-file.patch$')]
782 self._check_repo_status(os.path.dirname(recipefile), expected_status)
783
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500784 def test_devtool_update_recipe_git(self):
785 # Check preconditions
786 testrecipe = 'mtd-utils'
787 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
788 recipefile = bb_vars['FILE']
789 src_uri = bb_vars['SRC_URI']
790 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
791 patches = []
792 for entry in src_uri.split():
793 if entry.startswith('file://') and entry.endswith('.patch'):
794 patches.append(entry[7:].split(';')[0])
795 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
796 self._check_repo_status(os.path.dirname(recipefile), [])
797 # First, modify a recipe
798 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
799 self.track_for_cleanup(tempdir)
800 self.track_for_cleanup(self.workspacedir)
801 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
802 # (don't bother with cleaning the recipe on teardown, we won't be building it)
803 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
804 # Check git repo
805 self._check_src_repo(tempdir)
806 # Add a couple of commits
807 # FIXME: this only tests adding, need to also test update and remove
808 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
809 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
810 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
811 result = runCmd('git add devtool-new-file', cwd=tempdir)
812 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
813 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
814 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
815 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
816 [(' D', '.*/%s$' % patch) for patch in patches]
817 self._check_repo_status(os.path.dirname(recipefile), expected_status)
818
819 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
820 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
821 srcurilines = src_uri.split()
822 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
823 srcurilines.append('"')
824 removelines = ['SRCREV = ".*"'] + srcurilines
825 for line in result.output.splitlines():
826 if line.startswith('+++') or line.startswith('---'):
827 continue
828 elif line.startswith('+'):
829 matched = False
830 for item in addlines:
831 if re.match(item, line[1:].strip()):
832 matched = True
833 break
834 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
835 elif line.startswith('-'):
836 matched = False
837 for item in removelines:
838 if re.match(item, line[1:].strip()):
839 matched = True
840 break
841 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
842 # Now try with auto mode
843 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
844 result = runCmd('devtool update-recipe %s' % testrecipe)
845 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
846 topleveldir = result.output.strip()
847 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
848 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
849 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
850 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
851 self._check_repo_status(os.path.dirname(recipefile), expected_status)
852
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500853 def test_devtool_update_recipe_append(self):
854 # Check preconditions
855 testrecipe = 'mdadm'
856 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
857 recipefile = bb_vars['FILE']
858 src_uri = bb_vars['SRC_URI']
859 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
860 self._check_repo_status(os.path.dirname(recipefile), [])
861 # First, modify a recipe
862 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
863 tempsrcdir = os.path.join(tempdir, 'source')
864 templayerdir = os.path.join(tempdir, 'layer')
865 self.track_for_cleanup(tempdir)
866 self.track_for_cleanup(self.workspacedir)
867 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
868 # (don't bother with cleaning the recipe on teardown, we won't be building it)
869 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
870 # Check git repo
871 self._check_src_repo(tempsrcdir)
872 # Add a commit
873 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
874 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
875 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
876 # Create a temporary layer and add it to bblayers.conf
877 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
878 # Create the bbappend
879 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
880 self.assertNotIn('WARNING:', result.output)
881 # Check recipe is still clean
882 self._check_repo_status(os.path.dirname(recipefile), [])
883 # Check bbappend was created
884 splitpath = os.path.dirname(recipefile).split(os.sep)
885 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
886 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
887 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
888 self.assertExists(patchfile, 'Patch file not created')
889
890 # Check bbappend contents
891 expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
892 '\n',
893 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
894 '\n']
895 with open(bbappendfile, 'r') as f:
896 self.assertEqual(expectedlines, f.readlines())
897
898 # Check we can run it again and bbappend isn't modified
899 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
900 with open(bbappendfile, 'r') as f:
901 self.assertEqual(expectedlines, f.readlines())
902 # Drop new commit and check patch gets deleted
903 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
904 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
905 self.assertNotExists(patchfile, 'Patch file not deleted')
906 expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
907 '\n']
908 with open(bbappendfile, 'r') as f:
909 self.assertEqual(expectedlines2, f.readlines())
910 # Put commit back and check we can run it if layer isn't in bblayers.conf
911 os.remove(bbappendfile)
912 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
913 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
914 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
915 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
916 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
917 with open(bbappendfile, 'r') as f:
918 self.assertEqual(expectedlines, f.readlines())
919 # Deleting isn't expected to work under these circumstances
920
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500921 def test_devtool_update_recipe_append_git(self):
922 # Check preconditions
923 testrecipe = 'mtd-utils'
924 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
925 recipefile = bb_vars['FILE']
926 src_uri = bb_vars['SRC_URI']
927 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
928 for entry in src_uri.split():
929 if entry.startswith('git://'):
930 git_uri = entry
931 break
932 self._check_repo_status(os.path.dirname(recipefile), [])
933 # First, modify a recipe
934 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
935 tempsrcdir = os.path.join(tempdir, 'source')
936 templayerdir = os.path.join(tempdir, 'layer')
937 self.track_for_cleanup(tempdir)
938 self.track_for_cleanup(self.workspacedir)
939 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
940 # (don't bother with cleaning the recipe on teardown, we won't be building it)
941 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
942 # Check git repo
943 self._check_src_repo(tempsrcdir)
944 # Add a commit
945 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
946 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
947 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
948 # Create a temporary layer
949 os.makedirs(os.path.join(templayerdir, 'conf'))
950 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
951 f.write('BBPATH .= ":${LAYERDIR}"\n')
952 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
953 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
954 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
955 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
956 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400957 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500958 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
959 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
960 # Create the bbappend
961 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
962 self.assertNotIn('WARNING:', result.output)
963 # Check recipe is still clean
964 self._check_repo_status(os.path.dirname(recipefile), [])
965 # Check bbappend was created
966 splitpath = os.path.dirname(recipefile).split(os.sep)
967 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
968 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
969 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
970
971 # Check bbappend contents
972 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
973 expectedlines = set(['SRCREV = "%s"\n' % result.output,
974 '\n',
975 'SRC_URI = "%s"\n' % git_uri,
976 '\n'])
977 with open(bbappendfile, 'r') as f:
978 self.assertEqual(expectedlines, set(f.readlines()))
979
980 # Check we can run it again and bbappend isn't modified
981 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
982 with open(bbappendfile, 'r') as f:
983 self.assertEqual(expectedlines, set(f.readlines()))
984 # Drop new commit and check SRCREV changes
985 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
986 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
987 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
988 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
989 expectedlines = set(['SRCREV = "%s"\n' % result.output,
990 '\n',
991 'SRC_URI = "%s"\n' % git_uri,
992 '\n'])
993 with open(bbappendfile, 'r') as f:
994 self.assertEqual(expectedlines, set(f.readlines()))
995 # Put commit back and check we can run it if layer isn't in bblayers.conf
996 os.remove(bbappendfile)
997 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
998 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
999 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1000 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1001 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1002 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1003 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1004 '\n',
1005 'SRC_URI = "%s"\n' % git_uri,
1006 '\n'])
1007 with open(bbappendfile, 'r') as f:
1008 self.assertEqual(expectedlines, set(f.readlines()))
1009 # Deleting isn't expected to work under these circumstances
1010
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001011 def test_devtool_update_recipe_local_files(self):
1012 """Check that local source files are copied over instead of patched"""
1013 testrecipe = 'makedevs'
1014 recipefile = get_bb_var('FILE', testrecipe)
1015 # Setup srctree for modifying the recipe
1016 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1017 self.track_for_cleanup(tempdir)
1018 self.track_for_cleanup(self.workspacedir)
1019 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1020 # (don't bother with cleaning the recipe on teardown, we won't be
1021 # building it)
1022 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1023 # Check git repo
1024 self._check_src_repo(tempdir)
1025 # Try building just to ensure we haven't broken that
1026 bitbake("%s" % testrecipe)
1027 # Edit / commit local source
1028 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1029 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1030 runCmd('echo "Bar" > new-file', cwd=tempdir)
1031 runCmd('git add new-file', cwd=tempdir)
1032 runCmd('git commit -m "Add new file"', cwd=tempdir)
1033 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1034 os.path.dirname(recipefile))
1035 runCmd('devtool update-recipe %s' % testrecipe)
1036 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1037 (' M', '.*/makedevs/makedevs.c$'),
1038 ('??', '.*/makedevs/new-local$'),
1039 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1040 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1041
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001042 def test_devtool_update_recipe_local_files_2(self):
1043 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001044 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001045 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001046 recipedir = os.path.dirname(recipefile)
1047 result = runCmd('git status --porcelain .', cwd=recipedir)
1048 if result.output.strip():
1049 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001050 # Setup srctree for modifying the recipe
1051 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1052 self.track_for_cleanup(tempdir)
1053 self.track_for_cleanup(self.workspacedir)
1054 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1055 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1056 # Check git repo
1057 self._check_src_repo(tempdir)
1058 # Add oe-local-files to Git
1059 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1060 runCmd('git add oe-local-files', cwd=tempdir)
1061 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1062 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001063 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001064 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001065 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001066 runCmd('git commit -m"Remove file"', cwd=tempdir)
1067 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1068 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1069 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1070 runCmd('echo "Gar" > new-file', cwd=tempdir)
1071 runCmd('git add new-file', cwd=tempdir)
1072 runCmd('git commit -m "Add new file"', cwd=tempdir)
1073 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1074 os.path.dirname(recipefile))
1075 # Checkout unmodified file to working copy -> devtool should still pick
1076 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001077 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001078 runCmd('devtool update-recipe %s' % testrecipe)
1079 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001080 (' M', '.*/file1$'),
1081 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001082 ('??', '.*/new-local$'),
1083 ('??', '.*/0001-Add-new-file.patch$')]
1084 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1085
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001086 def test_devtool_update_recipe_local_files_3(self):
1087 # First, modify the recipe
1088 testrecipe = 'devtool-test-localonly'
1089 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1090 recipefile = bb_vars['FILE']
1091 src_uri = bb_vars['SRC_URI']
1092 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1093 self.track_for_cleanup(tempdir)
1094 self.track_for_cleanup(self.workspacedir)
1095 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1096 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1097 result = runCmd('devtool modify %s' % testrecipe)
1098 # Modify one file
1099 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1100 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1101 result = runCmd('devtool update-recipe %s' % testrecipe)
1102 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1103 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1104
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001105 def test_devtool_update_recipe_local_patch_gz(self):
1106 # First, modify the recipe
1107 testrecipe = 'devtool-test-patch-gz'
1108 if get_bb_var('DISTRO') == 'poky-tiny':
1109 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1110 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1111 recipefile = bb_vars['FILE']
1112 src_uri = bb_vars['SRC_URI']
1113 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1114 self.track_for_cleanup(tempdir)
1115 self.track_for_cleanup(self.workspacedir)
1116 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1117 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1118 result = runCmd('devtool modify %s' % testrecipe)
1119 # Modify one file
1120 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1121 runCmd('echo "Another line" >> README', cwd=srctree)
1122 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1123 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1124 result = runCmd('devtool update-recipe %s' % testrecipe)
1125 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1126 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1127 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1128 result = runCmd('file %s' % patch_gz)
1129 if 'gzip compressed data' not in result.output:
1130 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1131
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001132 def test_devtool_update_recipe_local_files_subdir(self):
1133 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1134 # SRC_URI such that it overwrites a file that was in an archive that
1135 # was also in SRC_URI
1136 # First, modify the recipe
1137 testrecipe = 'devtool-test-subdir'
1138 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1139 recipefile = bb_vars['FILE']
1140 src_uri = bb_vars['SRC_URI']
1141 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1142 self.track_for_cleanup(tempdir)
1143 self.track_for_cleanup(self.workspacedir)
1144 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1145 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1146 result = runCmd('devtool modify %s' % testrecipe)
1147 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1148 self.assertExists(testfile, 'Extracted source could not be found')
1149 with open(testfile, 'r') as f:
1150 contents = f.read().rstrip()
1151 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1152 # Test devtool update-recipe without modifying any files
1153 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1154 result = runCmd('devtool update-recipe %s' % testrecipe)
1155 expected_status = []
1156 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1157
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001158class DevtoolExtractTests(DevtoolBase):
1159
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001160 def test_devtool_extract(self):
1161 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1162 # Try devtool extract
1163 self.track_for_cleanup(tempdir)
1164 self.track_for_cleanup(self.workspacedir)
1165 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1166 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1167 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1168 self._check_src_repo(tempdir)
1169
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001170 def test_devtool_extract_virtual(self):
1171 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1172 # Try devtool extract
1173 self.track_for_cleanup(tempdir)
1174 self.track_for_cleanup(self.workspacedir)
1175 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1176 result = runCmd('devtool extract virtual/make %s' % tempdir)
1177 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1178 self._check_src_repo(tempdir)
1179
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001180 def test_devtool_reset_all(self):
1181 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1182 self.track_for_cleanup(tempdir)
1183 self.track_for_cleanup(self.workspacedir)
1184 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1185 testrecipe1 = 'mdadm'
1186 testrecipe2 = 'cronie'
1187 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1188 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1189 result = runCmd('devtool build %s' % testrecipe1)
1190 result = runCmd('devtool build %s' % testrecipe2)
1191 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1192 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1193 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1194 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1195 result = runCmd('devtool reset -a')
1196 self.assertIn(testrecipe1, result.output)
1197 self.assertIn(testrecipe2, result.output)
1198 result = runCmd('devtool status')
1199 self.assertNotIn(testrecipe1, result.output)
1200 self.assertNotIn(testrecipe2, result.output)
1201 matches1 = glob.glob(stampprefix1 + '*')
1202 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1203 matches2 = glob.glob(stampprefix2 + '*')
1204 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1205
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001206 def test_devtool_deploy_target(self):
1207 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1208 # unfortunately the runtime tests run under bitbake and you can't run
1209 # devtool within bitbake (since devtool needs to run bitbake itself).
1210 # Additionally we are testing build-time functionality as well, so
1211 # really this has to be done as an oe-selftest test.
1212 #
1213 # Check preconditions
1214 machine = get_bb_var('MACHINE')
1215 if not machine.startswith('qemu'):
1216 self.skipTest('This test only works with qemu machines')
1217 if not os.path.exists('/etc/runqemu-nosudo'):
1218 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1219 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1220 if result.status != 0:
1221 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1222 if result.status != 0:
1223 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1224 for line in result.output.splitlines():
1225 if line.startswith('tap'):
1226 break
1227 else:
1228 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1229 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1230 # Definitions
1231 testrecipe = 'mdadm'
1232 testfile = '/sbin/mdadm'
1233 testimage = 'oe-selftest-image'
1234 testcommand = '/sbin/mdadm --help'
1235 # Build an image to run
1236 bitbake("%s qemu-native qemu-helper-native" % testimage)
1237 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1238 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1239 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1240 # Clean recipe so the first deploy will fail
1241 bitbake("%s -c clean" % testrecipe)
1242 # Try devtool modify
1243 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1244 self.track_for_cleanup(tempdir)
1245 self.track_for_cleanup(self.workspacedir)
1246 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1247 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1248 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1249 # Test that deploy-target at this point fails (properly)
1250 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1251 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1252 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1253 result = runCmd('devtool build %s' % testrecipe)
1254 # First try a dry-run of deploy-target
1255 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1256 self.assertIn(' %s' % testfile, result.output)
1257 # Boot the image
1258 with runqemu(testimage) as qemu:
1259 # Now really test deploy-target
1260 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1261 # Run a test command to see if it was installed properly
1262 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1263 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1264 # Check if it deployed all of the files with the right ownership/perms
1265 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1266 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1267 installdir = bb_vars['D']
1268 fakerootenv = bb_vars['FAKEROOTENV']
1269 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001270 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001271 filelist1 = self._process_ls_output(result.output)
1272
1273 # Now look on the target
1274 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1275 self.track_for_cleanup(tempdir2)
1276 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1277 with open(tmpfilelist, 'w') as f:
1278 for line in filelist1:
1279 splitline = line.split()
1280 f.write(splitline[-1] + '\n')
1281 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1282 filelist2 = self._process_ls_output(result.output)
1283 filelist1.sort(key=lambda item: item.split()[-1])
1284 filelist2.sort(key=lambda item: item.split()[-1])
1285 self.assertEqual(filelist1, filelist2)
1286 # Test undeploy-target
1287 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1288 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1289 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1290
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001291 def test_devtool_build_image(self):
1292 """Test devtool build-image plugin"""
1293 # Check preconditions
1294 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1295 image = 'core-image-minimal'
1296 self.track_for_cleanup(self.workspacedir)
1297 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1298 self.add_command_to_tearDown('bitbake -c clean %s' % image)
1299 bitbake('%s -c clean' % image)
1300 # Add target and native recipes to workspace
1301 recipes = ['mdadm', 'parted-native']
1302 for recipe in recipes:
1303 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1304 self.track_for_cleanup(tempdir)
1305 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1306 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1307 # Try to build image
1308 result = runCmd('devtool build-image %s' % image)
1309 self.assertNotEqual(result, 0, 'devtool build-image failed')
1310 # Check if image contains expected packages
1311 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1312 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1313 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1314 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1315 for line in f:
1316 splitval = line.split()
1317 if splitval:
1318 pkg = splitval[0]
1319 if pkg in reqpkgs:
1320 reqpkgs.remove(pkg)
1321 if reqpkgs:
1322 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1323
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001324class DevtoolUpgradeTests(DevtoolBase):
1325
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001326 def test_devtool_upgrade(self):
1327 # Check preconditions
1328 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1329 self.track_for_cleanup(self.workspacedir)
1330 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1331 # Check parameters
1332 result = runCmd('devtool upgrade -h')
1333 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1334 self.assertIn(param, result.output)
1335 # For the moment, we are using a real recipe.
1336 recipe = 'devtool-upgrade-test1'
1337 version = '1.6.0'
1338 oldrecipefile = get_bb_var('FILE', recipe)
1339 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1340 self.track_for_cleanup(tempdir)
1341 # Check that recipe is not already under devtool control
1342 result = runCmd('devtool status')
1343 self.assertNotIn(recipe, result.output)
1344 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1345 # we are downgrading instead of upgrading.
1346 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1347 # Check if srctree at least is populated
1348 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1349 # Check new recipe subdirectory is present
1350 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1351 # Check new recipe file is present
1352 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1353 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1354 # Check devtool status and make sure recipe is present
1355 result = runCmd('devtool status')
1356 self.assertIn(recipe, result.output)
1357 self.assertIn(tempdir, result.output)
1358 # Check recipe got changed as expected
1359 with open(oldrecipefile + '.upgraded', 'r') as f:
1360 desiredlines = f.readlines()
1361 with open(newrecipefile, 'r') as f:
1362 newlines = f.readlines()
1363 self.assertEqual(desiredlines, newlines)
1364 # Check devtool reset recipe
1365 result = runCmd('devtool reset %s -n' % recipe)
1366 result = runCmd('devtool status')
1367 self.assertNotIn(recipe, result.output)
1368 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1369
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001370 def test_devtool_upgrade_git(self):
1371 # Check preconditions
1372 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1373 self.track_for_cleanup(self.workspacedir)
1374 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1375 recipe = 'devtool-upgrade-test2'
1376 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1377 oldrecipefile = get_bb_var('FILE', recipe)
1378 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1379 self.track_for_cleanup(tempdir)
1380 # Check that recipe is not already under devtool control
1381 result = runCmd('devtool status')
1382 self.assertNotIn(recipe, result.output)
1383 # Check upgrade
1384 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1385 # Check if srctree at least is populated
1386 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1387 # Check new recipe file is present
1388 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1389 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1390 # Check devtool status and make sure recipe is present
1391 result = runCmd('devtool status')
1392 self.assertIn(recipe, result.output)
1393 self.assertIn(tempdir, result.output)
1394 # Check recipe got changed as expected
1395 with open(oldrecipefile + '.upgraded', 'r') as f:
1396 desiredlines = f.readlines()
1397 with open(newrecipefile, 'r') as f:
1398 newlines = f.readlines()
1399 self.assertEqual(desiredlines, newlines)
1400 # Check devtool reset recipe
1401 result = runCmd('devtool reset %s -n' % recipe)
1402 result = runCmd('devtool status')
1403 self.assertNotIn(recipe, result.output)
1404 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1405
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001406 def test_devtool_layer_plugins(self):
1407 """Test that devtool can use plugins from other layers.
1408
1409 This test executes the selftest-reverse command from meta-selftest."""
1410
1411 self.track_for_cleanup(self.workspacedir)
1412 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1413
1414 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1415 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1416 self.assertEqual(result.output, s[::-1])
1417
1418 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1419 dstdir = basedstdir
1420 self.assertExists(dstdir)
1421 for p in paths:
1422 dstdir = os.path.join(dstdir, p)
1423 if not os.path.exists(dstdir):
1424 os.makedirs(dstdir)
1425 self.track_for_cleanup(dstdir)
1426 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1427 if srcfile != dstfile:
1428 shutil.copy(srcfile, dstfile)
1429 self.track_for_cleanup(dstfile)
1430
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001431 def test_devtool_load_plugin(self):
1432 """Test that devtool loads only the first found plugin in BBPATH."""
1433
1434 self.track_for_cleanup(self.workspacedir)
1435 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1436
1437 devtool = runCmd("which devtool")
1438 fromname = runCmd("devtool --quiet pluginfile")
1439 srcfile = fromname.output
1440 bbpath = get_bb_var('BBPATH')
1441 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1442 plugincontent = []
1443 with open(srcfile) as fh:
1444 plugincontent = fh.readlines()
1445 try:
1446 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1447 for path in searchpath:
1448 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1449 result = runCmd("devtool --quiet count")
1450 self.assertEqual(result.output, '1')
1451 result = runCmd("devtool --quiet multiloaded")
1452 self.assertEqual(result.output, "no")
1453 for path in searchpath:
1454 result = runCmd("devtool --quiet bbdir")
1455 self.assertEqual(result.output, path)
1456 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1457 finally:
1458 with open(srcfile, 'w') as fh:
1459 fh.writelines(plugincontent)
1460
1461 def _setup_test_devtool_finish_upgrade(self):
1462 # Check preconditions
1463 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1464 self.track_for_cleanup(self.workspacedir)
1465 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1466 # Use a "real" recipe from meta-selftest
1467 recipe = 'devtool-upgrade-test1'
1468 oldversion = '1.5.3'
1469 newversion = '1.6.0'
1470 oldrecipefile = get_bb_var('FILE', recipe)
1471 recipedir = os.path.dirname(oldrecipefile)
1472 result = runCmd('git status --porcelain .', cwd=recipedir)
1473 if result.output.strip():
1474 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1475 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1476 self.track_for_cleanup(tempdir)
1477 # Check that recipe is not already under devtool control
1478 result = runCmd('devtool status')
1479 self.assertNotIn(recipe, result.output)
1480 # Do the upgrade
1481 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1482 # Check devtool status and make sure recipe is present
1483 result = runCmd('devtool status')
1484 self.assertIn(recipe, result.output)
1485 self.assertIn(tempdir, result.output)
1486 # Make a change to the source
1487 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1488 result = runCmd('git status --porcelain', cwd=tempdir)
1489 self.assertIn('M src/pv/number.c', result.output)
1490 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1491 # Check if patch is there
1492 recipedir = os.path.dirname(oldrecipefile)
1493 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1494 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
1495 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
1496 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn
1497
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001498 def test_devtool_finish_upgrade_origlayer(self):
1499 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
1500 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1501 self.assertIn('/meta-selftest/', recipedir)
1502 # Try finish to the original layer
1503 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1504 result = runCmd('devtool finish %s meta-selftest' % recipe)
1505 result = runCmd('devtool status')
1506 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1507 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1508 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1509 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
1510 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1511 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1512 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1513 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
1514 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
1515
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001516 def test_devtool_finish_upgrade_otherlayer(self):
1517 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
1518 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1519 self.assertIn('/meta-selftest/', recipedir)
1520 # Try finish to a different layer - should create a bbappend
1521 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1522 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1523 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1524 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1525 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1526 self.track_for_cleanup(newrecipedir)
1527 result = runCmd('devtool finish %s oe-core' % recipe)
1528 result = runCmd('devtool status')
1529 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1530 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1531 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1532 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
1533 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1534 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1535 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
1536 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
1537
1538 def _setup_test_devtool_finish_modify(self):
1539 # Check preconditions
1540 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1541 # Try modifying a recipe
1542 self.track_for_cleanup(self.workspacedir)
1543 recipe = 'mdadm'
1544 oldrecipefile = get_bb_var('FILE', recipe)
1545 recipedir = os.path.dirname(oldrecipefile)
1546 result = runCmd('git status --porcelain .', cwd=recipedir)
1547 if result.output.strip():
1548 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1549 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1550 self.track_for_cleanup(tempdir)
1551 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1552 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1553 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1554 # Test devtool status
1555 result = runCmd('devtool status')
1556 self.assertIn(recipe, result.output)
1557 self.assertIn(tempdir, result.output)
1558 # Make a change to the source
1559 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1560 result = runCmd('git status --porcelain', cwd=tempdir)
1561 self.assertIn('M maps.c', result.output)
1562 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1563 for entry in os.listdir(recipedir):
1564 filesdir = os.path.join(recipedir, entry)
1565 if os.path.isdir(filesdir):
1566 break
1567 else:
1568 self.fail('Unable to find recipe files directory for %s' % recipe)
1569 return recipe, oldrecipefile, recipedir, filesdir
1570
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001571 def test_devtool_finish_modify_origlayer(self):
1572 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1573 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1574 self.assertIn('/meta/', recipedir)
1575 # Try finish to the original layer
1576 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1577 result = runCmd('devtool finish %s meta' % recipe)
1578 result = runCmd('devtool status')
1579 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1580 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1581 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1582 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1583 self._check_repo_status(recipedir, expected_status)
1584
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001585 def test_devtool_finish_modify_otherlayer(self):
1586 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1587 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1588 self.assertIn('/meta/', recipedir)
1589 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1590 appenddir = os.path.join(get_test_layer(), relpth)
1591 self.track_for_cleanup(appenddir)
1592 # Try finish to the original layer
1593 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1594 result = runCmd('devtool finish %s meta-selftest' % recipe)
1595 result = runCmd('devtool status')
1596 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1597 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1598 result = runCmd('git status --porcelain .', cwd=recipedir)
1599 if result.output.strip():
1600 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1601 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1602 recipefn = recipefn.split('_')[0] + '_%'
1603 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1604 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1605 newdir = os.path.join(appenddir, recipe)
1606 files = os.listdir(newdir)
1607 foundpatch = None
1608 for fn in files:
1609 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1610 foundpatch = fn
1611 if not foundpatch:
1612 self.fail('No patch file created next to bbappend')
1613 files.remove(foundpatch)
1614 if files:
1615 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1616
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001617 def test_devtool_rename(self):
1618 # Check preconditions
1619 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1620 self.track_for_cleanup(self.workspacedir)
1621 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1622
1623 # First run devtool add
1624 # We already have this recipe in OE-Core, but that doesn't matter
1625 recipename = 'i2c-tools'
1626 recipever = '3.1.2'
1627 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1628 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1629 def add_recipe():
1630 result = runCmd('devtool add %s' % url)
1631 self.assertExists(recipefile, 'Expected recipe file not created')
1632 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1633 checkvars = {}
1634 checkvars['S'] = None
1635 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1636 self._test_recipe_contents(recipefile, checkvars, [])
1637 add_recipe()
1638 # Now rename it - change both name and version
1639 newrecipename = 'mynewrecipe'
1640 newrecipever = '456'
1641 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1642 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1643 self.assertExists(newrecipefile, 'Recipe file not renamed')
1644 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1645 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1646 self.assertExists(newsrctree, 'Source directory not renamed')
1647 checkvars = {}
1648 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1649 checkvars['SRC_URI'] = url
1650 self._test_recipe_contents(newrecipefile, checkvars, [])
1651 # Try again - change just name this time
1652 result = runCmd('devtool reset -n %s' % newrecipename)
1653 shutil.rmtree(newsrctree)
1654 add_recipe()
1655 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1656 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1657 self.assertExists(newrecipefile, 'Recipe file not renamed')
1658 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1659 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1660 checkvars = {}
1661 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1662 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1663 self._test_recipe_contents(newrecipefile, checkvars, [])
1664 # Try again - change just version this time
1665 result = runCmd('devtool reset -n %s' % newrecipename)
1666 shutil.rmtree(newsrctree)
1667 add_recipe()
1668 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1669 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1670 self.assertExists(newrecipefile, 'Recipe file not renamed')
1671 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1672 checkvars = {}
1673 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1674 checkvars['SRC_URI'] = url
1675 self._test_recipe_contents(newrecipefile, checkvars, [])
1676
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001677 def test_devtool_virtual_kernel_modify(self):
1678 """
1679 Summary: The purpose of this test case is to verify that
1680 devtool modify works correctly when building
1681 the kernel.
1682 Dependencies: NA
1683 Steps: 1. Build kernel with bitbake.
1684 2. Save the config file generated.
1685 3. Clean the environment.
1686 4. Use `devtool modify virtual/kernel` to validate following:
1687 4.1 The source is checked out correctly.
1688 4.2 The resulting configuration is the same as
1689 what was get on step 2.
1690 4.3 The Kernel can be build correctly.
1691 4.4 Changes made on the source are reflected on the
1692 subsequent builds.
1693 4.5 Changes on the configuration are reflected on the
1694 subsequent builds
1695 Expected: devtool modify is able to checkout the source of the kernel
1696 and modification to the source and configurations are reflected
1697 when building the kernel.
1698 """
1699 kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
1700 # Clean up the enviroment
1701 bitbake('%s -c clean' % kernel_provider)
1702 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1703 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1704 self.track_for_cleanup(tempdir)
1705 self.track_for_cleanup(tempdir_cfg)
1706 self.track_for_cleanup(self.workspacedir)
1707 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1708 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
1709 #Step 1
1710 #Here is just generated the config file instead of all the kernel to optimize the
1711 #time of executing this test case.
1712 bitbake('%s -c configure' % kernel_provider)
1713 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1714 #Step 2
1715 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1716 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1717
1718 tmpconfig = os.path.join(tempdir_cfg, '.config')
1719 #Step 3
1720 bitbake('%s -c clean' % kernel_provider)
1721 #Step 4.1
1722 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1723 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1724 #Step 4.2
1725 configfile = os.path.join(tempdir,'.config')
1726 diff = runCmd('diff %s %s' % (tmpconfig, configfile))
1727 self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
1728 #Step 4.3
1729 #NOTE: virtual/kernel is mapped to kernel_provider
1730 result = runCmd('devtool build %s' % kernel_provider)
1731 self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
1732 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
1733 self.assertExists(kernelfile, 'Kernel was not build correctly')
1734
1735 #Modify the kernel source
1736 modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
1737 modstring = "Use a boot loader. Devtool testing."
1738 modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
1739 self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
1740 #Modify the configuration
1741 codeconfigfile = os.path.join(tempdir,'.config.new')
1742 modconfopt = "CONFIG_SG_POOL=n"
1743 modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
1744 self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
1745 #Build again kernel with devtool
1746 rebuild = runCmd('devtool build %s' % kernel_provider)
1747 self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
1748 #Step 4.4
1749 bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
1750 bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
1751 checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
1752 self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
1753 #Step 4.5
1754 checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
1755 self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')