Blame view

tools/buildman/func_test.py 18.5 KB
d4144e45b   Simon Glass   buildman: Add a f...
1
2
3
4
5
6
7
8
9
10
11
  #
  # Copyright (c) 2014 Google, Inc
  #
  # SPDX-License-Identifier:      GPL-2.0+
  #
  
  import os
  import shutil
  import sys
  import tempfile
  import unittest
823e60b62   Simon Glass   buildman: Allow t...
12
  import board
8b985eebd   Simon Glass   buildman: Avoid l...
13
  import bsettings
d4144e45b   Simon Glass   buildman: Add a f...
14
15
16
17
18
19
  import cmdline
  import command
  import control
  import gitutil
  import terminal
  import toolchain
8b985eebd   Simon Glass   buildman: Avoid l...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  settings_data = '''
  # Buildman settings file
  
  [toolchain]
  
  [toolchain-alias]
  
  [make-flags]
  src=/home/sjg/c/src
  chroot=/home/sjg/c/chroot
  vboot=USE_STDINT=1 VBOOT_DEBUG=1 MAKEFLAGS_VBOOT=DEBUG=1 CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS VBOOT_SOURCE=${src}/platform/vboot_reference
  chromeos_coreboot=VBOOT=${chroot}/build/link/usr ${vboot}
  chromeos_daisy=VBOOT=${chroot}/build/daisy/usr ${vboot}
  chromeos_peach=VBOOT=${chroot}/build/peach_pit/usr ${vboot}
  '''
823e60b62   Simon Glass   buildman: Allow t...
35
36
37
38
  boards = [
      ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0',  ''],
      ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''],
      ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''],
823e60b62   Simon Glass   buildman: Allow t...
39
40
      ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
  ]
