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