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