dfb7e9323   Simon Glass   buildman: Add add...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  commit_shortlog = """4aca821 patman: Avoid changing the order of tags
  39403bb patman: Use --no-pager' to stop git from forking a pager
  db6e6f2 patman: Remove the -a option
  f2ccf03 patman: Correct unit tests to run correctly
  1d097f9 patman: Fix indentation in terminal.py
  d073747 patman: Support the 'reverse' option for 'git log
  """
  
  commit_log = ["""commit 7f6b8315d18f683c5181d0c3694818c1b2a20dcd
  Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
  Date:   Fri Aug 22 19:12:41 2014 +0900
  
      buildman: refactor help message
  
      "buildman [options]" is displayed by default.
  
      Append the rest of help messages to parser.usage
      instead of replacing it.
  
      Besides, "-b <branch>" is not mandatory since commit fea5858e.
      Drop it from the usage.
  
      Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
  """,
  """commit d0737479be6baf4db5e2cdbee123e96bc5ed0ba8
  Author: Simon Glass <sjg@chromium.org>
  Date:   Thu Aug 14 16:48:25 2014 -0600
  
      patman: Support the 'reverse' option for 'git log'
  
      This option is currently not supported, but needs to be, for buildman to
      operate as expected.
  
      Series-changes: 7
      - Add new patch to fix the 'reverse' bug
950a23133   Simon Glass   buildman: Ignore ...
76
      Series-version: 8
dfb7e9323   Simon Glass   buildman: Add add...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  
      Change-Id: I79078f792e8b390b8a1272a8023537821d45feda
      Reported-by: York Sun <yorksun@freescale.com>
      Signed-off-by: Simon Glass <sjg@chromium.org>
  
  """,
  """commit 1d097f9ab487c5019152fd47bda126839f3bf9fc
  Author: Simon Glass <sjg@chromium.org>
  Date:   Sat Aug 9 11:44:32 2014 -0600
  
      patman: Fix indentation in terminal.py
  
      This code came from a different project with 2-character indentation. Fix
      it for U-Boot.
  
      Series-changes: 6
      - Add new patch to fix indentation in teminal.py
  
      Change-Id: I5a74d2ebbb3cc12a665f5c725064009ac96e8a34
      Signed-off-by: Simon Glass <sjg@chromium.org>
  
  """,
  """commit f2ccf03869d1e152c836515a3ceb83cdfe04a105
  Author: Simon Glass <sjg@chromium.org>
  Date:   Sat Aug 9 11:08:24 2014 -0600
  
      patman: Correct unit tests to run correctly
  
      It seems that doctest behaves differently now, and some of the unit tests
      do not run. Adjust the tests to work correctly.
  
       ./tools/patman/patman --test
      <unittest.result.TestResult run=10 errors=0 failures=0>
  
      Series-changes: 6
      - Add new patch to fix patman unit tests
  
      Change-Id: I3d2ca588f4933e1f9d6b1665a00e4ae58269ff3b
  
  """,
  """commit db6e6f2f9331c5a37647d6668768d4a40b8b0d1c
  Author: Simon Glass <sjg@chromium.org>
  Date:   Sat Aug 9 12:06:02 2014 -0600
  
      patman: Remove the -a option
  
      It seems that this is no longer needed, since checkpatch.pl will catch
      whitespace problems in patches. Also the option is not widely used, so
      it seems safe to just remove it.
  
      Series-changes: 6
      - Add new patch to remove patman's -a option
  
      Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
      Change-Id: I5821a1c75154e532c46513486ca40b808de7e2cc
  
  """,
  """commit 39403bb4f838153028a6f21ca30bf100f3791133
  Author: Simon Glass <sjg@chromium.org>
  Date:   Thu Aug 14 21:50:52 2014 -0600
  
      patman: Use --no-pager' to stop git from forking a pager
  
  """,
  """commit 4aca821e27e97925c039e69fd37375b09c6f129c
  Author: Simon Glass <sjg@chromium.org>
  Date:   Fri Aug 22 15:57:39 2014 -0600
  
      patman: Avoid changing the order of tags
  
      patman collects tags that it sees in the commit and places them nicely
      sorted at the end of the patch. However, this is not really necessary and
      in fact is apparently not desirable.
  
      Series-changes: 9
      - Add new patch to avoid changing the order of tags
950a23133   Simon Glass   buildman: Ignore ...
153
      Series-version: 9
dfb7e9323   Simon Glass   buildman: Add add...
154
155
156
157
158
      Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
      Change-Id: Ib1518588c1a189ad5c3198aae76f8654aed8d0db
  """]
  
  TEST_BRANCH = '__testbranch'
d4144e45b   Simon Glass   buildman: Add a f...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  class TestFunctional(unittest.TestCase):
      """Functional test for buildman.
  
      This aims to test from just below the invocation of buildman (parsing
      of arguments) to 'make' and 'git' invocation. It is not a true
      emd-to-end test, as it mocks git, make and the tool chain. But this
      makes it easier to detect when the builder is doing the wrong thing,
      since in many cases this test code will fail. For example, only a
      very limited subset of 'git' arguments is supported - anything
      unexpected will fail.
      """
      def setUp(self):
          self._base_dir = tempfile.mkdtemp()
          self._git_dir = os.path.join(self._base_dir, 'src')
          self._buildman_pathname = sys.argv[0]
bd6f5d98d   Simon Glass   buildman: Fix the...
174
          self._buildman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
d4144e45b   Simon Glass   buildman: Add a f...
175
          command.test_result = self._HandleCommand
dfb7e9323   Simon Glass   buildman: Add add...
176
177
178
          self.setupToolchains()
          self._toolchains.Add('arm-gcc', test=False)
          self._toolchains.Add('powerpc-gcc', test=False)
8b985eebd   Simon Glass   buildman: Avoid l...
179
180
          bsettings.Setup(None)
          bsettings.AddFile(settings_data)
823e60b62   Simon Glass   buildman: Allow t...
181
182
183
          self._boards = board.Boards()
          for brd in boards:
              self._boards.AddBoard(board.Board(*brd))
d4144e45b   Simon Glass   buildman: Add a f...
184

