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