1d4144e45SSimon Glass# 2d4144e45SSimon Glass# Copyright (c) 2014 Google, Inc 3d4144e45SSimon Glass# 4d4144e45SSimon Glass# SPDX-License-Identifier: GPL-2.0+ 5d4144e45SSimon Glass# 6d4144e45SSimon Glass 7d4144e45SSimon Glassimport os 8d4144e45SSimon Glassimport shutil 9d4144e45SSimon Glassimport sys 10d4144e45SSimon Glassimport tempfile 11d4144e45SSimon Glassimport unittest 12d4144e45SSimon Glass 13823e60b6SSimon Glassimport board 148b985eebSSimon Glassimport bsettings 15d4144e45SSimon Glassimport cmdline 16d4144e45SSimon Glassimport command 17d4144e45SSimon Glassimport control 18d4144e45SSimon Glassimport gitutil 19d4144e45SSimon Glassimport terminal 20d4144e45SSimon Glassimport toolchain 21d4144e45SSimon Glass 228b985eebSSimon Glasssettings_data = ''' 238b985eebSSimon Glass# Buildman settings file 248b985eebSSimon Glass 258b985eebSSimon Glass[toolchain] 268b985eebSSimon Glass 278b985eebSSimon Glass[toolchain-alias] 288b985eebSSimon Glass 298b985eebSSimon Glass[make-flags] 308b985eebSSimon Glasssrc=/home/sjg/c/src 318b985eebSSimon Glasschroot=/home/sjg/c/chroot 328b985eebSSimon Glassvboot=USE_STDINT=1 VBOOT_DEBUG=1 MAKEFLAGS_VBOOT=DEBUG=1 CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS VBOOT_SOURCE=${src}/platform/vboot_reference 338b985eebSSimon Glasschromeos_coreboot=VBOOT=${chroot}/build/link/usr ${vboot} 348b985eebSSimon Glasschromeos_daisy=VBOOT=${chroot}/build/daisy/usr ${vboot} 358b985eebSSimon Glasschromeos_peach=VBOOT=${chroot}/build/peach_pit/usr ${vboot} 368b985eebSSimon Glass''' 378b985eebSSimon Glass 38823e60b6SSimon Glassboards = [ 39823e60b6SSimon Glass ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0', ''], 40823e60b6SSimon Glass ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''], 41823e60b6SSimon Glass ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''], 42823e60b6SSimon Glass ['Active', 'powerpc', 'mpc5xx', '', 'Tester', 'PowerPC board 2', 'board3', ''], 43823e60b6SSimon Glass ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''], 44823e60b6SSimon Glass] 45823e60b6SSimon Glass 46dfb7e932SSimon Glasscommit_shortlog = """4aca821 patman: Avoid changing the order of tags 47dfb7e932SSimon Glass39403bb patman: Use --no-pager' to stop git from forking a pager 48dfb7e932SSimon Glassdb6e6f2 patman: Remove the -a option 49dfb7e932SSimon Glassf2ccf03 patman: Correct unit tests to run correctly 50dfb7e932SSimon Glass1d097f9 patman: Fix indentation in terminal.py 51dfb7e932SSimon Glassd073747 patman: Support the 'reverse' option for 'git log 52dfb7e932SSimon Glass""" 53dfb7e932SSimon Glass 54dfb7e932SSimon Glasscommit_log = ["""commit 7f6b8315d18f683c5181d0c3694818c1b2a20dcd 55dfb7e932SSimon GlassAuthor: Masahiro Yamada <yamada.m@jp.panasonic.com> 56dfb7e932SSimon GlassDate: Fri Aug 22 19:12:41 2014 +0900 57dfb7e932SSimon Glass 58dfb7e932SSimon Glass buildman: refactor help message 59dfb7e932SSimon Glass 60dfb7e932SSimon Glass "buildman [options]" is displayed by default. 61dfb7e932SSimon Glass 62dfb7e932SSimon Glass Append the rest of help messages to parser.usage 63dfb7e932SSimon Glass instead of replacing it. 64dfb7e932SSimon Glass 65dfb7e932SSimon Glass Besides, "-b <branch>" is not mandatory since commit fea5858e. 66dfb7e932SSimon Glass Drop it from the usage. 67dfb7e932SSimon Glass 68dfb7e932SSimon Glass Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com> 69dfb7e932SSimon Glass""", 70dfb7e932SSimon Glass"""commit d0737479be6baf4db5e2cdbee123e96bc5ed0ba8 71dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 72dfb7e932SSimon GlassDate: Thu Aug 14 16:48:25 2014 -0600 73dfb7e932SSimon Glass 74dfb7e932SSimon Glass patman: Support the 'reverse' option for 'git log' 75dfb7e932SSimon Glass 76dfb7e932SSimon Glass This option is currently not supported, but needs to be, for buildman to 77dfb7e932SSimon Glass operate as expected. 78dfb7e932SSimon Glass 79dfb7e932SSimon Glass Series-changes: 7 80dfb7e932SSimon Glass - Add new patch to fix the 'reverse' bug 81dfb7e932SSimon Glass 82dfb7e932SSimon Glass 83dfb7e932SSimon Glass Change-Id: I79078f792e8b390b8a1272a8023537821d45feda 84dfb7e932SSimon Glass Reported-by: York Sun <yorksun@freescale.com> 85dfb7e932SSimon Glass Signed-off-by: Simon Glass <sjg@chromium.org> 86dfb7e932SSimon Glass 87dfb7e932SSimon Glass""", 88dfb7e932SSimon Glass"""commit 1d097f9ab487c5019152fd47bda126839f3bf9fc 89dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 90dfb7e932SSimon GlassDate: Sat Aug 9 11:44:32 2014 -0600 91dfb7e932SSimon Glass 92dfb7e932SSimon Glass patman: Fix indentation in terminal.py 93dfb7e932SSimon Glass 94dfb7e932SSimon Glass This code came from a different project with 2-character indentation. Fix 95dfb7e932SSimon Glass it for U-Boot. 96dfb7e932SSimon Glass 97dfb7e932SSimon Glass Series-changes: 6 98dfb7e932SSimon Glass - Add new patch to fix indentation in teminal.py 99dfb7e932SSimon Glass 100dfb7e932SSimon Glass Change-Id: I5a74d2ebbb3cc12a665f5c725064009ac96e8a34 101dfb7e932SSimon Glass Signed-off-by: Simon Glass <sjg@chromium.org> 102dfb7e932SSimon Glass 103dfb7e932SSimon Glass""", 104dfb7e932SSimon Glass"""commit f2ccf03869d1e152c836515a3ceb83cdfe04a105 105dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 106dfb7e932SSimon GlassDate: Sat Aug 9 11:08:24 2014 -0600 107dfb7e932SSimon Glass 108dfb7e932SSimon Glass patman: Correct unit tests to run correctly 109dfb7e932SSimon Glass 110dfb7e932SSimon Glass It seems that doctest behaves differently now, and some of the unit tests 111dfb7e932SSimon Glass do not run. Adjust the tests to work correctly. 112dfb7e932SSimon Glass 113dfb7e932SSimon Glass ./tools/patman/patman --test 114dfb7e932SSimon Glass <unittest.result.TestResult run=10 errors=0 failures=0> 115dfb7e932SSimon Glass 116dfb7e932SSimon Glass Series-changes: 6 117dfb7e932SSimon Glass - Add new patch to fix patman unit tests 118dfb7e932SSimon Glass 119dfb7e932SSimon Glass Change-Id: I3d2ca588f4933e1f9d6b1665a00e4ae58269ff3b 120dfb7e932SSimon Glass 121dfb7e932SSimon Glass""", 122dfb7e932SSimon Glass"""commit db6e6f2f9331c5a37647d6668768d4a40b8b0d1c 123dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 124dfb7e932SSimon GlassDate: Sat Aug 9 12:06:02 2014 -0600 125dfb7e932SSimon Glass 126dfb7e932SSimon Glass patman: Remove the -a option 127dfb7e932SSimon Glass 128dfb7e932SSimon Glass It seems that this is no longer needed, since checkpatch.pl will catch 129dfb7e932SSimon Glass whitespace problems in patches. Also the option is not widely used, so 130dfb7e932SSimon Glass it seems safe to just remove it. 131dfb7e932SSimon Glass 132dfb7e932SSimon Glass Series-changes: 6 133dfb7e932SSimon Glass - Add new patch to remove patman's -a option 134dfb7e932SSimon Glass 135dfb7e932SSimon Glass Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com> 136dfb7e932SSimon Glass Change-Id: I5821a1c75154e532c46513486ca40b808de7e2cc 137dfb7e932SSimon Glass 138dfb7e932SSimon Glass""", 139dfb7e932SSimon Glass"""commit 39403bb4f838153028a6f21ca30bf100f3791133 140dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 141dfb7e932SSimon GlassDate: Thu Aug 14 21:50:52 2014 -0600 142dfb7e932SSimon Glass 143dfb7e932SSimon Glass patman: Use --no-pager' to stop git from forking a pager 144dfb7e932SSimon Glass 145dfb7e932SSimon Glass""", 146dfb7e932SSimon Glass"""commit 4aca821e27e97925c039e69fd37375b09c6f129c 147dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 148dfb7e932SSimon GlassDate: Fri Aug 22 15:57:39 2014 -0600 149dfb7e932SSimon Glass 150dfb7e932SSimon Glass patman: Avoid changing the order of tags 151dfb7e932SSimon Glass 152dfb7e932SSimon Glass patman collects tags that it sees in the commit and places them nicely 153dfb7e932SSimon Glass sorted at the end of the patch. However, this is not really necessary and 154dfb7e932SSimon Glass in fact is apparently not desirable. 155dfb7e932SSimon Glass 156dfb7e932SSimon Glass Series-changes: 9 157dfb7e932SSimon Glass - Add new patch to avoid changing the order of tags 158dfb7e932SSimon Glass 159dfb7e932SSimon Glass Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com> 160dfb7e932SSimon Glass Change-Id: Ib1518588c1a189ad5c3198aae76f8654aed8d0db 161dfb7e932SSimon Glass"""] 162dfb7e932SSimon Glass 163dfb7e932SSimon GlassTEST_BRANCH = '__testbranch' 164dfb7e932SSimon Glass 165d4144e45SSimon Glassclass TestFunctional(unittest.TestCase): 166d4144e45SSimon Glass """Functional test for buildman. 167d4144e45SSimon Glass 168d4144e45SSimon Glass This aims to test from just below the invocation of buildman (parsing 169d4144e45SSimon Glass of arguments) to 'make' and 'git' invocation. It is not a true 170d4144e45SSimon Glass emd-to-end test, as it mocks git, make and the tool chain. But this 171d4144e45SSimon Glass makes it easier to detect when the builder is doing the wrong thing, 172d4144e45SSimon Glass since in many cases this test code will fail. For example, only a 173d4144e45SSimon Glass very limited subset of 'git' arguments is supported - anything 174d4144e45SSimon Glass unexpected will fail. 175d4144e45SSimon Glass """ 176d4144e45SSimon Glass def setUp(self): 177d4144e45SSimon Glass self._base_dir = tempfile.mkdtemp() 178d4144e45SSimon Glass self._git_dir = os.path.join(self._base_dir, 'src') 179d4144e45SSimon Glass self._buildman_pathname = sys.argv[0] 180d4144e45SSimon Glass self._buildman_dir = os.path.dirname(sys.argv[0]) 181d4144e45SSimon Glass command.test_result = self._HandleCommand 182dfb7e932SSimon Glass self.setupToolchains() 183dfb7e932SSimon Glass self._toolchains.Add('arm-gcc', test=False) 184dfb7e932SSimon Glass self._toolchains.Add('powerpc-gcc', test=False) 1858b985eebSSimon Glass bsettings.Setup(None) 1868b985eebSSimon Glass bsettings.AddFile(settings_data) 187823e60b6SSimon Glass self._boards = board.Boards() 188823e60b6SSimon Glass for brd in boards: 189823e60b6SSimon Glass self._boards.AddBoard(board.Board(*brd)) 190d4144e45SSimon Glass 191dfb7e932SSimon Glass # Directories where the source been cloned 192dfb7e932SSimon Glass self._clone_dirs = [] 193dfb7e932SSimon Glass self._commits = len(commit_shortlog.splitlines()) + 1 194dfb7e932SSimon Glass self._total_builds = self._commits * len(boards) 195dfb7e932SSimon Glass 196dfb7e932SSimon Glass # Number of calls to make 197dfb7e932SSimon Glass self._make_calls = 0 198dfb7e932SSimon Glass 199dfb7e932SSimon Glass # Map of [board, commit] to error messages 200dfb7e932SSimon Glass self._error = {} 201dfb7e932SSimon Glass 202*f7582ce8SSimon Glass self._test_branch = TEST_BRANCH 203*f7582ce8SSimon Glass 204dfb7e932SSimon Glass # Avoid sending any output and clear all terminal output 205dfb7e932SSimon Glass terminal.SetPrintTestMode() 206dfb7e932SSimon Glass terminal.GetPrintTestLines() 207dfb7e932SSimon Glass 208d4144e45SSimon Glass def tearDown(self): 209d4144e45SSimon Glass shutil.rmtree(self._base_dir) 210d4144e45SSimon Glass 211dfb7e932SSimon Glass def setupToolchains(self): 212dfb7e932SSimon Glass self._toolchains = toolchain.Toolchains() 213dfb7e932SSimon Glass self._toolchains.Add('gcc', test=False) 214dfb7e932SSimon Glass 215d4144e45SSimon Glass def _RunBuildman(self, *args): 216d4144e45SSimon Glass return command.RunPipe([[self._buildman_pathname] + list(args)], 217d4144e45SSimon Glass capture=True, capture_stderr=True) 218d4144e45SSimon Glass 219dfb7e932SSimon Glass def _RunControl(self, *args, **kwargs): 220d4144e45SSimon Glass sys.argv = [sys.argv[0]] + list(args) 221d4144e45SSimon Glass options, args = cmdline.ParseArgs() 222dfb7e932SSimon Glass result = control.DoBuildman(options, args, toolchains=self._toolchains, 223dfb7e932SSimon Glass make_func=self._HandleMake, boards=self._boards, 224dfb7e932SSimon Glass clean_dir=kwargs.get('clean_dir', True)) 225dfb7e932SSimon Glass self._builder = control.builder 226dfb7e932SSimon Glass return result 227d4144e45SSimon Glass 228d4144e45SSimon Glass def testFullHelp(self): 229d4144e45SSimon Glass command.test_result = None 230d4144e45SSimon Glass result = self._RunBuildman('-H') 231d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 232d4144e45SSimon Glass self.assertEqual(len(result.stdout), os.path.getsize(help_file)) 233d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 234d4144e45SSimon Glass self.assertEqual(0, result.return_code) 235d4144e45SSimon Glass 236d4144e45SSimon Glass def testHelp(self): 237d4144e45SSimon Glass command.test_result = None 238d4144e45SSimon Glass result = self._RunBuildman('-h') 239d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 240d4144e45SSimon Glass self.assertTrue(len(result.stdout) > 1000) 241d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 242d4144e45SSimon Glass self.assertEqual(0, result.return_code) 243d4144e45SSimon Glass 244d4144e45SSimon Glass def testGitSetup(self): 245d4144e45SSimon Glass """Test gitutils.Setup(), from outside the module itself""" 246d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=1) 247d4144e45SSimon Glass gitutil.Setup() 248d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, False) 249d4144e45SSimon Glass 250d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=0) 251d4144e45SSimon Glass gitutil.Setup() 252d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, True) 253d4144e45SSimon Glass 254d4144e45SSimon Glass def _HandleCommandGitLog(self, args): 255d4144e45SSimon Glass if '-n0' in args: 256d4144e45SSimon Glass return command.CommandResult(return_code=0) 257*f7582ce8SSimon Glass elif args[-1] == 'upstream/master..%s' % self._test_branch: 258dfb7e932SSimon Glass return command.CommandResult(return_code=0, stdout=commit_shortlog) 259dfb7e932SSimon Glass elif args[:3] == ['--no-color', '--no-decorate', '--reverse']: 260*f7582ce8SSimon Glass if args[-1] == self._test_branch: 261dfb7e932SSimon Glass count = int(args[3][2:]) 262dfb7e932SSimon Glass return command.CommandResult(return_code=0, 263dfb7e932SSimon Glass stdout=''.join(commit_log[:count])) 264d4144e45SSimon Glass 265d4144e45SSimon Glass # Not handled, so abort 266d4144e45SSimon Glass print 'git log', args 267d4144e45SSimon Glass sys.exit(1) 268d4144e45SSimon Glass 269dfb7e932SSimon Glass def _HandleCommandGitConfig(self, args): 270dfb7e932SSimon Glass config = args[0] 271dfb7e932SSimon Glass if config == 'sendemail.aliasesfile': 272dfb7e932SSimon Glass return command.CommandResult(return_code=0) 273dfb7e932SSimon Glass elif config.startswith('branch.badbranch'): 274dfb7e932SSimon Glass return command.CommandResult(return_code=1) 275*f7582ce8SSimon Glass elif config == 'branch.%s.remote' % self._test_branch: 276dfb7e932SSimon Glass return command.CommandResult(return_code=0, stdout='upstream\n') 277*f7582ce8SSimon Glass elif config == 'branch.%s.merge' % self._test_branch: 278dfb7e932SSimon Glass return command.CommandResult(return_code=0, 279dfb7e932SSimon Glass stdout='refs/heads/master\n') 280dfb7e932SSimon Glass 281dfb7e932SSimon Glass # Not handled, so abort 282dfb7e932SSimon Glass print 'git config', args 283dfb7e932SSimon Glass sys.exit(1) 284dfb7e932SSimon Glass 285d4144e45SSimon Glass def _HandleCommandGit(self, in_args): 286d4144e45SSimon Glass """Handle execution of a git command 287d4144e45SSimon Glass 288d4144e45SSimon Glass This uses a hacked-up parser. 289d4144e45SSimon Glass 290d4144e45SSimon Glass Args: 291d4144e45SSimon Glass in_args: Arguments after 'git' from the command line 292d4144e45SSimon Glass """ 293d4144e45SSimon Glass git_args = [] # Top-level arguments to git itself 294d4144e45SSimon Glass sub_cmd = None # Git sub-command selected 295d4144e45SSimon Glass args = [] # Arguments to the git sub-command 296d4144e45SSimon Glass for arg in in_args: 297d4144e45SSimon Glass if sub_cmd: 298d4144e45SSimon Glass args.append(arg) 299d4144e45SSimon Glass elif arg[0] == '-': 300d4144e45SSimon Glass git_args.append(arg) 301d4144e45SSimon Glass else: 302dfb7e932SSimon Glass if git_args and git_args[-1] in ['--git-dir', '--work-tree']: 303dfb7e932SSimon Glass git_args.append(arg) 304dfb7e932SSimon Glass else: 305d4144e45SSimon Glass sub_cmd = arg 306d4144e45SSimon Glass if sub_cmd == 'config': 307dfb7e932SSimon Glass return self._HandleCommandGitConfig(args) 308d4144e45SSimon Glass elif sub_cmd == 'log': 309d4144e45SSimon Glass return self._HandleCommandGitLog(args) 310dfb7e932SSimon Glass elif sub_cmd == 'clone': 311dfb7e932SSimon Glass return command.CommandResult(return_code=0) 312dfb7e932SSimon Glass elif sub_cmd == 'checkout': 313dfb7e932SSimon Glass return command.CommandResult(return_code=0) 314d4144e45SSimon Glass 315d4144e45SSimon Glass # Not handled, so abort 316d4144e45SSimon Glass print 'git', git_args, sub_cmd, args 317d4144e45SSimon Glass sys.exit(1) 318d4144e45SSimon Glass 319d4144e45SSimon Glass def _HandleCommandNm(self, args): 320d4144e45SSimon Glass return command.CommandResult(return_code=0) 321d4144e45SSimon Glass 322d4144e45SSimon Glass def _HandleCommandObjdump(self, args): 323d4144e45SSimon Glass return command.CommandResult(return_code=0) 324d4144e45SSimon Glass 325d4144e45SSimon Glass def _HandleCommandSize(self, args): 326d4144e45SSimon Glass return command.CommandResult(return_code=0) 327d4144e45SSimon Glass 328d4144e45SSimon Glass def _HandleCommand(self, **kwargs): 329d4144e45SSimon Glass """Handle a command execution. 330d4144e45SSimon Glass 331d4144e45SSimon Glass The command is in kwargs['pipe-list'], as a list of pipes, each a 332d4144e45SSimon Glass list of commands. The command should be emulated as required for 333d4144e45SSimon Glass testing purposes. 334d4144e45SSimon Glass 335d4144e45SSimon Glass Returns: 336d4144e45SSimon Glass A CommandResult object 337d4144e45SSimon Glass """ 338d4144e45SSimon Glass pipe_list = kwargs['pipe_list'] 339dfb7e932SSimon Glass wc = False 340d4144e45SSimon Glass if len(pipe_list) != 1: 341dfb7e932SSimon Glass if pipe_list[1] == ['wc', '-l']: 342dfb7e932SSimon Glass wc = True 343dfb7e932SSimon Glass else: 344d4144e45SSimon Glass print 'invalid pipe', kwargs 345d4144e45SSimon Glass sys.exit(1) 346d4144e45SSimon Glass cmd = pipe_list[0][0] 347d4144e45SSimon Glass args = pipe_list[0][1:] 348dfb7e932SSimon Glass result = None 349d4144e45SSimon Glass if cmd == 'git': 350dfb7e932SSimon Glass result = self._HandleCommandGit(args) 351d4144e45SSimon Glass elif cmd == './scripts/show-gnu-make': 352d4144e45SSimon Glass return command.CommandResult(return_code=0, stdout='make') 353dfb7e932SSimon Glass elif cmd.endswith('nm'): 354d4144e45SSimon Glass return self._HandleCommandNm(args) 355dfb7e932SSimon Glass elif cmd.endswith('objdump'): 356d4144e45SSimon Glass return self._HandleCommandObjdump(args) 357dfb7e932SSimon Glass elif cmd.endswith( 'size'): 358d4144e45SSimon Glass return self._HandleCommandSize(args) 359d4144e45SSimon Glass 360dfb7e932SSimon Glass if not result: 361d4144e45SSimon Glass # Not handled, so abort 362d4144e45SSimon Glass print 'unknown command', kwargs 363d4144e45SSimon Glass sys.exit(1) 364dfb7e932SSimon Glass 365dfb7e932SSimon Glass if wc: 366dfb7e932SSimon Glass result.stdout = len(result.stdout.splitlines()) 367dfb7e932SSimon Glass return result 368d4144e45SSimon Glass 369d4144e45SSimon Glass def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): 370d4144e45SSimon Glass """Handle execution of 'make' 371d4144e45SSimon Glass 372d4144e45SSimon Glass Args: 373d4144e45SSimon Glass commit: Commit object that is being built 374d4144e45SSimon Glass brd: Board object that is being built 375d4144e45SSimon Glass stage: Stage that we are at (mrproper, config, build) 376d4144e45SSimon Glass cwd: Directory where make should be run 377d4144e45SSimon Glass args: Arguments to pass to make 378d4144e45SSimon Glass kwargs: Arguments to pass to command.RunPipe() 379d4144e45SSimon Glass """ 380dfb7e932SSimon Glass self._make_calls += 1 381d4144e45SSimon Glass if stage == 'mrproper': 382d4144e45SSimon Glass return command.CommandResult(return_code=0) 383d4144e45SSimon Glass elif stage == 'config': 384d4144e45SSimon Glass return command.CommandResult(return_code=0, 385d4144e45SSimon Glass combined='Test configuration complete') 386d4144e45SSimon Glass elif stage == 'build': 387dfb7e932SSimon Glass stderr = '' 388dfb7e932SSimon Glass if type(commit) is not str: 389dfb7e932SSimon Glass stderr = self._error.get((brd.target, commit.sequence)) 390dfb7e932SSimon Glass if stderr: 391dfb7e932SSimon Glass return command.CommandResult(return_code=1, stderr=stderr) 392d4144e45SSimon Glass return command.CommandResult(return_code=0) 393d4144e45SSimon Glass 394d4144e45SSimon Glass # Not handled, so abort 395d4144e45SSimon Glass print 'make', stage 396d4144e45SSimon Glass sys.exit(1) 397d4144e45SSimon Glass 398dfb7e932SSimon Glass # Example function to print output lines 399dfb7e932SSimon Glass def print_lines(self, lines): 400dfb7e932SSimon Glass print len(lines) 401dfb7e932SSimon Glass for line in lines: 402dfb7e932SSimon Glass print line 403dfb7e932SSimon Glass #self.print_lines(terminal.GetPrintTestLines()) 404dfb7e932SSimon Glass 405823e60b6SSimon Glass def testNoBoards(self): 406823e60b6SSimon Glass """Test that buildman aborts when there are no boards""" 407823e60b6SSimon Glass self._boards = board.Boards() 408823e60b6SSimon Glass with self.assertRaises(SystemExit): 409823e60b6SSimon Glass self._RunControl() 410823e60b6SSimon Glass 411d4144e45SSimon Glass def testCurrentSource(self): 412d4144e45SSimon Glass """Very simple test to invoke buildman on the current source""" 413dfb7e932SSimon Glass self.setupToolchains(); 414d4144e45SSimon Glass self._RunControl() 415d4144e45SSimon Glass lines = terminal.GetPrintTestLines() 416dfb7e932SSimon Glass self.assertIn('Building current source for %d boards' % len(boards), 417dfb7e932SSimon Glass lines[0].text) 418dfb7e932SSimon Glass 419dfb7e932SSimon Glass def testBadBranch(self): 420dfb7e932SSimon Glass """Test that we can detect an invalid branch""" 421dfb7e932SSimon Glass with self.assertRaises(ValueError): 422dfb7e932SSimon Glass self._RunControl('-b', 'badbranch') 423dfb7e932SSimon Glass 424dfb7e932SSimon Glass def testBadToolchain(self): 425dfb7e932SSimon Glass """Test that missing toolchains are detected""" 426dfb7e932SSimon Glass self.setupToolchains(); 427dfb7e932SSimon Glass ret_code = self._RunControl('-b', TEST_BRANCH) 428dfb7e932SSimon Glass lines = terminal.GetPrintTestLines() 429dfb7e932SSimon Glass 430dfb7e932SSimon Glass # Buildman always builds the upstream commit as well 431dfb7e932SSimon Glass self.assertIn('Building %d commits for %d boards' % 432dfb7e932SSimon Glass (self._commits, len(boards)), lines[0].text) 433dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 434dfb7e932SSimon Glass 435dfb7e932SSimon Glass # Only sandbox should succeed, the others don't have toolchains 436dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 437dfb7e932SSimon Glass self._total_builds - self._commits) 438dfb7e932SSimon Glass self.assertEqual(ret_code, 128) 439dfb7e932SSimon Glass 440dfb7e932SSimon Glass for commit in range(self._commits): 441dfb7e932SSimon Glass for board in self._boards.GetList(): 442dfb7e932SSimon Glass if board.arch != 'sandbox': 443dfb7e932SSimon Glass errfile = self._builder.GetErrFile(commit, board.target) 444dfb7e932SSimon Glass fd = open(errfile) 445dfb7e932SSimon Glass self.assertEqual(fd.readlines(), 446dfb7e932SSimon Glass ['No tool chain for %s\n' % board.arch]) 447dfb7e932SSimon Glass fd.close() 448dfb7e932SSimon Glass 449dfb7e932SSimon Glass def testBranch(self): 450dfb7e932SSimon Glass """Test building a branch with all toolchains present""" 451dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 452dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 453dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 454dfb7e932SSimon Glass 455dfb7e932SSimon Glass def testCount(self): 456dfb7e932SSimon Glass """Test building a specific number of commitst""" 457dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-c2') 458dfb7e932SSimon Glass self.assertEqual(self._builder.count, 2 * len(boards)) 459dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 460dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 461dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (2 + 2)) 462dfb7e932SSimon Glass 463dfb7e932SSimon Glass def testIncremental(self): 464dfb7e932SSimon Glass """Test building a branch twice - the second time should do nothing""" 465dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 466dfb7e932SSimon Glass 467dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 468dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (self._commits + 2)) 469dfb7e932SSimon Glass self._make_calls = 0 470dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, clean_dir=False) 471dfb7e932SSimon Glass self.assertEqual(self._make_calls, 0) 472dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 473dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 474dfb7e932SSimon Glass 475dfb7e932SSimon Glass def testForceBuild(self): 476dfb7e932SSimon Glass """The -f flag should force a rebuild""" 477dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 478dfb7e932SSimon Glass self._make_calls = 0 479dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-f', clean_dir=False) 480dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 481dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (self._commits + 2)) 482dfb7e932SSimon Glass 483dfb7e932SSimon Glass def testForceReconfigure(self): 484dfb7e932SSimon Glass """The -f flag should force a rebuild""" 485dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-C') 486dfb7e932SSimon Glass # Each commit has a mrproper, config and make 487dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * self._commits * 3) 488dfb7e932SSimon Glass 489dfb7e932SSimon Glass def testErrors(self): 490dfb7e932SSimon Glass """Test handling of build errors""" 491dfb7e932SSimon Glass self._error['board2', 1] = 'fred\n' 492dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 493dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 494dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 1) 495dfb7e932SSimon Glass 496dfb7e932SSimon Glass # Remove the error. This should have no effect since the commit will 497dfb7e932SSimon Glass # not be rebuilt 498dfb7e932SSimon Glass del self._error['board2', 1] 499dfb7e932SSimon Glass self._make_calls = 0 500dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, clean_dir=False) 501dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 502dfb7e932SSimon Glass self.assertEqual(self._make_calls, 0) 503dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 1) 504dfb7e932SSimon Glass 505dfb7e932SSimon Glass # Now use the -F flag to force rebuild of the bad commit 506dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-F', clean_dir=False) 507dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 508dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 509dfb7e932SSimon Glass self.assertEqual(self._make_calls, 3) 510*f7582ce8SSimon Glass 511*f7582ce8SSimon Glass def testBranchWithSlash(self): 512*f7582ce8SSimon Glass """Test building a branch with a '/' in the name""" 513*f7582ce8SSimon Glass self._test_branch = '/__dev/__testbranch' 514*f7582ce8SSimon Glass self._RunControl('-b', self._test_branch, clean_dir=False) 515*f7582ce8SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 516*f7582ce8SSimon Glass self.assertEqual(self._builder.fail, 0) 517