u-boot/tools/buildman/func_test.py
Simon Glass d4144e45b4 buildman: Add a functional test
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>
2014-09-09 16:38:28 -06:00

182 lines
6.1 KiB
Python

#
# 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'))