Buildman currently lacks testing in many areas, including its use of git, make and many command-line flags. Add a functional test which covers some of these areas. So far it does a fake 'build' of all boards for the current source tree. This version reads the real ~/.buildman and boards.cfg files. Future work will improve this. Signed-off-by: Simon Glass <sjg@chromium.org>master
parent
82012dd284
commit
d4144e45b4
@ -0,0 +1,182 @@ |
|||||||
|
# |
||||||
|
# Copyright (c) 2014 Google, Inc |
||||||
|
# |
||||||
|
# SPDX-License-Identifier: GPL-2.0+ |
||||||
|
# |
||||||
|
|
||||||
|
import os |
||||||
|
import shutil |
||||||
|
import sys |
||||||
|
import tempfile |
||||||
|
import unittest |
||||||
|
|
||||||
|
import cmdline |
||||||
|
import command |
||||||
|
import control |
||||||
|
import gitutil |
||||||
|
import terminal |
||||||
|
import toolchain |
||||||
|
|
||||||
|
class TestFunctional(unittest.TestCase): |
||||||
|
"""Functional test for buildman. |
||||||
|
|
||||||
|
This aims to test from just below the invocation of buildman (parsing |
||||||
|
of arguments) to 'make' and 'git' invocation. It is not a true |
||||||
|
emd-to-end test, as it mocks git, make and the tool chain. But this |
||||||
|
makes it easier to detect when the builder is doing the wrong thing, |
||||||
|
since in many cases this test code will fail. For example, only a |
||||||
|
very limited subset of 'git' arguments is supported - anything |
||||||
|
unexpected will fail. |
||||||
|
""" |
||||||
|
def setUp(self): |
||||||
|
self._base_dir = tempfile.mkdtemp() |
||||||
|
self._git_dir = os.path.join(self._base_dir, 'src') |
||||||
|
self._buildman_pathname = sys.argv[0] |
||||||
|
self._buildman_dir = os.path.dirname(sys.argv[0]) |
||||||
|
command.test_result = self._HandleCommand |
||||||
|
self._toolchains = toolchain.Toolchains() |
||||||
|
self._toolchains.Add('gcc', test=False) |
||||||
|
|
||||||
|
def tearDown(self): |
||||||
|
shutil.rmtree(self._base_dir) |
||||||
|
|
||||||
|
def _RunBuildman(self, *args): |
||||||
|
return command.RunPipe([[self._buildman_pathname] + list(args)], |
||||||
|
capture=True, capture_stderr=True) |
||||||
|
|
||||||
|
def _RunControl(self, *args): |
||||||
|
sys.argv = [sys.argv[0]] + list(args) |
||||||
|
options, args = cmdline.ParseArgs() |
||||||
|
return control.DoBuildman(options, args, toolchains=self._toolchains, |
||||||
|
make_func=self._HandleMake) |
||||||
|
|
||||||
|
def testFullHelp(self): |
||||||
|
command.test_result = None |
||||||
|
result = self._RunBuildman('-H') |
||||||
|
help_file = os.path.join(self._buildman_dir, 'README') |
||||||
|
self.assertEqual(len(result.stdout), os.path.getsize(help_file)) |
||||||
|
self.assertEqual(0, len(result.stderr)) |
||||||
|
self.assertEqual(0, result.return_code) |
||||||
|
|
||||||
|
def testHelp(self): |
||||||
|
command.test_result = None |
||||||
|
result = self._RunBuildman('-h') |
||||||
|
help_file = os.path.join(self._buildman_dir, 'README') |
||||||
|
self.assertTrue(len(result.stdout) > 1000) |
||||||
|
self.assertEqual(0, len(result.stderr)) |
||||||
|
self.assertEqual(0, result.return_code) |
||||||
|
|
||||||
|
def testGitSetup(self): |
||||||
|
"""Test gitutils.Setup(), from outside the module itself""" |
||||||
|
command.test_result = command.CommandResult(return_code=1) |
||||||
|
gitutil.Setup() |
||||||
|
self.assertEqual(gitutil.use_no_decorate, False) |
||||||
|
|
||||||
|
command.test_result = command.CommandResult(return_code=0) |
||||||
|
gitutil.Setup() |
||||||
|
self.assertEqual(gitutil.use_no_decorate, True) |
||||||
|
|
||||||
|
def _HandleCommandGitLog(self, args): |
||||||
|
if '-n0' in args: |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
|
||||||
|
# Not handled, so abort |
||||||
|
print 'git log', args |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
def _HandleCommandGit(self, in_args): |
||||||
|
"""Handle execution of a git command |
||||||
|
|
||||||
|
This uses a hacked-up parser. |
||||||
|
|
||||||
|
Args: |
||||||
|
in_args: Arguments after 'git' from the command line |
||||||
|
""" |
||||||
|
git_args = [] # Top-level arguments to git itself |
||||||
|
sub_cmd = None # Git sub-command selected |
||||||
|
args = [] # Arguments to the git sub-command |
||||||
|
for arg in in_args: |
||||||
|
if sub_cmd: |
||||||
|
args.append(arg) |
||||||
|
elif arg[0] == '-': |
||||||
|
git_args.append(arg) |
||||||
|
else: |
||||||
|
sub_cmd = arg |
||||||
|
if sub_cmd == 'config': |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
elif sub_cmd == 'log': |
||||||
|
return self._HandleCommandGitLog(args) |
||||||
|
|
||||||
|
# Not handled, so abort |
||||||
|
print 'git', git_args, sub_cmd, args |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
def _HandleCommandNm(self, args): |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
|
||||||
|
def _HandleCommandObjdump(self, args): |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
|
||||||
|
def _HandleCommandSize(self, args): |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
|
||||||
|
def _HandleCommand(self, **kwargs): |
||||||
|
"""Handle a command execution. |
||||||
|
|
||||||
|
The command is in kwargs['pipe-list'], as a list of pipes, each a |
||||||
|
list of commands. The command should be emulated as required for |
||||||
|
testing purposes. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A CommandResult object |
||||||
|
""" |
||||||
|
pipe_list = kwargs['pipe_list'] |
||||||
|
if len(pipe_list) != 1: |
||||||
|
print 'invalid pipe', kwargs |
||||||
|
sys.exit(1) |
||||||
|
cmd = pipe_list[0][0] |
||||||
|
args = pipe_list[0][1:] |
||||||
|
if cmd == 'git': |
||||||
|
return self._HandleCommandGit(args) |
||||||
|
elif cmd == './scripts/show-gnu-make': |
||||||
|
return command.CommandResult(return_code=0, stdout='make') |
||||||
|
elif cmd == 'nm': |
||||||
|
return self._HandleCommandNm(args) |
||||||
|
elif cmd == 'objdump': |
||||||
|
return self._HandleCommandObjdump(args) |
||||||
|
elif cmd == 'size': |
||||||
|
return self._HandleCommandSize(args) |
||||||
|
|
||||||
|
# Not handled, so abort |
||||||
|
print 'unknown command', kwargs |
||||||
|
sys.exit(1) |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
|
||||||
|
def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): |
||||||
|
"""Handle execution of 'make' |
||||||
|
|
||||||
|
Args: |
||||||
|
commit: Commit object that is being built |
||||||
|
brd: Board object that is being built |
||||||
|
stage: Stage that we are at (mrproper, config, build) |
||||||
|
cwd: Directory where make should be run |
||||||
|
args: Arguments to pass to make |
||||||
|
kwargs: Arguments to pass to command.RunPipe() |
||||||
|
""" |
||||||
|
if stage == 'mrproper': |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
elif stage == 'config': |
||||||
|
return command.CommandResult(return_code=0, |
||||||
|
combined='Test configuration complete') |
||||||
|
elif stage == 'build': |
||||||
|
return command.CommandResult(return_code=0) |
||||||
|
|
||||||
|
# Not handled, so abort |
||||||
|
print 'make', stage |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
def testCurrentSource(self): |
||||||
|
"""Very simple test to invoke buildman on the current source""" |
||||||
|
self._RunControl() |
||||||
|
lines = terminal.GetPrintTestLines() |
||||||
|
self.assertTrue(lines[0].text.startswith('Building current source')) |
Loading…
Reference in new issue