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 82950a2313SSimon 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 160950a2313SSimon Glass Series-version: 9 161950a2313SSimon 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): 258*d4c8572bSSimon Glass if args[-1] == '--': 259*d4c8572bSSimon Glass args = args[:-1] 260d4144e45SSimon Glass if '-n0' in args: 261d4144e45SSimon Glass return command.CommandResult(return_code=0) 262f7582ce8SSimon Glass elif args[-1] == 'upstream/master..%s' % self._test_branch: 263dfb7e932SSimon Glass return command.CommandResult(return_code=0, stdout=commit_shortlog) 264dfb7e932SSimon Glass elif args[:3] == ['--no-color', '--no-decorate', '--reverse']: 265f7582ce8SSimon Glass if args[-1] == self._test_branch: 266dfb7e932SSimon Glass count = int(args[3][2:]) 267dfb7e932SSimon Glass return command.CommandResult(return_code=0, 268dfb7e932SSimon Glass stdout=''.join(commit_log[:count])) 269d4144e45SSimon Glass 270d4144e45SSimon Glass # Not handled, so abort 271d4144e45SSimon Glass print 'git log', args 272d4144e45SSimon Glass sys.exit(1) 273d4144e45SSimon Glass 274dfb7e932SSimon Glass def _HandleCommandGitConfig(self, args): 275dfb7e932SSimon Glass config = args[0] 276dfb7e932SSimon Glass if config == 'sendemail.aliasesfile': 277dfb7e932SSimon Glass return command.CommandResult(return_code=0) 278dfb7e932SSimon Glass elif config.startswith('branch.badbranch'): 279dfb7e932SSimon Glass return command.CommandResult(return_code=1) 280f7582ce8SSimon Glass elif config == 'branch.%s.remote' % self._test_branch: 281dfb7e932SSimon Glass return command.CommandResult(return_code=0, stdout='upstream\n') 282f7582ce8SSimon Glass elif config == 'branch.%s.merge' % self._test_branch: 283dfb7e932SSimon Glass return command.CommandResult(return_code=0, 284dfb7e932SSimon Glass stdout='refs/heads/master\n') 285dfb7e932SSimon Glass 286dfb7e932SSimon Glass # Not handled, so abort 287dfb7e932SSimon Glass print 'git config', args 288dfb7e932SSimon Glass sys.exit(1) 289dfb7e932SSimon Glass 290d4144e45SSimon Glass def _HandleCommandGit(self, in_args): 291d4144e45SSimon Glass """Handle execution of a git command 292d4144e45SSimon Glass 293d4144e45SSimon Glass This uses a hacked-up parser. 294d4144e45SSimon Glass 295d4144e45SSimon Glass Args: 296d4144e45SSimon Glass in_args: Arguments after 'git' from the command line 297d4144e45SSimon Glass """ 298d4144e45SSimon Glass git_args = [] # Top-level arguments to git itself 299d4144e45SSimon Glass sub_cmd = None # Git sub-command selected 300d4144e45SSimon Glass args = [] # Arguments to the git sub-command 301d4144e45SSimon Glass for arg in in_args: 302d4144e45SSimon Glass if sub_cmd: 303d4144e45SSimon Glass args.append(arg) 304d4144e45SSimon Glass elif arg[0] == '-': 305d4144e45SSimon Glass git_args.append(arg) 306d4144e45SSimon Glass else: 307dfb7e932SSimon Glass if git_args and git_args[-1] in ['--git-dir', '--work-tree']: 308dfb7e932SSimon Glass git_args.append(arg) 309dfb7e932SSimon Glass else: 310d4144e45SSimon Glass sub_cmd = arg 311d4144e45SSimon Glass if sub_cmd == 'config': 312dfb7e932SSimon Glass return self._HandleCommandGitConfig(args) 313d4144e45SSimon Glass elif sub_cmd == 'log': 314d4144e45SSimon Glass return self._HandleCommandGitLog(args) 315dfb7e932SSimon Glass elif sub_cmd == 'clone': 316dfb7e932SSimon Glass return command.CommandResult(return_code=0) 317dfb7e932SSimon Glass elif sub_cmd == 'checkout': 318dfb7e932SSimon Glass return command.CommandResult(return_code=0) 319d4144e45SSimon Glass 320d4144e45SSimon Glass # Not handled, so abort 321d4144e45SSimon Glass print 'git', git_args, sub_cmd, args 322d4144e45SSimon Glass sys.exit(1) 323d4144e45SSimon Glass 324d4144e45SSimon Glass def _HandleCommandNm(self, args): 325d4144e45SSimon Glass return command.CommandResult(return_code=0) 326d4144e45SSimon Glass 327d4144e45SSimon Glass def _HandleCommandObjdump(self, args): 328d4144e45SSimon Glass return command.CommandResult(return_code=0) 329d4144e45SSimon Glass 330d4144e45SSimon Glass def _HandleCommandSize(self, args): 331d4144e45SSimon Glass return command.CommandResult(return_code=0) 332d4144e45SSimon Glass 333d4144e45SSimon Glass def _HandleCommand(self, **kwargs): 334d4144e45SSimon Glass """Handle a command execution. 335d4144e45SSimon Glass 336d4144e45SSimon Glass The command is in kwargs['pipe-list'], as a list of pipes, each a 337d4144e45SSimon Glass list of commands. The command should be emulated as required for 338d4144e45SSimon Glass testing purposes. 339d4144e45SSimon Glass 340d4144e45SSimon Glass Returns: 341d4144e45SSimon Glass A CommandResult object 342d4144e45SSimon Glass """ 343d4144e45SSimon Glass pipe_list = kwargs['pipe_list'] 344dfb7e932SSimon Glass wc = False 345d4144e45SSimon Glass if len(pipe_list) != 1: 346dfb7e932SSimon Glass if pipe_list[1] == ['wc', '-l']: 347dfb7e932SSimon Glass wc = True 348dfb7e932SSimon Glass else: 349d4144e45SSimon Glass print 'invalid pipe', kwargs 350d4144e45SSimon Glass sys.exit(1) 351d4144e45SSimon Glass cmd = pipe_list[0][0] 352d4144e45SSimon Glass args = pipe_list[0][1:] 353dfb7e932SSimon Glass result = None 354d4144e45SSimon Glass if cmd == 'git': 355dfb7e932SSimon Glass result = self._HandleCommandGit(args) 356d4144e45SSimon Glass elif cmd == './scripts/show-gnu-make': 357d4144e45SSimon Glass return command.CommandResult(return_code=0, stdout='make') 358dfb7e932SSimon Glass elif cmd.endswith('nm'): 359d4144e45SSimon Glass return self._HandleCommandNm(args) 360dfb7e932SSimon Glass elif cmd.endswith('objdump'): 361d4144e45SSimon Glass return self._HandleCommandObjdump(args) 362dfb7e932SSimon Glass elif cmd.endswith( 'size'): 363d4144e45SSimon Glass return self._HandleCommandSize(args) 364d4144e45SSimon Glass 365dfb7e932SSimon Glass if not result: 366d4144e45SSimon Glass # Not handled, so abort 367d4144e45SSimon Glass print 'unknown command', kwargs 368d4144e45SSimon Glass sys.exit(1) 369dfb7e932SSimon Glass 370dfb7e932SSimon Glass if wc: 371dfb7e932SSimon Glass result.stdout = len(result.stdout.splitlines()) 372dfb7e932SSimon Glass return result 373d4144e45SSimon Glass 374d4144e45SSimon Glass def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): 375d4144e45SSimon Glass """Handle execution of 'make' 376d4144e45SSimon Glass 377d4144e45SSimon Glass Args: 378d4144e45SSimon Glass commit: Commit object that is being built 379d4144e45SSimon Glass brd: Board object that is being built 380d4144e45SSimon Glass stage: Stage that we are at (mrproper, config, build) 381d4144e45SSimon Glass cwd: Directory where make should be run 382d4144e45SSimon Glass args: Arguments to pass to make 383d4144e45SSimon Glass kwargs: Arguments to pass to command.RunPipe() 384d4144e45SSimon Glass """ 385dfb7e932SSimon Glass self._make_calls += 1 386d4144e45SSimon Glass if stage == 'mrproper': 387d4144e45SSimon Glass return command.CommandResult(return_code=0) 388d4144e45SSimon Glass elif stage == 'config': 389d4144e45SSimon Glass return command.CommandResult(return_code=0, 390d4144e45SSimon Glass combined='Test configuration complete') 391d4144e45SSimon Glass elif stage == 'build': 392dfb7e932SSimon Glass stderr = '' 393dfb7e932SSimon Glass if type(commit) is not str: 394dfb7e932SSimon Glass stderr = self._error.get((brd.target, commit.sequence)) 395dfb7e932SSimon Glass if stderr: 396dfb7e932SSimon Glass return command.CommandResult(return_code=1, stderr=stderr) 397d4144e45SSimon Glass return command.CommandResult(return_code=0) 398d4144e45SSimon Glass 399d4144e45SSimon Glass # Not handled, so abort 400d4144e45SSimon Glass print 'make', stage 401d4144e45SSimon Glass sys.exit(1) 402d4144e45SSimon Glass 403dfb7e932SSimon Glass # Example function to print output lines 404dfb7e932SSimon Glass def print_lines(self, lines): 405dfb7e932SSimon Glass print len(lines) 406dfb7e932SSimon Glass for line in lines: 407dfb7e932SSimon Glass print line 408dfb7e932SSimon Glass #self.print_lines(terminal.GetPrintTestLines()) 409dfb7e932SSimon Glass 410823e60b6SSimon Glass def testNoBoards(self): 411823e60b6SSimon Glass """Test that buildman aborts when there are no boards""" 412823e60b6SSimon Glass self._boards = board.Boards() 413823e60b6SSimon Glass with self.assertRaises(SystemExit): 414823e60b6SSimon Glass self._RunControl() 415823e60b6SSimon Glass 416d4144e45SSimon Glass def testCurrentSource(self): 417d4144e45SSimon Glass """Very simple test to invoke buildman on the current source""" 418dfb7e932SSimon Glass self.setupToolchains(); 419d4144e45SSimon Glass self._RunControl() 420d4144e45SSimon Glass lines = terminal.GetPrintTestLines() 421dfb7e932SSimon Glass self.assertIn('Building current source for %d boards' % len(boards), 422dfb7e932SSimon Glass lines[0].text) 423dfb7e932SSimon Glass 424dfb7e932SSimon Glass def testBadBranch(self): 425dfb7e932SSimon Glass """Test that we can detect an invalid branch""" 426dfb7e932SSimon Glass with self.assertRaises(ValueError): 427dfb7e932SSimon Glass self._RunControl('-b', 'badbranch') 428dfb7e932SSimon Glass 429dfb7e932SSimon Glass def testBadToolchain(self): 430dfb7e932SSimon Glass """Test that missing toolchains are detected""" 431dfb7e932SSimon Glass self.setupToolchains(); 432dfb7e932SSimon Glass ret_code = self._RunControl('-b', TEST_BRANCH) 433dfb7e932SSimon Glass lines = terminal.GetPrintTestLines() 434dfb7e932SSimon Glass 435dfb7e932SSimon Glass # Buildman always builds the upstream commit as well 436dfb7e932SSimon Glass self.assertIn('Building %d commits for %d boards' % 437dfb7e932SSimon Glass (self._commits, len(boards)), lines[0].text) 438dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 439dfb7e932SSimon Glass 440dfb7e932SSimon Glass # Only sandbox should succeed, the others don't have toolchains 441dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 442dfb7e932SSimon Glass self._total_builds - self._commits) 443dfb7e932SSimon Glass self.assertEqual(ret_code, 128) 444dfb7e932SSimon Glass 445dfb7e932SSimon Glass for commit in range(self._commits): 446dfb7e932SSimon Glass for board in self._boards.GetList(): 447dfb7e932SSimon Glass if board.arch != 'sandbox': 448dfb7e932SSimon Glass errfile = self._builder.GetErrFile(commit, board.target) 449dfb7e932SSimon Glass fd = open(errfile) 450dfb7e932SSimon Glass self.assertEqual(fd.readlines(), 451dfb7e932SSimon Glass ['No tool chain for %s\n' % board.arch]) 452dfb7e932SSimon Glass fd.close() 453dfb7e932SSimon Glass 454dfb7e932SSimon Glass def testBranch(self): 455dfb7e932SSimon Glass """Test building a branch with all toolchains present""" 456dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 457dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 458dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 459dfb7e932SSimon Glass 460dfb7e932SSimon Glass def testCount(self): 461dfb7e932SSimon Glass """Test building a specific number of commitst""" 462dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-c2') 463dfb7e932SSimon Glass self.assertEqual(self._builder.count, 2 * len(boards)) 464dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 465dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 466dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (2 + 2)) 467dfb7e932SSimon Glass 468dfb7e932SSimon Glass def testIncremental(self): 469dfb7e932SSimon Glass """Test building a branch twice - the second time should do nothing""" 470dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 471dfb7e932SSimon Glass 472dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 473dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (self._commits + 2)) 474dfb7e932SSimon Glass self._make_calls = 0 475dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, clean_dir=False) 476dfb7e932SSimon Glass self.assertEqual(self._make_calls, 0) 477dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 478dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 479dfb7e932SSimon Glass 480dfb7e932SSimon Glass def testForceBuild(self): 481dfb7e932SSimon Glass """The -f flag should force a rebuild""" 482dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 483dfb7e932SSimon Glass self._make_calls = 0 484dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-f', clean_dir=False) 485dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 486dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (self._commits + 2)) 487dfb7e932SSimon Glass 488dfb7e932SSimon Glass def testForceReconfigure(self): 489dfb7e932SSimon Glass """The -f flag should force a rebuild""" 490dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-C') 491dfb7e932SSimon Glass # Each commit has a mrproper, config and make 492dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * self._commits * 3) 493dfb7e932SSimon Glass 494dfb7e932SSimon Glass def testErrors(self): 495dfb7e932SSimon Glass """Test handling of build errors""" 496dfb7e932SSimon Glass self._error['board2', 1] = 'fred\n' 497dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 498dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 499dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 1) 500dfb7e932SSimon Glass 501dfb7e932SSimon Glass # Remove the error. This should have no effect since the commit will 502dfb7e932SSimon Glass # not be rebuilt 503dfb7e932SSimon Glass del self._error['board2', 1] 504dfb7e932SSimon Glass self._make_calls = 0 505dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, clean_dir=False) 506dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 507dfb7e932SSimon Glass self.assertEqual(self._make_calls, 0) 508dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 1) 509dfb7e932SSimon Glass 510dfb7e932SSimon Glass # Now use the -F flag to force rebuild of the bad commit 511dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-F', clean_dir=False) 512dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 513dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 514dfb7e932SSimon Glass self.assertEqual(self._make_calls, 3) 515f7582ce8SSimon Glass 516f7582ce8SSimon Glass def testBranchWithSlash(self): 517f7582ce8SSimon Glass """Test building a branch with a '/' in the name""" 518f7582ce8SSimon Glass self._test_branch = '/__dev/__testbranch' 519f7582ce8SSimon Glass self._RunControl('-b', self._test_branch, clean_dir=False) 520f7582ce8SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 521f7582ce8SSimon Glass self.assertEqual(self._builder.fail, 0) 522