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