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', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''], 43823e60b6SSimon Glass] 44823e60b6SSimon Glass 45dfb7e932SSimon Glasscommit_shortlog = """4aca821 patman: Avoid changing the order of tags 46dfb7e932SSimon Glass39403bb patman: Use --no-pager' to stop git from forking a pager 47dfb7e932SSimon Glassdb6e6f2 patman: Remove the -a option 48dfb7e932SSimon Glassf2ccf03 patman: Correct unit tests to run correctly 49dfb7e932SSimon Glass1d097f9 patman: Fix indentation in terminal.py 50dfb7e932SSimon Glassd073747 patman: Support the 'reverse' option for 'git log 51dfb7e932SSimon Glass""" 52dfb7e932SSimon Glass 53dfb7e932SSimon Glasscommit_log = ["""commit 7f6b8315d18f683c5181d0c3694818c1b2a20dcd 54dfb7e932SSimon GlassAuthor: Masahiro Yamada <yamada.m@jp.panasonic.com> 55dfb7e932SSimon GlassDate: Fri Aug 22 19:12:41 2014 +0900 56dfb7e932SSimon Glass 57dfb7e932SSimon Glass buildman: refactor help message 58dfb7e932SSimon Glass 59dfb7e932SSimon Glass "buildman [options]" is displayed by default. 60dfb7e932SSimon Glass 61dfb7e932SSimon Glass Append the rest of help messages to parser.usage 62dfb7e932SSimon Glass instead of replacing it. 63dfb7e932SSimon Glass 64dfb7e932SSimon Glass Besides, "-b <branch>" is not mandatory since commit fea5858e. 65dfb7e932SSimon Glass Drop it from the usage. 66dfb7e932SSimon Glass 67dfb7e932SSimon Glass Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com> 68dfb7e932SSimon Glass""", 69dfb7e932SSimon Glass"""commit d0737479be6baf4db5e2cdbee123e96bc5ed0ba8 70dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org> 71dfb7e932SSimon GlassDate: Thu Aug 14 16:48:25 2014 -0600 72dfb7e932SSimon Glass 73dfb7e932SSimon Glass patman: Support the 'reverse' option for 'git log' 74dfb7e932SSimon Glass 75dfb7e932SSimon Glass This option is currently not supported, but needs to be, for buildman to 76dfb7e932SSimon Glass operate as expected. 77dfb7e932SSimon Glass 78dfb7e932SSimon Glass Series-changes: 7 79dfb7e932SSimon Glass - Add new patch to fix the 'reverse' bug 80dfb7e932SSimon Glass 81950a2313SSimon Glass Series-version: 8 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 159950a2313SSimon Glass Series-version: 9 160950a2313SSimon Glass 161dfb7e932SSimon Glass Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com> 162dfb7e932SSimon Glass Change-Id: Ib1518588c1a189ad5c3198aae76f8654aed8d0db 163dfb7e932SSimon Glass"""] 164dfb7e932SSimon Glass 165dfb7e932SSimon GlassTEST_BRANCH = '__testbranch' 166dfb7e932SSimon Glass 167d4144e45SSimon Glassclass TestFunctional(unittest.TestCase): 168d4144e45SSimon Glass """Functional test for buildman. 169d4144e45SSimon Glass 170d4144e45SSimon Glass This aims to test from just below the invocation of buildman (parsing 171d4144e45SSimon Glass of arguments) to 'make' and 'git' invocation. It is not a true 172d4144e45SSimon Glass emd-to-end test, as it mocks git, make and the tool chain. But this 173d4144e45SSimon Glass makes it easier to detect when the builder is doing the wrong thing, 174d4144e45SSimon Glass since in many cases this test code will fail. For example, only a 175d4144e45SSimon Glass very limited subset of 'git' arguments is supported - anything 176d4144e45SSimon Glass unexpected will fail. 177d4144e45SSimon Glass """ 178d4144e45SSimon Glass def setUp(self): 179d4144e45SSimon Glass self._base_dir = tempfile.mkdtemp() 180d4144e45SSimon Glass self._git_dir = os.path.join(self._base_dir, 'src') 181d4144e45SSimon Glass self._buildman_pathname = sys.argv[0] 182*bd6f5d98SSimon Glass self._buildman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) 183d4144e45SSimon Glass command.test_result = self._HandleCommand 184dfb7e932SSimon Glass self.setupToolchains() 185dfb7e932SSimon Glass self._toolchains.Add('arm-gcc', test=False) 186dfb7e932SSimon Glass self._toolchains.Add('powerpc-gcc', test=False) 1878b985eebSSimon Glass bsettings.Setup(None) 1888b985eebSSimon Glass bsettings.AddFile(settings_data) 189823e60b6SSimon Glass self._boards = board.Boards() 190823e60b6SSimon Glass for brd in boards: 191823e60b6SSimon Glass self._boards.AddBoard(board.Board(*brd)) 192d4144e45SSimon Glass 193dfb7e932SSimon Glass # Directories where the source been cloned 194dfb7e932SSimon Glass self._clone_dirs = [] 195dfb7e932SSimon Glass self._commits = len(commit_shortlog.splitlines()) + 1 196dfb7e932SSimon Glass self._total_builds = self._commits * len(boards) 197dfb7e932SSimon Glass 198dfb7e932SSimon Glass # Number of calls to make 199dfb7e932SSimon Glass self._make_calls = 0 200dfb7e932SSimon Glass 201dfb7e932SSimon Glass # Map of [board, commit] to error messages 202dfb7e932SSimon Glass self._error = {} 203dfb7e932SSimon Glass 204f7582ce8SSimon Glass self._test_branch = TEST_BRANCH 205f7582ce8SSimon Glass 206dfb7e932SSimon Glass # Avoid sending any output and clear all terminal output 207dfb7e932SSimon Glass terminal.SetPrintTestMode() 208dfb7e932SSimon Glass terminal.GetPrintTestLines() 209dfb7e932SSimon Glass 210d4144e45SSimon Glass def tearDown(self): 211d4144e45SSimon Glass shutil.rmtree(self._base_dir) 212d4144e45SSimon Glass 213dfb7e932SSimon Glass def setupToolchains(self): 214dfb7e932SSimon Glass self._toolchains = toolchain.Toolchains() 215dfb7e932SSimon Glass self._toolchains.Add('gcc', test=False) 216dfb7e932SSimon Glass 217d4144e45SSimon Glass def _RunBuildman(self, *args): 218d4144e45SSimon Glass return command.RunPipe([[self._buildman_pathname] + list(args)], 219d4144e45SSimon Glass capture=True, capture_stderr=True) 220d4144e45SSimon Glass 221dfb7e932SSimon Glass def _RunControl(self, *args, **kwargs): 222d4144e45SSimon Glass sys.argv = [sys.argv[0]] + list(args) 223d4144e45SSimon Glass options, args = cmdline.ParseArgs() 224dfb7e932SSimon Glass result = control.DoBuildman(options, args, toolchains=self._toolchains, 225dfb7e932SSimon Glass make_func=self._HandleMake, boards=self._boards, 226dfb7e932SSimon Glass clean_dir=kwargs.get('clean_dir', True)) 227dfb7e932SSimon Glass self._builder = control.builder 228dfb7e932SSimon Glass return result 229d4144e45SSimon Glass 230d4144e45SSimon Glass def testFullHelp(self): 231d4144e45SSimon Glass command.test_result = None 232d4144e45SSimon Glass result = self._RunBuildman('-H') 233d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 234d4144e45SSimon Glass self.assertEqual(len(result.stdout), os.path.getsize(help_file)) 235d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 236d4144e45SSimon Glass self.assertEqual(0, result.return_code) 237d4144e45SSimon Glass 238d4144e45SSimon Glass def testHelp(self): 239d4144e45SSimon Glass command.test_result = None 240d4144e45SSimon Glass result = self._RunBuildman('-h') 241d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 242d4144e45SSimon Glass self.assertTrue(len(result.stdout) > 1000) 243d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 244d4144e45SSimon Glass self.assertEqual(0, result.return_code) 245d4144e45SSimon Glass 246d4144e45SSimon Glass def testGitSetup(self): 247d4144e45SSimon Glass """Test gitutils.Setup(), from outside the module itself""" 248d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=1) 249d4144e45SSimon Glass gitutil.Setup() 250d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, False) 251d4144e45SSimon Glass 252d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=0) 253d4144e45SSimon Glass gitutil.Setup() 254d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, True) 255d4144e45SSimon Glass 256d4144e45SSimon Glass def _HandleCommandGitLog(self, args): 257d4c8572bSSimon Glass if args[-1] == '--': 258d4c8572bSSimon Glass args = args[:-1] 259d4144e45SSimon Glass if '-n0' in args: 260d4144e45SSimon Glass return command.CommandResult(return_code=0) 261f7582ce8SSimon Glass elif args[-1] == 'upstream/master..%s' % self._test_branch: 262dfb7e932SSimon Glass return command.CommandResult(return_code=0, stdout=commit_shortlog) 263dfb7e932SSimon Glass elif args[:3] == ['--no-color', '--no-decorate', '--reverse']: 264f7582ce8SSimon Glass if args[-1] == self._test_branch: 265dfb7e932SSimon Glass count = int(args[3][2:]) 266dfb7e932SSimon Glass return command.CommandResult(return_code=0, 267dfb7e932SSimon Glass stdout=''.join(commit_log[:count])) 268d4144e45SSimon Glass 269d4144e45SSimon Glass # Not handled, so abort 270d4144e45SSimon Glass print 'git log', args 271d4144e45SSimon Glass sys.exit(1) 272d4144e45SSimon Glass 273dfb7e932SSimon Glass def _HandleCommandGitConfig(self, args): 274dfb7e932SSimon Glass config = args[0] 275dfb7e932SSimon Glass if config == 'sendemail.aliasesfile': 276dfb7e932SSimon Glass return command.CommandResult(return_code=0) 277dfb7e932SSimon Glass elif config.startswith('branch.badbranch'): 278dfb7e932SSimon Glass return command.CommandResult(return_code=1) 279f7582ce8SSimon Glass elif config == 'branch.%s.remote' % self._test_branch: 280dfb7e932SSimon Glass return command.CommandResult(return_code=0, stdout='upstream\n') 281f7582ce8SSimon Glass elif config == 'branch.%s.merge' % self._test_branch: 282dfb7e932SSimon Glass return command.CommandResult(return_code=0, 283dfb7e932SSimon Glass stdout='refs/heads/master\n') 284dfb7e932SSimon Glass 285dfb7e932SSimon Glass # Not handled, so abort 286dfb7e932SSimon Glass print 'git config', args 287dfb7e932SSimon Glass sys.exit(1) 288dfb7e932SSimon Glass 289d4144e45SSimon Glass def _HandleCommandGit(self, in_args): 290d4144e45SSimon Glass """Handle execution of a git command 291d4144e45SSimon Glass 292d4144e45SSimon Glass This uses a hacked-up parser. 293d4144e45SSimon Glass 294d4144e45SSimon Glass Args: 295d4144e45SSimon Glass in_args: Arguments after 'git' from the command line 296d4144e45SSimon Glass """ 297d4144e45SSimon Glass git_args = [] # Top-level arguments to git itself 298d4144e45SSimon Glass sub_cmd = None # Git sub-command selected 299d4144e45SSimon Glass args = [] # Arguments to the git sub-command 300d4144e45SSimon Glass for arg in in_args: 301d4144e45SSimon Glass if sub_cmd: 302d4144e45SSimon Glass args.append(arg) 303d4144e45SSimon Glass elif arg[0] == '-': 304d4144e45SSimon Glass git_args.append(arg) 305d4144e45SSimon Glass else: 306dfb7e932SSimon Glass if git_args and git_args[-1] in ['--git-dir', '--work-tree']: 307dfb7e932SSimon Glass git_args.append(arg) 308dfb7e932SSimon Glass else: 309d4144e45SSimon Glass sub_cmd = arg 310d4144e45SSimon Glass if sub_cmd == 'config': 311dfb7e932SSimon Glass return self._HandleCommandGitConfig(args) 312d4144e45SSimon Glass elif sub_cmd == 'log': 313d4144e45SSimon Glass return self._HandleCommandGitLog(args) 314dfb7e932SSimon Glass elif sub_cmd == 'clone': 315dfb7e932SSimon Glass return command.CommandResult(return_code=0) 316dfb7e932SSimon Glass elif sub_cmd == 'checkout': 317dfb7e932SSimon Glass return command.CommandResult(return_code=0) 318d4144e45SSimon Glass 319d4144e45SSimon Glass # Not handled, so abort 320d4144e45SSimon Glass print 'git', git_args, sub_cmd, args 321d4144e45SSimon Glass sys.exit(1) 322d4144e45SSimon Glass 323d4144e45SSimon Glass def _HandleCommandNm(self, args): 324d4144e45SSimon Glass return command.CommandResult(return_code=0) 325d4144e45SSimon Glass 326d4144e45SSimon Glass def _HandleCommandObjdump(self, args): 327d4144e45SSimon Glass return command.CommandResult(return_code=0) 328d4144e45SSimon Glass 329d4144e45SSimon Glass def _HandleCommandSize(self, args): 330d4144e45SSimon Glass return command.CommandResult(return_code=0) 331d4144e45SSimon Glass 332d4144e45SSimon Glass def _HandleCommand(self, **kwargs): 333d4144e45SSimon Glass """Handle a command execution. 334d4144e45SSimon Glass 335d4144e45SSimon Glass The command is in kwargs['pipe-list'], as a list of pipes, each a 336d4144e45SSimon Glass list of commands. The command should be emulated as required for 337d4144e45SSimon Glass testing purposes. 338d4144e45SSimon Glass 339d4144e45SSimon Glass Returns: 340d4144e45SSimon Glass A CommandResult object 341d4144e45SSimon Glass """ 342d4144e45SSimon Glass pipe_list = kwargs['pipe_list'] 343dfb7e932SSimon Glass wc = False 344d4144e45SSimon Glass if len(pipe_list) != 1: 345dfb7e932SSimon Glass if pipe_list[1] == ['wc', '-l']: 346dfb7e932SSimon Glass wc = True 347dfb7e932SSimon Glass else: 348d4144e45SSimon Glass print 'invalid pipe', kwargs 349d4144e45SSimon Glass sys.exit(1) 350d4144e45SSimon Glass cmd = pipe_list[0][0] 351d4144e45SSimon Glass args = pipe_list[0][1:] 352dfb7e932SSimon Glass result = None 353d4144e45SSimon Glass if cmd == 'git': 354dfb7e932SSimon Glass result = self._HandleCommandGit(args) 355d4144e45SSimon Glass elif cmd == './scripts/show-gnu-make': 356d4144e45SSimon Glass return command.CommandResult(return_code=0, stdout='make') 357dfb7e932SSimon Glass elif cmd.endswith('nm'): 358d4144e45SSimon Glass return self._HandleCommandNm(args) 359dfb7e932SSimon Glass elif cmd.endswith('objdump'): 360d4144e45SSimon Glass return self._HandleCommandObjdump(args) 361dfb7e932SSimon Glass elif cmd.endswith( 'size'): 362d4144e45SSimon Glass return self._HandleCommandSize(args) 363d4144e45SSimon Glass 364dfb7e932SSimon Glass if not result: 365d4144e45SSimon Glass # Not handled, so abort 366d4144e45SSimon Glass print 'unknown command', kwargs 367d4144e45SSimon Glass sys.exit(1) 368dfb7e932SSimon Glass 369dfb7e932SSimon Glass if wc: 370dfb7e932SSimon Glass result.stdout = len(result.stdout.splitlines()) 371dfb7e932SSimon Glass return result 372d4144e45SSimon Glass 373d4144e45SSimon Glass def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): 374d4144e45SSimon Glass """Handle execution of 'make' 375d4144e45SSimon Glass 376d4144e45SSimon Glass Args: 377d4144e45SSimon Glass commit: Commit object that is being built 378d4144e45SSimon Glass brd: Board object that is being built 379d4144e45SSimon Glass stage: Stage that we are at (mrproper, config, build) 380d4144e45SSimon Glass cwd: Directory where make should be run 381d4144e45SSimon Glass args: Arguments to pass to make 382d4144e45SSimon Glass kwargs: Arguments to pass to command.RunPipe() 383d4144e45SSimon Glass """ 384dfb7e932SSimon Glass self._make_calls += 1 385d4144e45SSimon Glass if stage == 'mrproper': 386d4144e45SSimon Glass return command.CommandResult(return_code=0) 387d4144e45SSimon Glass elif stage == 'config': 388d4144e45SSimon Glass return command.CommandResult(return_code=0, 389d4144e45SSimon Glass combined='Test configuration complete') 390d4144e45SSimon Glass elif stage == 'build': 391dfb7e932SSimon Glass stderr = '' 392dfb7e932SSimon Glass if type(commit) is not str: 393dfb7e932SSimon Glass stderr = self._error.get((brd.target, commit.sequence)) 394dfb7e932SSimon Glass if stderr: 395dfb7e932SSimon Glass return command.CommandResult(return_code=1, stderr=stderr) 396d4144e45SSimon Glass return command.CommandResult(return_code=0) 397d4144e45SSimon Glass 398d4144e45SSimon Glass # Not handled, so abort 399d4144e45SSimon Glass print 'make', stage 400d4144e45SSimon Glass sys.exit(1) 401d4144e45SSimon Glass 402dfb7e932SSimon Glass # Example function to print output lines 403dfb7e932SSimon Glass def print_lines(self, lines): 404dfb7e932SSimon Glass print len(lines) 405dfb7e932SSimon Glass for line in lines: 406dfb7e932SSimon Glass print line 407dfb7e932SSimon Glass #self.print_lines(terminal.GetPrintTestLines()) 408dfb7e932SSimon Glass 409823e60b6SSimon Glass def testNoBoards(self): 410823e60b6SSimon Glass """Test that buildman aborts when there are no boards""" 411823e60b6SSimon Glass self._boards = board.Boards() 412823e60b6SSimon Glass with self.assertRaises(SystemExit): 413823e60b6SSimon Glass self._RunControl() 414823e60b6SSimon Glass 415d4144e45SSimon Glass def testCurrentSource(self): 416d4144e45SSimon Glass """Very simple test to invoke buildman on the current source""" 417dfb7e932SSimon Glass self.setupToolchains(); 418d4144e45SSimon Glass self._RunControl() 419d4144e45SSimon Glass lines = terminal.GetPrintTestLines() 420dfb7e932SSimon Glass self.assertIn('Building current source for %d boards' % len(boards), 421dfb7e932SSimon Glass lines[0].text) 422dfb7e932SSimon Glass 423dfb7e932SSimon Glass def testBadBranch(self): 424dfb7e932SSimon Glass """Test that we can detect an invalid branch""" 425dfb7e932SSimon Glass with self.assertRaises(ValueError): 426dfb7e932SSimon Glass self._RunControl('-b', 'badbranch') 427dfb7e932SSimon Glass 428dfb7e932SSimon Glass def testBadToolchain(self): 429dfb7e932SSimon Glass """Test that missing toolchains are detected""" 430dfb7e932SSimon Glass self.setupToolchains(); 431dfb7e932SSimon Glass ret_code = self._RunControl('-b', TEST_BRANCH) 432dfb7e932SSimon Glass lines = terminal.GetPrintTestLines() 433dfb7e932SSimon Glass 434dfb7e932SSimon Glass # Buildman always builds the upstream commit as well 435dfb7e932SSimon Glass self.assertIn('Building %d commits for %d boards' % 436dfb7e932SSimon Glass (self._commits, len(boards)), lines[0].text) 437dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 438dfb7e932SSimon Glass 439dfb7e932SSimon Glass # Only sandbox should succeed, the others don't have toolchains 440dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 441dfb7e932SSimon Glass self._total_builds - self._commits) 442dfb7e932SSimon Glass self.assertEqual(ret_code, 128) 443dfb7e932SSimon Glass 444dfb7e932SSimon Glass for commit in range(self._commits): 445dfb7e932SSimon Glass for board in self._boards.GetList(): 446dfb7e932SSimon Glass if board.arch != 'sandbox': 447dfb7e932SSimon Glass errfile = self._builder.GetErrFile(commit, board.target) 448dfb7e932SSimon Glass fd = open(errfile) 449dfb7e932SSimon Glass self.assertEqual(fd.readlines(), 450dfb7e932SSimon Glass ['No tool chain for %s\n' % board.arch]) 451dfb7e932SSimon Glass fd.close() 452dfb7e932SSimon Glass 453dfb7e932SSimon Glass def testBranch(self): 454dfb7e932SSimon Glass """Test building a branch with all toolchains present""" 455dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 456dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 457dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 458dfb7e932SSimon Glass 459dfb7e932SSimon Glass def testCount(self): 460dfb7e932SSimon Glass """Test building a specific number of commitst""" 461dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-c2') 462dfb7e932SSimon Glass self.assertEqual(self._builder.count, 2 * len(boards)) 463dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 464dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 465dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (2 + 2)) 466dfb7e932SSimon Glass 467dfb7e932SSimon Glass def testIncremental(self): 468dfb7e932SSimon Glass """Test building a branch twice - the second time should do nothing""" 469dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 470dfb7e932SSimon Glass 471dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 472dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (self._commits + 2)) 473dfb7e932SSimon Glass self._make_calls = 0 474dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, clean_dir=False) 475dfb7e932SSimon Glass self.assertEqual(self._make_calls, 0) 476dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 477dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 478dfb7e932SSimon Glass 479dfb7e932SSimon Glass def testForceBuild(self): 480dfb7e932SSimon Glass """The -f flag should force a rebuild""" 481dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 482dfb7e932SSimon Glass self._make_calls = 0 483dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-f', clean_dir=False) 484dfb7e932SSimon Glass # Each board has a mrproper, config, and then one make per commit 485dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * (self._commits + 2)) 486dfb7e932SSimon Glass 487dfb7e932SSimon Glass def testForceReconfigure(self): 488dfb7e932SSimon Glass """The -f flag should force a rebuild""" 489dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-C') 490dfb7e932SSimon Glass # Each commit has a mrproper, config and make 491dfb7e932SSimon Glass self.assertEqual(self._make_calls, len(boards) * self._commits * 3) 492dfb7e932SSimon Glass 493dfb7e932SSimon Glass def testErrors(self): 494dfb7e932SSimon Glass """Test handling of build errors""" 495dfb7e932SSimon Glass self._error['board2', 1] = 'fred\n' 496dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH) 497dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 498dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 1) 499dfb7e932SSimon Glass 500dfb7e932SSimon Glass # Remove the error. This should have no effect since the commit will 501dfb7e932SSimon Glass # not be rebuilt 502dfb7e932SSimon Glass del self._error['board2', 1] 503dfb7e932SSimon Glass self._make_calls = 0 504dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, clean_dir=False) 505dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 506dfb7e932SSimon Glass self.assertEqual(self._make_calls, 0) 507dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 1) 508dfb7e932SSimon Glass 509dfb7e932SSimon Glass # Now use the -F flag to force rebuild of the bad commit 510dfb7e932SSimon Glass self._RunControl('-b', TEST_BRANCH, '-F', clean_dir=False) 511dfb7e932SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 512dfb7e932SSimon Glass self.assertEqual(self._builder.fail, 0) 513dfb7e932SSimon Glass self.assertEqual(self._make_calls, 3) 514f7582ce8SSimon Glass 515f7582ce8SSimon Glass def testBranchWithSlash(self): 516f7582ce8SSimon Glass """Test building a branch with a '/' in the name""" 517f7582ce8SSimon Glass self._test_branch = '/__dev/__testbranch' 518f7582ce8SSimon Glass self._RunControl('-b', self._test_branch, clean_dir=False) 519f7582ce8SSimon Glass self.assertEqual(self._builder.count, self._total_builds) 520f7582ce8SSimon Glass self.assertEqual(self._builder.fail, 0) 521