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