blob: b8edc897687c3ba4029fd668631229df4a327bb2 [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)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050059 # avoid race condition by not copying .pyc files YPBZ#13421,13803
60 shutil.copytree(pth, destdir, ignore=ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080061 else:
62 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
63 bb.utils.mkdirhier(destdir)
64 shutil.copy2(pth, destdir)
65 return newmetapath
66 else:
67 return layerpath
68 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
69
70def tearDownModule():
71 if oldmetapath:
72 edited_layers = []
73 def bblayers_edit_cb(layerpath, canonical_layerpath):
74 if not edited_layers and canonical_layerpath.endswith('/meta'):
75 edited_layers.append(layerpath)
76 return oldmetapath
77 else:
78 return layerpath
79 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
80 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
81 shutil.rmtree(templayerdir)
82
Brad Bishopd7bf8c12018-02-25 22:55:05 -050083class DevtoolBase(OESelftestTestCase):
84
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080085 @classmethod
86 def setUpClass(cls):
87 super(DevtoolBase, cls).setUpClass()
88 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
89 cls.original_sstate = bb_vars['SSTATE_DIR']
90 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
91 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
92 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
93 % cls.original_sstate)
94
95 @classmethod
96 def tearDownClass(cls):
97 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
98 runCmd('rm -rf %s' % cls.devtool_sstate)
99 super(DevtoolBase, cls).tearDownClass()
100
101 def setUp(self):
102 """Test case setup function"""
103 super(DevtoolBase, self).setUp()
104 self.workspacedir = os.path.join(self.builddir, 'workspace')
105 self.assertTrue(not os.path.exists(self.workspacedir),
106 'This test cannot be run with a workspace directory '
107 'under the build directory')
108 self.append_config(self.sstate_conf)
109
110 def _check_src_repo(self, repo_dir):
111 """Check srctree git repository"""
112 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
113 'git repository for external source tree not found')
114 result = runCmd('git status --porcelain', cwd=repo_dir)
115 self.assertEqual(result.output.strip(), "",
116 'Created git repo is not clean')
117 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
118 self.assertEqual(result.output.strip(), "refs/heads/devtool",
119 'Wrong branch in git repo')
120
121 def _check_repo_status(self, repo_dir, expected_status):
122 """Check the worktree status of a repository"""
123 result = runCmd('git status . --porcelain',
124 cwd=repo_dir)
125 for line in result.output.splitlines():
126 for ind, (f_status, fn_re) in enumerate(expected_status):
127 if re.match(fn_re, line[3:]):
128 if f_status != line[:2]:
129 self.fail('Unexpected status in line: %s' % line)
130 expected_status.pop(ind)
131 break
132 else:
133 self.fail('Unexpected modified file in line: %s' % line)
134 if expected_status:
135 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500136
137 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
138 with open(recipefile, 'r') as f:
139 invar = None
140 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500141 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500142 for line in f:
143 var = None
144 if invar:
145 value = line.strip().strip('"')
146 if value.endswith('\\'):
147 invalue += ' ' + value[:-1].strip()
148 continue
149 else:
150 invalue += ' ' + value.strip()
151 var = invar
152 value = invalue
153 invar = None
154 elif '=' in line:
155 splitline = line.split('=', 1)
156 var = splitline[0].rstrip()
157 value = splitline[1].strip().strip('"')
158 if value.endswith('\\'):
159 invalue = value[:-1].strip()
160 invar = var
161 continue
162 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500163 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500164
165 if var and var in checkvars:
166 needvalue = checkvars.pop(var)
167 if needvalue is None:
168 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
169 if isinstance(needvalue, set):
170 if var == 'LICENSE':
171 value = set(value.split(' & '))
172 else:
173 value = set(value.split())
174 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
175
176
177 missingvars = {}
178 for var, value in checkvars.items():
179 if value is not None:
180 missingvars[var] = value
181 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
182
183 for inherit in checkinherits:
184 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
185
186 def _check_bbappend(self, testrecipe, recipefile, appenddir):
187 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
188 resultlines = result.output.splitlines()
189 inrecipe = False
190 bbappends = []
191 bbappendfile = None
192 for line in resultlines:
193 if inrecipe:
194 if line.startswith(' '):
195 bbappends.append(line.strip())
196 else:
197 break
198 elif line == '%s:' % os.path.basename(recipefile):
199 inrecipe = True
200 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
201 for bbappend in bbappends:
202 if bbappend.startswith(appenddir):
203 bbappendfile = bbappend
204 break
205 else:
206 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
207 return bbappendfile
208
209 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
210 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
211 if addlayer:
212 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
213 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
214
215 def _process_ls_output(self, output):
216 """
217 Convert ls -l output to a format we can reasonably compare from one context
218 to another (e.g. from host to target)
219 """
220 filelist = []
221 for line in output.splitlines():
222 splitline = line.split()
223 if len(splitline) < 8:
224 self.fail('_process_ls_output: invalid output line: %s' % line)
225 # Remove trailing . on perms
226 splitline[0] = splitline[0].rstrip('.')
227 # Remove leading . on paths
228 splitline[-1] = splitline[-1].lstrip('.')
229 # Drop fields we don't want to compare
230 del splitline[7]
231 del splitline[6]
232 del splitline[5]
233 del splitline[4]
234 del splitline[1]
235 filelist.append(' '.join(splitline))
236 return filelist
237
238
239class DevtoolTests(DevtoolBase):
240
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500241 def test_create_workspace(self):
242 # Check preconditions
243 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400244 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 -0400245 # remove conf/devtool.conf to avoid it corrupting tests
246 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
247 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500248 # Try creating a workspace layer with a specific path
249 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
250 self.track_for_cleanup(tempdir)
251 result = runCmd('devtool create-workspace %s' % tempdir)
252 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
253 result = runCmd('bitbake-layers show-layers')
254 self.assertIn(tempdir, result.output)
255 # Try creating a workspace layer with the default path
256 self.track_for_cleanup(self.workspacedir)
257 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
258 result = runCmd('devtool create-workspace')
259 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
260 result = runCmd('bitbake-layers show-layers')
261 self.assertNotIn(tempdir, result.output)
262 self.assertIn(self.workspacedir, result.output)
263
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800264class DevtoolAddTests(DevtoolBase):
265
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500266 def test_devtool_add(self):
267 # Fetch source
268 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
269 self.track_for_cleanup(tempdir)
270 pn = 'pv'
271 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600272 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500273 result = runCmd('wget %s' % url, cwd=tempdir)
274 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
275 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
276 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
277 # Test devtool add
278 self.track_for_cleanup(self.workspacedir)
279 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
280 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
281 result = runCmd('devtool add %s %s' % (pn, srcdir))
282 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
283 # Test devtool status
284 result = runCmd('devtool status')
285 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
286 self.assertIn(recipepath, result.output)
287 self.assertIn(srcdir, result.output)
288 # Test devtool find-recipe
289 result = runCmd('devtool -q find-recipe %s' % pn)
290 self.assertEqual(recipepath, result.output.strip())
291 # Test devtool edit-recipe
292 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
293 self.assertEqual('123 %s' % recipepath, result.output.strip())
294 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
295 bitbake('%s -c cleansstate' % pn)
296 # Test devtool build
297 result = runCmd('devtool build %s' % pn)
298 bb_vars = get_bb_vars(['D', 'bindir'], pn)
299 installdir = bb_vars['D']
300 self.assertTrue(installdir, 'Could not query installdir variable')
301 bindir = bb_vars['bindir']
302 self.assertTrue(bindir, 'Could not query bindir variable')
303 if bindir[0] == '/':
304 bindir = bindir[1:]
305 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
306
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500307 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800308 # We need dbus built so that DEPENDS recognition works
309 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 # Fetch source from a remote URL, but do it outside of devtool
311 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
312 self.track_for_cleanup(tempdir)
313 pn = 'dbus-wait'
314 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
315 # We choose an https:// git URL here to check rewriting the URL works
316 url = 'https://git.yoctoproject.org/git/dbus-wait'
317 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
318 # instead of the directory name
319 result = runCmd('git clone %s noname' % url, cwd=tempdir)
320 srcdir = os.path.join(tempdir, 'noname')
321 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
322 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
323 # Test devtool add
324 self.track_for_cleanup(self.workspacedir)
325 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
326 # Don't specify a name since we should be able to auto-detect it
327 result = runCmd('devtool add %s' % srcdir)
328 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
329 # Check the recipe name is correct
330 recipefile = get_bb_var('FILE', pn)
331 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
332 self.assertIn(recipefile, result.output)
333 # Test devtool status
334 result = runCmd('devtool status')
335 self.assertIn(pn, result.output)
336 self.assertIn(srcdir, result.output)
337 self.assertIn(recipefile, result.output)
338 checkvars = {}
339 checkvars['LICENSE'] = 'GPLv2'
340 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
341 checkvars['S'] = '${WORKDIR}/git'
342 checkvars['PV'] = '0.1+git${SRCPV}'
343 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https'
344 checkvars['SRCREV'] = srcrev
345 checkvars['DEPENDS'] = set(['dbus'])
346 self._test_recipe_contents(recipefile, checkvars, [])
347
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500348 def test_devtool_add_library(self):
349 # Fetch source
350 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
351 self.track_for_cleanup(tempdir)
352 version = '1.1'
353 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
354 result = runCmd('wget %s' % url, cwd=tempdir)
355 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
356 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
357 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
358 # Test devtool add (and use -V so we test that too)
359 self.track_for_cleanup(self.workspacedir)
360 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
361 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
362 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
363 # Test devtool status
364 result = runCmd('devtool status')
365 self.assertIn('libftdi', result.output)
366 self.assertIn(srcdir, result.output)
367 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
368 bitbake('libftdi -c cleansstate')
369 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
370 # There's also the matter of it installing cmake files to a path we don't
371 # normally cover, which triggers the installed-vs-shipped QA test we have
372 # within do_package
373 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
374 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
375 with open(recipefile, 'a') as f:
376 f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n')
377 # We don't have the ability to pick up this dependency automatically yet...
378 f.write('\nDEPENDS += "libusb1"\n')
379 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
380 # Test devtool build
381 result = runCmd('devtool build libftdi')
382 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
383 staging_libdir = bb_vars['TESTLIBOUTPUT']
384 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
385 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)
386 # Test devtool reset
387 stampprefix = bb_vars['STAMP']
388 result = runCmd('devtool reset libftdi')
389 result = runCmd('devtool status')
390 self.assertNotIn('libftdi', result.output)
391 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
392 matches = glob.glob(stampprefix + '*')
393 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
394 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
395
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500396 def test_devtool_add_fetch(self):
397 # Fetch source
398 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
399 self.track_for_cleanup(tempdir)
400 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400401 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500402 testrecipe = 'python-markupsafe'
403 srcdir = os.path.join(tempdir, testrecipe)
404 # Test devtool add
405 self.track_for_cleanup(self.workspacedir)
406 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
407 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
408 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
409 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
410 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
411 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
412 # Test devtool status
413 result = runCmd('devtool status')
414 self.assertIn(testrecipe, result.output)
415 self.assertIn(srcdir, result.output)
416 # Check recipe
417 recipefile = get_bb_var('FILE', testrecipe)
418 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
419 checkvars = {}
420 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
421 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
422 self._test_recipe_contents(recipefile, checkvars, [])
423 # Try with version specified
424 result = runCmd('devtool reset -n %s' % testrecipe)
425 shutil.rmtree(srcdir)
426 fakever = '1.9'
427 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
428 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
429 # Test devtool status
430 result = runCmd('devtool status')
431 self.assertIn(testrecipe, result.output)
432 self.assertIn(srcdir, result.output)
433 # Check recipe
434 recipefile = get_bb_var('FILE', testrecipe)
435 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
436 checkvars = {}
437 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
438 checkvars['SRC_URI'] = url
439 self._test_recipe_contents(recipefile, checkvars, [])
440
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500441 def test_devtool_add_fetch_git(self):
442 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
443 self.track_for_cleanup(tempdir)
444 url = 'gitsm://git.yoctoproject.org/mraa'
445 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
446 testrecipe = 'mraa'
447 srcdir = os.path.join(tempdir, testrecipe)
448 # Test devtool add
449 self.track_for_cleanup(self.workspacedir)
450 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
451 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
452 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
453 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
454 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
455 # Test devtool status
456 result = runCmd('devtool status')
457 self.assertIn(testrecipe, result.output)
458 self.assertIn(srcdir, result.output)
459 # Check recipe
460 recipefile = get_bb_var('FILE', testrecipe)
461 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
462 checkvars = {}
463 checkvars['S'] = '${WORKDIR}/git'
464 checkvars['PV'] = '1.0+git${SRCPV}'
465 checkvars['SRC_URI'] = url
466 checkvars['SRCREV'] = '${AUTOREV}'
467 self._test_recipe_contents(recipefile, checkvars, [])
468 # Try with revision and version specified
469 result = runCmd('devtool reset -n %s' % testrecipe)
470 shutil.rmtree(srcdir)
471 url_rev = '%s;rev=%s' % (url, checkrev)
472 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
473 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
474 # Test devtool status
475 result = runCmd('devtool status')
476 self.assertIn(testrecipe, result.output)
477 self.assertIn(srcdir, result.output)
478 # Check recipe
479 recipefile = get_bb_var('FILE', testrecipe)
480 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
481 checkvars = {}
482 checkvars['S'] = '${WORKDIR}/git'
483 checkvars['PV'] = '1.5+git${SRCPV}'
484 checkvars['SRC_URI'] = url
485 checkvars['SRCREV'] = checkrev
486 self._test_recipe_contents(recipefile, checkvars, [])
487
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500488 def test_devtool_add_fetch_simple(self):
489 # Fetch source from a remote URL, auto-detecting name
490 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
491 self.track_for_cleanup(tempdir)
492 testver = '1.6.0'
493 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
494 testrecipe = 'pv'
495 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
496 # Test devtool add
497 self.track_for_cleanup(self.workspacedir)
498 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
499 result = runCmd('devtool add %s' % url)
500 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
501 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
502 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
503 # Test devtool status
504 result = runCmd('devtool status')
505 self.assertIn(testrecipe, result.output)
506 self.assertIn(srcdir, result.output)
507 # Check recipe
508 recipefile = get_bb_var('FILE', testrecipe)
509 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
510 checkvars = {}
511 checkvars['S'] = None
512 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
513 self._test_recipe_contents(recipefile, checkvars, [])
514
Andrew Geissler82c905d2020-04-13 13:39:40 -0500515 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600516 collections = get_bb_var('BBFILE_COLLECTIONS').split()
517 if "openembedded-layer" not in collections:
518 self.skipTest("Test needs meta-oe for nodejs")
519
Andrew Geissler82c905d2020-04-13 13:39:40 -0500520 pn = 'savoirfairelinux-node-server-example'
521 pv = '1.0.0'
522 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
523 # Test devtool add
524 self.track_for_cleanup(self.workspacedir)
525 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
526 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
527 result = runCmd('devtool add \'%s\'' % url)
528 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
529 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
530 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
531 # Test devtool status
532 result = runCmd('devtool status')
533 self.assertIn(pn, result.output)
534 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
535 bitbake('%s -c cleansstate' % pn)
536 # Test devtool build
537 result = runCmd('devtool build %s' % pn)
538
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800539class DevtoolModifyTests(DevtoolBase):
540
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500541 def test_devtool_modify(self):
542 import oe.path
543
544 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
545 self.track_for_cleanup(tempdir)
546 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500547 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400548 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500549 result = runCmd('devtool modify mdadm -x %s' % tempdir)
550 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
551 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
552 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
553 self.assertTrue(matches, 'bbappend not created %s' % result.output)
554
555 # Test devtool status
556 result = runCmd('devtool status')
557 self.assertIn('mdadm', result.output)
558 self.assertIn(tempdir, result.output)
559 self._check_src_repo(tempdir)
560
561 bitbake('mdadm -C unpack')
562
563 def check_line(checkfile, expected, message, present=True):
564 # Check for $expected, on a line on its own, in checkfile.
565 with open(checkfile, 'r') as f:
566 if present:
567 self.assertIn(expected + '\n', f, message)
568 else:
569 self.assertNotIn(expected + '\n', f, message)
570
571 modfile = os.path.join(tempdir, 'mdadm.8.in')
572 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
573 pkgd = bb_vars['PKGD']
574 self.assertTrue(pkgd, 'Could not query PKGD variable')
575 mandir = bb_vars['mandir']
576 self.assertTrue(mandir, 'Could not query mandir variable')
577 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
578
579 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
580 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
581
582 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
583 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
584
585 bitbake('mdadm -c package')
586 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
587
588 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
589 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
590
591 bitbake('mdadm -c package')
592 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
593
594 result = runCmd('devtool reset mdadm')
595 result = runCmd('devtool status')
596 self.assertNotIn('mdadm', result.output)
597
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500598 def test_devtool_buildclean(self):
599 def assertFile(path, *paths):
600 f = os.path.join(path, *paths)
601 self.assertExists(f)
602 def assertNoFile(path, *paths):
603 f = os.path.join(path, *paths)
604 self.assertNotExists(f)
605
606 # Clean up anything in the workdir/sysroot/sstate cache
607 bitbake('mdadm m4 -c cleansstate')
608 # Try modifying a recipe
609 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
610 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
611 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
612 self.track_for_cleanup(tempdir_mdadm)
613 self.track_for_cleanup(tempdir_m4)
614 self.track_for_cleanup(builddir_m4)
615 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500616 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400617 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500618 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
619 try:
620 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
621 runCmd('devtool modify m4 -x %s' % tempdir_m4)
622 assertNoFile(tempdir_mdadm, 'mdadm')
623 assertNoFile(builddir_m4, 'src/m4')
624 result = bitbake('m4 -e')
625 result = bitbake('mdadm m4 -c compile')
626 self.assertEqual(result.status, 0)
627 assertFile(tempdir_mdadm, 'mdadm')
628 assertFile(builddir_m4, 'src/m4')
629 # Check that buildclean task exists and does call make clean
630 bitbake('mdadm m4 -c buildclean')
631 assertNoFile(tempdir_mdadm, 'mdadm')
632 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400633 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500634 bitbake('mdadm m4 -c compile')
635 assertFile(tempdir_mdadm, 'mdadm')
636 assertFile(builddir_m4, 'src/m4')
637 bitbake('mdadm m4 -c clean')
638 # Check that buildclean task is run before clean for B == S
639 assertNoFile(tempdir_mdadm, 'mdadm')
640 # Check that buildclean task is not run before clean for B != S
641 assertFile(builddir_m4, 'src/m4')
642 finally:
643 self.delete_recipeinc('m4')
644
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500645 def test_devtool_modify_invalid(self):
646 # Try modifying some recipes
647 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
648 self.track_for_cleanup(tempdir)
649 self.track_for_cleanup(self.workspacedir)
650 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
651
652 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split()
653 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
654 result = runCmd('bitbake-layers show-recipes gcc-source*')
655 for line in result.output.splitlines():
656 # just match those lines that contain a real target
657 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
658 if m:
659 testrecipes.append(m.group('recipe'))
660 for testrecipe in testrecipes:
661 # Check it's a valid recipe
662 bitbake('%s -e' % testrecipe)
663 # devtool extract should fail
664 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
665 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
666 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
667 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
668 # devtool modify should fail
669 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
670 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
671 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
672
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500673 def test_devtool_modify_native(self):
674 # Check preconditions
675 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
676 # Try modifying some recipes
677 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
678 self.track_for_cleanup(tempdir)
679 self.track_for_cleanup(self.workspacedir)
680 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
681
682 bbclassextended = False
683 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500684 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500685 for testrecipe in testrecipes:
686 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
687 if not bbclassextended:
688 bbclassextended = checkextend
689 if not inheritnative:
690 inheritnative = not checkextend
691 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
692 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
693 result = runCmd('devtool build %s' % testrecipe)
694 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
695 result = runCmd('devtool reset %s' % testrecipe)
696 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
697
698 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
699 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
700
701
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500702 def test_devtool_modify_git(self):
703 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400704 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500705 src_uri = get_bb_var('SRC_URI', testrecipe)
706 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
707 # Clean up anything in the workdir/sysroot/sstate cache
708 bitbake('%s -c cleansstate' % testrecipe)
709 # Try modifying a recipe
710 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
711 self.track_for_cleanup(tempdir)
712 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500713 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400714 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500715 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400716 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500717 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 -0400718 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500719 self.assertTrue(matches, 'bbappend not created')
720 # Test devtool status
721 result = runCmd('devtool status')
722 self.assertIn(testrecipe, result.output)
723 self.assertIn(tempdir, result.output)
724 # Check git repo
725 self._check_src_repo(tempdir)
726 # Try building
727 bitbake(testrecipe)
728
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500729 def test_devtool_modify_localfiles(self):
730 # Check preconditions
731 testrecipe = 'lighttpd'
732 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
733 foundlocal = False
734 for item in src_uri:
735 if item.startswith('file://') and '.patch' not in item:
736 foundlocal = True
737 break
738 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
739 # Clean up anything in the workdir/sysroot/sstate cache
740 bitbake('%s -c cleansstate' % testrecipe)
741 # Try modifying a recipe
742 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
743 self.track_for_cleanup(tempdir)
744 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500745 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400746 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500747 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
748 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
749 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
750 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
751 self.assertTrue(matches, 'bbappend not created')
752 # Test devtool status
753 result = runCmd('devtool status')
754 self.assertIn(testrecipe, result.output)
755 self.assertIn(tempdir, result.output)
756 # Try building
757 bitbake(testrecipe)
758
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500759 def test_devtool_modify_virtual(self):
760 # Try modifying a virtual recipe
761 virtrecipe = 'virtual/make'
762 realrecipe = 'make'
763 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
764 self.track_for_cleanup(tempdir)
765 self.track_for_cleanup(self.workspacedir)
766 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
767 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
768 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
769 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
770 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
771 self.assertTrue(matches, 'bbappend not created %s' % result.output)
772 # Test devtool status
773 result = runCmd('devtool status')
774 self.assertNotIn(virtrecipe, result.output)
775 self.assertIn(realrecipe, result.output)
776 # Check git repo
777 self._check_src_repo(tempdir)
778 # This is probably sufficient
779
Andrew Geisslerf0343792020-11-18 10:42:21 -0600780 def test_devtool_modify_overrides(self):
781 # Try modifying a recipe with patches in overrides
782 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
783 self.track_for_cleanup(tempdir)
784 self.track_for_cleanup(self.workspacedir)
785 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
786 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
787
788 self._check_src_repo(tempdir)
789 source = os.path.join(tempdir, "source")
790 def check(branch, expected):
791 runCmd('git -C %s checkout %s' % (tempdir, branch))
792 with open(source, "rt") as f:
793 content = f.read()
794 self.assertEquals(content, expected)
795 check('devtool', 'This is a test for something\n')
796 check('devtool-no-overrides', 'This is a test for something\n')
797 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
798 check('devtool-override-qemux86', 'This is a test for qemux86\n')
799
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800800class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500801
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500802 def test_devtool_update_recipe(self):
803 # Check preconditions
804 testrecipe = 'minicom'
805 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
806 recipefile = bb_vars['FILE']
807 src_uri = bb_vars['SRC_URI']
808 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
809 self._check_repo_status(os.path.dirname(recipefile), [])
810 # First, modify a recipe
811 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
812 self.track_for_cleanup(tempdir)
813 self.track_for_cleanup(self.workspacedir)
814 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
815 # (don't bother with cleaning the recipe on teardown, we won't be building it)
816 # We don't use -x here so that we test the behaviour of devtool modify without it
817 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
818 # Check git repo
819 self._check_src_repo(tempdir)
820 # Add a couple of commits
821 # FIXME: this only tests adding, need to also test update and remove
822 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
823 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
824 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
825 result = runCmd('git add devtool-new-file', cwd=tempdir)
826 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
827 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
828 result = runCmd('devtool update-recipe %s' % testrecipe)
829 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
830 ('??', '.*/0001-Change-the-README.patch$'),
831 ('??', '.*/0002-Add-a-new-file.patch$')]
832 self._check_repo_status(os.path.dirname(recipefile), expected_status)
833
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 def test_devtool_update_recipe_git(self):
835 # Check preconditions
836 testrecipe = 'mtd-utils'
837 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
838 recipefile = bb_vars['FILE']
839 src_uri = bb_vars['SRC_URI']
840 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
841 patches = []
842 for entry in src_uri.split():
843 if entry.startswith('file://') and entry.endswith('.patch'):
844 patches.append(entry[7:].split(';')[0])
845 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
846 self._check_repo_status(os.path.dirname(recipefile), [])
847 # First, modify a recipe
848 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
849 self.track_for_cleanup(tempdir)
850 self.track_for_cleanup(self.workspacedir)
851 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
852 # (don't bother with cleaning the recipe on teardown, we won't be building it)
853 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
854 # Check git repo
855 self._check_src_repo(tempdir)
856 # Add a couple of commits
857 # FIXME: this only tests adding, need to also test update and remove
858 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
859 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
860 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
861 result = runCmd('git add devtool-new-file', cwd=tempdir)
862 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
863 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
864 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
865 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
866 [(' D', '.*/%s$' % patch) for patch in patches]
867 self._check_repo_status(os.path.dirname(recipefile), expected_status)
868
869 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
870 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
871 srcurilines = src_uri.split()
872 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
873 srcurilines.append('"')
874 removelines = ['SRCREV = ".*"'] + srcurilines
875 for line in result.output.splitlines():
876 if line.startswith('+++') or line.startswith('---'):
877 continue
878 elif line.startswith('+'):
879 matched = False
880 for item in addlines:
881 if re.match(item, line[1:].strip()):
882 matched = True
883 break
884 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
885 elif line.startswith('-'):
886 matched = False
887 for item in removelines:
888 if re.match(item, line[1:].strip()):
889 matched = True
890 break
891 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
892 # Now try with auto mode
893 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
894 result = runCmd('devtool update-recipe %s' % testrecipe)
895 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
896 topleveldir = result.output.strip()
897 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
898 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
899 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
900 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
901 self._check_repo_status(os.path.dirname(recipefile), expected_status)
902
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500903 def test_devtool_update_recipe_append(self):
904 # Check preconditions
905 testrecipe = 'mdadm'
906 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
907 recipefile = bb_vars['FILE']
908 src_uri = bb_vars['SRC_URI']
909 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
910 self._check_repo_status(os.path.dirname(recipefile), [])
911 # First, modify a recipe
912 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
913 tempsrcdir = os.path.join(tempdir, 'source')
914 templayerdir = os.path.join(tempdir, 'layer')
915 self.track_for_cleanup(tempdir)
916 self.track_for_cleanup(self.workspacedir)
917 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
918 # (don't bother with cleaning the recipe on teardown, we won't be building it)
919 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
920 # Check git repo
921 self._check_src_repo(tempsrcdir)
922 # Add a commit
923 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
924 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
925 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
926 # Create a temporary layer and add it to bblayers.conf
927 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
928 # Create the bbappend
929 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
930 self.assertNotIn('WARNING:', result.output)
931 # Check recipe is still clean
932 self._check_repo_status(os.path.dirname(recipefile), [])
933 # Check bbappend was created
934 splitpath = os.path.dirname(recipefile).split(os.sep)
935 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
936 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
937 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
938 self.assertExists(patchfile, 'Patch file not created')
939
940 # Check bbappend contents
941 expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
942 '\n',
943 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
944 '\n']
945 with open(bbappendfile, 'r') as f:
946 self.assertEqual(expectedlines, f.readlines())
947
948 # Check we can run it again and bbappend isn't modified
949 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
950 with open(bbappendfile, 'r') as f:
951 self.assertEqual(expectedlines, f.readlines())
952 # Drop new commit and check patch gets deleted
953 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
954 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
955 self.assertNotExists(patchfile, 'Patch file not deleted')
956 expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
957 '\n']
958 with open(bbappendfile, 'r') as f:
959 self.assertEqual(expectedlines2, f.readlines())
960 # Put commit back and check we can run it if layer isn't in bblayers.conf
961 os.remove(bbappendfile)
962 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
963 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
964 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
965 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
966 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
967 with open(bbappendfile, 'r') as f:
968 self.assertEqual(expectedlines, f.readlines())
969 # Deleting isn't expected to work under these circumstances
970
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500971 def test_devtool_update_recipe_append_git(self):
972 # Check preconditions
973 testrecipe = 'mtd-utils'
974 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
975 recipefile = bb_vars['FILE']
976 src_uri = bb_vars['SRC_URI']
977 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
978 for entry in src_uri.split():
979 if entry.startswith('git://'):
980 git_uri = entry
981 break
982 self._check_repo_status(os.path.dirname(recipefile), [])
983 # First, modify a recipe
984 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
985 tempsrcdir = os.path.join(tempdir, 'source')
986 templayerdir = os.path.join(tempdir, 'layer')
987 self.track_for_cleanup(tempdir)
988 self.track_for_cleanup(self.workspacedir)
989 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
990 # (don't bother with cleaning the recipe on teardown, we won't be building it)
991 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
992 # Check git repo
993 self._check_src_repo(tempsrcdir)
994 # Add a commit
995 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
996 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
997 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
998 # Create a temporary layer
999 os.makedirs(os.path.join(templayerdir, 'conf'))
1000 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1001 f.write('BBPATH .= ":${LAYERDIR}"\n')
1002 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1003 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1004 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1005 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1006 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -04001007 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001008 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1009 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1010 # Create the bbappend
1011 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1012 self.assertNotIn('WARNING:', result.output)
1013 # Check recipe is still clean
1014 self._check_repo_status(os.path.dirname(recipefile), [])
1015 # Check bbappend was created
1016 splitpath = os.path.dirname(recipefile).split(os.sep)
1017 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1018 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1019 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1020
1021 # Check bbappend contents
1022 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1023 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1024 '\n',
1025 'SRC_URI = "%s"\n' % git_uri,
1026 '\n'])
1027 with open(bbappendfile, 'r') as f:
1028 self.assertEqual(expectedlines, set(f.readlines()))
1029
1030 # Check we can run it again and bbappend isn't modified
1031 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1032 with open(bbappendfile, 'r') as f:
1033 self.assertEqual(expectedlines, set(f.readlines()))
1034 # Drop new commit and check SRCREV changes
1035 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1036 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1037 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1038 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1039 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1040 '\n',
1041 'SRC_URI = "%s"\n' % git_uri,
1042 '\n'])
1043 with open(bbappendfile, 'r') as f:
1044 self.assertEqual(expectedlines, set(f.readlines()))
1045 # Put commit back and check we can run it if layer isn't in bblayers.conf
1046 os.remove(bbappendfile)
1047 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1048 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1049 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1050 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1051 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1052 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1053 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1054 '\n',
1055 'SRC_URI = "%s"\n' % git_uri,
1056 '\n'])
1057 with open(bbappendfile, 'r') as f:
1058 self.assertEqual(expectedlines, set(f.readlines()))
1059 # Deleting isn't expected to work under these circumstances
1060
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001061 def test_devtool_update_recipe_local_files(self):
1062 """Check that local source files are copied over instead of patched"""
1063 testrecipe = 'makedevs'
1064 recipefile = get_bb_var('FILE', testrecipe)
1065 # Setup srctree for modifying the recipe
1066 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1067 self.track_for_cleanup(tempdir)
1068 self.track_for_cleanup(self.workspacedir)
1069 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1070 # (don't bother with cleaning the recipe on teardown, we won't be
1071 # building it)
1072 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1073 # Check git repo
1074 self._check_src_repo(tempdir)
1075 # Try building just to ensure we haven't broken that
1076 bitbake("%s" % testrecipe)
1077 # Edit / commit local source
1078 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1079 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1080 runCmd('echo "Bar" > new-file', cwd=tempdir)
1081 runCmd('git add new-file', cwd=tempdir)
1082 runCmd('git commit -m "Add new file"', cwd=tempdir)
1083 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1084 os.path.dirname(recipefile))
1085 runCmd('devtool update-recipe %s' % testrecipe)
1086 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1087 (' M', '.*/makedevs/makedevs.c$'),
1088 ('??', '.*/makedevs/new-local$'),
1089 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1090 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1091
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001092 def test_devtool_update_recipe_local_files_2(self):
1093 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001094 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001095 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001096 recipedir = os.path.dirname(recipefile)
1097 result = runCmd('git status --porcelain .', cwd=recipedir)
1098 if result.output.strip():
1099 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001100 # Setup srctree for modifying the recipe
1101 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1102 self.track_for_cleanup(tempdir)
1103 self.track_for_cleanup(self.workspacedir)
1104 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1105 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1106 # Check git repo
1107 self._check_src_repo(tempdir)
1108 # Add oe-local-files to Git
1109 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1110 runCmd('git add oe-local-files', cwd=tempdir)
1111 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1112 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001113 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001114 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001115 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001116 runCmd('git commit -m"Remove file"', cwd=tempdir)
1117 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1118 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1119 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1120 runCmd('echo "Gar" > new-file', cwd=tempdir)
1121 runCmd('git add new-file', cwd=tempdir)
1122 runCmd('git commit -m "Add new file"', cwd=tempdir)
1123 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1124 os.path.dirname(recipefile))
1125 # Checkout unmodified file to working copy -> devtool should still pick
1126 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001127 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001128 runCmd('devtool update-recipe %s' % testrecipe)
1129 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001130 (' M', '.*/file1$'),
1131 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001132 ('??', '.*/new-local$'),
1133 ('??', '.*/0001-Add-new-file.patch$')]
1134 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1135
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001136 def test_devtool_update_recipe_with_gitignore(self):
1137 # First, modify the recipe
1138 testrecipe = 'devtool-test-ignored'
1139 bb_vars = get_bb_vars(['FILE'], testrecipe)
1140 recipefile = bb_vars['FILE']
1141 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1142 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1143 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1144 self.track_for_cleanup(tempdir)
1145 self.track_for_cleanup(self.workspacedir)
1146 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1147 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1148 result = runCmd('devtool modify %s' % testrecipe)
1149 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1150 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1151 # Check recipe got changed as expected
1152 with open(newpatchfile, 'r') as f:
1153 desiredlines = f.readlines()
1154 with open(patchfile, 'r') as f:
1155 newlines = f.readlines()
1156 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1157 # which changes the metadata subject which is added into the patch, but keep
1158 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1159 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1160 self.assertEqual(desiredlines[5:], newlines[5:])
1161
1162 def test_devtool_update_recipe_long_filename(self):
1163 # First, modify the recipe
1164 testrecipe = 'devtool-test-long-filename'
1165 bb_vars = get_bb_vars(['FILE'], testrecipe)
1166 recipefile = bb_vars['FILE']
1167 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1168 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1169 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1170 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1171 self.track_for_cleanup(tempdir)
1172 self.track_for_cleanup(self.workspacedir)
1173 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1174 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1175 result = runCmd('devtool modify %s' % testrecipe)
1176 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1177 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1178 # Check recipe got changed as expected
1179 with open(newpatchfile, 'r') as f:
1180 desiredlines = f.readlines()
1181 with open(patchfile, 'r') as f:
1182 newlines = f.readlines()
1183 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1184 # which changes the metadata subject which is added into the patch, but keep
1185 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1186 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1187 self.assertEqual(desiredlines[5:], newlines[5:])
1188
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001189 def test_devtool_update_recipe_local_files_3(self):
1190 # First, modify the recipe
1191 testrecipe = 'devtool-test-localonly'
1192 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1193 recipefile = bb_vars['FILE']
1194 src_uri = bb_vars['SRC_URI']
1195 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1196 self.track_for_cleanup(tempdir)
1197 self.track_for_cleanup(self.workspacedir)
1198 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1199 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1200 result = runCmd('devtool modify %s' % testrecipe)
1201 # Modify one file
1202 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1203 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1204 result = runCmd('devtool update-recipe %s' % testrecipe)
1205 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1206 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1207
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001208 def test_devtool_update_recipe_local_patch_gz(self):
1209 # First, modify the recipe
1210 testrecipe = 'devtool-test-patch-gz'
1211 if get_bb_var('DISTRO') == 'poky-tiny':
1212 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1213 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1214 recipefile = bb_vars['FILE']
1215 src_uri = bb_vars['SRC_URI']
1216 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1217 self.track_for_cleanup(tempdir)
1218 self.track_for_cleanup(self.workspacedir)
1219 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1220 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1221 result = runCmd('devtool modify %s' % testrecipe)
1222 # Modify one file
1223 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1224 runCmd('echo "Another line" >> README', cwd=srctree)
1225 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1226 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1227 result = runCmd('devtool update-recipe %s' % testrecipe)
1228 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1229 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1230 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1231 result = runCmd('file %s' % patch_gz)
1232 if 'gzip compressed data' not in result.output:
1233 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1234
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001235 def test_devtool_update_recipe_local_files_subdir(self):
1236 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1237 # SRC_URI such that it overwrites a file that was in an archive that
1238 # was also in SRC_URI
1239 # First, modify the recipe
1240 testrecipe = 'devtool-test-subdir'
1241 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1242 recipefile = bb_vars['FILE']
1243 src_uri = bb_vars['SRC_URI']
1244 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1245 self.track_for_cleanup(tempdir)
1246 self.track_for_cleanup(self.workspacedir)
1247 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1248 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1249 result = runCmd('devtool modify %s' % testrecipe)
1250 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1251 self.assertExists(testfile, 'Extracted source could not be found')
1252 with open(testfile, 'r') as f:
1253 contents = f.read().rstrip()
1254 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1255 # Test devtool update-recipe without modifying any files
1256 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1257 result = runCmd('devtool update-recipe %s' % testrecipe)
1258 expected_status = []
1259 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1260
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001261class DevtoolExtractTests(DevtoolBase):
1262
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001263 def test_devtool_extract(self):
1264 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1265 # Try devtool extract
1266 self.track_for_cleanup(tempdir)
1267 self.track_for_cleanup(self.workspacedir)
1268 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1269 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1270 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1271 self._check_src_repo(tempdir)
1272
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001273 def test_devtool_extract_virtual(self):
1274 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1275 # Try devtool extract
1276 self.track_for_cleanup(tempdir)
1277 self.track_for_cleanup(self.workspacedir)
1278 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1279 result = runCmd('devtool extract virtual/make %s' % tempdir)
1280 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1281 self._check_src_repo(tempdir)
1282
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001283 def test_devtool_reset_all(self):
1284 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1285 self.track_for_cleanup(tempdir)
1286 self.track_for_cleanup(self.workspacedir)
1287 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1288 testrecipe1 = 'mdadm'
1289 testrecipe2 = 'cronie'
1290 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1291 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1292 result = runCmd('devtool build %s' % testrecipe1)
1293 result = runCmd('devtool build %s' % testrecipe2)
1294 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1295 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1296 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1297 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1298 result = runCmd('devtool reset -a')
1299 self.assertIn(testrecipe1, result.output)
1300 self.assertIn(testrecipe2, result.output)
1301 result = runCmd('devtool status')
1302 self.assertNotIn(testrecipe1, result.output)
1303 self.assertNotIn(testrecipe2, result.output)
1304 matches1 = glob.glob(stampprefix1 + '*')
1305 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1306 matches2 = glob.glob(stampprefix2 + '*')
1307 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1308
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001309 def test_devtool_deploy_target(self):
1310 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1311 # unfortunately the runtime tests run under bitbake and you can't run
1312 # devtool within bitbake (since devtool needs to run bitbake itself).
1313 # Additionally we are testing build-time functionality as well, so
1314 # really this has to be done as an oe-selftest test.
1315 #
1316 # Check preconditions
1317 machine = get_bb_var('MACHINE')
1318 if not machine.startswith('qemu'):
1319 self.skipTest('This test only works with qemu machines')
1320 if not os.path.exists('/etc/runqemu-nosudo'):
1321 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1322 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1323 if result.status != 0:
1324 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1325 if result.status != 0:
1326 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1327 for line in result.output.splitlines():
1328 if line.startswith('tap'):
1329 break
1330 else:
1331 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1332 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1333 # Definitions
1334 testrecipe = 'mdadm'
1335 testfile = '/sbin/mdadm'
1336 testimage = 'oe-selftest-image'
1337 testcommand = '/sbin/mdadm --help'
1338 # Build an image to run
1339 bitbake("%s qemu-native qemu-helper-native" % testimage)
1340 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1341 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1342 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1343 # Clean recipe so the first deploy will fail
1344 bitbake("%s -c clean" % testrecipe)
1345 # Try devtool modify
1346 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1347 self.track_for_cleanup(tempdir)
1348 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001349 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001350 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001351 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1352 # Test that deploy-target at this point fails (properly)
1353 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1354 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1355 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1356 result = runCmd('devtool build %s' % testrecipe)
1357 # First try a dry-run of deploy-target
1358 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1359 self.assertIn(' %s' % testfile, result.output)
1360 # Boot the image
1361 with runqemu(testimage) as qemu:
1362 # Now really test deploy-target
1363 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1364 # Run a test command to see if it was installed properly
1365 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1366 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1367 # Check if it deployed all of the files with the right ownership/perms
1368 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1369 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1370 installdir = bb_vars['D']
1371 fakerootenv = bb_vars['FAKEROOTENV']
1372 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001373 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001374 filelist1 = self._process_ls_output(result.output)
1375
1376 # Now look on the target
1377 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1378 self.track_for_cleanup(tempdir2)
1379 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1380 with open(tmpfilelist, 'w') as f:
1381 for line in filelist1:
1382 splitline = line.split()
1383 f.write(splitline[-1] + '\n')
1384 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1385 filelist2 = self._process_ls_output(result.output)
1386 filelist1.sort(key=lambda item: item.split()[-1])
1387 filelist2.sort(key=lambda item: item.split()[-1])
1388 self.assertEqual(filelist1, filelist2)
1389 # Test undeploy-target
1390 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1391 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1392 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1393
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001394 def test_devtool_build_image(self):
1395 """Test devtool build-image plugin"""
1396 # Check preconditions
1397 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1398 image = 'core-image-minimal'
1399 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001400 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001401 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001402 bitbake('%s -c clean' % image)
1403 # Add target and native recipes to workspace
1404 recipes = ['mdadm', 'parted-native']
1405 for recipe in recipes:
1406 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1407 self.track_for_cleanup(tempdir)
1408 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1409 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1410 # Try to build image
1411 result = runCmd('devtool build-image %s' % image)
1412 self.assertNotEqual(result, 0, 'devtool build-image failed')
1413 # Check if image contains expected packages
1414 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1415 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1416 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1417 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1418 for line in f:
1419 splitval = line.split()
1420 if splitval:
1421 pkg = splitval[0]
1422 if pkg in reqpkgs:
1423 reqpkgs.remove(pkg)
1424 if reqpkgs:
1425 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1426
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001427class DevtoolUpgradeTests(DevtoolBase):
1428
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001429 def test_devtool_upgrade(self):
1430 # Check preconditions
1431 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1432 self.track_for_cleanup(self.workspacedir)
1433 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1434 # Check parameters
1435 result = runCmd('devtool upgrade -h')
1436 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1437 self.assertIn(param, result.output)
1438 # For the moment, we are using a real recipe.
1439 recipe = 'devtool-upgrade-test1'
1440 version = '1.6.0'
1441 oldrecipefile = get_bb_var('FILE', recipe)
1442 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1443 self.track_for_cleanup(tempdir)
1444 # Check that recipe is not already under devtool control
1445 result = runCmd('devtool status')
1446 self.assertNotIn(recipe, result.output)
1447 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1448 # we are downgrading instead of upgrading.
1449 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1450 # Check if srctree at least is populated
1451 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1452 # Check new recipe subdirectory is present
1453 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1454 # Check new recipe file is present
1455 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1456 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1457 # Check devtool status and make sure recipe is present
1458 result = runCmd('devtool status')
1459 self.assertIn(recipe, result.output)
1460 self.assertIn(tempdir, result.output)
1461 # Check recipe got changed as expected
1462 with open(oldrecipefile + '.upgraded', 'r') as f:
1463 desiredlines = f.readlines()
1464 with open(newrecipefile, 'r') as f:
1465 newlines = f.readlines()
1466 self.assertEqual(desiredlines, newlines)
1467 # Check devtool reset recipe
1468 result = runCmd('devtool reset %s -n' % recipe)
1469 result = runCmd('devtool status')
1470 self.assertNotIn(recipe, result.output)
1471 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1472
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001473 def test_devtool_upgrade_git(self):
1474 # Check preconditions
1475 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1476 self.track_for_cleanup(self.workspacedir)
1477 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1478 recipe = 'devtool-upgrade-test2'
1479 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1480 oldrecipefile = get_bb_var('FILE', recipe)
1481 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1482 self.track_for_cleanup(tempdir)
1483 # Check that recipe is not already under devtool control
1484 result = runCmd('devtool status')
1485 self.assertNotIn(recipe, result.output)
1486 # Check upgrade
1487 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1488 # Check if srctree at least is populated
1489 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1490 # Check new recipe file is present
1491 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1492 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1493 # Check devtool status and make sure recipe is present
1494 result = runCmd('devtool status')
1495 self.assertIn(recipe, result.output)
1496 self.assertIn(tempdir, result.output)
1497 # Check recipe got changed as expected
1498 with open(oldrecipefile + '.upgraded', 'r') as f:
1499 desiredlines = f.readlines()
1500 with open(newrecipefile, 'r') as f:
1501 newlines = f.readlines()
1502 self.assertEqual(desiredlines, newlines)
1503 # Check devtool reset recipe
1504 result = runCmd('devtool reset %s -n' % recipe)
1505 result = runCmd('devtool status')
1506 self.assertNotIn(recipe, result.output)
1507 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1508
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001509 def test_devtool_layer_plugins(self):
1510 """Test that devtool can use plugins from other layers.
1511
1512 This test executes the selftest-reverse command from meta-selftest."""
1513
1514 self.track_for_cleanup(self.workspacedir)
1515 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1516
1517 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1518 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1519 self.assertEqual(result.output, s[::-1])
1520
1521 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1522 dstdir = basedstdir
1523 self.assertExists(dstdir)
1524 for p in paths:
1525 dstdir = os.path.join(dstdir, p)
1526 if not os.path.exists(dstdir):
1527 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001528 if p == "lib":
1529 # Can race with other tests
1530 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1531 else:
1532 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001533 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1534 if srcfile != dstfile:
1535 shutil.copy(srcfile, dstfile)
1536 self.track_for_cleanup(dstfile)
1537
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001538 def test_devtool_load_plugin(self):
1539 """Test that devtool loads only the first found plugin in BBPATH."""
1540
1541 self.track_for_cleanup(self.workspacedir)
1542 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1543
1544 devtool = runCmd("which devtool")
1545 fromname = runCmd("devtool --quiet pluginfile")
1546 srcfile = fromname.output
1547 bbpath = get_bb_var('BBPATH')
1548 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1549 plugincontent = []
1550 with open(srcfile) as fh:
1551 plugincontent = fh.readlines()
1552 try:
1553 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1554 for path in searchpath:
1555 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1556 result = runCmd("devtool --quiet count")
1557 self.assertEqual(result.output, '1')
1558 result = runCmd("devtool --quiet multiloaded")
1559 self.assertEqual(result.output, "no")
1560 for path in searchpath:
1561 result = runCmd("devtool --quiet bbdir")
1562 self.assertEqual(result.output, path)
1563 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1564 finally:
1565 with open(srcfile, 'w') as fh:
1566 fh.writelines(plugincontent)
1567
1568 def _setup_test_devtool_finish_upgrade(self):
1569 # Check preconditions
1570 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1571 self.track_for_cleanup(self.workspacedir)
1572 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1573 # Use a "real" recipe from meta-selftest
1574 recipe = 'devtool-upgrade-test1'
1575 oldversion = '1.5.3'
1576 newversion = '1.6.0'
1577 oldrecipefile = get_bb_var('FILE', recipe)
1578 recipedir = os.path.dirname(oldrecipefile)
1579 result = runCmd('git status --porcelain .', cwd=recipedir)
1580 if result.output.strip():
1581 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1582 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1583 self.track_for_cleanup(tempdir)
1584 # Check that recipe is not already under devtool control
1585 result = runCmd('devtool status')
1586 self.assertNotIn(recipe, result.output)
1587 # Do the upgrade
1588 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1589 # Check devtool status and make sure recipe is present
1590 result = runCmd('devtool status')
1591 self.assertIn(recipe, result.output)
1592 self.assertIn(tempdir, result.output)
1593 # Make a change to the source
1594 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1595 result = runCmd('git status --porcelain', cwd=tempdir)
1596 self.assertIn('M src/pv/number.c', result.output)
1597 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1598 # Check if patch is there
1599 recipedir = os.path.dirname(oldrecipefile)
1600 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1601 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001602 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001603 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001604 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1605 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001606
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001607 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001608 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001609 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1610 self.assertIn('/meta-selftest/', recipedir)
1611 # Try finish to the original layer
1612 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1613 result = runCmd('devtool finish %s meta-selftest' % recipe)
1614 result = runCmd('devtool status')
1615 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1616 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1617 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1618 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001619 self.assertNotExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should have been deleted but wasn\'t')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001620 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1621 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1622 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1623 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001624 self.assertNotExists(os.path.join(newdir, backportedpatchfn), 'Backported patch file should not have been copied into new directory but was')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001625 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001626 with open(newrecipefile, 'r') as f:
1627 newcontent = f.read()
1628 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1629 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1630 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1631 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1632
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001633
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001634 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001635 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001636 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1637 self.assertIn('/meta-selftest/', recipedir)
1638 # Try finish to a different layer - should create a bbappend
1639 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1640 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1641 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1642 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1643 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1644 self.track_for_cleanup(newrecipedir)
1645 result = runCmd('devtool finish %s oe-core' % recipe)
1646 result = runCmd('devtool status')
1647 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1648 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1649 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1650 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001651 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001652 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1653 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1654 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001655 self.assertNotExists(os.path.join(newdir, backportedpatchfn), 'Backported patch file should not have been copied into new directory but was')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001656 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001657 with open(newrecipefile, 'r') as f:
1658 newcontent = f.read()
1659 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1660 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1661 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1662 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001663
1664 def _setup_test_devtool_finish_modify(self):
1665 # Check preconditions
1666 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1667 # Try modifying a recipe
1668 self.track_for_cleanup(self.workspacedir)
1669 recipe = 'mdadm'
1670 oldrecipefile = get_bb_var('FILE', recipe)
1671 recipedir = os.path.dirname(oldrecipefile)
1672 result = runCmd('git status --porcelain .', cwd=recipedir)
1673 if result.output.strip():
1674 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1675 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1676 self.track_for_cleanup(tempdir)
1677 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1678 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1679 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1680 # Test devtool status
1681 result = runCmd('devtool status')
1682 self.assertIn(recipe, result.output)
1683 self.assertIn(tempdir, result.output)
1684 # Make a change to the source
1685 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1686 result = runCmd('git status --porcelain', cwd=tempdir)
1687 self.assertIn('M maps.c', result.output)
1688 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1689 for entry in os.listdir(recipedir):
1690 filesdir = os.path.join(recipedir, entry)
1691 if os.path.isdir(filesdir):
1692 break
1693 else:
1694 self.fail('Unable to find recipe files directory for %s' % recipe)
1695 return recipe, oldrecipefile, recipedir, filesdir
1696
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001697 def test_devtool_finish_modify_origlayer(self):
1698 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1699 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1700 self.assertIn('/meta/', recipedir)
1701 # Try finish to the original layer
1702 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1703 result = runCmd('devtool finish %s meta' % recipe)
1704 result = runCmd('devtool status')
1705 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1706 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1707 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1708 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1709 self._check_repo_status(recipedir, expected_status)
1710
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001711 def test_devtool_finish_modify_otherlayer(self):
1712 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1713 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1714 self.assertIn('/meta/', recipedir)
1715 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1716 appenddir = os.path.join(get_test_layer(), relpth)
1717 self.track_for_cleanup(appenddir)
1718 # Try finish to the original layer
1719 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1720 result = runCmd('devtool finish %s meta-selftest' % recipe)
1721 result = runCmd('devtool status')
1722 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1723 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1724 result = runCmd('git status --porcelain .', cwd=recipedir)
1725 if result.output.strip():
1726 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1727 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1728 recipefn = recipefn.split('_')[0] + '_%'
1729 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1730 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1731 newdir = os.path.join(appenddir, recipe)
1732 files = os.listdir(newdir)
1733 foundpatch = None
1734 for fn in files:
1735 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1736 foundpatch = fn
1737 if not foundpatch:
1738 self.fail('No patch file created next to bbappend')
1739 files.remove(foundpatch)
1740 if files:
1741 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1742
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001743 def test_devtool_rename(self):
1744 # Check preconditions
1745 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1746 self.track_for_cleanup(self.workspacedir)
1747 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1748
1749 # First run devtool add
1750 # We already have this recipe in OE-Core, but that doesn't matter
1751 recipename = 'i2c-tools'
1752 recipever = '3.1.2'
1753 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1754 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1755 def add_recipe():
1756 result = runCmd('devtool add %s' % url)
1757 self.assertExists(recipefile, 'Expected recipe file not created')
1758 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1759 checkvars = {}
1760 checkvars['S'] = None
1761 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1762 self._test_recipe_contents(recipefile, checkvars, [])
1763 add_recipe()
1764 # Now rename it - change both name and version
1765 newrecipename = 'mynewrecipe'
1766 newrecipever = '456'
1767 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1768 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1769 self.assertExists(newrecipefile, 'Recipe file not renamed')
1770 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1771 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1772 self.assertExists(newsrctree, 'Source directory not renamed')
1773 checkvars = {}
1774 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1775 checkvars['SRC_URI'] = url
1776 self._test_recipe_contents(newrecipefile, checkvars, [])
1777 # Try again - change just name this time
1778 result = runCmd('devtool reset -n %s' % newrecipename)
1779 shutil.rmtree(newsrctree)
1780 add_recipe()
1781 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1782 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1783 self.assertExists(newrecipefile, 'Recipe file not renamed')
1784 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1785 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1786 checkvars = {}
1787 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1788 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1789 self._test_recipe_contents(newrecipefile, checkvars, [])
1790 # Try again - change just version this time
1791 result = runCmd('devtool reset -n %s' % newrecipename)
1792 shutil.rmtree(newsrctree)
1793 add_recipe()
1794 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1795 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1796 self.assertExists(newrecipefile, 'Recipe file not renamed')
1797 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1798 checkvars = {}
1799 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1800 checkvars['SRC_URI'] = url
1801 self._test_recipe_contents(newrecipefile, checkvars, [])
1802
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001803 def test_devtool_virtual_kernel_modify(self):
1804 """
1805 Summary: The purpose of this test case is to verify that
1806 devtool modify works correctly when building
1807 the kernel.
1808 Dependencies: NA
1809 Steps: 1. Build kernel with bitbake.
1810 2. Save the config file generated.
1811 3. Clean the environment.
1812 4. Use `devtool modify virtual/kernel` to validate following:
1813 4.1 The source is checked out correctly.
1814 4.2 The resulting configuration is the same as
1815 what was get on step 2.
1816 4.3 The Kernel can be build correctly.
1817 4.4 Changes made on the source are reflected on the
1818 subsequent builds.
1819 4.5 Changes on the configuration are reflected on the
1820 subsequent builds
1821 Expected: devtool modify is able to checkout the source of the kernel
1822 and modification to the source and configurations are reflected
1823 when building the kernel.
1824 """
1825 kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
Andrew Geissler82c905d2020-04-13 13:39:40 -05001826 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001827 bitbake('%s -c clean' % kernel_provider)
1828 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1829 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1830 self.track_for_cleanup(tempdir)
1831 self.track_for_cleanup(tempdir_cfg)
1832 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001833 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04001834 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001835 #Step 1
1836 #Here is just generated the config file instead of all the kernel to optimize the
1837 #time of executing this test case.
1838 bitbake('%s -c configure' % kernel_provider)
1839 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1840 #Step 2
1841 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1842 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1843
1844 tmpconfig = os.path.join(tempdir_cfg, '.config')
1845 #Step 3
1846 bitbake('%s -c clean' % kernel_provider)
1847 #Step 4.1
1848 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1849 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1850 #Step 4.2
1851 configfile = os.path.join(tempdir,'.config')
1852 diff = runCmd('diff %s %s' % (tmpconfig, configfile))
1853 self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
1854 #Step 4.3
1855 #NOTE: virtual/kernel is mapped to kernel_provider
1856 result = runCmd('devtool build %s' % kernel_provider)
1857 self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
1858 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
1859 self.assertExists(kernelfile, 'Kernel was not build correctly')
1860
1861 #Modify the kernel source
1862 modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
1863 modstring = "Use a boot loader. Devtool testing."
1864 modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
1865 self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
1866 #Modify the configuration
1867 codeconfigfile = os.path.join(tempdir,'.config.new')
1868 modconfopt = "CONFIG_SG_POOL=n"
1869 modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
1870 self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
1871 #Build again kernel with devtool
1872 rebuild = runCmd('devtool build %s' % kernel_provider)
1873 self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
1874 #Step 4.4
1875 bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
1876 bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
1877 checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
1878 self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
1879 #Step 4.5
1880 checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
1881 self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')