]> Git Repo - J-u-boot.git/blob - tools/buildman/func_test.py
buildman: Add --allow-missing flag to allow missing blobs
[J-u-boot.git] / tools / buildman / func_test.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2014 Google, Inc
3 #
4
5 import os
6 import shutil
7 import sys
8 import tempfile
9 import unittest
10
11 from buildman import board
12 from buildman import boards
13 from buildman import bsettings
14 from buildman import cmdline
15 from buildman import control
16 from buildman import toolchain
17 from patman import command
18 from patman import gitutil
19 from patman import terminal
20 from patman import test_util
21 from patman import tools
22
23 settings_data = '''
24 # Buildman settings file
25 [global]
26
27 [toolchain]
28
29 [toolchain-alias]
30
31 [make-flags]
32 src=/home/sjg/c/src
33 chroot=/home/sjg/c/chroot
34 vboot=VBOOT_DEBUG=1 MAKEFLAGS_VBOOT=DEBUG=1 CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS VBOOT_SOURCE=${src}/platform/vboot_reference
35 chromeos_coreboot=VBOOT=${chroot}/build/link/usr ${vboot}
36 chromeos_daisy=VBOOT=${chroot}/build/daisy/usr ${vboot}
37 chromeos_peach=VBOOT=${chroot}/build/peach_pit/usr ${vboot}
38 '''
39
40 BOARDS = [
41     ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0',  ''],
42     ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''],
43     ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''],
44     ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
45 ]
46
47 commit_shortlog = """4aca821 patman: Avoid changing the order of tags
48 39403bb patman: Use --no-pager' to stop git from forking a pager
49 db6e6f2 patman: Remove the -a option
50 f2ccf03 patman: Correct unit tests to run correctly
51 1d097f9 patman: Fix indentation in terminal.py
52 d073747 patman: Support the 'reverse' option for 'git log
53 """
54
55 commit_log = ["""commit 7f6b8315d18f683c5181d0c3694818c1b2a20dcd
56 Author: Masahiro Yamada <[email protected]>
57 Date:   Fri Aug 22 19:12:41 2014 +0900
58
59     buildman: refactor help message
60
61     "buildman [options]" is displayed by default.
62
63     Append the rest of help messages to parser.usage
64     instead of replacing it.
65
66     Besides, "-b <branch>" is not mandatory since commit fea5858e.
67     Drop it from the usage.
68
69     Signed-off-by: Masahiro Yamada <[email protected]>
70 """,
71 """commit d0737479be6baf4db5e2cdbee123e96bc5ed0ba8
72 Author: Simon Glass <[email protected]>
73 Date:   Thu Aug 14 16:48:25 2014 -0600
74
75     patman: Support the 'reverse' option for 'git log'
76
77     This option is currently not supported, but needs to be, for buildman to
78     operate as expected.
79
80     Series-changes: 7
81     - Add new patch to fix the 'reverse' bug
82
83     Series-version: 8
84
85     Change-Id: I79078f792e8b390b8a1272a8023537821d45feda
86     Reported-by: York Sun <[email protected]>
87     Signed-off-by: Simon Glass <[email protected]>
88
89 """,
90 """commit 1d097f9ab487c5019152fd47bda126839f3bf9fc
91 Author: Simon Glass <[email protected]>
92 Date:   Sat Aug 9 11:44:32 2014 -0600
93
94     patman: Fix indentation in terminal.py
95
96     This code came from a different project with 2-character indentation. Fix
97     it for U-Boot.
98
99     Series-changes: 6
100     - Add new patch to fix indentation in teminal.py
101
102     Change-Id: I5a74d2ebbb3cc12a665f5c725064009ac96e8a34
103     Signed-off-by: Simon Glass <[email protected]>
104
105 """,
106 """commit f2ccf03869d1e152c836515a3ceb83cdfe04a105
107 Author: Simon Glass <[email protected]>
108 Date:   Sat Aug 9 11:08:24 2014 -0600
109
110     patman: Correct unit tests to run correctly
111
112     It seems that doctest behaves differently now, and some of the unit tests
113     do not run. Adjust the tests to work correctly.
114
115      ./tools/patman/patman --test
116     <unittest.result.TestResult run=10 errors=0 failures=0>
117
118     Series-changes: 6
119     - Add new patch to fix patman unit tests
120
121     Change-Id: I3d2ca588f4933e1f9d6b1665a00e4ae58269ff3b
122
123 """,
124 """commit db6e6f2f9331c5a37647d6668768d4a40b8b0d1c
125 Author: Simon Glass <[email protected]>
126 Date:   Sat Aug 9 12:06:02 2014 -0600
127
128     patman: Remove the -a option
129
130     It seems that this is no longer needed, since checkpatch.pl will catch
131     whitespace problems in patches. Also the option is not widely used, so
132     it seems safe to just remove it.
133
134     Series-changes: 6
135     - Add new patch to remove patman's -a option
136
137     Suggested-by: Masahiro Yamada <[email protected]>
138     Change-Id: I5821a1c75154e532c46513486ca40b808de7e2cc
139
140 """,
141 """commit 39403bb4f838153028a6f21ca30bf100f3791133
142 Author: Simon Glass <[email protected]>
143 Date:   Thu Aug 14 21:50:52 2014 -0600
144
145     patman: Use --no-pager' to stop git from forking a pager
146
147 """,
148 """commit 4aca821e27e97925c039e69fd37375b09c6f129c
149 Author: Simon Glass <[email protected]>
150 Date:   Fri Aug 22 15:57:39 2014 -0600
151
152     patman: Avoid changing the order of tags
153
154     patman collects tags that it sees in the commit and places them nicely
155     sorted at the end of the patch. However, this is not really necessary and
156     in fact is apparently not desirable.
157
158     Series-changes: 9
159     - Add new patch to avoid changing the order of tags
160
161     Series-version: 9
162
163     Suggested-by: Masahiro Yamada <[email protected]>
164     Change-Id: Ib1518588c1a189ad5c3198aae76f8654aed8d0db
165 """]
166
167 TEST_BRANCH = '__testbranch'
168
169 class TestFunctional(unittest.TestCase):
170     """Functional test for buildman.
171
172     This aims to test from just below the invocation of buildman (parsing
173     of arguments) to 'make' and 'git' invocation. It is not a true
174     emd-to-end test, as it mocks git, make and the tool chain. But this
175     makes it easier to detect when the builder is doing the wrong thing,
176     since in many cases this test code will fail. For example, only a
177     very limited subset of 'git' arguments is supported - anything
178     unexpected will fail.
179     """
180     def setUp(self):
181         self._base_dir = tempfile.mkdtemp()
182         self._output_dir = tempfile.mkdtemp()
183         self._git_dir = os.path.join(self._base_dir, 'src')
184         self._buildman_pathname = sys.argv[0]
185         self._buildman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
186         command.test_result = self._HandleCommand
187         bsettings.Setup(None)
188         bsettings.AddFile(settings_data)
189         self.setupToolchains()
190         self._toolchains.Add('arm-gcc', test=False)
191         self._toolchains.Add('powerpc-gcc', test=False)
192         self._boards = boards.Boards()
193         for brd in BOARDS:
194             self._boards.add_board(board.Board(*brd))
195
196         # Directories where the source been cloned
197         self._clone_dirs = []
198         self._commits = len(commit_shortlog.splitlines()) + 1
199         self._total_builds = self._commits * len(BOARDS)
200
201         # Number of calls to make
202         self._make_calls = 0
203
204         # Map of [board, commit] to error messages
205         self._error = {}
206
207         self._test_branch = TEST_BRANCH
208
209         # Set to True to report missing blobs
210         self._missing = False
211
212         # Avoid sending any output and clear all terminal output
213         terminal.set_print_test_mode()
214         terminal.get_print_test_lines()
215
216     def tearDown(self):
217         shutil.rmtree(self._base_dir)
218         shutil.rmtree(self._output_dir)
219
220     def setupToolchains(self):
221         self._toolchains = toolchain.Toolchains()
222         self._toolchains.Add('gcc', test=False)
223
224     def _RunBuildman(self, *args):
225         return command.run_pipe([[self._buildman_pathname] + list(args)],
226                 capture=True, capture_stderr=True)
227
228     def _RunControl(self, *args, brds=None, clean_dir=False,
229                     test_thread_exceptions=False):
230         """Run buildman
231
232         Args:
233             args: List of arguments to pass
234             brds: Boards object
235             clean_dir: Used for tests only, indicates that the existing output_dir
236                 should be removed before starting the build
237             test_thread_exceptions: Uses for tests only, True to make the threads
238                 raise an exception instead of reporting their result. This simulates
239                 a failure in the code somewhere
240
241         Returns:
242             result code from buildman
243         """
244         sys.argv = [sys.argv[0]] + list(args)
245         options, args = cmdline.ParseArgs()
246         result = control.DoBuildman(options, args, toolchains=self._toolchains,
247                 make_func=self._HandleMake, brds=brds or self._boards,
248                 clean_dir=clean_dir,
249                 test_thread_exceptions=test_thread_exceptions)
250         self._builder = control.builder
251         return result
252
253     def testFullHelp(self):
254         command.test_result = None
255         result = self._RunBuildman('-H')
256         help_file = os.path.join(self._buildman_dir, 'README.rst')
257         # Remove possible extraneous strings
258         extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
259         gothelp = result.stdout.replace(extra, '')
260         self.assertEqual(len(gothelp), os.path.getsize(help_file))
261         self.assertEqual(0, len(result.stderr))
262         self.assertEqual(0, result.return_code)
263
264     def testHelp(self):
265         command.test_result = None
266         result = self._RunBuildman('-h')
267         help_file = os.path.join(self._buildman_dir, 'README.rst')
268         self.assertTrue(len(result.stdout) > 1000)
269         self.assertEqual(0, len(result.stderr))
270         self.assertEqual(0, result.return_code)
271
272     def testGitSetup(self):
273         """Test gitutils.Setup(), from outside the module itself"""
274         command.test_result = command.CommandResult(return_code=1)
275         gitutil.setup()
276         self.assertEqual(gitutil.use_no_decorate, False)
277
278         command.test_result = command.CommandResult(return_code=0)
279         gitutil.setup()
280         self.assertEqual(gitutil.use_no_decorate, True)
281
282     def _HandleCommandGitLog(self, args):
283         if args[-1] == '--':
284             args = args[:-1]
285         if '-n0' in args:
286             return command.CommandResult(return_code=0)
287         elif args[-1] == 'upstream/master..%s' % self._test_branch:
288             return command.CommandResult(return_code=0, stdout=commit_shortlog)
289         elif args[:3] == ['--no-color', '--no-decorate', '--reverse']:
290             if args[-1] == self._test_branch:
291                 count = int(args[3][2:])
292                 return command.CommandResult(return_code=0,
293                                             stdout=''.join(commit_log[:count]))
294
295         # Not handled, so abort
296         print('git log', args)
297         sys.exit(1)
298
299     def _HandleCommandGitConfig(self, args):
300         config = args[0]
301         if config == 'sendemail.aliasesfile':
302             return command.CommandResult(return_code=0)
303         elif config.startswith('branch.badbranch'):
304             return command.CommandResult(return_code=1)
305         elif config == 'branch.%s.remote' % self._test_branch:
306             return command.CommandResult(return_code=0, stdout='upstream\n')
307         elif config == 'branch.%s.merge' % self._test_branch:
308             return command.CommandResult(return_code=0,
309                                          stdout='refs/heads/master\n')
310
311         # Not handled, so abort
312         print('git config', args)
313         sys.exit(1)
314
315     def _HandleCommandGit(self, in_args):
316         """Handle execution of a git command
317
318         This uses a hacked-up parser.
319
320         Args:
321             in_args: Arguments after 'git' from the command line
322         """
323         git_args = []           # Top-level arguments to git itself
324         sub_cmd = None          # Git sub-command selected
325         args = []               # Arguments to the git sub-command
326         for arg in in_args:
327             if sub_cmd:
328                 args.append(arg)
329             elif arg[0] == '-':
330                 git_args.append(arg)
331             else:
332                 if git_args and git_args[-1] in ['--git-dir', '--work-tree']:
333                     git_args.append(arg)
334                 else:
335                     sub_cmd = arg
336         if sub_cmd == 'config':
337             return self._HandleCommandGitConfig(args)
338         elif sub_cmd == 'log':
339             return self._HandleCommandGitLog(args)
340         elif sub_cmd == 'clone':
341             return command.CommandResult(return_code=0)
342         elif sub_cmd == 'checkout':
343             return command.CommandResult(return_code=0)
344         elif sub_cmd == 'worktree':
345             return command.CommandResult(return_code=0)
346
347         # Not handled, so abort
348         print('git', git_args, sub_cmd, args)
349         sys.exit(1)
350
351     def _HandleCommandNm(self, args):
352         return command.CommandResult(return_code=0)
353
354     def _HandleCommandObjdump(self, args):
355         return command.CommandResult(return_code=0)
356
357     def _HandleCommandObjcopy(self, args):
358         return command.CommandResult(return_code=0)
359
360     def _HandleCommandSize(self, args):
361         return command.CommandResult(return_code=0)
362
363     def _HandleCommand(self, **kwargs):
364         """Handle a command execution.
365
366         The command is in kwargs['pipe-list'], as a list of pipes, each a
367         list of commands. The command should be emulated as required for
368         testing purposes.
369
370         Returns:
371             A CommandResult object
372         """
373         pipe_list = kwargs['pipe_list']
374         wc = False
375         if len(pipe_list) != 1:
376             if pipe_list[1] == ['wc', '-l']:
377                 wc = True
378             else:
379                 print('invalid pipe', kwargs)
380                 sys.exit(1)
381         cmd = pipe_list[0][0]
382         args = pipe_list[0][1:]
383         result = None
384         if cmd == 'git':
385             result = self._HandleCommandGit(args)
386         elif cmd == './scripts/show-gnu-make':
387             return command.CommandResult(return_code=0, stdout='make')
388         elif cmd.endswith('nm'):
389             return self._HandleCommandNm(args)
390         elif cmd.endswith('objdump'):
391             return self._HandleCommandObjdump(args)
392         elif cmd.endswith('objcopy'):
393             return self._HandleCommandObjcopy(args)
394         elif cmd.endswith( 'size'):
395             return self._HandleCommandSize(args)
396
397         if not result:
398             # Not handled, so abort
399             print('unknown command', kwargs)
400             sys.exit(1)
401
402         if wc:
403             result.stdout = len(result.stdout.splitlines())
404         return result
405
406     def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs):
407         """Handle execution of 'make'
408
409         Args:
410             commit: Commit object that is being built
411             brd: Board object that is being built
412             stage: Stage that we are at (mrproper, config, build)
413             cwd: Directory where make should be run
414             args: Arguments to pass to make
415             kwargs: Arguments to pass to command.run_pipe()
416         """
417         self._make_calls += 1
418         if stage == 'mrproper':
419             return command.CommandResult(return_code=0)
420         elif stage == 'config':
421             return command.CommandResult(return_code=0,
422                     combined='Test configuration complete')
423         elif stage == 'build':
424             stderr = ''
425             out_dir = ''
426             for arg in args:
427                 if arg.startswith('O='):
428                     out_dir = arg[2:]
429             fname = os.path.join(cwd or '', out_dir, 'u-boot')
430             tools.write_file(fname, b'U-Boot')
431
432             # Handle missing blobs
433             if self._missing:
434                 if 'BINMAN_ALLOW_MISSING=1' in args:
435                     stderr = '''+Image 'main-section' is missing external blobs and is non-functional: intel-descriptor intel-ifwi intel-fsp-m intel-fsp-s intel-vbt
436 Image 'main-section' has faked external blobs and is non-functional: descriptor.bin fsp_m.bin fsp_s.bin vbt.bin
437
438 Some images are invalid'''
439                 else:
440                     stderr = "binman: Filename 'fsp.bin' not found in input path"
441             elif type(commit) is not str:
442                 stderr = self._error.get((brd.target, commit.sequence))
443
444             if stderr:
445                 return command.CommandResult(return_code=2, stderr=stderr)
446             return command.CommandResult(return_code=0)
447
448         # Not handled, so abort
449         print('make', stage)
450         sys.exit(1)
451
452     # Example function to print output lines
453     def print_lines(self, lines):
454         print(len(lines))
455         for line in lines:
456             print(line)
457         #self.print_lines(terminal.get_print_test_lines())
458
459     def testNoBoards(self):
460         """Test that buildman aborts when there are no boards"""
461         self._boards = boards.Boards()
462         with self.assertRaises(SystemExit):
463             self._RunControl()
464
465     def testCurrentSource(self):
466         """Very simple test to invoke buildman on the current source"""
467         self.setupToolchains();
468         self._RunControl('-o', self._output_dir)
469         lines = terminal.get_print_test_lines()
470         self.assertIn('Building current source for %d boards' % len(BOARDS),
471                       lines[0].text)
472
473     def testBadBranch(self):
474         """Test that we can detect an invalid branch"""
475         with self.assertRaises(ValueError):
476             self._RunControl('-b', 'badbranch')
477
478     def testBadToolchain(self):
479         """Test that missing toolchains are detected"""
480         self.setupToolchains();
481         ret_code = self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
482         lines = terminal.get_print_test_lines()
483
484         # Buildman always builds the upstream commit as well
485         self.assertIn('Building %d commits for %d boards' %
486                 (self._commits, len(BOARDS)), lines[0].text)
487         self.assertEqual(self._builder.count, self._total_builds)
488
489         # Only sandbox should succeed, the others don't have toolchains
490         self.assertEqual(self._builder.fail,
491                          self._total_builds - self._commits)
492         self.assertEqual(ret_code, 100)
493
494         for commit in range(self._commits):
495             for brd in self._boards.get_list():
496                 if brd.arch != 'sandbox':
497                   errfile = self._builder.GetErrFile(commit, brd.target)
498                   fd = open(errfile)
499                   self.assertEqual(fd.readlines(),
500                           ['No tool chain for %s\n' % brd.arch])
501                   fd.close()
502
503     def testBranch(self):
504         """Test building a branch with all toolchains present"""
505         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
506         self.assertEqual(self._builder.count, self._total_builds)
507         self.assertEqual(self._builder.fail, 0)
508
509     def testCount(self):
510         """Test building a specific number of commitst"""
511         self._RunControl('-b', TEST_BRANCH, '-c2', '-o', self._output_dir)
512         self.assertEqual(self._builder.count, 2 * len(BOARDS))
513         self.assertEqual(self._builder.fail, 0)
514         # Each board has a config, and then one make per commit
515         self.assertEqual(self._make_calls, len(BOARDS) * (1 + 2))
516
517     def testIncremental(self):
518         """Test building a branch twice - the second time should do nothing"""
519         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
520
521         # Each board has a mrproper, config, and then one make per commit
522         self.assertEqual(self._make_calls, len(BOARDS) * (self._commits + 1))
523         self._make_calls = 0
524         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, clean_dir=False)
525         self.assertEqual(self._make_calls, 0)
526         self.assertEqual(self._builder.count, self._total_builds)
527         self.assertEqual(self._builder.fail, 0)
528
529     def testForceBuild(self):
530         """The -f flag should force a rebuild"""
531         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
532         self._make_calls = 0
533         self._RunControl('-b', TEST_BRANCH, '-f', '-o', self._output_dir, clean_dir=False)
534         # Each board has a config and one make per commit
535         self.assertEqual(self._make_calls, len(BOARDS) * (self._commits + 1))
536
537     def testForceReconfigure(self):
538         """The -f flag should force a rebuild"""
539         self._RunControl('-b', TEST_BRANCH, '-C', '-o', self._output_dir)
540         # Each commit has a config and make
541         self.assertEqual(self._make_calls, len(BOARDS) * self._commits * 2)
542
543     def testMrproper(self):
544         """The -f flag should force a rebuild"""
545         self._RunControl('-b', TEST_BRANCH, '-m', '-o', self._output_dir)
546         # Each board has a mkproper, config and then one make per commit
547         self.assertEqual(self._make_calls, len(BOARDS) * (self._commits + 2))
548
549     def testErrors(self):
550         """Test handling of build errors"""
551         self._error['board2', 1] = 'fred\n'
552         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
553         self.assertEqual(self._builder.count, self._total_builds)
554         self.assertEqual(self._builder.fail, 1)
555
556         # Remove the error. This should have no effect since the commit will
557         # not be rebuilt
558         del self._error['board2', 1]
559         self._make_calls = 0
560         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, clean_dir=False)
561         self.assertEqual(self._builder.count, self._total_builds)
562         self.assertEqual(self._make_calls, 0)
563         self.assertEqual(self._builder.fail, 1)
564
565         # Now use the -F flag to force rebuild of the bad commit
566         self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, '-F', clean_dir=False)
567         self.assertEqual(self._builder.count, self._total_builds)
568         self.assertEqual(self._builder.fail, 0)
569         self.assertEqual(self._make_calls, 2)
570
571     def testBranchWithSlash(self):
572         """Test building a branch with a '/' in the name"""
573         self._test_branch = '/__dev/__testbranch'
574         self._RunControl('-b', self._test_branch, clean_dir=False)
575         self.assertEqual(self._builder.count, self._total_builds)
576         self.assertEqual(self._builder.fail, 0)
577
578     def testEnvironment(self):
579         """Test that the done and environment files are written to out-env"""
580         self._RunControl('-o', self._output_dir)
581         board0_dir = os.path.join(self._output_dir, 'current', 'board0')
582         self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done')))
583         self.assertTrue(os.path.exists(os.path.join(board0_dir, 'out-env')))
584
585     def testEnvironmentUnicode(self):
586         """Test there are no unicode errors when the env has non-ASCII chars"""
587         try:
588             varname = b'buildman_test_var'
589             os.environb[varname] = b'strange\x80chars'
590             self.assertEqual(0, self._RunControl('-o', self._output_dir))
591             board0_dir = os.path.join(self._output_dir, 'current', 'board0')
592             self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done')))
593             self.assertTrue(os.path.exists(os.path.join(board0_dir, 'out-env')))
594         finally:
595             del os.environb[varname]
596
597     def testWorkInOutput(self):
598         """Test the -w option which should write directly to the output dir"""
599         board_list = boards.Boards()
600         board_list.add_board(board.Board(*BOARDS[0]))
601         self._RunControl('-o', self._output_dir, '-w', clean_dir=False,
602                          brds=board_list)
603         self.assertTrue(
604             os.path.exists(os.path.join(self._output_dir, 'u-boot')))
605         self.assertTrue(
606             os.path.exists(os.path.join(self._output_dir, 'done')))
607         self.assertTrue(
608             os.path.exists(os.path.join(self._output_dir, 'out-env')))
609
610     def testWorkInOutputFail(self):
611         """Test the -w option failures"""
612         with self.assertRaises(SystemExit) as e:
613             self._RunControl('-o', self._output_dir, '-w', clean_dir=False)
614         self.assertIn("single board", str(e.exception))
615         self.assertFalse(
616             os.path.exists(os.path.join(self._output_dir, 'u-boot')))
617
618         board_list = boards.Boards()
619         board_list.add_board(board.Board(*BOARDS[0]))
620         with self.assertRaises(SystemExit) as e:
621             self._RunControl('-b', self._test_branch, '-o', self._output_dir,
622                              '-w', clean_dir=False, brds=board_list)
623         self.assertIn("single commit", str(e.exception))
624
625         board_list = boards.Boards()
626         board_list.add_board(board.Board(*BOARDS[0]))
627         with self.assertRaises(SystemExit) as e:
628             self._RunControl('-w', clean_dir=False)
629         self.assertIn("specify -o", str(e.exception))
630
631     def testThreadExceptions(self):
632         """Test that exceptions in threads are reported"""
633         with test_util.capture_sys_output() as (stdout, stderr):
634             self.assertEqual(102, self._RunControl('-o', self._output_dir,
635                                                    test_thread_exceptions=True))
636         self.assertIn(
637             'Thread exception (use -T0 to run without threads): test exception',
638             stdout.getvalue())
639
640     def testBlobs(self):
641         """Test handling of missing blobs"""
642         self._missing = True
643
644         board0_dir = os.path.join(self._output_dir, 'current', 'board0')
645         errfile = os.path.join(board0_dir, 'err')
646         logfile = os.path.join(board0_dir, 'log')
647
648         # We expect failure when there are missing blobs
649         result = self._RunControl('board0', '-o', self._output_dir)
650         self.assertEqual(100, result)
651         self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done')))
652         self.assertTrue(os.path.exists(errfile))
653         self.assertIn(b"Filename 'fsp.bin' not found in input path",
654                       tools.read_file(errfile))
655
656     def testBlobsAllowMissing(self):
657         """Allow missing blobs - still failure but a different exit code"""
658         self._missing = True
659         result = self._RunControl('board0', '-o', self._output_dir, '-M',
660                                   clean_dir=True)
661         self.assertEqual(101, result)
662         board0_dir = os.path.join(self._output_dir, 'current', 'board0')
663         errfile = os.path.join(board0_dir, 'err')
664         self.assertTrue(os.path.exists(errfile))
665         self.assertIn(b'Some images are invalid', tools.read_file(errfile))
666
667     def testBlobsWarning(self):
668         """Allow missing blobs and ignore warnings"""
669         self._missing = True
670         result = self._RunControl('board0', '-o', self._output_dir, '-MW')
671         self.assertEqual(0, result)
672         board0_dir = os.path.join(self._output_dir, 'current', 'board0')
673         errfile = os.path.join(board0_dir, 'err')
674         self.assertIn(b'Some images are invalid', tools.read_file(errfile))
675
676     def testBlobSettings(self):
677         """Test with no settings"""
678         self.assertEqual(False,
679                          control.get_allow_missing(False, False, 1, False))
680         self.assertEqual(True,
681                          control.get_allow_missing(True, False, 1, False))
682         self.assertEqual(False,
683                          control.get_allow_missing(True, True, 1, False))
684
685     def testBlobSettingsAlways(self):
686         """Test the 'always' policy"""
687         bsettings.SetItem('global', 'allow-missing', 'always')
688         self.assertEqual(True,
689                          control.get_allow_missing(False, False, 1, False))
690         self.assertEqual(False,
691                          control.get_allow_missing(False, True, 1, False))
692
693     def testBlobSettingsBranch(self):
694         """Test the 'branch' policy"""
695         bsettings.SetItem('global', 'allow-missing', 'branch')
696         self.assertEqual(False,
697                          control.get_allow_missing(False, False, 1, False))
698         self.assertEqual(True,
699                          control.get_allow_missing(False, False, 1, True))
700         self.assertEqual(False,
701                          control.get_allow_missing(False, True, 1, True))
702
703     def testBlobSettingsMultiple(self):
704         """Test the 'multiple' policy"""
705         bsettings.SetItem('global', 'allow-missing', 'multiple')
706         self.assertEqual(False,
707                          control.get_allow_missing(False, False, 1, False))
708         self.assertEqual(True,
709                          control.get_allow_missing(False, False, 2, False))
710         self.assertEqual(False,
711                          control.get_allow_missing(False, True, 2, False))
712
713     def testBlobSettingsBranchMultiple(self):
714         """Test the 'branch multiple' policy"""
715         bsettings.SetItem('global', 'allow-missing', 'branch multiple')
716         self.assertEqual(False,
717                          control.get_allow_missing(False, False, 1, False))
718         self.assertEqual(True,
719                          control.get_allow_missing(False, False, 1, True))
720         self.assertEqual(True,
721                          control.get_allow_missing(False, False, 2, False))
722         self.assertEqual(True,
723                          control.get_allow_missing(False, False, 2, True))
724         self.assertEqual(False,
725                          control.get_allow_missing(False, True, 2, True))
This page took 0.069364 seconds and 4 git commands to generate.