blob: 6e731d677794ee7dcea52c02ab510d6c7eaae751 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001import unittest
2import os
3import logging
4import re
5import shutil
6import tempfile
7import glob
8
9import oeqa.utils.ftools as ftools
10from oeqa.selftest.base import oeSelfTest
11from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer, runqemu
12from oeqa.utils.decorators import testcase
13
14class DevtoolBase(oeSelfTest):
15
16 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
17 with open(recipefile, 'r') as f:
18 for line in f:
19 if '=' in line:
20 splitline = line.split('=', 1)
21 var = splitline[0].rstrip()
22 value = splitline[1].strip().strip('"')
23 if var in checkvars:
24 needvalue = checkvars.pop(var)
25 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
26 if line.startswith('inherit '):
27 inherits = line.split()[1:]
28
29 self.assertEqual(checkvars, {}, 'Some variables not found: %s' % checkvars)
30
31 for inherit in checkinherits:
32 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
33
34 def _check_bbappend(self, testrecipe, recipefile, appenddir):
35 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
36 resultlines = result.output.splitlines()
37 inrecipe = False
38 bbappends = []
39 bbappendfile = None
40 for line in resultlines:
41 if inrecipe:
42 if line.startswith(' '):
43 bbappends.append(line.strip())
44 else:
45 break
46 elif line == '%s:' % os.path.basename(recipefile):
47 inrecipe = True
48 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
49 for bbappend in bbappends:
50 if bbappend.startswith(appenddir):
51 bbappendfile = bbappend
52 break
53 else:
54 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
55 return bbappendfile
56
57 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
58 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
59 if addlayer:
60 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
61 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
62
63 def _process_ls_output(self, output):
64 """
65 Convert ls -l output to a format we can reasonably compare from one context
66 to another (e.g. from host to target)
67 """
68 filelist = []
69 for line in output.splitlines():
70 splitline = line.split()
71 # Remove trailing . on perms
72 splitline[0] = splitline[0].rstrip('.')
73 # Remove leading . on paths
74 splitline[-1] = splitline[-1].lstrip('.')
75 # Drop fields we don't want to compare
76 del splitline[7]
77 del splitline[6]
78 del splitline[5]
79 del splitline[4]
80 del splitline[1]
81 filelist.append(' '.join(splitline))
82 return filelist
83
84
85class DevtoolTests(DevtoolBase):
86
87 @testcase(1158)
88 def test_create_workspace(self):
89 # Check preconditions
90 workspacedir = os.path.join(self.builddir, 'workspace')
91 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
92 result = runCmd('bitbake-layers show-layers')
93 self.assertTrue('/workspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf')
94 # Try creating a workspace layer with a specific path
95 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
96 self.track_for_cleanup(tempdir)
97 result = runCmd('devtool create-workspace %s' % tempdir)
98 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
99 result = runCmd('bitbake-layers show-layers')
100 self.assertIn(tempdir, result.output)
101 # Try creating a workspace layer with the default path
102 self.track_for_cleanup(workspacedir)
103 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
104 result = runCmd('devtool create-workspace')
105 self.assertTrue(os.path.isfile(os.path.join(workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
106 result = runCmd('bitbake-layers show-layers')
107 self.assertNotIn(tempdir, result.output)
108 self.assertIn(workspacedir, result.output)
109
110 @testcase(1159)
111 def test_devtool_add(self):
112 # Check preconditions
113 workspacedir = os.path.join(self.builddir, 'workspace')
114 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
115 # Fetch source
116 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
117 self.track_for_cleanup(tempdir)
118 url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2'
119 result = runCmd('wget %s' % url, cwd=tempdir)
120 result = runCmd('tar xfv pv-1.5.3.tar.bz2', cwd=tempdir)
121 srcdir = os.path.join(tempdir, 'pv-1.5.3')
122 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
123 # Test devtool add
124 self.track_for_cleanup(workspacedir)
125 self.add_command_to_tearDown('bitbake -c cleansstate pv')
126 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
127 result = runCmd('devtool add pv %s' % srcdir)
128 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created')
129 # Test devtool status
130 result = runCmd('devtool status')
131 self.assertIn('pv', result.output)
132 self.assertIn(srcdir, result.output)
133 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
134 bitbake('pv -c cleansstate')
135 # Test devtool build
136 result = runCmd('devtool build pv')
137 installdir = get_bb_var('D', 'pv')
138 self.assertTrue(installdir, 'Could not query installdir variable')
139 bindir = get_bb_var('bindir', 'pv')
140 self.assertTrue(bindir, 'Could not query bindir variable')
141 if bindir[0] == '/':
142 bindir = bindir[1:]
143 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
144
145 @testcase(1162)
146 def test_devtool_add_library(self):
147 # Check preconditions
148 workspacedir = os.path.join(self.builddir, 'workspace')
149 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
150 # We don't have the ability to pick up this dependency automatically yet...
151 bitbake('libusb1')
152 # Fetch source
153 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
154 self.track_for_cleanup(tempdir)
155 url = 'http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.1.tar.bz2'
156 result = runCmd('wget %s' % url, cwd=tempdir)
157 result = runCmd('tar xfv libftdi1-1.1.tar.bz2', cwd=tempdir)
158 srcdir = os.path.join(tempdir, 'libftdi1-1.1')
159 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
160 # Test devtool add (and use -V so we test that too)
161 self.track_for_cleanup(workspacedir)
162 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
163 result = runCmd('devtool add libftdi %s -V 1.1' % srcdir)
164 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created')
165 # Test devtool status
166 result = runCmd('devtool status')
167 self.assertIn('libftdi', result.output)
168 self.assertIn(srcdir, result.output)
169 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
170 bitbake('libftdi -c cleansstate')
171 # Test devtool build
172 result = runCmd('devtool build libftdi')
173 staging_libdir = get_bb_var('STAGING_LIBDIR', 'libftdi')
174 self.assertTrue(staging_libdir, 'Could not query STAGING_LIBDIR variable')
175 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)
176 # Test devtool reset
177 stampprefix = get_bb_var('STAMP', 'libftdi')
178 result = runCmd('devtool reset libftdi')
179 result = runCmd('devtool status')
180 self.assertNotIn('libftdi', result.output)
181 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
182 matches = glob.glob(stampprefix + '*')
183 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
184 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
185
186 @testcase(1160)
187 def test_devtool_add_fetch(self):
188 # Check preconditions
189 workspacedir = os.path.join(self.builddir, 'workspace')
190 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
191 # Fetch source
192 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
193 self.track_for_cleanup(tempdir)
194 testver = '0.23'
195 url = 'https://pypi.python.org/packages/source/M/MarkupSafe/MarkupSafe-%s.tar.gz' % testver
196 testrecipe = 'python-markupsafe'
197 srcdir = os.path.join(tempdir, testrecipe)
198 # Test devtool add
199 self.track_for_cleanup(workspacedir)
200 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
201 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
202 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
203 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. %s' % result.output)
204 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
205 # Test devtool status
206 result = runCmd('devtool status')
207 self.assertIn(testrecipe, result.output)
208 self.assertIn(srcdir, result.output)
209 # Check recipe
210 recipefile = get_bb_var('FILE', testrecipe)
211 self.assertIn('%s.bb' % testrecipe, recipefile, 'Recipe file incorrectly named')
212 checkvars = {}
213 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
214 checkvars['SRC_URI'] = url
215 self._test_recipe_contents(recipefile, checkvars, [])
216 # Try with version specified
217 result = runCmd('devtool reset -n %s' % testrecipe)
218 shutil.rmtree(srcdir)
219 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, testver))
220 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
221 # Test devtool status
222 result = runCmd('devtool status')
223 self.assertIn(testrecipe, result.output)
224 self.assertIn(srcdir, result.output)
225 # Check recipe
226 recipefile = get_bb_var('FILE', testrecipe)
227 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
228 checkvars = {}
229 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
230 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
231 self._test_recipe_contents(recipefile, checkvars, [])
232
233 @testcase(1161)
234 def test_devtool_add_fetch_git(self):
235 # Check preconditions
236 workspacedir = os.path.join(self.builddir, 'workspace')
237 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
238 # Fetch source
239 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
240 self.track_for_cleanup(tempdir)
241 url = 'git://git.yoctoproject.org/libmatchbox'
242 checkrev = '462f0652055d89c648ddd54fd7b03f175c2c6973'
243 testrecipe = 'libmatchbox2'
244 srcdir = os.path.join(tempdir, testrecipe)
245 # Test devtool add
246 self.track_for_cleanup(workspacedir)
247 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
248 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
249 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
250 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created: %s' % result.output)
251 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure.ac in source directory')
252 # Test devtool status
253 result = runCmd('devtool status')
254 self.assertIn(testrecipe, result.output)
255 self.assertIn(srcdir, result.output)
256 # Check recipe
257 recipefile = get_bb_var('FILE', testrecipe)
258 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
259 checkvars = {}
260 checkvars['S'] = '${WORKDIR}/git'
261 checkvars['PV'] = '1.0+git${SRCPV}'
262 checkvars['SRC_URI'] = url
263 checkvars['SRCREV'] = '${AUTOREV}'
264 self._test_recipe_contents(recipefile, checkvars, [])
265 # Try with revision and version specified
266 result = runCmd('devtool reset -n %s' % testrecipe)
267 shutil.rmtree(srcdir)
268 url_rev = '%s;rev=%s' % (url, checkrev)
269 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
270 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure.ac in source directory')
271 # Test devtool status
272 result = runCmd('devtool status')
273 self.assertIn(testrecipe, result.output)
274 self.assertIn(srcdir, result.output)
275 # Check recipe
276 recipefile = get_bb_var('FILE', testrecipe)
277 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
278 checkvars = {}
279 checkvars['S'] = '${WORKDIR}/git'
280 checkvars['PV'] = '1.5+git${SRCPV}'
281 checkvars['SRC_URI'] = url
282 checkvars['SRCREV'] = checkrev
283 self._test_recipe_contents(recipefile, checkvars, [])
284
285 @testcase(1164)
286 def test_devtool_modify(self):
287 # Check preconditions
288 workspacedir = os.path.join(self.builddir, 'workspace')
289 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
290 # Clean up anything in the workdir/sysroot/sstate cache
291 bitbake('mdadm -c cleansstate')
292 # Try modifying a recipe
293 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
294 self.track_for_cleanup(tempdir)
295 self.track_for_cleanup(workspacedir)
296 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
297 self.add_command_to_tearDown('bitbake -c clean mdadm')
298 result = runCmd('devtool modify mdadm -x %s' % tempdir)
299 self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found')
300 self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found')
301 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created')
302 matches = glob.glob(os.path.join(workspacedir, 'appends', 'mdadm_*.bbappend'))
303 self.assertTrue(matches, 'bbappend not created %s' % result.output)
304 # Test devtool status
305 result = runCmd('devtool status')
306 self.assertIn('mdadm', result.output)
307 self.assertIn(tempdir, result.output)
308 # Check git repo
309 result = runCmd('git status --porcelain', cwd=tempdir)
310 self.assertEqual(result.output.strip(), "", 'Created git repo is not clean')
311 result = runCmd('git symbolic-ref HEAD', cwd=tempdir)
312 self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo')
313 # Try building
314 bitbake('mdadm')
315 # Try making (minor) modifications to the source
316 result = runCmd("sed -i 's!^\.TH.*!.TH MDADM 8 \"\" v9.999-custom!' %s" % os.path.join(tempdir, 'mdadm.8.in'))
317 bitbake('mdadm -c package')
318 pkgd = get_bb_var('PKGD', 'mdadm')
319 self.assertTrue(pkgd, 'Could not query PKGD variable')
320 mandir = get_bb_var('mandir', 'mdadm')
321 self.assertTrue(mandir, 'Could not query mandir variable')
322 if mandir[0] == '/':
323 mandir = mandir[1:]
324 with open(os.path.join(pkgd, mandir, 'man8', 'mdadm.8'), 'r') as f:
325 for line in f:
326 if line.startswith('.TH'):
327 self.assertEqual(line.rstrip(), '.TH MDADM 8 "" v9.999-custom', 'man file not modified. man searched file path: %s' % os.path.join(pkgd, mandir, 'man8', 'mdadm.8'))
328 # Test devtool reset
329 stampprefix = get_bb_var('STAMP', 'mdadm')
330 result = runCmd('devtool reset mdadm')
331 result = runCmd('devtool status')
332 self.assertNotIn('mdadm', result.output)
333 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe mdadm')
334 matches = glob.glob(stampprefix + '*')
335 self.assertFalse(matches, 'Stamp files exist for recipe mdadm that should have been cleaned')
336
337 @testcase(1166)
338 def test_devtool_modify_invalid(self):
339 # Check preconditions
340 workspacedir = os.path.join(self.builddir, 'workspace')
341 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
342 # Try modifying some recipes
343 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
344 self.track_for_cleanup(tempdir)
345 self.track_for_cleanup(workspacedir)
346 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
347
348 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split()
349 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
350 result = runCmd('bitbake-layers show-recipes gcc-source*')
351 reading = False
352 for line in result.output.splitlines():
353 if line.startswith('=='):
354 reading = True
355 elif reading and not line.startswith(' '):
356 testrecipes.append(line.split(':')[0])
357 for testrecipe in testrecipes:
358 # Check it's a valid recipe
359 bitbake('%s -e' % testrecipe)
360 # devtool extract should fail
361 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
362 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
363 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
364 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
365 # devtool modify should fail
366 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
367 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
368 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
369
370 def test_devtool_modify_native(self):
371 # Check preconditions
372 workspacedir = os.path.join(self.builddir, 'workspace')
373 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
374 # Try modifying some recipes
375 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
376 self.track_for_cleanup(tempdir)
377 self.track_for_cleanup(workspacedir)
378 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
379
380 bbclassextended = False
381 inheritnative = False
382 testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split()
383 for testrecipe in testrecipes:
384 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
385 if not bbclassextended:
386 bbclassextended = checkextend
387 if not inheritnative:
388 inheritnative = not checkextend
389 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
390 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
391 result = runCmd('devtool build %s' % testrecipe)
392 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
393 result = runCmd('devtool reset %s' % testrecipe)
394 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
395
396 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
397 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
398
399
400 @testcase(1165)
401 def test_devtool_modify_git(self):
402 # Check preconditions
403 workspacedir = os.path.join(self.builddir, 'workspace')
404 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
405 testrecipe = 'mkelfimage'
406 src_uri = get_bb_var('SRC_URI', testrecipe)
407 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
408 # Clean up anything in the workdir/sysroot/sstate cache
409 bitbake('%s -c cleansstate' % testrecipe)
410 # Try modifying a recipe
411 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
412 self.track_for_cleanup(tempdir)
413 self.track_for_cleanup(workspacedir)
414 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
415 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
416 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
417 self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found')
418 self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found')
419 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. devtool output: %s' % result.output)
420 matches = glob.glob(os.path.join(workspacedir, 'appends', 'mkelfimage_*.bbappend'))
421 self.assertTrue(matches, 'bbappend not created')
422 # Test devtool status
423 result = runCmd('devtool status')
424 self.assertIn(testrecipe, result.output)
425 self.assertIn(tempdir, result.output)
426 # Check git repo
427 result = runCmd('git status --porcelain', cwd=tempdir)
428 self.assertEqual(result.output.strip(), "", 'Created git repo is not clean')
429 result = runCmd('git symbolic-ref HEAD', cwd=tempdir)
430 self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo')
431 # Try building
432 bitbake(testrecipe)
433
434 @testcase(1167)
435 def test_devtool_modify_localfiles(self):
436 # Check preconditions
437 workspacedir = os.path.join(self.builddir, 'workspace')
438 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
439 testrecipe = 'lighttpd'
440 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
441 foundlocal = False
442 for item in src_uri:
443 if item.startswith('file://') and '.patch' not in item:
444 foundlocal = True
445 break
446 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
447 # Clean up anything in the workdir/sysroot/sstate cache
448 bitbake('%s -c cleansstate' % testrecipe)
449 # Try modifying a recipe
450 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
451 self.track_for_cleanup(tempdir)
452 self.track_for_cleanup(workspacedir)
453 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
454 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
455 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
456 self.assertTrue(os.path.exists(os.path.join(tempdir, 'configure.ac')), 'Extracted source could not be found')
457 self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created')
458 matches = glob.glob(os.path.join(workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
459 self.assertTrue(matches, 'bbappend not created')
460 # Test devtool status
461 result = runCmd('devtool status')
462 self.assertIn(testrecipe, result.output)
463 self.assertIn(tempdir, result.output)
464 # Try building
465 bitbake(testrecipe)
466
467 @testcase(1169)
468 def test_devtool_update_recipe(self):
469 # Check preconditions
470 workspacedir = os.path.join(self.builddir, 'workspace')
471 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
472 testrecipe = 'minicom'
473 recipefile = get_bb_var('FILE', testrecipe)
474 src_uri = get_bb_var('SRC_URI', testrecipe)
475 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
476 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
477 self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe)
478 # First, modify a recipe
479 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
480 self.track_for_cleanup(tempdir)
481 self.track_for_cleanup(workspacedir)
482 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
483 # (don't bother with cleaning the recipe on teardown, we won't be building it)
484 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
485 # Check git repo
486 self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found')
487 result = runCmd('git status --porcelain', cwd=tempdir)
488 self.assertEqual(result.output.strip(), "", 'Created git repo is not clean')
489 result = runCmd('git symbolic-ref HEAD', cwd=tempdir)
490 self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo')
491 # Add a couple of commits
492 # FIXME: this only tests adding, need to also test update and remove
493 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
494 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
495 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
496 result = runCmd('git add devtool-new-file', cwd=tempdir)
497 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
498 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
499 result = runCmd('devtool update-recipe %s' % testrecipe)
500 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
501 self.assertNotEqual(result.output.strip(), "", '%s recipe should be modified' % testrecipe)
502 status = result.output.splitlines()
503 self.assertEqual(len(status), 3, 'Less/more files modified than expected. Entire status:\n%s' % result.output)
504 for line in status:
505 if line.endswith('0001-Change-the-README.patch'):
506 self.assertEqual(line[:3], '?? ', 'Unexpected status in line: %s' % line)
507 elif line.endswith('0002-Add-a-new-file.patch'):
508 self.assertEqual(line[:3], '?? ', 'Unexpected status in line: %s' % line)
509 elif re.search('%s_[^_]*.bb$' % testrecipe, line):
510 self.assertEqual(line[:3], ' M ', 'Unexpected status in line: %s' % line)
511 else:
512 raise AssertionError('Unexpected modified file in status: %s' % line)
513
514 @testcase(1172)
515 def test_devtool_update_recipe_git(self):
516 # Check preconditions
517 workspacedir = os.path.join(self.builddir, 'workspace')
518 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
519 testrecipe = 'mtd-utils'
520 recipefile = get_bb_var('FILE', testrecipe)
521 src_uri = get_bb_var('SRC_URI', testrecipe)
522 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
523 patches = []
524 for entry in src_uri.split():
525 if entry.startswith('file://') and entry.endswith('.patch'):
526 patches.append(entry[7:].split(';')[0])
527 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
528 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
529 self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe)
530 # First, modify a recipe
531 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
532 self.track_for_cleanup(tempdir)
533 self.track_for_cleanup(workspacedir)
534 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
535 # (don't bother with cleaning the recipe on teardown, we won't be building it)
536 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
537 # Check git repo
538 self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found')
539 result = runCmd('git status --porcelain', cwd=tempdir)
540 self.assertEqual(result.output.strip(), "", 'Created git repo is not clean')
541 result = runCmd('git symbolic-ref HEAD', cwd=tempdir)
542 self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo')
543 # Add a couple of commits
544 # FIXME: this only tests adding, need to also test update and remove
545 result = runCmd('echo "# Additional line" >> Makefile', cwd=tempdir)
546 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
547 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
548 result = runCmd('git add devtool-new-file', cwd=tempdir)
549 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
550 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
551 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
552 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
553 self.assertNotEqual(result.output.strip(), "", '%s recipe should be modified' % testrecipe)
554 status = result.output.splitlines()
555 for line in status:
556 for patch in patches:
557 if line.endswith(patch):
558 self.assertEqual(line[:3], ' D ', 'Unexpected status in line: %s' % line)
559 break
560 else:
561 if re.search('%s_[^_]*.bb$' % testrecipe, line):
562 self.assertEqual(line[:3], ' M ', 'Unexpected status in line: %s' % line)
563 else:
564 raise AssertionError('Unexpected modified file in status: %s' % line)
565 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
566 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
567 srcurilines = src_uri.split()
568 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
569 srcurilines.append('"')
570 removelines = ['SRCREV = ".*"'] + srcurilines
571 for line in result.output.splitlines():
572 if line.startswith('+++') or line.startswith('---'):
573 continue
574 elif line.startswith('+'):
575 matched = False
576 for item in addlines:
577 if re.match(item, line[1:].strip()):
578 matched = True
579 break
580 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
581 elif line.startswith('-'):
582 matched = False
583 for item in removelines:
584 if re.match(item, line[1:].strip()):
585 matched = True
586 break
587 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
588 # Now try with auto mode
589 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
590 result = runCmd('devtool update-recipe %s' % testrecipe)
591 result = runCmd('git rev-parse --show-toplevel')
592 topleveldir = result.output.strip()
593 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
594 status = result.output.splitlines()
595 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
596 expectedstatus = [('M', os.path.relpath(recipefile, topleveldir)),
597 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
598 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
599 for line in status:
600 statusline = line.split(None, 1)
601 for fstatus, fn in expectedstatus:
602 if fn == statusline[1]:
603 if fstatus != statusline[0]:
604 self.fail('Unexpected status in line: %s' % line)
605 break
606 else:
607 self.fail('Unexpected modified file in line: %s' % line)
608
609 @testcase(1170)
610 def test_devtool_update_recipe_append(self):
611 # Check preconditions
612 workspacedir = os.path.join(self.builddir, 'workspace')
613 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
614 testrecipe = 'mdadm'
615 recipefile = get_bb_var('FILE', testrecipe)
616 src_uri = get_bb_var('SRC_URI', testrecipe)
617 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
618 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
619 self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe)
620 # First, modify a recipe
621 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
622 tempsrcdir = os.path.join(tempdir, 'source')
623 templayerdir = os.path.join(tempdir, 'layer')
624 self.track_for_cleanup(tempdir)
625 self.track_for_cleanup(workspacedir)
626 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
627 # (don't bother with cleaning the recipe on teardown, we won't be building it)
628 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
629 # Check git repo
630 self.assertTrue(os.path.isdir(os.path.join(tempsrcdir, '.git')), 'git repository for external source tree not found')
631 result = runCmd('git status --porcelain', cwd=tempsrcdir)
632 self.assertEqual(result.output.strip(), "", 'Created git repo is not clean')
633 result = runCmd('git symbolic-ref HEAD', cwd=tempsrcdir)
634 self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo')
635 # Add a commit
636 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
637 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
638 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
639 # Create a temporary layer and add it to bblayers.conf
640 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
641 # Create the bbappend
642 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
643 self.assertNotIn('WARNING:', result.output)
644 # Check recipe is still clean
645 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
646 self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe)
647 # Check bbappend was created
648 splitpath = os.path.dirname(recipefile).split(os.sep)
649 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
650 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
651 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
652 self.assertTrue(os.path.exists(patchfile), 'Patch file not created')
653
654 # Check bbappend contents
655 expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
656 '\n',
657 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
658 '\n']
659 with open(bbappendfile, 'r') as f:
660 self.assertEqual(expectedlines, f.readlines())
661
662 # Check we can run it again and bbappend isn't modified
663 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
664 with open(bbappendfile, 'r') as f:
665 self.assertEqual(expectedlines, f.readlines())
666 # Drop new commit and check patch gets deleted
667 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
668 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
669 self.assertFalse(os.path.exists(patchfile), 'Patch file not deleted')
670 expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
671 '\n']
672 with open(bbappendfile, 'r') as f:
673 self.assertEqual(expectedlines2, f.readlines())
674 # Put commit back and check we can run it if layer isn't in bblayers.conf
675 os.remove(bbappendfile)
676 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
677 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
678 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
679 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
680 self.assertTrue(os.path.exists(patchfile), 'Patch file not created (with disabled layer)')
681 with open(bbappendfile, 'r') as f:
682 self.assertEqual(expectedlines, f.readlines())
683 # Deleting isn't expected to work under these circumstances
684
685 @testcase(1171)
686 def test_devtool_update_recipe_append_git(self):
687 # Check preconditions
688 workspacedir = os.path.join(self.builddir, 'workspace')
689 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
690 testrecipe = 'mtd-utils'
691 recipefile = get_bb_var('FILE', testrecipe)
692 src_uri = get_bb_var('SRC_URI', testrecipe)
693 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
694 for entry in src_uri.split():
695 if entry.startswith('git://'):
696 git_uri = entry
697 break
698 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
699 self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe)
700 # First, modify a recipe
701 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
702 tempsrcdir = os.path.join(tempdir, 'source')
703 templayerdir = os.path.join(tempdir, 'layer')
704 self.track_for_cleanup(tempdir)
705 self.track_for_cleanup(workspacedir)
706 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
707 # (don't bother with cleaning the recipe on teardown, we won't be building it)
708 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
709 # Check git repo
710 self.assertTrue(os.path.isdir(os.path.join(tempsrcdir, '.git')), 'git repository for external source tree not found')
711 result = runCmd('git status --porcelain', cwd=tempsrcdir)
712 self.assertEqual(result.output.strip(), "", 'Created git repo is not clean')
713 result = runCmd('git symbolic-ref HEAD', cwd=tempsrcdir)
714 self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo')
715 # Add a commit
716 result = runCmd('echo "# Additional line" >> Makefile', cwd=tempsrcdir)
717 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
718 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
719 # Create a temporary layer
720 os.makedirs(os.path.join(templayerdir, 'conf'))
721 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
722 f.write('BBPATH .= ":${LAYERDIR}"\n')
723 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
724 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
725 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
726 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
727 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
728 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
729 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
730 # Create the bbappend
731 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
732 self.assertNotIn('WARNING:', result.output)
733 # Check recipe is still clean
734 result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
735 self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe)
736 # Check bbappend was created
737 splitpath = os.path.dirname(recipefile).split(os.sep)
738 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
739 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
740 self.assertFalse(os.path.exists(os.path.join(appenddir, testrecipe)), 'Patch directory should not be created')
741
742 # Check bbappend contents
743 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
744 expectedlines = ['SRCREV = "%s"\n' % result.output,
745 '\n',
746 'SRC_URI = "%s"\n' % git_uri,
747 '\n']
748 with open(bbappendfile, 'r') as f:
749 self.assertEqual(expectedlines, f.readlines())
750
751 # Check we can run it again and bbappend isn't modified
752 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
753 with open(bbappendfile, 'r') as f:
754 self.assertEqual(expectedlines, f.readlines())
755 # Drop new commit and check SRCREV changes
756 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
757 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
758 self.assertFalse(os.path.exists(os.path.join(appenddir, testrecipe)), 'Patch directory should not be created')
759 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
760 expectedlines = ['SRCREV = "%s"\n' % result.output,
761 '\n',
762 'SRC_URI = "%s"\n' % git_uri,
763 '\n']
764 with open(bbappendfile, 'r') as f:
765 self.assertEqual(expectedlines, f.readlines())
766 # Put commit back and check we can run it if layer isn't in bblayers.conf
767 os.remove(bbappendfile)
768 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
769 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
770 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
771 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
772 self.assertFalse(os.path.exists(os.path.join(appenddir, testrecipe)), 'Patch directory should not be created')
773 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
774 expectedlines = ['SRCREV = "%s"\n' % result.output,
775 '\n',
776 'SRC_URI = "%s"\n' % git_uri,
777 '\n']
778 with open(bbappendfile, 'r') as f:
779 self.assertEqual(expectedlines, f.readlines())
780 # Deleting isn't expected to work under these circumstances
781
782 @testcase(1163)
783 def test_devtool_extract(self):
784 # Check preconditions
785 workspacedir = os.path.join(self.builddir, 'workspace')
786 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
787 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
788 # Try devtool extract
789 self.track_for_cleanup(tempdir)
790 self.track_for_cleanup(workspacedir)
791 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
792 result = runCmd('devtool extract remake %s' % tempdir)
793 self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found')
794 self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found')
795
796 @testcase(1168)
797 def test_devtool_reset_all(self):
798 # Check preconditions
799 workspacedir = os.path.join(self.builddir, 'workspace')
800 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
801 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
802 self.track_for_cleanup(tempdir)
803 self.track_for_cleanup(workspacedir)
804 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
805 testrecipe1 = 'mdadm'
806 testrecipe2 = 'cronie'
807 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
808 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
809 result = runCmd('devtool build %s' % testrecipe1)
810 result = runCmd('devtool build %s' % testrecipe2)
811 stampprefix1 = get_bb_var('STAMP', testrecipe1)
812 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
813 stampprefix2 = get_bb_var('STAMP', testrecipe2)
814 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
815 result = runCmd('devtool reset -a')
816 self.assertIn(testrecipe1, result.output)
817 self.assertIn(testrecipe2, result.output)
818 result = runCmd('devtool status')
819 self.assertNotIn(testrecipe1, result.output)
820 self.assertNotIn(testrecipe2, result.output)
821 matches1 = glob.glob(stampprefix1 + '*')
822 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
823 matches2 = glob.glob(stampprefix2 + '*')
824 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
825
826 def test_devtool_deploy_target(self):
827 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
828 # unfortunately the runtime tests run under bitbake and you can't run
829 # devtool within bitbake (since devtool needs to run bitbake itself).
830 # Additionally we are testing build-time functionality as well, so
831 # really this has to be done as an oe-selftest test.
832 #
833 # Check preconditions
834 machine = get_bb_var('MACHINE')
835 if not machine.startswith('qemu'):
836 self.skipTest('This test only works with qemu machines')
837 if not os.path.exists('/etc/runqemu-nosudo'):
838 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
839 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
840 if result.status != 0:
841 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
842 if result.status != 0:
843 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
844 for line in result.output.splitlines():
845 if line.startswith('tap'):
846 break
847 else:
848 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
849 workspacedir = os.path.join(self.builddir, 'workspace')
850 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
851 # Definitions
852 testrecipe = 'mdadm'
853 testfile = '/sbin/mdadm'
854 testimage = 'oe-selftest-image'
855 testcommand = '/sbin/mdadm --help'
856 # Build an image to run
857 bitbake("%s qemu-native qemu-helper-native" % testimage)
858 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
859 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
860 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
861 # Clean recipe so the first deploy will fail
862 bitbake("%s -c clean" % testrecipe)
863 # Try devtool modify
864 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
865 self.track_for_cleanup(tempdir)
866 self.track_for_cleanup(workspacedir)
867 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
868 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
869 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
870 # Test that deploy-target at this point fails (properly)
871 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
872 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
873 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
874 result = runCmd('devtool build %s' % testrecipe)
875 # First try a dry-run of deploy-target
876 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
877 self.assertIn(' %s' % testfile, result.output)
878 # Boot the image
879 with runqemu(testimage, self) as qemu:
880 # Now really test deploy-target
881 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
882 # Run a test command to see if it was installed properly
883 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
884 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
885 # Check if it deployed all of the files with the right ownership/perms
886 # First look on the host - need to do this under pseudo to get the correct ownership/perms
887 installdir = get_bb_var('D', testrecipe)
888 fakerootenv = get_bb_var('FAKEROOTENV', testrecipe)
889 fakerootcmd = get_bb_var('FAKEROOTCMD', testrecipe)
890 result = runCmd('%s %s find . -type f -exec ls -l {} \;' % (fakerootenv, fakerootcmd), cwd=installdir)
891 filelist1 = self._process_ls_output(result.output)
892
893 # Now look on the target
894 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
895 self.track_for_cleanup(tempdir2)
896 tmpfilelist = os.path.join(tempdir2, 'files.txt')
897 with open(tmpfilelist, 'w') as f:
898 for line in filelist1:
899 splitline = line.split()
900 f.write(splitline[-1] + '\n')
901 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
902 filelist2 = self._process_ls_output(result.output)
903 filelist1.sort(key=lambda item: item.split()[-1])
904 filelist2.sort(key=lambda item: item.split()[-1])
905 self.assertEqual(filelist1, filelist2)
906 # Test undeploy-target
907 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
908 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
909 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
910
911 def test_devtool_build_image(self):
912 """Test devtool build-image plugin"""
913 # Check preconditions
914 workspacedir = os.path.join(self.builddir, 'workspace')
915 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
916 image = 'core-image-minimal'
917 self.track_for_cleanup(workspacedir)
918 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
919 self.add_command_to_tearDown('bitbake -c clean %s' % image)
920 bitbake('%s -c clean' % image)
921 # Add target and native recipes to workspace
922 for recipe in ('mdadm', 'parted-native'):
923 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
924 self.track_for_cleanup(tempdir)
925 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
926 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
927 # Try to build image
928 result = runCmd('devtool build-image %s' % image)
929 self.assertNotEqual(result, 0, 'devtool build-image failed')
930 # Check if image.bbappend has required content
931 bbappend = os.path.join(workspacedir, 'appends', image+'.bbappend')
932 self.assertTrue(os.path.isfile(bbappend), 'bbappend not created %s' % result.output)
933 # NOTE: native recipe parted-native should not be in IMAGE_INSTALL_append
934 self.assertTrue('IMAGE_INSTALL_append = " mdadm"\n' in open(bbappend).readlines(),
935 'IMAGE_INSTALL_append = " mdadm" not found in %s' % bbappend)
936
937 def test_devtool_upgrade(self):
938 # Check preconditions
939 workspacedir = os.path.join(self.builddir, 'workspace')
940 self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory')
941 # Check parameters
942 result = runCmd('devtool upgrade -h')
943 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
944 self.assertIn(param, result.output)
945 # For the moment, we are using a real recipe.
946 recipe='devtool-upgrade'
947 version='0.2'
948 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
949 # Check that recipe is not already under devtool control
950 result = runCmd('devtool status')
951 self.assertNotIn(recipe, result.output)
952 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
953 # we are downgrading instead of upgrading.
954 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
955 # Check if srctree at least is populated
956 self.assertTrue(len(os.listdir(tempdir)) > 0, 'scrtree (%s) should be populated with new (%s) source code' % (tempdir, version))
957 # Check new recipe folder is present
958 self.assertTrue(os.path.exists(os.path.join(workspacedir,'recipes',recipe)), 'Recipe folder should exist')
959 # Check new recipe file is present
960 self.assertTrue(os.path.exists(os.path.join(workspacedir,'recipes',recipe,"%s_%s.bb" % (recipe,version))), 'Recipe folder should exist')
961 # Check devtool status and make sure recipe is present
962 result = runCmd('devtool status')
963 self.assertIn(recipe, result.output)
964 self.assertIn(tempdir, result.output)
965 # Check devtool reset recipe
966 result = runCmd('devtool reset %s -n' % recipe)
967 result = runCmd('devtool status')
968 self.assertNotIn(recipe, result.output)
969 self.track_for_cleanup(tempdir)
970 self.track_for_cleanup(workspacedir)
971 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')