Revert of Remove the 'gyp_config' concept from MB. (patchset #2 id:20001 of https...
[chromium-blink-merge.git] / tools / mb / mb_unittest.py
blob8c76e5048bed8c724a438957f587afea9cd49d26
1 #!/usr/bin/python
2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Tests for mb.py."""
8 import json
9 import StringIO
10 import sys
11 import unittest
13 import mb
16 class FakeMBW(mb.MetaBuildWrapper):
17 def __init__(self):
18 super(FakeMBW, self).__init__()
19 self.files = {}
20 self.calls = []
21 self.cmds = []
22 self.cross_compile = None
23 self.out = ''
24 self.err = ''
25 self.platform = 'linux2'
26 self.chromium_src_dir = '/fake_src'
27 self.default_config = '/fake_src/tools/mb/mb_config.pyl'
28 self.rmdirs = []
30 def ExpandUser(self, path):
31 return '$HOME/%s' % path
33 def Exists(self, path):
34 return self.files.get(path) is not None
36 def MaybeMakeDirectory(self, path):
37 self.files[path] = True
39 def ReadFile(self, path):
40 return self.files[path]
42 def WriteFile(self, path, contents, force_verbose=False):
43 self.files[path] = contents
45 def Call(self, cmd, env=None):
46 if env:
47 self.cross_compile = env.get('GYP_CROSSCOMPILE')
48 self.calls.append(cmd)
49 if self.cmds:
50 return self.cmds.pop(0)
51 return 0, '', ''
53 def Print(self, *args, **kwargs):
54 sep = kwargs.get('sep', ' ')
55 end = kwargs.get('end', '\n')
56 f = kwargs.get('file', sys.stdout)
57 if f == sys.stderr:
58 self.err += sep.join(args) + end
59 else:
60 self.out += sep.join(args) + end
62 def TempFile(self, mode='w'):
63 return FakeFile(self.files)
65 def RemoveFile(self, path):
66 del self.files[path]
68 def RemoveDirectory(self, path):
69 self.rmdirs.append(path)
70 files_to_delete = [f for f in self.files if f.startswith(path)]
71 for f in files_to_delete:
72 self.files[f] = None
75 class FakeFile(object):
76 def __init__(self, files):
77 self.name = '/tmp/file'
78 self.buf = ''
79 self.files = files
81 def write(self, contents):
82 self.buf += contents
84 def close(self):
85 self.files[self.name] = self.buf
88 TEST_CONFIG = """\
90 'common_dev_configs': ['gn_debug'],
91 'configs': {
92 'gyp_rel_bot': ['gyp', 'rel', 'goma'],
93 'gn_debug': ['gn', 'debug'],
94 'gyp_debug': ['gyp', 'debug'],
95 'gn_rel_bot': ['gn', 'rel', 'goma'],
96 'private': ['gyp', 'rel', 'fake_feature1'],
97 'unsupported': ['gn', 'fake_feature2'],
99 'masters': {
100 'fake_master': {
101 'fake_builder': 'gyp_rel_bot',
102 'fake_gn_builder': 'gn_rel_bot',
103 'fake_gyp_builder': 'gyp_debug',
106 'mixins': {
107 'fake_feature1': {
108 'gn_args': 'enable_doom_melon=true',
109 'gyp_crosscompile': True,
110 'gyp_defines': 'doom_melon=1',
112 'fake_feature2': {
113 'gn_args': 'enable_doom_melon=false',
114 'gyp_defaults': 'doom_melon=0',
116 'gyp': {'type': 'gyp'},
117 'gn': {'type': 'gn'},
118 'goma': {
119 'gn_args': 'use_goma=true goma_dir="$(goma_dir)"',
120 'gyp_defines': 'goma=1 gomadir="$(goma_dir)"',
122 'rel': {
123 'gn_args': 'is_debug=false',
124 'gyp_config': 'Release',
126 'debug': {
127 'gn_args': 'is_debug=true',
128 'gyp_config': 'Debug',
131 'private_configs': ['private'],
132 'unsupported_configs': ['unsupported'],
137 class UnitTest(unittest.TestCase):
138 def fake_mbw(self, files=None):
139 mbw = FakeMBW()
140 mbw.files.setdefault(mbw.default_config, TEST_CONFIG)
141 if files:
142 for path, contents in files.items():
143 mbw.files[path] = contents
144 return mbw
146 def check(self, args, mbw=None, files=None, out=None, err=None, ret=None):
147 if not mbw:
148 mbw = self.fake_mbw(files)
149 mbw.ParseArgs(args)
150 actual_ret = mbw.args.func()
151 if ret is not None:
152 self.assertEqual(actual_ret, ret)
153 if out is not None:
154 self.assertEqual(mbw.out, out)
155 if err is not None:
156 self.assertEqual(mbw.err, err)
157 return mbw
159 def test_clobber(self):
160 files = {
161 '/fake_src/out/Debug': None,
162 '/fake_src/out/Debug/mb_type': None,
164 mbw = self.fake_mbw(files)
166 # The first time we run this, the build dir doesn't exist, so no clobber.
167 self.check(['gen', '-c', 'gn_debug', '//out/Debug'], mbw=mbw, ret=0)
168 self.assertEqual(mbw.rmdirs, [])
169 self.assertTrue(mbw.files['/fake_src/out/Debug/mb_type'], 'gn')
171 # The second time we run this, the build dir exists and matches, so no
172 # clobber.
173 self.check(['gen', '-c', 'gn_debug', '//out/Debug'], mbw=mbw, ret=0)
174 self.assertEqual(mbw.rmdirs, [])
175 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gn')
177 # Now we switch build types; this should result in a clobber.
178 self.check(['gen', '-c', 'gyp_debug', '//out/Debug'], mbw=mbw, ret=0)
179 self.assertEqual(mbw.rmdirs, ['/fake_src/out/Debug'])
180 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp')
182 # Now we delete mb_type; this checks the case where the build dir
183 # exists but wasn't populated by mb; this should also result in a clobber.
184 del mbw.files['/fake_src/out/Debug/mb_type']
185 self.check(['gen', '-c', 'gyp_debug', '//out/Debug'], mbw=mbw, ret=0)
186 self.assertEqual(mbw.rmdirs,
187 ['/fake_src/out/Debug', '/fake_src/out/Debug'])
188 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp')
190 def test_gn_analyze(self):
191 files = {'/tmp/in.json': """{\
192 "files": ["foo/foo_unittest.cc"],
193 "targets": ["foo_unittests", "bar_unittests"]
194 }"""}
196 mbw = self.fake_mbw(files)
197 mbw.Call = lambda cmd, env=None: (0, 'out/Default/foo_unittests\n', '')
199 self.check(['analyze', '-c', 'gn_debug', '//out/Default',
200 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
201 out = json.loads(mbw.files['/tmp/out.json'])
202 self.assertEqual(out, {
203 'status': 'Found dependency',
204 'targets': ['foo_unittests'],
205 'build_targets': ['foo_unittests']
208 def test_gn_analyze_all(self):
209 files = {'/tmp/in.json': """{\
210 "files": ["foo/foo_unittest.cc"],
211 "targets": ["all", "bar_unittests"]
212 }"""}
213 mbw = self.fake_mbw(files)
214 mbw.Call = lambda cmd, env=None: (0, 'out/Default/foo_unittests\n', '')
215 self.check(['analyze', '-c', 'gn_debug', '//out/Default',
216 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
217 out = json.loads(mbw.files['/tmp/out.json'])
218 self.assertEqual(out, {
219 'status': 'Found dependency (all)',
222 def test_gn_analyze_missing_file(self):
223 files = {'/tmp/in.json': """{\
224 "files": ["foo/foo_unittest.cc"],
225 "targets": ["bar_unittests"]
226 }"""}
227 mbw = self.fake_mbw(files)
228 mbw.cmds = [
229 (0, '', ''),
230 (1, 'The input matches no targets, configs, or files\n', ''),
231 (1, 'The input matches no targets, configs, or files\n', ''),
234 self.check(['analyze', '-c', 'gn_debug', '//out/Default',
235 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
236 out = json.loads(mbw.files['/tmp/out.json'])
237 self.assertEqual(out, {
238 'build_targets': [],
239 'targets': [],
240 'status': 'No dependency',
243 def test_gn_gen(self):
244 self.check(['gen', '-c', 'gn_debug', '//out/Default'], ret=0)
245 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], ret=0)
247 def test_gn_gen_fails(self):
248 mbw = self.fake_mbw()
249 mbw.Call = lambda cmd, env=None: (1, '', '')
250 self.check(['gen', '-c', 'gn_debug', '//out/Default'], mbw=mbw, ret=1)
252 def test_gn_gen_swarming(self):
253 files = {
254 '/tmp/swarming_targets': 'base_unittests\n',
255 '/fake_src/testing/buildbot/gn_isolate_map.pyl': (
256 "{'base_unittests': {"
257 " 'label': '//base:base_unittests',"
258 " 'type': 'raw',"
259 " 'args': [],"
260 "}}\n"
262 '/fake_src/out/Default/base_unittests.runtime_deps': (
263 "base_unittests\n"
266 mbw = self.fake_mbw(files)
267 self.check(['gen',
268 '-c', 'gn_debug',
269 '--swarming-targets-file', '/tmp/swarming_targets',
270 '//out/Default'], mbw=mbw, ret=0)
271 self.assertIn('/fake_src/out/Default/base_unittests.isolate',
272 mbw.files)
273 self.assertIn('/fake_src/out/Default/base_unittests.isolated.gen.json',
274 mbw.files)
276 def test_gn_lookup(self):
277 self.check(['lookup', '-c', 'gn_debug'], ret=0)
279 def test_gn_lookup_goma_dir_expansion(self):
280 self.check(['lookup', '-c', 'gn_rel_bot', '-g', '/foo'], ret=0,
281 out=("/fake_src/buildtools/linux64/gn gen '<path>' "
282 "'--args=is_debug=false use_goma=true "
283 "goma_dir=\"/foo\"'\n" ))
285 def test_gyp_analyze(self):
286 mbw = self.check(['analyze', '-c', 'gyp_rel_bot', '//out/Release',
287 '/tmp/in.json', '/tmp/out.json'],
288 ret=0)
289 self.assertIn('analyzer', mbw.calls[0])
291 def test_gyp_crosscompile(self):
292 mbw = self.fake_mbw()
293 self.check(['gen', '-c', 'private', '//out/Release'], mbw=mbw)
294 self.assertTrue(mbw.cross_compile)
296 def test_gyp_gen(self):
297 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], ret=0)
299 def test_gyp_gen_fails(self):
300 mbw = self.fake_mbw()
301 mbw.Call = lambda cmd, env=None: (1, '', '')
302 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], mbw=mbw, ret=1)
304 def test_gyp_lookup_goma_dir_expansion(self):
305 self.check(['lookup', '-c', 'gyp_rel_bot', '-g', '/foo'], ret=0,
306 out=("python build/gyp_chromium -G 'output_dir=<path>' "
307 "-G config=Release -D goma=1 -D gomadir=/foo\n"))
309 def test_help(self):
310 orig_stdout = sys.stdout
311 try:
312 sys.stdout = StringIO.StringIO()
313 self.assertRaises(SystemExit, self.check, ['-h'])
314 self.assertRaises(SystemExit, self.check, ['help'])
315 self.assertRaises(SystemExit, self.check, ['help', 'gen'])
316 finally:
317 sys.stdout = orig_stdout
320 def test_validate(self):
321 self.check(['validate'], ret=0)
324 if __name__ == '__main__':
325 unittest.main()