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 13*823e60b6SSimon 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 38*823e60b6SSimon Glassboards = [ 39*823e60b6SSimon Glass ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0', ''], 40*823e60b6SSimon Glass ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''], 41*823e60b6SSimon Glass ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''], 42*823e60b6SSimon Glass ['Active', 'powerpc', 'mpc5xx', '', 'Tester', 'PowerPC board 2', 'board3', ''], 43*823e60b6SSimon Glass ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''], 44*823e60b6SSimon Glass] 45*823e60b6SSimon Glass 46d4144e45SSimon Glassclass TestFunctional(unittest.TestCase): 47d4144e45SSimon Glass """Functional test for buildman. 48d4144e45SSimon Glass 49d4144e45SSimon Glass This aims to test from just below the invocation of buildman (parsing 50d4144e45SSimon Glass of arguments) to 'make' and 'git' invocation. It is not a true 51d4144e45SSimon Glass emd-to-end test, as it mocks git, make and the tool chain. But this 52d4144e45SSimon Glass makes it easier to detect when the builder is doing the wrong thing, 53d4144e45SSimon Glass since in many cases this test code will fail. For example, only a 54d4144e45SSimon Glass very limited subset of 'git' arguments is supported - anything 55d4144e45SSimon Glass unexpected will fail. 56d4144e45SSimon Glass """ 57d4144e45SSimon Glass def setUp(self): 58d4144e45SSimon Glass self._base_dir = tempfile.mkdtemp() 59d4144e45SSimon Glass self._git_dir = os.path.join(self._base_dir, 'src') 60d4144e45SSimon Glass self._buildman_pathname = sys.argv[0] 61d4144e45SSimon Glass self._buildman_dir = os.path.dirname(sys.argv[0]) 62d4144e45SSimon Glass command.test_result = self._HandleCommand 63d4144e45SSimon Glass self._toolchains = toolchain.Toolchains() 64d4144e45SSimon Glass self._toolchains.Add('gcc', test=False) 658b985eebSSimon Glass bsettings.Setup(None) 668b985eebSSimon Glass bsettings.AddFile(settings_data) 67*823e60b6SSimon Glass self._boards = board.Boards() 68*823e60b6SSimon Glass for brd in boards: 69*823e60b6SSimon Glass self._boards.AddBoard(board.Board(*brd)) 70d4144e45SSimon Glass 71d4144e45SSimon Glass def tearDown(self): 72d4144e45SSimon Glass shutil.rmtree(self._base_dir) 73d4144e45SSimon Glass 74d4144e45SSimon Glass def _RunBuildman(self, *args): 75d4144e45SSimon Glass return command.RunPipe([[self._buildman_pathname] + list(args)], 76d4144e45SSimon Glass capture=True, capture_stderr=True) 77d4144e45SSimon Glass 78d4144e45SSimon Glass def _RunControl(self, *args): 79d4144e45SSimon Glass sys.argv = [sys.argv[0]] + list(args) 80d4144e45SSimon Glass options, args = cmdline.ParseArgs() 81d4144e45SSimon Glass return control.DoBuildman(options, args, toolchains=self._toolchains, 82*823e60b6SSimon Glass make_func=self._HandleMake, boards=self._boards) 83d4144e45SSimon Glass 84d4144e45SSimon Glass def testFullHelp(self): 85d4144e45SSimon Glass command.test_result = None 86d4144e45SSimon Glass result = self._RunBuildman('-H') 87d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 88d4144e45SSimon Glass self.assertEqual(len(result.stdout), os.path.getsize(help_file)) 89d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 90d4144e45SSimon Glass self.assertEqual(0, result.return_code) 91d4144e45SSimon Glass 92d4144e45SSimon Glass def testHelp(self): 93d4144e45SSimon Glass command.test_result = None 94d4144e45SSimon Glass result = self._RunBuildman('-h') 95d4144e45SSimon Glass help_file = os.path.join(self._buildman_dir, 'README') 96d4144e45SSimon Glass self.assertTrue(len(result.stdout) > 1000) 97d4144e45SSimon Glass self.assertEqual(0, len(result.stderr)) 98d4144e45SSimon Glass self.assertEqual(0, result.return_code) 99d4144e45SSimon Glass 100d4144e45SSimon Glass def testGitSetup(self): 101d4144e45SSimon Glass """Test gitutils.Setup(), from outside the module itself""" 102d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=1) 103d4144e45SSimon Glass gitutil.Setup() 104d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, False) 105d4144e45SSimon Glass 106d4144e45SSimon Glass command.test_result = command.CommandResult(return_code=0) 107d4144e45SSimon Glass gitutil.Setup() 108d4144e45SSimon Glass self.assertEqual(gitutil.use_no_decorate, True) 109d4144e45SSimon Glass 110d4144e45SSimon Glass def _HandleCommandGitLog(self, args): 111d4144e45SSimon Glass if '-n0' in args: 112d4144e45SSimon Glass return command.CommandResult(return_code=0) 113d4144e45SSimon Glass 114d4144e45SSimon Glass # Not handled, so abort 115d4144e45SSimon Glass print 'git log', args 116d4144e45SSimon Glass sys.exit(1) 117d4144e45SSimon Glass 118d4144e45SSimon Glass def _HandleCommandGit(self, in_args): 119d4144e45SSimon Glass """Handle execution of a git command 120d4144e45SSimon Glass 121d4144e45SSimon Glass This uses a hacked-up parser. 122d4144e45SSimon Glass 123d4144e45SSimon Glass Args: 124d4144e45SSimon Glass in_args: Arguments after 'git' from the command line 125d4144e45SSimon Glass """ 126d4144e45SSimon Glass git_args = [] # Top-level arguments to git itself 127d4144e45SSimon Glass sub_cmd = None # Git sub-command selected 128d4144e45SSimon Glass args = [] # Arguments to the git sub-command 129d4144e45SSimon Glass for arg in in_args: 130d4144e45SSimon Glass if sub_cmd: 131d4144e45SSimon Glass args.append(arg) 132d4144e45SSimon Glass elif arg[0] == '-': 133d4144e45SSimon Glass git_args.append(arg) 134d4144e45SSimon Glass else: 135d4144e45SSimon Glass sub_cmd = arg 136d4144e45SSimon Glass if sub_cmd == 'config': 137d4144e45SSimon Glass return command.CommandResult(return_code=0) 138d4144e45SSimon Glass elif sub_cmd == 'log': 139d4144e45SSimon Glass return self._HandleCommandGitLog(args) 140d4144e45SSimon Glass 141d4144e45SSimon Glass # Not handled, so abort 142d4144e45SSimon Glass print 'git', git_args, sub_cmd, args 143d4144e45SSimon Glass sys.exit(1) 144d4144e45SSimon Glass 145d4144e45SSimon Glass def _HandleCommandNm(self, args): 146d4144e45SSimon Glass return command.CommandResult(return_code=0) 147d4144e45SSimon Glass 148d4144e45SSimon Glass def _HandleCommandObjdump(self, args): 149d4144e45SSimon Glass return command.CommandResult(return_code=0) 150d4144e45SSimon Glass 151d4144e45SSimon Glass def _HandleCommandSize(self, args): 152d4144e45SSimon Glass return command.CommandResult(return_code=0) 153d4144e45SSimon Glass 154d4144e45SSimon Glass def _HandleCommand(self, **kwargs): 155d4144e45SSimon Glass """Handle a command execution. 156d4144e45SSimon Glass 157d4144e45SSimon Glass The command is in kwargs['pipe-list'], as a list of pipes, each a 158d4144e45SSimon Glass list of commands. The command should be emulated as required for 159d4144e45SSimon Glass testing purposes. 160d4144e45SSimon Glass 161d4144e45SSimon Glass Returns: 162d4144e45SSimon Glass A CommandResult object 163d4144e45SSimon Glass """ 164d4144e45SSimon Glass pipe_list = kwargs['pipe_list'] 165d4144e45SSimon Glass if len(pipe_list) != 1: 166d4144e45SSimon Glass print 'invalid pipe', kwargs 167d4144e45SSimon Glass sys.exit(1) 168d4144e45SSimon Glass cmd = pipe_list[0][0] 169d4144e45SSimon Glass args = pipe_list[0][1:] 170d4144e45SSimon Glass if cmd == 'git': 171d4144e45SSimon Glass return self._HandleCommandGit(args) 172d4144e45SSimon Glass elif cmd == './scripts/show-gnu-make': 173d4144e45SSimon Glass return command.CommandResult(return_code=0, stdout='make') 174d4144e45SSimon Glass elif cmd == 'nm': 175d4144e45SSimon Glass return self._HandleCommandNm(args) 176d4144e45SSimon Glass elif cmd == 'objdump': 177d4144e45SSimon Glass return self._HandleCommandObjdump(args) 178d4144e45SSimon Glass elif cmd == 'size': 179d4144e45SSimon Glass return self._HandleCommandSize(args) 180d4144e45SSimon Glass 181d4144e45SSimon Glass # Not handled, so abort 182d4144e45SSimon Glass print 'unknown command', kwargs 183d4144e45SSimon Glass sys.exit(1) 184d4144e45SSimon Glass return command.CommandResult(return_code=0) 185d4144e45SSimon Glass 186d4144e45SSimon Glass def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): 187d4144e45SSimon Glass """Handle execution of 'make' 188d4144e45SSimon Glass 189d4144e45SSimon Glass Args: 190d4144e45SSimon Glass commit: Commit object that is being built 191d4144e45SSimon Glass brd: Board object that is being built 192d4144e45SSimon Glass stage: Stage that we are at (mrproper, config, build) 193d4144e45SSimon Glass cwd: Directory where make should be run 194d4144e45SSimon Glass args: Arguments to pass to make 195d4144e45SSimon Glass kwargs: Arguments to pass to command.RunPipe() 196d4144e45SSimon Glass """ 197d4144e45SSimon Glass if stage == 'mrproper': 198d4144e45SSimon Glass return command.CommandResult(return_code=0) 199d4144e45SSimon Glass elif stage == 'config': 200d4144e45SSimon Glass return command.CommandResult(return_code=0, 201d4144e45SSimon Glass combined='Test configuration complete') 202d4144e45SSimon Glass elif stage == 'build': 203d4144e45SSimon Glass return command.CommandResult(return_code=0) 204d4144e45SSimon Glass 205d4144e45SSimon Glass # Not handled, so abort 206d4144e45SSimon Glass print 'make', stage 207d4144e45SSimon Glass sys.exit(1) 208d4144e45SSimon Glass 209*823e60b6SSimon Glass def testNoBoards(self): 210*823e60b6SSimon Glass """Test that buildman aborts when there are no boards""" 211*823e60b6SSimon Glass self._boards = board.Boards() 212*823e60b6SSimon Glass with self.assertRaises(SystemExit): 213*823e60b6SSimon Glass self._RunControl() 214*823e60b6SSimon Glass 215d4144e45SSimon Glass def testCurrentSource(self): 216d4144e45SSimon Glass """Very simple test to invoke buildman on the current source""" 217d4144e45SSimon Glass self._RunControl() 218d4144e45SSimon Glass lines = terminal.GetPrintTestLines() 219d4144e45SSimon Glass self.assertTrue(lines[0].text.startswith('Building current source')) 220