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