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