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