blob: 237a80b4301a4977ec49182bb1a05a7ba7f0f816 [file] [log] [blame]
Simon Glassd4144e42014-09-05 19:00:13 -06001#
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
Simon Glass823e60b2014-09-05 19:00:16 -060013import board
Simon Glass8b985ee2014-09-05 19:00:15 -060014import bsettings
Simon Glassd4144e42014-09-05 19:00:13 -060015import cmdline
16import command
17import control
18import gitutil
19import terminal
20import toolchain
21
Simon Glass8b985ee2014-09-05 19:00:15 -060022settings_data = '''
23# Buildman settings file
24
25[toolchain]
26
27[toolchain-alias]
28
29[make-flags]
30src=/home/sjg/c/src
31chroot=/home/sjg/c/chroot
32vboot=USE_STDINT=1 VBOOT_DEBUG=1 MAKEFLAGS_VBOOT=DEBUG=1 CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS VBOOT_SOURCE=${src}/platform/vboot_reference
33chromeos_coreboot=VBOOT=${chroot}/build/link/usr ${vboot}
34chromeos_daisy=VBOOT=${chroot}/build/daisy/usr ${vboot}
35chromeos_peach=VBOOT=${chroot}/build/peach_pit/usr ${vboot}
36'''
37
Simon Glass823e60b2014-09-05 19:00:16 -060038boards = [
39 ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0', ''],
40 ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''],
41 ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''],
42 ['Active', 'powerpc', 'mpc5xx', '', 'Tester', 'PowerPC board 2', 'board3', ''],
43 ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
44]
45
Simon Glassd4144e42014-09-05 19:00:13 -060046class TestFunctional(unittest.TestCase):
47 """Functional test for buildman.
48
49 This aims to test from just below the invocation of buildman (parsing
50 of arguments) to 'make' and 'git' invocation. It is not a true
51 emd-to-end test, as it mocks git, make and the tool chain. But this
52 makes it easier to detect when the builder is doing the wrong thing,
53 since in many cases this test code will fail. For example, only a
54 very limited subset of 'git' arguments is supported - anything
55 unexpected will fail.
56 """
57 def setUp(self):
58 self._base_dir = tempfile.mkdtemp()
59 self._git_dir = os.path.join(self._base_dir, 'src')
60 self._buildman_pathname = sys.argv[0]
61 self._buildman_dir = os.path.dirname(sys.argv[0])
62 command.test_result = self._HandleCommand
63 self._toolchains = toolchain.Toolchains()
64 self._toolchains.Add('gcc', test=False)
Simon Glass8b985ee2014-09-05 19:00:15 -060065 bsettings.Setup(None)
66 bsettings.AddFile(settings_data)
Simon Glass823e60b2014-09-05 19:00:16 -060067 self._boards = board.Boards()
68 for brd in boards:
69 self._boards.AddBoard(board.Board(*brd))
Simon Glassd4144e42014-09-05 19:00:13 -060070
71 def tearDown(self):
72 shutil.rmtree(self._base_dir)
73
74 def _RunBuildman(self, *args):
75 return command.RunPipe([[self._buildman_pathname] + list(args)],
76 capture=True, capture_stderr=True)
77
78 def _RunControl(self, *args):
79 sys.argv = [sys.argv[0]] + list(args)
80 options, args = cmdline.ParseArgs()
81 return control.DoBuildman(options, args, toolchains=self._toolchains,
Simon Glass823e60b2014-09-05 19:00:16 -060082 make_func=self._HandleMake, boards=self._boards)
Simon Glassd4144e42014-09-05 19:00:13 -060083
84 def testFullHelp(self):
85 command.test_result = None
86 result = self._RunBuildman('-H')
87 help_file = os.path.join(self._buildman_dir, 'README')
88 self.assertEqual(len(result.stdout), os.path.getsize(help_file))
89 self.assertEqual(0, len(result.stderr))
90 self.assertEqual(0, result.return_code)
91
92 def testHelp(self):
93 command.test_result = None
94 result = self._RunBuildman('-h')
95 help_file = os.path.join(self._buildman_dir, 'README')
96 self.assertTrue(len(result.stdout) > 1000)
97 self.assertEqual(0, len(result.stderr))
98 self.assertEqual(0, result.return_code)
99
100 def testGitSetup(self):
101 """Test gitutils.Setup(), from outside the module itself"""
102 command.test_result = command.CommandResult(return_code=1)
103 gitutil.Setup()
104 self.assertEqual(gitutil.use_no_decorate, False)
105
106 command.test_result = command.CommandResult(return_code=0)
107 gitutil.Setup()
108 self.assertEqual(gitutil.use_no_decorate, True)
109
110 def _HandleCommandGitLog(self, args):
111 if '-n0' in args:
112 return command.CommandResult(return_code=0)
113
114 # Not handled, so abort
115 print 'git log', args
116 sys.exit(1)
117
118 def _HandleCommandGit(self, in_args):
119 """Handle execution of a git command
120
121 This uses a hacked-up parser.
122
123 Args:
124 in_args: Arguments after 'git' from the command line
125 """
126 git_args = [] # Top-level arguments to git itself
127 sub_cmd = None # Git sub-command selected
128 args = [] # Arguments to the git sub-command
129 for arg in in_args:
130 if sub_cmd:
131 args.append(arg)
132 elif arg[0] == '-':
133 git_args.append(arg)
134 else:
135 sub_cmd = arg
136 if sub_cmd == 'config':
137 return command.CommandResult(return_code=0)
138 elif sub_cmd == 'log':
139 return self._HandleCommandGitLog(args)
140
141 # Not handled, so abort
142 print 'git', git_args, sub_cmd, args
143 sys.exit(1)
144
145 def _HandleCommandNm(self, args):
146 return command.CommandResult(return_code=0)
147
148 def _HandleCommandObjdump(self, args):
149 return command.CommandResult(return_code=0)
150
151 def _HandleCommandSize(self, args):
152 return command.CommandResult(return_code=0)
153
154 def _HandleCommand(self, **kwargs):
155 """Handle a command execution.
156
157 The command is in kwargs['pipe-list'], as a list of pipes, each a
158 list of commands. The command should be emulated as required for
159 testing purposes.
160
161 Returns:
162 A CommandResult object
163 """
164 pipe_list = kwargs['pipe_list']
165 if len(pipe_list) != 1:
166 print 'invalid pipe', kwargs
167 sys.exit(1)
168 cmd = pipe_list[0][0]
169 args = pipe_list[0][1:]
170 if cmd == 'git':
171 return self._HandleCommandGit(args)
172 elif cmd == './scripts/show-gnu-make':
173 return command.CommandResult(return_code=0, stdout='make')
174 elif cmd == 'nm':
175 return self._HandleCommandNm(args)
176 elif cmd == 'objdump':
177 return self._HandleCommandObjdump(args)
178 elif cmd == 'size':
179 return self._HandleCommandSize(args)
180
181 # Not handled, so abort
182 print 'unknown command', kwargs
183 sys.exit(1)
184 return command.CommandResult(return_code=0)
185
186 def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs):
187 """Handle execution of 'make'
188
189 Args:
190 commit: Commit object that is being built
191 brd: Board object that is being built
192 stage: Stage that we are at (mrproper, config, build)
193 cwd: Directory where make should be run
194 args: Arguments to pass to make
195 kwargs: Arguments to pass to command.RunPipe()
196 """
197 if stage == 'mrproper':
198 return command.CommandResult(return_code=0)
199 elif stage == 'config':
200 return command.CommandResult(return_code=0,
201 combined='Test configuration complete')
202 elif stage == 'build':
203 return command.CommandResult(return_code=0)
204
205 # Not handled, so abort
206 print 'make', stage
207 sys.exit(1)
208
Simon Glass823e60b2014-09-05 19:00:16 -0600209 def testNoBoards(self):
210 """Test that buildman aborts when there are no boards"""
211 self._boards = board.Boards()
212 with self.assertRaises(SystemExit):
213 self._RunControl()
214
Simon Glassd4144e42014-09-05 19:00:13 -0600215 def testCurrentSource(self):
216 """Very simple test to invoke buildman on the current source"""
217 self._RunControl()
218 lines = terminal.GetPrintTestLines()
219 self.assertTrue(lines[0].text.startswith('Building current source'))