dfb7e9323   Simon Glass   buildman: Add add...
185
186
187
188
189
190
191
192
193
194
          # Directories where the source been cloned
          self._clone_dirs = []
          self._commits = len(commit_shortlog.splitlines()) + 1
          self._total_builds = self._commits * len(boards)
  
          # Number of calls to make
          self._make_calls = 0
  
          # Map of [board, commit] to error messages
          self._error = {}
f7582ce84   Simon Glass   buildman: Permit ...
195
          self._test_branch = TEST_BRANCH
dfb7e9323   Simon Glass   buildman: Add add...
196
197
198
          # Avoid sending any output and clear all terminal output
          terminal.SetPrintTestMode()
          terminal.GetPrintTestLines()
d4144e45b   Simon Glass   buildman: Add a f...
199
200
      def tearDown(self):
          shutil.rmtree(self._base_dir)
dfb7e9323   Simon Glass   buildman: Add add...
201
202
203
      def setupToolchains(self):
          self._toolchains = toolchain.Toolchains()
          self._toolchains.Add('gcc', test=False)
d4144e45b   Simon Glass   buildman: Add a f...
204
205
206
      def _RunBuildman(self, *args):
          return command.RunPipe([[self._buildman_pathname] + list(args)],
                  capture=True, capture_stderr=True)
dfb7e9323   Simon Glass   buildman: Add add...
207
      def _RunControl(self, *args, **kwargs):
d4144e45b   Simon Glass   buildman: Add a f...
208
209
          sys.argv = [sys.argv[0]] + list(args)
          options, args = cmdline.ParseArgs()
dfb7e9323   Simon Glass   buildman: Add add...
210
211
212
213
214
          result = control.DoBuildman(options, args, toolchains=self._toolchains,
                  make_func=self._HandleMake, boards=self._boards,
                  clean_dir=kwargs.get('clean_dir', True))
          self._builder = control.builder
          return result
d4144e45b   Simon Glass   buildman: Add a f...
215
216
217
218
219
  
      def testFullHelp(self):
          command.test_result = None
          result = self._RunBuildman('-H')
          help_file = os.path.join(self._buildman_dir, 'README')
3759df0c0   Tom Rini   tools: Update pyt...
220
221
222
223
224
225
226
          # Remove possible extraneous strings
          extra = '::::::::::::::
  ' + help_file + '
  ::::::::::::::
  '
          gothelp = result.stdout.replace(extra, '')
          self.assertEqual(len(gothelp), os.path.getsize(help_file))
d4144e45b   Simon Glass   buildman: Add a f...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
          self.assertEqual(0, len(result.stderr))
          self.assertEqual(0, result.return_code)
  
      def testHelp(self):
          command.test_result = None
          result = self._RunBuildman('-h')
          help_file = os.path.join(self._buildman_dir, 'README')
          self.assertTrue(len(result.stdout) > 1000)
          self.assertEqual(0, len(result.stderr))
          self.assertEqual(0, result.return_code)
  
      def testGitSetup(self):
          """Test gitutils.Setup(), from outside the module itself"""
          command.test_result = command.CommandResult(return_code=1)
          gitutil.Setup()
          self.assertEqual(gitutil.use_no_decorate, False)
  
          command.test_result = command.CommandResult(return_code=0)
          gitutil.Setup()
          self.assertEqual(gitutil.use_no_decorate, True)
  
      def _HandleCommandGitLog(self, args):
d4c8572b7   Simon Glass   buildman: Allow b...
249
250
          if args[-1] == '--':
              args = args[:-1]
d4144e45b   Simon Glass   buildman: Add a f...
251
252
          if '-n0' in args:
              return command.CommandResult(return_code=0)
f7582ce84   Simon Glass   buildman: Permit ...
253
          elif args[-1] == 'upstream/master..%s' % self._test_branch:
dfb7e9323   Simon Glass   buildman: Add add...
254
255
              return command.CommandResult(return_code=0, stdout=commit_shortlog)
          elif args[:3] == ['--no-color', '--no-decorate', '--reverse']:
f7582ce84   Simon Glass   buildman: Permit ...
256
              if args[-1] == self._test_branch:
