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