xref: /rk3399_rockchip-uboot/tools/buildman/func_test.py (revision d4c8572b7187cc21ca39d185fd19813e69fbd515)
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
13823e60b6SSimon Glassimport board
148b985eebSSimon Glassimport bsettings
15d4144e45SSimon Glassimport cmdline
16d4144e45SSimon Glassimport command
17d4144e45SSimon Glassimport control
18d4144e45SSimon Glassimport gitutil
19d4144e45SSimon Glassimport terminal
20d4144e45SSimon Glassimport toolchain
21d4144e45SSimon Glass
228b985eebSSimon Glasssettings_data = '''
238b985eebSSimon Glass# Buildman settings file
248b985eebSSimon Glass
258b985eebSSimon Glass[toolchain]
268b985eebSSimon Glass
278b985eebSSimon Glass[toolchain-alias]
288b985eebSSimon Glass
298b985eebSSimon Glass[make-flags]
308b985eebSSimon Glasssrc=/home/sjg/c/src
318b985eebSSimon Glasschroot=/home/sjg/c/chroot
328b985eebSSimon Glassvboot=USE_STDINT=1 VBOOT_DEBUG=1 MAKEFLAGS_VBOOT=DEBUG=1 CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS VBOOT_SOURCE=${src}/platform/vboot_reference
338b985eebSSimon Glasschromeos_coreboot=VBOOT=${chroot}/build/link/usr ${vboot}
348b985eebSSimon Glasschromeos_daisy=VBOOT=${chroot}/build/daisy/usr ${vboot}
358b985eebSSimon Glasschromeos_peach=VBOOT=${chroot}/build/peach_pit/usr ${vboot}
368b985eebSSimon Glass'''
378b985eebSSimon Glass
38823e60b6SSimon Glassboards = [
39823e60b6SSimon Glass    ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0',  ''],
40823e60b6SSimon Glass    ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''],
41823e60b6SSimon Glass    ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''],
42823e60b6SSimon Glass    ['Active', 'powerpc', 'mpc5xx', '', 'Tester', 'PowerPC board 2', 'board3', ''],
43823e60b6SSimon Glass    ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
44823e60b6SSimon Glass]
45823e60b6SSimon Glass
46dfb7e932SSimon Glasscommit_shortlog = """4aca821 patman: Avoid changing the order of tags
47dfb7e932SSimon Glass39403bb patman: Use --no-pager' to stop git from forking a pager
48dfb7e932SSimon Glassdb6e6f2 patman: Remove the -a option
49dfb7e932SSimon Glassf2ccf03 patman: Correct unit tests to run correctly
50dfb7e932SSimon Glass1d097f9 patman: Fix indentation in terminal.py
51dfb7e932SSimon Glassd073747 patman: Support the 'reverse' option for 'git log
52dfb7e932SSimon Glass"""
53dfb7e932SSimon Glass
54dfb7e932SSimon Glasscommit_log = ["""commit 7f6b8315d18f683c5181d0c3694818c1b2a20dcd
55dfb7e932SSimon GlassAuthor: Masahiro Yamada <yamada.m@jp.panasonic.com>
56dfb7e932SSimon GlassDate:   Fri Aug 22 19:12:41 2014 +0900
57dfb7e932SSimon Glass
58dfb7e932SSimon Glass    buildman: refactor help message
59dfb7e932SSimon Glass
60dfb7e932SSimon Glass    "buildman [options]" is displayed by default.
61dfb7e932SSimon Glass
62dfb7e932SSimon Glass    Append the rest of help messages to parser.usage
63dfb7e932SSimon Glass    instead of replacing it.
64dfb7e932SSimon Glass
65dfb7e932SSimon Glass    Besides, "-b <branch>" is not mandatory since commit fea5858e.
66dfb7e932SSimon Glass    Drop it from the usage.
67dfb7e932SSimon Glass
68dfb7e932SSimon Glass    Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
69dfb7e932SSimon Glass""",
70dfb7e932SSimon Glass"""commit d0737479be6baf4db5e2cdbee123e96bc5ed0ba8
71dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org>
72dfb7e932SSimon GlassDate:   Thu Aug 14 16:48:25 2014 -0600
73dfb7e932SSimon Glass
74dfb7e932SSimon Glass    patman: Support the 'reverse' option for 'git log'
75dfb7e932SSimon Glass
76dfb7e932SSimon Glass    This option is currently not supported, but needs to be, for buildman to
77dfb7e932SSimon Glass    operate as expected.
78dfb7e932SSimon Glass
79dfb7e932SSimon Glass    Series-changes: 7
80dfb7e932SSimon Glass    - Add new patch to fix the 'reverse' bug
81dfb7e932SSimon Glass
82950a2313SSimon Glass    Series-version: 8
83dfb7e932SSimon Glass
84dfb7e932SSimon Glass    Change-Id: I79078f792e8b390b8a1272a8023537821d45feda
85dfb7e932SSimon Glass    Reported-by: York Sun <yorksun@freescale.com>
86dfb7e932SSimon Glass    Signed-off-by: Simon Glass <sjg@chromium.org>
87dfb7e932SSimon Glass
88dfb7e932SSimon Glass""",
89dfb7e932SSimon Glass"""commit 1d097f9ab487c5019152fd47bda126839f3bf9fc
90dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org>
91dfb7e932SSimon GlassDate:   Sat Aug 9 11:44:32 2014 -0600
92dfb7e932SSimon Glass
93dfb7e932SSimon Glass    patman: Fix indentation in terminal.py
94dfb7e932SSimon Glass
95dfb7e932SSimon Glass    This code came from a different project with 2-character indentation. Fix
96dfb7e932SSimon Glass    it for U-Boot.
97dfb7e932SSimon Glass
98dfb7e932SSimon Glass    Series-changes: 6
99dfb7e932SSimon Glass    - Add new patch to fix indentation in teminal.py
100dfb7e932SSimon Glass
101dfb7e932SSimon Glass    Change-Id: I5a74d2ebbb3cc12a665f5c725064009ac96e8a34
102dfb7e932SSimon Glass    Signed-off-by: Simon Glass <sjg@chromium.org>
103dfb7e932SSimon Glass
104dfb7e932SSimon Glass""",
105dfb7e932SSimon Glass"""commit f2ccf03869d1e152c836515a3ceb83cdfe04a105
106dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org>
107dfb7e932SSimon GlassDate:   Sat Aug 9 11:08:24 2014 -0600
108dfb7e932SSimon Glass
109dfb7e932SSimon Glass    patman: Correct unit tests to run correctly
110dfb7e932SSimon Glass
111dfb7e932SSimon Glass    It seems that doctest behaves differently now, and some of the unit tests
112dfb7e932SSimon Glass    do not run. Adjust the tests to work correctly.
113dfb7e932SSimon Glass
114dfb7e932SSimon Glass     ./tools/patman/patman --test
115dfb7e932SSimon Glass    <unittest.result.TestResult run=10 errors=0 failures=0>
116dfb7e932SSimon Glass
117dfb7e932SSimon Glass    Series-changes: 6
118dfb7e932SSimon Glass    - Add new patch to fix patman unit tests
119dfb7e932SSimon Glass
120dfb7e932SSimon Glass    Change-Id: I3d2ca588f4933e1f9d6b1665a00e4ae58269ff3b
121dfb7e932SSimon Glass
122dfb7e932SSimon Glass""",
123dfb7e932SSimon Glass"""commit db6e6f2f9331c5a37647d6668768d4a40b8b0d1c
124dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org>
125dfb7e932SSimon GlassDate:   Sat Aug 9 12:06:02 2014 -0600
126dfb7e932SSimon Glass
127dfb7e932SSimon Glass    patman: Remove the -a option
128dfb7e932SSimon Glass
129dfb7e932SSimon Glass    It seems that this is no longer needed, since checkpatch.pl will catch
130dfb7e932SSimon Glass    whitespace problems in patches. Also the option is not widely used, so
131dfb7e932SSimon Glass    it seems safe to just remove it.
132dfb7e932SSimon Glass
133dfb7e932SSimon Glass    Series-changes: 6
134dfb7e932SSimon Glass    - Add new patch to remove patman's -a option
135dfb7e932SSimon Glass
136dfb7e932SSimon Glass    Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
137dfb7e932SSimon Glass    Change-Id: I5821a1c75154e532c46513486ca40b808de7e2cc
138dfb7e932SSimon Glass
139dfb7e932SSimon Glass""",
140dfb7e932SSimon Glass"""commit 39403bb4f838153028a6f21ca30bf100f3791133
141dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org>
142dfb7e932SSimon GlassDate:   Thu Aug 14 21:50:52 2014 -0600
143dfb7e932SSimon Glass
144dfb7e932SSimon Glass    patman: Use --no-pager' to stop git from forking a pager
145dfb7e932SSimon Glass
146dfb7e932SSimon Glass""",
147dfb7e932SSimon Glass"""commit 4aca821e27e97925c039e69fd37375b09c6f129c
148dfb7e932SSimon GlassAuthor: Simon Glass <sjg@chromium.org>
149dfb7e932SSimon GlassDate:   Fri Aug 22 15:57:39 2014 -0600
150dfb7e932SSimon Glass
151dfb7e932SSimon Glass    patman: Avoid changing the order of tags
152dfb7e932SSimon Glass
153dfb7e932SSimon Glass    patman collects tags that it sees in the commit and places them nicely
154dfb7e932SSimon Glass    sorted at the end of the patch. However, this is not really necessary and
155dfb7e932SSimon Glass    in fact is apparently not desirable.
156dfb7e932SSimon Glass
157dfb7e932SSimon Glass    Series-changes: 9
158dfb7e932SSimon Glass    - Add new patch to avoid changing the order of tags
159dfb7e932SSimon Glass
160950a2313SSimon Glass    Series-version: 9
161950a2313SSimon Glass
162dfb7e932SSimon Glass    Suggested-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
163dfb7e932SSimon Glass    Change-Id: Ib1518588c1a189ad5c3198aae76f8654aed8d0db
164dfb7e932SSimon Glass"""]
165dfb7e932SSimon Glass
166dfb7e932SSimon GlassTEST_BRANCH = '__testbranch'
167dfb7e932SSimon Glass
168d4144e45SSimon Glassclass TestFunctional(unittest.TestCase):
169d4144e45SSimon Glass    """Functional test for buildman.
170d4144e45SSimon Glass
171d4144e45SSimon Glass    This aims to test from just below the invocation of buildman (parsing
172d4144e45SSimon Glass    of arguments) to 'make' and 'git' invocation. It is not a true
173d4144e45SSimon Glass    emd-to-end test, as it mocks git, make and the tool chain. But this
174d4144e45SSimon Glass    makes it easier to detect when the builder is doing the wrong thing,
175d4144e45SSimon Glass    since in many cases this test code will fail. For example, only a
176d4144e45SSimon Glass    very limited subset of 'git' arguments is supported - anything
177d4144e45SSimon Glass    unexpected will fail.
178d4144e45SSimon Glass    """
179d4144e45SSimon Glass    def setUp(self):
180d4144e45SSimon Glass        self._base_dir = tempfile.mkdtemp()
181d4144e45SSimon Glass        self._git_dir = os.path.join(self._base_dir, 'src')
182d4144e45SSimon Glass        self._buildman_pathname = sys.argv[0]
183d4144e45SSimon Glass        self._buildman_dir = os.path.dirname(sys.argv[0])
184d4144e45SSimon Glass        command.test_result = self._HandleCommand
185dfb7e932SSimon Glass        self.setupToolchains()
186dfb7e932SSimon Glass        self._toolchains.Add('arm-gcc', test=False)
187dfb7e932SSimon Glass        self._toolchains.Add('powerpc-gcc', test=False)
1888b985eebSSimon Glass        bsettings.Setup(None)
1898b985eebSSimon Glass        bsettings.AddFile(settings_data)
190823e60b6SSimon Glass        self._boards = board.Boards()
191823e60b6SSimon Glass        for brd in boards:
192823e60b6SSimon Glass            self._boards.AddBoard(board.Board(*brd))
193d4144e45SSimon Glass
194dfb7e932SSimon Glass        # Directories where the source been cloned
195dfb7e932SSimon Glass        self._clone_dirs = []
196dfb7e932SSimon Glass        self._commits = len(commit_shortlog.splitlines()) + 1
197dfb7e932SSimon Glass        self._total_builds = self._commits * len(boards)
198dfb7e932SSimon Glass
199dfb7e932SSimon Glass        # Number of calls to make
200dfb7e932SSimon Glass        self._make_calls = 0
201dfb7e932SSimon Glass
202dfb7e932SSimon Glass        # Map of [board, commit] to error messages
203dfb7e932SSimon Glass        self._error = {}
204dfb7e932SSimon Glass
205f7582ce8SSimon Glass        self._test_branch = TEST_BRANCH
206f7582ce8SSimon Glass
207dfb7e932SSimon Glass        # Avoid sending any output and clear all terminal output
208dfb7e932SSimon Glass        terminal.SetPrintTestMode()
209dfb7e932SSimon Glass        terminal.GetPrintTestLines()
210dfb7e932SSimon Glass
211d4144e45SSimon Glass    def tearDown(self):
212d4144e45SSimon Glass        shutil.rmtree(self._base_dir)
213d4144e45SSimon Glass
214dfb7e932SSimon Glass    def setupToolchains(self):
215dfb7e932SSimon Glass        self._toolchains = toolchain.Toolchains()
216dfb7e932SSimon Glass        self._toolchains.Add('gcc', test=False)
217dfb7e932SSimon Glass
218d4144e45SSimon Glass    def _RunBuildman(self, *args):
219d4144e45SSimon Glass        return command.RunPipe([[self._buildman_pathname] + list(args)],
220d4144e45SSimon Glass                capture=True, capture_stderr=True)
221d4144e45SSimon Glass
222dfb7e932SSimon Glass    def _RunControl(self, *args, **kwargs):
223d4144e45SSimon Glass        sys.argv = [sys.argv[0]] + list(args)
224d4144e45SSimon Glass        options, args = cmdline.ParseArgs()
225dfb7e932SSimon Glass        result = control.DoBuildman(options, args, toolchains=self._toolchains,
226dfb7e932SSimon Glass                make_func=self._HandleMake, boards=self._boards,
227dfb7e932SSimon Glass                clean_dir=kwargs.get('clean_dir', True))
228dfb7e932SSimon Glass        self._builder = control.builder
229dfb7e932SSimon Glass        return result
230d4144e45SSimon Glass
231d4144e45SSimon Glass    def testFullHelp(self):
232d4144e45SSimon Glass        command.test_result = None
233d4144e45SSimon Glass        result = self._RunBuildman('-H')
234d4144e45SSimon Glass        help_file = os.path.join(self._buildman_dir, 'README')
235d4144e45SSimon Glass        self.assertEqual(len(result.stdout), os.path.getsize(help_file))
236d4144e45SSimon Glass        self.assertEqual(0, len(result.stderr))
237d4144e45SSimon Glass        self.assertEqual(0, result.return_code)
238d4144e45SSimon Glass
239d4144e45SSimon Glass    def testHelp(self):
240d4144e45SSimon Glass        command.test_result = None
241d4144e45SSimon Glass        result = self._RunBuildman('-h')
242d4144e45SSimon Glass        help_file = os.path.join(self._buildman_dir, 'README')
243d4144e45SSimon Glass        self.assertTrue(len(result.stdout) > 1000)
244d4144e45SSimon Glass        self.assertEqual(0, len(result.stderr))
245d4144e45SSimon Glass        self.assertEqual(0, result.return_code)
246d4144e45SSimon Glass
247d4144e45SSimon Glass    def testGitSetup(self):
248d4144e45SSimon Glass        """Test gitutils.Setup(), from outside the module itself"""
249d4144e45SSimon Glass        command.test_result = command.CommandResult(return_code=1)
250d4144e45SSimon Glass        gitutil.Setup()
251d4144e45SSimon Glass        self.assertEqual(gitutil.use_no_decorate, False)
252d4144e45SSimon Glass
253d4144e45SSimon Glass        command.test_result = command.CommandResult(return_code=0)
254d4144e45SSimon Glass        gitutil.Setup()
255d4144e45SSimon Glass        self.assertEqual(gitutil.use_no_decorate, True)
256d4144e45SSimon Glass
257d4144e45SSimon Glass    def _HandleCommandGitLog(self, args):
258*d4c8572bSSimon Glass        if args[-1] == '--':
259*d4c8572bSSimon Glass            args = args[:-1]
260d4144e45SSimon Glass        if '-n0' in args:
261d4144e45SSimon Glass            return command.CommandResult(return_code=0)
262f7582ce8SSimon Glass        elif args[-1] == 'upstream/master..%s' % self._test_branch:
263dfb7e932SSimon Glass            return command.CommandResult(return_code=0, stdout=commit_shortlog)
264dfb7e932SSimon Glass        elif args[:3] == ['--no-color', '--no-decorate', '--reverse']:
265f7582ce8SSimon Glass            if args[-1] == self._test_branch:
266dfb7e932SSimon Glass                count = int(args[3][2:])
267dfb7e932SSimon Glass                return command.CommandResult(return_code=0,
268dfb7e932SSimon Glass                                            stdout=''.join(commit_log[:count]))
269d4144e45SSimon Glass
270d4144e45SSimon Glass        # Not handled, so abort
271d4144e45SSimon Glass        print 'git log', args
272d4144e45SSimon Glass        sys.exit(1)
273d4144e45SSimon Glass
274dfb7e932SSimon Glass    def _HandleCommandGitConfig(self, args):
275dfb7e932SSimon Glass        config = args[0]
276dfb7e932SSimon Glass        if config == 'sendemail.aliasesfile':
277dfb7e932SSimon Glass            return command.CommandResult(return_code=0)
278dfb7e932SSimon Glass        elif config.startswith('branch.badbranch'):
279dfb7e932SSimon Glass            return command.CommandResult(return_code=1)
280f7582ce8SSimon Glass        elif config == 'branch.%s.remote' % self._test_branch:
281dfb7e932SSimon Glass            return command.CommandResult(return_code=0, stdout='upstream\n')
282f7582ce8SSimon Glass        elif config == 'branch.%s.merge' % self._test_branch:
283dfb7e932SSimon Glass            return command.CommandResult(return_code=0,
284dfb7e932SSimon Glass                                         stdout='refs/heads/master\n')
285dfb7e932SSimon Glass
286dfb7e932SSimon Glass        # Not handled, so abort
287dfb7e932SSimon Glass        print 'git config', args
288dfb7e932SSimon Glass        sys.exit(1)
289dfb7e932SSimon Glass
290d4144e45SSimon Glass    def _HandleCommandGit(self, in_args):
291d4144e45SSimon Glass        """Handle execution of a git command
292d4144e45SSimon Glass
293d4144e45SSimon Glass        This uses a hacked-up parser.
294d4144e45SSimon Glass
295d4144e45SSimon Glass        Args:
296d4144e45SSimon Glass            in_args: Arguments after 'git' from the command line
297d4144e45SSimon Glass        """
298d4144e45SSimon Glass        git_args = []           # Top-level arguments to git itself
299d4144e45SSimon Glass        sub_cmd = None          # Git sub-command selected
300d4144e45SSimon Glass        args = []               # Arguments to the git sub-command
301d4144e45SSimon Glass        for arg in in_args:
302d4144e45SSimon Glass            if sub_cmd:
303d4144e45SSimon Glass                args.append(arg)
304d4144e45SSimon Glass            elif arg[0] == '-':
305d4144e45SSimon Glass                git_args.append(arg)
306d4144e45SSimon Glass            else:
307dfb7e932SSimon Glass                if git_args and git_args[-1] in ['--git-dir', '--work-tree']:
308dfb7e932SSimon Glass                    git_args.append(arg)
309dfb7e932SSimon Glass                else:
310d4144e45SSimon Glass                    sub_cmd = arg
311d4144e45SSimon Glass        if sub_cmd == 'config':
312dfb7e932SSimon Glass            return self._HandleCommandGitConfig(args)
313d4144e45SSimon Glass        elif sub_cmd == 'log':
314d4144e45SSimon Glass            return self._HandleCommandGitLog(args)
315dfb7e932SSimon Glass        elif sub_cmd == 'clone':
316dfb7e932SSimon Glass            return command.CommandResult(return_code=0)
317dfb7e932SSimon Glass        elif sub_cmd == 'checkout':
318dfb7e932SSimon Glass            return command.CommandResult(return_code=0)
319d4144e45SSimon Glass
320d4144e45SSimon Glass        # Not handled, so abort
321d4144e45SSimon Glass        print 'git', git_args, sub_cmd, args
322d4144e45SSimon Glass        sys.exit(1)
323d4144e45SSimon Glass
324d4144e45SSimon Glass    def _HandleCommandNm(self, args):
325d4144e45SSimon Glass        return command.CommandResult(return_code=0)
326d4144e45SSimon Glass
327d4144e45SSimon Glass    def _HandleCommandObjdump(self, args):
328d4144e45SSimon Glass        return command.CommandResult(return_code=0)
329d4144e45SSimon Glass
330d4144e45SSimon Glass    def _HandleCommandSize(self, args):
331d4144e45SSimon Glass        return command.CommandResult(return_code=0)
332d4144e45SSimon Glass
333d4144e45SSimon Glass    def _HandleCommand(self, **kwargs):
334d4144e45SSimon Glass        """Handle a command execution.
335d4144e45SSimon Glass
336d4144e45SSimon Glass        The command is in kwargs['pipe-list'], as a list of pipes, each a
337d4144e45SSimon Glass        list of commands. The command should be emulated as required for
338d4144e45SSimon Glass        testing purposes.
339d4144e45SSimon Glass
340d4144e45SSimon Glass        Returns:
341d4144e45SSimon Glass            A CommandResult object
342d4144e45SSimon Glass        """
343d4144e45SSimon Glass        pipe_list = kwargs['pipe_list']
344dfb7e932SSimon Glass        wc = False
345d4144e45SSimon Glass        if len(pipe_list) != 1:
346dfb7e932SSimon Glass            if pipe_list[1] == ['wc', '-l']:
347dfb7e932SSimon Glass                wc = True
348dfb7e932SSimon Glass            else:
349d4144e45SSimon Glass                print 'invalid pipe', kwargs
350d4144e45SSimon Glass                sys.exit(1)
351d4144e45SSimon Glass        cmd = pipe_list[0][0]
352d4144e45SSimon Glass        args = pipe_list[0][1:]
353dfb7e932SSimon Glass        result = None
354d4144e45SSimon Glass        if cmd == 'git':
355dfb7e932SSimon Glass            result = self._HandleCommandGit(args)
356d4144e45SSimon Glass        elif cmd == './scripts/show-gnu-make':
357d4144e45SSimon Glass            return command.CommandResult(return_code=0, stdout='make')
358dfb7e932SSimon Glass        elif cmd.endswith('nm'):
359d4144e45SSimon Glass            return self._HandleCommandNm(args)
360dfb7e932SSimon Glass        elif cmd.endswith('objdump'):
361d4144e45SSimon Glass            return self._HandleCommandObjdump(args)
362dfb7e932SSimon Glass        elif cmd.endswith( 'size'):
363d4144e45SSimon Glass            return self._HandleCommandSize(args)
364d4144e45SSimon Glass
365dfb7e932SSimon Glass        if not result:
366d4144e45SSimon Glass            # Not handled, so abort
367d4144e45SSimon Glass            print 'unknown command', kwargs
368d4144e45SSimon Glass            sys.exit(1)
369dfb7e932SSimon Glass
370dfb7e932SSimon Glass        if wc:
371dfb7e932SSimon Glass            result.stdout = len(result.stdout.splitlines())
372dfb7e932SSimon Glass        return result
373d4144e45SSimon Glass
374d4144e45SSimon Glass    def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs):
375d4144e45SSimon Glass        """Handle execution of 'make'
376d4144e45SSimon Glass
377d4144e45SSimon Glass        Args:
378d4144e45SSimon Glass            commit: Commit object that is being built
379d4144e45SSimon Glass            brd: Board object that is being built
380d4144e45SSimon Glass            stage: Stage that we are at (mrproper, config, build)
381d4144e45SSimon Glass            cwd: Directory where make should be run
382d4144e45SSimon Glass            args: Arguments to pass to make
383d4144e45SSimon Glass            kwargs: Arguments to pass to command.RunPipe()
384d4144e45SSimon Glass        """
385dfb7e932SSimon Glass        self._make_calls += 1
386d4144e45SSimon Glass        if stage == 'mrproper':
387d4144e45SSimon Glass            return command.CommandResult(return_code=0)
388d4144e45SSimon Glass        elif stage == 'config':
389d4144e45SSimon Glass            return command.CommandResult(return_code=0,
390d4144e45SSimon Glass                    combined='Test configuration complete')
391d4144e45SSimon Glass        elif stage == 'build':
392dfb7e932SSimon Glass            stderr = ''
393dfb7e932SSimon Glass            if type(commit) is not str:
394dfb7e932SSimon Glass                stderr = self._error.get((brd.target, commit.sequence))
395dfb7e932SSimon Glass            if stderr:
396dfb7e932SSimon Glass                return command.CommandResult(return_code=1, stderr=stderr)
397d4144e45SSimon Glass            return command.CommandResult(return_code=0)
398d4144e45SSimon Glass
399d4144e45SSimon Glass        # Not handled, so abort
400d4144e45SSimon Glass        print 'make', stage
401d4144e45SSimon Glass        sys.exit(1)
402d4144e45SSimon Glass
403dfb7e932SSimon Glass    # Example function to print output lines
404dfb7e932SSimon Glass    def print_lines(self, lines):
405dfb7e932SSimon Glass        print len(lines)
406dfb7e932SSimon Glass        for line in lines:
407dfb7e932SSimon Glass            print line
408dfb7e932SSimon Glass        #self.print_lines(terminal.GetPrintTestLines())
409dfb7e932SSimon Glass
410823e60b6SSimon Glass    def testNoBoards(self):
411823e60b6SSimon Glass        """Test that buildman aborts when there are no boards"""
412823e60b6SSimon Glass        self._boards = board.Boards()
413823e60b6SSimon Glass        with self.assertRaises(SystemExit):
414823e60b6SSimon Glass            self._RunControl()
415823e60b6SSimon Glass
416d4144e45SSimon Glass    def testCurrentSource(self):
417d4144e45SSimon Glass        """Very simple test to invoke buildman on the current source"""
418dfb7e932SSimon Glass        self.setupToolchains();
419d4144e45SSimon Glass        self._RunControl()
420d4144e45SSimon Glass        lines = terminal.GetPrintTestLines()
421dfb7e932SSimon Glass        self.assertIn('Building current source for %d boards' % len(boards),
422dfb7e932SSimon Glass                      lines[0].text)
423dfb7e932SSimon Glass
424dfb7e932SSimon Glass    def testBadBranch(self):
425dfb7e932SSimon Glass        """Test that we can detect an invalid branch"""
426dfb7e932SSimon Glass        with self.assertRaises(ValueError):
427dfb7e932SSimon Glass            self._RunControl('-b', 'badbranch')
428dfb7e932SSimon Glass
429dfb7e932SSimon Glass    def testBadToolchain(self):
430dfb7e932SSimon Glass        """Test that missing toolchains are detected"""
431dfb7e932SSimon Glass        self.setupToolchains();
432dfb7e932SSimon Glass        ret_code = self._RunControl('-b', TEST_BRANCH)
433dfb7e932SSimon Glass        lines = terminal.GetPrintTestLines()
434dfb7e932SSimon Glass
435dfb7e932SSimon Glass        # Buildman always builds the upstream commit as well
436dfb7e932SSimon Glass        self.assertIn('Building %d commits for %d boards' %
437dfb7e932SSimon Glass                (self._commits, len(boards)), lines[0].text)
438dfb7e932SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
439dfb7e932SSimon Glass
440dfb7e932SSimon Glass        # Only sandbox should succeed, the others don't have toolchains
441dfb7e932SSimon Glass        self.assertEqual(self._builder.fail,
442dfb7e932SSimon Glass                         self._total_builds - self._commits)
443dfb7e932SSimon Glass        self.assertEqual(ret_code, 128)
444dfb7e932SSimon Glass
445dfb7e932SSimon Glass        for commit in range(self._commits):
446dfb7e932SSimon Glass            for board in self._boards.GetList():
447dfb7e932SSimon Glass                if board.arch != 'sandbox':
448dfb7e932SSimon Glass                  errfile = self._builder.GetErrFile(commit, board.target)
449dfb7e932SSimon Glass                  fd = open(errfile)
450dfb7e932SSimon Glass                  self.assertEqual(fd.readlines(),
451dfb7e932SSimon Glass                          ['No tool chain for %s\n' % board.arch])
452dfb7e932SSimon Glass                  fd.close()
453dfb7e932SSimon Glass
454dfb7e932SSimon Glass    def testBranch(self):
455dfb7e932SSimon Glass        """Test building a branch with all toolchains present"""
456dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH)
457dfb7e932SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
458dfb7e932SSimon Glass        self.assertEqual(self._builder.fail, 0)
459dfb7e932SSimon Glass
460dfb7e932SSimon Glass    def testCount(self):
461dfb7e932SSimon Glass        """Test building a specific number of commitst"""
462dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH, '-c2')
463dfb7e932SSimon Glass        self.assertEqual(self._builder.count, 2 * len(boards))
464dfb7e932SSimon Glass        self.assertEqual(self._builder.fail, 0)
465dfb7e932SSimon Glass        # Each board has a mrproper, config, and then one make per commit
466dfb7e932SSimon Glass        self.assertEqual(self._make_calls, len(boards) * (2 + 2))
467dfb7e932SSimon Glass
468dfb7e932SSimon Glass    def testIncremental(self):
469dfb7e932SSimon Glass        """Test building a branch twice - the second time should do nothing"""
470dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH)
471dfb7e932SSimon Glass
472dfb7e932SSimon Glass        # Each board has a mrproper, config, and then one make per commit
473dfb7e932SSimon Glass        self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
474dfb7e932SSimon Glass        self._make_calls = 0
475dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH, clean_dir=False)
476dfb7e932SSimon Glass        self.assertEqual(self._make_calls, 0)
477dfb7e932SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
478dfb7e932SSimon Glass        self.assertEqual(self._builder.fail, 0)
479dfb7e932SSimon Glass
480dfb7e932SSimon Glass    def testForceBuild(self):
481dfb7e932SSimon Glass        """The -f flag should force a rebuild"""
482dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH)
483dfb7e932SSimon Glass        self._make_calls = 0
484dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH, '-f', clean_dir=False)
485dfb7e932SSimon Glass        # Each board has a mrproper, config, and then one make per commit
486dfb7e932SSimon Glass        self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
487dfb7e932SSimon Glass
488dfb7e932SSimon Glass    def testForceReconfigure(self):
489dfb7e932SSimon Glass        """The -f flag should force a rebuild"""
490dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH, '-C')
491dfb7e932SSimon Glass        # Each commit has a mrproper, config and make
492dfb7e932SSimon Glass        self.assertEqual(self._make_calls, len(boards) * self._commits * 3)
493dfb7e932SSimon Glass
494dfb7e932SSimon Glass    def testErrors(self):
495dfb7e932SSimon Glass        """Test handling of build errors"""
496dfb7e932SSimon Glass        self._error['board2', 1] = 'fred\n'
497dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH)
498dfb7e932SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
499dfb7e932SSimon Glass        self.assertEqual(self._builder.fail, 1)
500dfb7e932SSimon Glass
501dfb7e932SSimon Glass        # Remove the error. This should have no effect since the commit will
502dfb7e932SSimon Glass        # not be rebuilt
503dfb7e932SSimon Glass        del self._error['board2', 1]
504dfb7e932SSimon Glass        self._make_calls = 0
505dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH, clean_dir=False)
506dfb7e932SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
507dfb7e932SSimon Glass        self.assertEqual(self._make_calls, 0)
508dfb7e932SSimon Glass        self.assertEqual(self._builder.fail, 1)
509dfb7e932SSimon Glass
510dfb7e932SSimon Glass        # Now use the -F flag to force rebuild of the bad commit
511dfb7e932SSimon Glass        self._RunControl('-b', TEST_BRANCH, '-F', clean_dir=False)
512dfb7e932SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
513dfb7e932SSimon Glass        self.assertEqual(self._builder.fail, 0)
514dfb7e932SSimon Glass        self.assertEqual(self._make_calls, 3)
515f7582ce8SSimon Glass
516f7582ce8SSimon Glass    def testBranchWithSlash(self):
517f7582ce8SSimon Glass        """Test building a branch with a '/' in the name"""
518f7582ce8SSimon Glass        self._test_branch = '/__dev/__testbranch'
519f7582ce8SSimon Glass        self._RunControl('-b', self._test_branch, clean_dir=False)
520f7582ce8SSimon Glass        self.assertEqual(self._builder.count, self._total_builds)
521f7582ce8SSimon Glass        self.assertEqual(self._builder.fail, 0)
522