dfb7e9323   Simon Glass   buildman: Add add...
257
258
259
                  count = int(args[3][2:])
                  return command.CommandResult(return_code=0,
                                              stdout=''.join(commit_log[:count]))
d4144e45b   Simon Glass   buildman: Add a f...
260
261
262
263
  
          # Not handled, so abort
          print 'git log', args
          sys.exit(1)
dfb7e9323   Simon Glass   buildman: Add add...
264
265
266
267
268
269
      def _HandleCommandGitConfig(self, args):
          config = args[0]
          if config == 'sendemail.aliasesfile':
              return command.CommandResult(return_code=0)
          elif config.startswith('branch.badbranch'):
              return command.CommandResult(return_code=1)
f7582ce84   Simon Glass   buildman: Permit ...
270
          elif config == 'branch.%s.remote' % self._test_branch:
dfb7e9323   Simon Glass   buildman: Add add...
271
272
              return command.CommandResult(return_code=0, stdout='upstream
  ')
f7582ce84   Simon Glass   buildman: Permit ...
273
          elif config == 'branch.%s.merge' % self._test_branch:
dfb7e9323   Simon Glass   buildman: Add add...
274
275
276
277
278
279
280
              return command.CommandResult(return_code=0,
                                           stdout='refs/heads/master
  ')
  
          # Not handled, so abort
          print 'git config', args
          sys.exit(1)
d4144e45b   Simon Glass   buildman: Add a f...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
      def _HandleCommandGit(self, in_args):
          """Handle execution of a git command
  
          This uses a hacked-up parser.
  
          Args:
              in_args: Arguments after 'git' from the command line
          """
          git_args = []           # Top-level arguments to git itself
          sub_cmd = None          # Git sub-command selected
          args = []               # Arguments to the git sub-command
          for arg in in_args:
              if sub_cmd:
                  args.append(arg)
              elif arg[0] == '-':
                  git_args.append(arg)
              else:
dfb7e9323   Simon Glass   buildman: Add add...
298
299
300
301
                  if git_args and git_args[-1] in ['--git-dir', '--work-tree']:
                      git_args.append(arg)
                  else:
                      sub_cmd = arg
d4144e45b   Simon Glass   buildman: Add a f...
302
          if sub_cmd == 'config':
dfb7e9323   Simon Glass   buildman: Add add...
303
              return self._HandleCommandGitConfig(args)
d4144e45b   Simon Glass   buildman: Add a f...
304
305
          elif sub_cmd == 'log':
              return self._HandleCommandGitLog(args)
dfb7e9323   Simon Glass   buildman: Add add...
306
307
308
309
          elif sub_cmd == 'clone':
              return command.CommandResult(return_code=0)
          elif sub_cmd == 'checkout':
              return command.CommandResult(return_code=0)
d4144e45b   Simon Glass   buildman: Add a f...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  
          # Not handled, so abort
          print 'git', git_args, sub_cmd, args
          sys.exit(1)
  
      def _HandleCommandNm(self, args):
          return command.CommandResult(return_code=0)
  
      def _HandleCommandObjdump(self, args):
          return command.CommandResult(return_code=0)
  
      def _HandleCommandSize(self, args):
          return command.CommandResult(return_code=0)
  
      def _HandleCommand(self, **kwargs):
          """Handle a command execution.
  
          The command is in kwargs['pipe-list'], as a list of pipes, each a
          list of commands. The command should be emulated as required for
          testing purposes.
  
          Returns:
              A CommandResult object
          """
          pipe_list = kwargs['pipe_list']
dfb7e9323   Simon Glass   buildman: Add add...
335
          wc = False
d4144e45b   Simon Glass   buildman: Add a f...
336
          if len(pipe_list) != 1:
dfb7e9323   Simon Glass   buildman: Add add...
337
338
339
340
341
              if pipe_list[1] == ['wc', '-l']:
                  wc = True
              else:
                  print 'invalid pipe', kwargs
                  sys.exit(1)
d4144e45b   Simon Glass   buildman: Add a f...
342
343
          cmd = pipe_list[0][0]
          args = pipe_list[0][1:]
dfb7e9323   Simon Glass   buildman: Add add...
344
          result = None
d4144e45b   Simon Glass   buildman: Add a f...
345
          if cmd == 'git':
dfb7e9323   Simon Glass   buildman: Add add...
346
              result = self._HandleCommandGit(args)
d4144e45b   Simon Glass   buildman: Add a f...
347
348
          elif cmd == './scripts/show-gnu-make':
              return command.CommandResult(return_code=0, stdout='make')
dfb7e9323   Simon Glass   buildman: Add add...
349
          elif cmd.endswith('nm'):
d4144e45b   Simon Glass   buildman: Add a f...
350
              return self._HandleCommandNm(args)
dfb7e9323   Simon Glass   buildman: Add add...
351
          elif cmd.endswith('objdump'):
d4144e45b   Simon Glass   buildman: Add a f...
352
              return self._HandleCommandObjdump(args)
dfb7e9323   Simon Glass   buildman: Add add...
353
          elif cmd.endswith( 'size'):
d4144e45b   Simon Glass   buildman: Add a f...
354
              return self._HandleCommandSize(args)
dfb7e9323   Simon Glass   buildman: Add add...
355
356
357
358
359
360
361
362
          if not result:
              # Not handled, so abort
              print 'unknown command', kwargs
              sys.exit(1)
  
          if wc:
              result.stdout = len(result.stdout.splitlines())
          return result
d4144e45b   Simon Glass   buildman: Add a f...
363
364
365
366
367
368
369
370
371
372
373
374
  
      def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs):
          """Handle execution of 'make'
  
          Args:
              commit: Commit object that is being built
              brd: Board object that is being built
              stage: Stage that we are at (mrproper, config, build)
              cwd: Directory where make should be run
              args: Arguments to pass to make
              kwargs: Arguments to pass to command.RunPipe()
          """
dfb7e9323   Simon Glass   buildman: Add add...
375
          self._make_calls += 1
d4144e45b   Simon Glass   buildman: Add a f...
376
377
378
379
380
381
          if stage == 'mrproper':
              return command.CommandResult(return_code=0)
          elif stage == 'config':
              return command.CommandResult(return_code=0,
                      combined='Test configuration complete')
          elif stage == 'build':
dfb7e9323   Simon Glass   buildman: Add add...
382
383
384
385
386
              stderr = ''
              if type(commit) is not str:
                  stderr = self._error.get((brd.target, commit.sequence))
              if stderr:
                  return command.CommandResult(return_code=1, stderr=stderr)
d4144e45b   Simon Glass   buildman: Add a f...
387
388
389
390
391
              return command.CommandResult(return_code=0)
  
          # Not handled, so abort
          print 'make', stage
          sys.exit(1)
dfb7e9323   Simon Glass   buildman: Add add...
392
393
394
395
396
397
      # Example function to print output lines
      def print_lines(self, lines):
          print len(lines)
          for line in lines:
              print line
          #self.print_lines(terminal.GetPrintTestLines())
823e60b62   Simon Glass   buildman: Allow t...
398
399
400
401
402
      def testNoBoards(self):
          """Test that buildman aborts when there are no boards"""
          self._boards = board.Boards()
          with self.assertRaises(SystemExit):
              self._RunControl()
d4144e45b   Simon Glass   buildman: Add a f...
403
404
      def testCurrentSource(self):
          """Very simple test to invoke buildman on the current source"""
dfb7e9323   Simon Glass   buildman: Add add...
405
          self.setupToolchains();
d4144e45b   Simon Glass   buildman: Add a f...
406
407
          self._RunControl()
          lines = terminal.GetPrintTestLines()
dfb7e9323   Simon Glass   buildman: Add add...
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
          self.assertIn('Building current source for %d boards' % len(boards),
                        lines[0].text)
  
      def testBadBranch(self):
          """Test that we can detect an invalid branch"""
          with self.assertRaises(ValueError):
              self._RunControl('-b', 'badbranch')
  
      def testBadToolchain(self):
          """Test that missing toolchains are detected"""
          self.setupToolchains();
          ret_code = self._RunControl('-b', TEST_BRANCH)
          lines = terminal.GetPrintTestLines()
  
          # Buildman always builds the upstream commit as well
          self.assertIn('Building %d commits for %d boards' %
                  (self._commits, len(boards)), lines[0].text)
          self.assertEqual(self._builder.count, self._total_builds)
  
          # Only sandbox should succeed, the others don't have toolchains
          self.assertEqual(self._builder.fail,
                           self._total_builds - self._commits)
          self.assertEqual(ret_code, 128)
  
          for commit in range(self._commits):
              for board in self._boards.GetList():
                  if board.arch != 'sandbox':
                    errfile = self._builder.GetErrFile(commit, board.target)
                    fd = open(errfile)
                    self.assertEqual(fd.readlines(),
                            ['No tool chain for %s
  ' % board.arch])
                    fd.close()
  
      def testBranch(self):
          """Test building a branch with all toolchains present"""
          self._RunControl('-b', TEST_BRANCH)
          self.assertEqual(self._builder.count, self._total_builds)
          self.assertEqual(self._builder.fail, 0)
  
      def testCount(self):
          """Test building a specific number of commitst"""
          self._RunControl('-b', TEST_BRANCH, '-c2')
          self.assertEqual(self._builder.count, 2 * len(boards))
          self.assertEqual(self._builder.fail, 0)
          # Each board has a mrproper, config, and then one make per commit
          self.assertEqual(self._make_calls, len(boards) * (2 + 2))
  
      def testIncremental(self):
          """Test building a branch twice - the second time should do nothing"""
          self._RunControl('-b', TEST_BRANCH)
  
          # Each board has a mrproper, config, and then one make per commit
          self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
          self._make_calls = 0
          self._RunControl('-b', TEST_BRANCH, clean_dir=False)
          self.assertEqual(self._make_calls, 0)
          self.assertEqual(self._builder.count, self._total_builds)
          self.assertEqual(self._builder.fail, 0)
  
      def testForceBuild(self):
          """The -f flag should force a rebuild"""
          self._RunControl('-b', TEST_BRANCH)
          self._make_calls = 0
          self._RunControl('-b', TEST_BRANCH, '-f', clean_dir=False)
          # Each board has a mrproper, config, and then one make per commit
          self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
  
      def testForceReconfigure(self):
          """The -f flag should force a rebuild"""
          self._RunControl('-b', TEST_BRANCH, '-C')
          # Each commit has a mrproper, config and make
          self.assertEqual(self._make_calls, len(boards) * self._commits * 3)
  
      def testErrors(self):
          """Test handling of build errors"""
          self._error['board2', 1] = 'fred
  '
          self._RunControl('-b', TEST_BRANCH)
          self.assertEqual(self._builder.count, self._total_builds)
          self.assertEqual(self._builder.fail, 1)
  
          # Remove the error. This should have no effect since the commit will
          # not be rebuilt
          del self._error['board2', 1]
          self._make_calls = 0
          self._RunControl('-b', TEST_BRANCH, clean_dir=False)
          self.assertEqual(self._builder.count, self._total_builds)
          self.assertEqual(self._make_calls, 0)
          self.assertEqual(self._builder.fail, 1)
  
          # Now use the -F flag to force rebuild of the bad commit
          self._RunControl('-b', TEST_BRANCH, '-F', clean_dir=False)
          self.assertEqual(self._builder.count, self._total_builds)
          self.assertEqual(self._builder.fail, 0)
          self.assertEqual(self._make_calls, 3)
f7582ce84   Simon Glass   buildman: Permit ...
504
505
506
507
508
509
510
  
      def testBranchWithSlash(self):
          """Test building a branch with a '/' in the name"""
          self._test_branch = '/__dev/__testbranch'
          self._RunControl('-b', self._test_branch, clean_dir=False)
          self.assertEqual(self._builder.count, self._total_builds)
          self.assertEqual(self._builder.fail, 0)