1*d4144e45SSimon Glass# 2*d4144e45SSimon Glass# Copyright (c) 2014 Google, Inc 3*d4144e45SSimon Glass# 4*d4144e45SSimon Glass# SPDX-License-Identifier: GPL-2.0+ 5*d4144e45SSimon Glass# 6*d4144e45SSimon Glass 7*d4144e45SSimon Glassimport os 8*d4144e45SSimon Glassimport shutil 9*d4144e45SSimon Glassimport sys 10*d4144e45SSimon Glassimport tempfile 11*d4144e45SSimon Glassimport unittest 12*d4144e45SSimon Glass 13*d4144e45SSimon Glassimport cmdline 14*d4144e45SSimon Glassimport command 15*d4144e45SSimon Glassimport control 16*d4144e45SSimon Glassimport gitutil 17*d4144e45SSimon Glassimport terminal 18*d4144e45SSimon Glassimport toolchain 19*d4144e45SSimon Glass 20*d4144e45SSimon Glassclass TestFunctional(unittest.TestCase): 21*d4144e45SSimon Glass """Functional test for buildman. 22*d4144e45SSimon Glass 23*d4144e45SSimon Glass This aims to test from just below the invocation of buildman (parsing 24*d4144e45SSimon Glass of arguments) to 'make' and 'git' invocation. It is not a true 25*d4144e45SSimon Glass emd-to-end test, as it mocks git, make and the tool chain. But this 26*d4144e45SSimon Glass makes it easier to detect when the builder is doing the wrong thing, 27*d4144e45SSimon Glass since in many cases this test code will fail. For example, only a 28*d4144e45SSimon Glass very limited subset of 'git' arguments is supported - anything 29*d4144e45SSimon Glass unexpected will fail. 30*d4144e45SSimon Glass """ 31*d4144e45SSimon Glass def setUp(self): 32*d4144e45SSimon Glass self._base_dir = tempfile.mkdtemp() 33*d4144e45SSimon Glass self._git_dir = os.path.join(self._base_dir, 'src') 34*d4144e45SSimon Glass self._buildman_pathname = sys.argv[0] 35*d4144e45SSimon Glass self._buildman_dir = os.path.dirname(sys.argv[0]) 36*d4144e45SSimon Glass command.test_result = self._HandleCommand 37*d4144e45SSimon Glass self._toolchains = toolchain.Toolchains() 38*d4144e45SSimon Glass self._toolchains.Add('gcc', test=False) 39*d4144e45SSimon Glass 40*d4144e45SSimon Glass def tearDown(self): 41*d4144e45SSimon Glass shutil.rmtree(self._base_dir) 42*d4144e45SSimon Glass 43*d4144e45SSimon Glass def _RunBuildman(self, *args): 44*d4144e45SSimon Glass return command.RunPipe([[self._buildman_pathname] + list(args)], 45*d4144e45SSimon Glass capture=True, capture_stderr=True) 46*d4144e45SSimon Glass 47*d4144e45SSimon Glass def _RunControl(self, *args): 48*d4144e45SSimon Glass sys.argv = [sys.argv[0]] + list(args) 49*d4144e45SSimon Glass options, args = cmdline.ParseArgs() 50*d4144e45SSimon Glass return control.DoBuildman(options, args, toolchains=self._toolchains, 51*d4144e45SSimon Glass make_func=self._HandleMake) 52*d4144e45SSimon Glass 53*d4144e45SSimon Glass def testFullHelp(self): 54*d4144e45SSimon Glass command.test_result = None 55*d4144e45SSimon Glass result = self._RunBuildman('-H') 56*d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 57*d4144e45SSimon Glass self.assertEqual(len(result.stdout), os.path.getsize(help_file)) 58*d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 59*d4144e45SSimon Glass self.assertEqual(0, result.return_code) 60*d4144e45SSimon Glass 61*d4144e45SSimon Glass def testHelp(self): 62*d4144e45SSimon Glass command.test_result = None 63*d4144e45SSimon Glass result = self._RunBuildman('-h') 64*d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 65*d4144e45SSimon Glass self.assertTrue(len(result.stdout) > 1000) 66*d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 67*d4144e45SSimon Glass self.assertEqual(0, result.return_code) 68*d4144e45SSimon Glass 69*d4144e45SSimon Glass def testGitSetup(self): 70*d4144e45SSimon Glass """Test gitutils.Setup(), from outside the module itself""" 71*d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=1) 72*d4144e45SSimon Glass gitutil.Setup() 73*d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, False) 74*d4144e45SSimon Glass 75*d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=0) 76*d4144e45SSimon Glass gitutil.Setup() 77*d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, True) 78*d4144e45SSimon Glass 79*d4144e45SSimon Glass def _HandleCommandGitLog(self, args): 80*d4144e45SSimon Glass if '-n0' in args: 81*d4144e45SSimon Glass return command.CommandResult(return_code=0) 82*d4144e45SSimon Glass 83*d4144e45SSimon Glass # Not handled, so abort 84*d4144e45SSimon Glass print 'git log', args 85*d4144e45SSimon Glass sys.exit(1) 86*d4144e45SSimon Glass 87*d4144e45SSimon Glass def _HandleCommandGit(self, in_args): 88*d4144e45SSimon Glass """Handle execution of a git command 89*d4144e45SSimon Glass 90*d4144e45SSimon Glass This uses a hacked-up parser. 91*d4144e45SSimon Glass 92*d4144e45SSimon Glass Args: 93*d4144e45SSimon Glass in_args: Arguments after 'git' from the command line 94*d4144e45SSimon Glass """ 95*d4144e45SSimon Glass git_args = [] # Top-level arguments to git itself 96*d4144e45SSimon Glass sub_cmd = None # Git sub-command selected 97*d4144e45SSimon Glass args = [] # Arguments to the git sub-command 98*d4144e45SSimon Glass for arg in in_args: 99*d4144e45SSimon Glass if sub_cmd: 100*d4144e45SSimon Glass args.append(arg) 101*d4144e45SSimon Glass elif arg[0] == '-': 102*d4144e45SSimon Glass git_args.append(arg) 103*d4144e45SSimon Glass else: 104*d4144e45SSimon Glass sub_cmd = arg 105*d4144e45SSimon Glass if sub_cmd == 'config': 106*d4144e45SSimon Glass return command.CommandResult(return_code=0) 107*d4144e45SSimon Glass elif sub_cmd == 'log': 108*d4144e45SSimon Glass return self._HandleCommandGitLog(args) 109*d4144e45SSimon Glass 110*d4144e45SSimon Glass # Not handled, so abort 111*d4144e45SSimon Glass print 'git', git_args, sub_cmd, args 112*d4144e45SSimon Glass sys.exit(1) 113*d4144e45SSimon Glass 114*d4144e45SSimon Glass def _HandleCommandNm(self, args): 115*d4144e45SSimon Glass return command.CommandResult(return_code=0) 116*d4144e45SSimon Glass 117*d4144e45SSimon Glass def _HandleCommandObjdump(self, args): 118*d4144e45SSimon Glass return command.CommandResult(return_code=0) 119*d4144e45SSimon Glass 120*d4144e45SSimon Glass def _HandleCommandSize(self, args): 121*d4144e45SSimon Glass return command.CommandResult(return_code=0) 122*d4144e45SSimon Glass 123*d4144e45SSimon Glass def _HandleCommand(self, **kwargs): 124*d4144e45SSimon Glass """Handle a command execution. 125*d4144e45SSimon Glass 126*d4144e45SSimon Glass The command is in kwargs['pipe-list'], as a list of pipes, each a 127*d4144e45SSimon Glass list of commands. The command should be emulated as required for 128*d4144e45SSimon Glass testing purposes. 129*d4144e45SSimon Glass 130*d4144e45SSimon Glass Returns: 131*d4144e45SSimon Glass A CommandResult object 132*d4144e45SSimon Glass """ 133*d4144e45SSimon Glass pipe_list = kwargs['pipe_list'] 134*d4144e45SSimon Glass if len(pipe_list) != 1: 135*d4144e45SSimon Glass print 'invalid pipe', kwargs 136*d4144e45SSimon Glass sys.exit(1) 137*d4144e45SSimon Glass cmd = pipe_list[0][0] 138*d4144e45SSimon Glass args = pipe_list[0][1:] 139*d4144e45SSimon Glass if cmd == 'git': 140*d4144e45SSimon Glass return self._HandleCommandGit(args) 141*d4144e45SSimon Glass elif cmd == './scripts/show-gnu-make': 142*d4144e45SSimon Glass return command.CommandResult(return_code=0, stdout='make') 143*d4144e45SSimon Glass elif cmd == 'nm': 144*d4144e45SSimon Glass return self._HandleCommandNm(args) 145*d4144e45SSimon Glass elif cmd == 'objdump': 146*d4144e45SSimon Glass return self._HandleCommandObjdump(args) 147*d4144e45SSimon Glass elif cmd == 'size': 148*d4144e45SSimon Glass return self._HandleCommandSize(args) 149*d4144e45SSimon Glass 150*d4144e45SSimon Glass # Not handled, so abort 151*d4144e45SSimon Glass print 'unknown command', kwargs 152*d4144e45SSimon Glass sys.exit(1) 153*d4144e45SSimon Glass return command.CommandResult(return_code=0) 154*d4144e45SSimon Glass 155*d4144e45SSimon Glass def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): 156*d4144e45SSimon Glass """Handle execution of 'make' 157*d4144e45SSimon Glass 158*d4144e45SSimon Glass Args: 159*d4144e45SSimon Glass commit: Commit object that is being built 160*d4144e45SSimon Glass brd: Board object that is being built 161*d4144e45SSimon Glass stage: Stage that we are at (mrproper, config, build) 162*d4144e45SSimon Glass cwd: Directory where make should be run 163*d4144e45SSimon Glass args: Arguments to pass to make 164*d4144e45SSimon Glass kwargs: Arguments to pass to command.RunPipe() 165*d4144e45SSimon Glass """ 166*d4144e45SSimon Glass if stage == 'mrproper': 167*d4144e45SSimon Glass return command.CommandResult(return_code=0) 168*d4144e45SSimon Glass elif stage == 'config': 169*d4144e45SSimon Glass return command.CommandResult(return_code=0, 170*d4144e45SSimon Glass combined='Test configuration complete') 171*d4144e45SSimon Glass elif stage == 'build': 172*d4144e45SSimon Glass return command.CommandResult(return_code=0) 173*d4144e45SSimon Glass 174*d4144e45SSimon Glass # Not handled, so abort 175*d4144e45SSimon Glass print 'make', stage 176*d4144e45SSimon Glass sys.exit(1) 177*d4144e45SSimon Glass 178*d4144e45SSimon Glass def testCurrentSource(self): 179*d4144e45SSimon Glass """Very simple test to invoke buildman on the current source""" 180*d4144e45SSimon Glass self._RunControl() 181*d4144e45SSimon Glass lines = terminal.GetPrintTestLines() 182*d4144e45SSimon Glass self.assertTrue(lines[0].text.startswith('Building current source')) 183