Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: tools/mb/mb_unittest.py

Issue 1370593003: Merge MB from trunk back to M45. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@branch_2454
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/mb/mb_config.pyl ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python
1 # Copyright 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 4 # found in the LICENSE file.
4 5
5 """Tests for mb.py.""" 6 """Tests for mb.py."""
6 7
7 import json 8 import json
9 import StringIO
10 import os
8 import sys 11 import sys
9 import unittest 12 import unittest
10 13
11 import mb 14 import mb
12 15
13 16
14 class FakeMBW(mb.MetaBuildWrapper): 17 class FakeMBW(mb.MetaBuildWrapper):
15 def __init__(self): 18 def __init__(self, win32=False):
16 super(FakeMBW, self).__init__() 19 super(FakeMBW, self).__init__()
20
21 # Override vars for test portability.
22 if win32:
23 self.chromium_src_dir = 'c:\\fake_src'
24 self.default_config = 'c:\\fake_src\\tools\\mb\\mb_config.pyl'
25 self.platform = 'win32'
26 self.executable = 'c:\\python\\python.exe'
27 self.sep = '\\'
28 else:
29 self.chromium_src_dir = '/fake_src'
30 self.default_config = '/fake_src/tools/mb/mb_config.pyl'
31 self.executable = '/usr/bin/python'
32 self.platform = 'linux2'
33 self.sep = '/'
34
17 self.files = {} 35 self.files = {}
18 self.calls = [] 36 self.calls = []
19 self.cmds = [] 37 self.cmds = []
38 self.cross_compile = None
20 self.out = '' 39 self.out = ''
21 self.err = '' 40 self.err = ''
22 self.platform = 'linux2' 41 self.rmdirs = []
23 self.chromium_src_dir = '/fake_src'
24 self.default_config = '/fake_src/tools/mb/mb_config.pyl'
25 42
26 def ExpandUser(self, path): 43 def ExpandUser(self, path):
27 return '$HOME/%s' % path 44 return '$HOME/%s' % path
28 45
29 def Exists(self, path): 46 def Exists(self, path):
30 return self.files.get(path) is not None 47 return self.files.get(path) is not None
31 48
32 def MaybeMakeDirectory(self, path): 49 def MaybeMakeDirectory(self, path):
33 pass 50 self.files[path] = True
51
52 def PathJoin(self, *comps):
53 return self.sep.join(comps)
34 54
35 def ReadFile(self, path): 55 def ReadFile(self, path):
36 return self.files[path] 56 return self.files[path]
37 57
38 def WriteFile(self, path, contents): 58 def WriteFile(self, path, contents, force_verbose=False):
39 self.files[path] = contents 59 self.files[path] = contents
40 60
41 def Call(self, cmd): 61 def Call(self, cmd, env=None):
62 if env:
63 self.cross_compile = env.get('GYP_CROSSCOMPILE')
42 self.calls.append(cmd) 64 self.calls.append(cmd)
43 if self.cmds: 65 if self.cmds:
44 return self.cmds.pop(0) 66 return self.cmds.pop(0)
45 return 0, '', '' 67 return 0, '', ''
46 68
47 def Print(self, *args, **kwargs): 69 def Print(self, *args, **kwargs):
48 sep = kwargs.get('sep', ' ') 70 sep = kwargs.get('sep', ' ')
49 end = kwargs.get('end', '\n') 71 end = kwargs.get('end', '\n')
50 f = kwargs.get('file', sys.stdout) 72 f = kwargs.get('file', sys.stdout)
51 if f == sys.stderr: 73 if f == sys.stderr:
52 self.err += sep.join(args) + end 74 self.err += sep.join(args) + end
53 else: 75 else:
54 self.out += sep.join(args) + end 76 self.out += sep.join(args) + end
55 77
56 def TempFile(self, mode='w'): 78 def TempFile(self, mode='w'):
57 return FakeFile(self.files) 79 return FakeFile(self.files)
58 80
59 def RemoveFile(self, path): 81 def RemoveFile(self, path):
60 del self.files[path] 82 del self.files[path]
61 83
84 def RemoveDirectory(self, path):
85 self.rmdirs.append(path)
86 files_to_delete = [f for f in self.files if f.startswith(path)]
87 for f in files_to_delete:
88 self.files[f] = None
89
62 90
63 class FakeFile(object): 91 class FakeFile(object):
64 def __init__(self, files): 92 def __init__(self, files):
65 self.name = '/tmp/file' 93 self.name = '/tmp/file'
66 self.buf = '' 94 self.buf = ''
67 self.files = files 95 self.files = files
68 96
69 def write(self, contents): 97 def write(self, contents):
70 self.buf += contents 98 self.buf += contents
71 99
72 def close(self): 100 def close(self):
73 self.files[self.name] = self.buf 101 self.files[self.name] = self.buf
74 102
75 103
76 class IntegrationTest(unittest.TestCase):
77 def test_validate(self):
78 # Note that this validates that the actual mb_config.pyl is valid.
79 ret = mb.main(['validate', '--quiet'])
80 self.assertEqual(ret, 0)
81
82
83 TEST_CONFIG = """\ 104 TEST_CONFIG = """\
84 { 105 {
85 'common_dev_configs': ['gn_debug'], 106 'common_dev_configs': ['gn_debug'],
86 'configs': { 107 'configs': {
87 'gyp_rel_bot': ['gyp', 'rel', 'goma'], 108 'gyp_rel_bot': ['gyp', 'rel', 'goma'],
88 'gn_debug': ['gn', 'debug'], 109 'gn_debug': ['gn', 'debug', 'goma'],
110 'gyp_debug': ['gyp', 'debug'],
89 'gn_rel_bot': ['gn', 'rel', 'goma'], 111 'gn_rel_bot': ['gn', 'rel', 'goma'],
90 'private': ['gyp', 'fake_feature1'], 112 'private': ['gyp', 'rel', 'fake_feature1'],
91 'unsupported': ['gn', 'fake_feature2'], 113 'unsupported': ['gn', 'fake_feature2'],
92 }, 114 },
93 'masters': { 115 'masters': {
94 'fake_master': { 116 'fake_master': {
95 'fake_builder': 'gyp_rel_bot', 117 'fake_builder': 'gyp_rel_bot',
96 'fake_gn_builder': 'gn_rel_bot', 118 'fake_gn_builder': 'gn_rel_bot',
119 'fake_gyp_builder': 'gyp_debug',
97 }, 120 },
98 }, 121 },
99 'mixins': { 122 'mixins': {
100 'fake_feature1': { 123 'fake_feature1': {
101 'gn_args': 'enable_doom_melon=true', 124 'gn_args': 'enable_doom_melon=true',
125 'gyp_crosscompile': True,
102 'gyp_defines': 'doom_melon=1', 126 'gyp_defines': 'doom_melon=1',
103 }, 127 },
104 'fake_feature2': { 128 'fake_feature2': {
105 'gn_args': 'enable_doom_melon=false', 129 'gn_args': 'enable_doom_melon=false',
106 'gyp_defaults': 'doom_melon=0', 130 'gyp_defaults': 'doom_melon=0',
107 }, 131 },
108 'gyp': {'type': 'gyp'}, 132 'gyp': {'type': 'gyp'},
109 'gn': {'type': 'gn'}, 133 'gn': {'type': 'gn'},
110 'goma': { 134 'goma': {
111 'gn_args': 'use_goma=true goma_dir="$(goma_dir)"', 135 'gn_args': 'use_goma=true goma_dir="$(goma_dir)"',
112 'gyp_defines': 'goma=1 gomadir="$(goma_dir)"', 136 'gyp_defines': 'goma=1 gomadir=$(goma_dir)',
113 }, 137 },
114 'rel': { 138 'rel': {
115 'gn_args': 'is_debug=false', 139 'gn_args': 'is_debug=false',
116 'gyp_config': 'Release',
117 }, 140 },
118 'debug': { 141 'debug': {
119 'gn_args': 'is_debug=true', 142 'gn_args': 'is_debug=true',
120 }, 143 },
121 }, 144 },
122 'private_configs': ['private'], 145 'private_configs': ['private'],
123 'unsupported_configs': ['unsupported'], 146 'unsupported_configs': ['unsupported'],
124 } 147 }
125 """ 148 """
126 149
127 150
128 class UnitTest(unittest.TestCase): 151 class UnitTest(unittest.TestCase):
129 def fake_mbw(self, files=None): 152 def fake_mbw(self, files=None, win32=False):
130 mbw = FakeMBW() 153 mbw = FakeMBW(win32=win32)
131 mbw.files.setdefault(mbw.default_config, TEST_CONFIG) 154 mbw.files.setdefault(mbw.default_config, TEST_CONFIG)
132 if files: 155 if files:
133 for path, contents in files.items(): 156 for path, contents in files.items():
134 mbw.files[path] = contents 157 mbw.files[path] = contents
135 return mbw 158 return mbw
136 159
137 def check(self, args, mbw=None, files=None, out=None, err=None, ret=None): 160 def check(self, args, mbw=None, files=None, out=None, err=None, ret=None):
138 if not mbw: 161 if not mbw:
139 mbw = self.fake_mbw(files) 162 mbw = self.fake_mbw(files)
140 mbw.ParseArgs(args) 163 mbw.ParseArgs(args)
141 actual_ret = mbw.args.func() 164 actual_ret = mbw.args.func()
142 if ret is not None: 165 if ret is not None:
143 self.assertEqual(actual_ret, ret) 166 self.assertEqual(actual_ret, ret)
144 if out is not None: 167 if out is not None:
145 self.assertEqual(mbw.out, out) 168 self.assertEqual(mbw.out, out)
146 if err is not None: 169 if err is not None:
147 self.assertEqual(mbw.err, err) 170 self.assertEqual(mbw.err, err)
148 return mbw 171 return mbw
149 172
173 def test_clobber(self):
174 files = {
175 '/fake_src/out/Debug': None,
176 '/fake_src/out/Debug/mb_type': None,
177 }
178 mbw = self.fake_mbw(files)
179
180 # The first time we run this, the build dir doesn't exist, so no clobber.
181 self.check(['gen', '-c', 'gn_debug', '//out/Debug'], mbw=mbw, ret=0)
182 self.assertEqual(mbw.rmdirs, [])
183 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gn')
184
185 # The second time we run this, the build dir exists and matches, so no
186 # clobber.
187 self.check(['gen', '-c', 'gn_debug', '//out/Debug'], mbw=mbw, ret=0)
188 self.assertEqual(mbw.rmdirs, [])
189 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gn')
190
191 # Now we switch build types; this should result in a clobber.
192 self.check(['gen', '-c', 'gyp_debug', '//out/Debug'], mbw=mbw, ret=0)
193 self.assertEqual(mbw.rmdirs, ['/fake_src/out/Debug'])
194 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp')
195
196 # Now we delete mb_type; this checks the case where the build dir
197 # exists but wasn't populated by mb; this should also result in a clobber.
198 del mbw.files['/fake_src/out/Debug/mb_type']
199 self.check(['gen', '-c', 'gyp_debug', '//out/Debug'], mbw=mbw, ret=0)
200 self.assertEqual(mbw.rmdirs,
201 ['/fake_src/out/Debug', '/fake_src/out/Debug'])
202 self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp')
203
150 def test_gn_analyze(self): 204 def test_gn_analyze(self):
151 files = {'/tmp/in.json': """{\ 205 files = {'/tmp/in.json': """{\
152 "files": ["foo/foo_unittest.cc"], 206 "files": ["foo/foo_unittest.cc"],
153 "targets": ["foo_unittests", "bar_unittests"] 207 "targets": ["foo_unittests", "bar_unittests"]
154 }"""} 208 }"""}
155 209
156 mbw = self.fake_mbw(files) 210 mbw = self.fake_mbw(files)
157 mbw.Call = lambda cmd: (0, 'out/Default/foo_unittests\n', '') 211 mbw.Call = lambda cmd, env=None: (0, 'out/Default/foo_unittests\n', '')
158 212
159 self.check(['analyze', '-c', 'gn_debug', '//out/Default', 213 self.check(['analyze', '-c', 'gn_debug', '//out/Default',
160 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) 214 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
161 out = json.loads(mbw.files['/tmp/out.json']) 215 out = json.loads(mbw.files['/tmp/out.json'])
162 self.assertEqual(out, { 216 self.assertEqual(out, {
163 'status': 'Found dependency', 217 'status': 'Found dependency',
164 'targets': ['foo_unittests'], 218 'targets': ['foo_unittests'],
165 'build_targets': ['foo_unittests'] 219 'build_targets': ['foo_unittests']
166 }) 220 })
167 221
168 def test_gn_analyze_all(self): 222 def test_gn_analyze_all(self):
169 files = {'/tmp/in.json': """{\ 223 files = {'/tmp/in.json': """{\
170 "files": ["foo/foo_unittest.cc"], 224 "files": ["foo/foo_unittest.cc"],
171 "targets": ["all", "bar_unittests"] 225 "targets": ["all", "bar_unittests"]
172 }"""} 226 }"""}
173 mbw = self.fake_mbw(files) 227 mbw = self.fake_mbw(files)
174 mbw.Call = lambda cmd: (0, 'out/Default/foo_unittests\n', '') 228 mbw.Call = lambda cmd, env=None: (0, 'out/Default/foo_unittests\n', '')
175 self.check(['analyze', '-c', 'gn_debug', '//out/Default', 229 self.check(['analyze', '-c', 'gn_debug', '//out/Default',
176 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) 230 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
177 out = json.loads(mbw.files['/tmp/out.json']) 231 out = json.loads(mbw.files['/tmp/out.json'])
178 self.assertEqual(out, { 232 self.assertEqual(out, {
179 'status': 'Found dependency (all)', 233 'status': 'Found dependency (all)',
180 }) 234 })
181 235
182 def test_gn_analyze_missing_file(self): 236 def test_gn_analyze_missing_file(self):
183 files = {'/tmp/in.json': """{\ 237 files = {'/tmp/in.json': """{\
184 "files": ["foo/foo_unittest.cc"], 238 "files": ["foo/foo_unittest.cc"],
185 "targets": ["bar_unittests"] 239 "targets": ["bar_unittests"]
186 }"""} 240 }"""}
187 mbw = self.fake_mbw(files) 241 mbw = self.fake_mbw(files)
188 mbw.cmds = [ 242 mbw.cmds = [
189 (0, '', ''), 243 (0, '', ''),
190 (1, 'The input matches no targets, configs, or files\n', ''), 244 (1, 'The input matches no targets, configs, or files\n', ''),
191 (1, 'The input matches no targets, configs, or files\n', ''), 245 (1, 'The input matches no targets, configs, or files\n', ''),
192 ] 246 ]
193 247
194 self.check(['analyze', '-c', 'gn_debug', '//out/Default', 248 self.check(['analyze', '-c', 'gn_debug', '//out/Default',
195 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) 249 '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
196 out = json.loads(mbw.files['/tmp/out.json']) 250 out = json.loads(mbw.files['/tmp/out.json'])
197 self.assertEqual(out, { 251 self.assertEqual(out, {
198 'build_targets': [], 252 'build_targets': [],
199 'targets': [], 253 'targets': [],
200 'status': 'No dependency', 254 'status': 'No dependency',
201 }) 255 })
202 256
203 def test_gn_gen(self): 257 def test_gn_gen(self):
204 self.check(['gen', '-c', 'gn_debug', '//out/Default'], ret=0) 258 self.check(['gen', '-c', 'gn_debug', '//out/Default', '-g', '/goma'],
205 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], ret=0) 259 ret=0,
260 out=('/fake_src/buildtools/linux64/gn gen //out/Default '
261 '\'--args=is_debug=true use_goma=true goma_dir="/goma"\' '
262 '--check\n'))
263
264 mbw = self.fake_mbw(win32=True)
265 self.check(['gen', '-c', 'gn_debug', '-g', 'c:\\goma', '//out/Debug'],
266 mbw=mbw, ret=0,
267 out=('c:\\fake_src\\buildtools\\win\\gn gen //out/Debug '
268 '"--args=is_debug=true use_goma=true goma_dir=\\"'
269 'c:\\goma\\"" --check\n'))
270
206 271
207 def test_gn_gen_fails(self): 272 def test_gn_gen_fails(self):
208 mbw = self.fake_mbw() 273 mbw = self.fake_mbw()
209 mbw.Call = lambda cmd: (1, '', '') 274 mbw.Call = lambda cmd, env=None: (1, '', '')
210 self.check(['gen', '-c', 'gn_debug', '//out/Default'], mbw=mbw, ret=1) 275 self.check(['gen', '-c', 'gn_debug', '//out/Default'], mbw=mbw, ret=1)
211 276
212 def test_gn_gen_swarming(self): 277 def test_gn_gen_swarming(self):
213 files = { 278 files = {
214 '/tmp/swarming_targets': 'base_unittests\n', 279 '/tmp/swarming_targets': 'base_unittests\n',
215 '/fake_src/testing/buildbot/ninja_to_gn.pyl': ( 280 '/fake_src/testing/buildbot/gn_isolate_map.pyl': (
216 "{'base_unittests': '//base:base_unittests'}\n" 281 "{'base_unittests': {"
282 " 'label': '//base:base_unittests',"
283 " 'type': 'raw',"
284 " 'args': [],"
285 "}}\n"
217 ), 286 ),
218 '/fake_src/out/Default/base_unittests.runtime_deps': ( 287 '/fake_src/out/Default/base_unittests.runtime_deps': (
219 "base_unittests\n" 288 "base_unittests\n"
220 ), 289 ),
221 } 290 }
222 mbw = self.fake_mbw(files) 291 mbw = self.fake_mbw(files)
223 self.check(['gen', 292 self.check(['gen',
224 '-c', 'gn_debug', 293 '-c', 'gn_debug',
225 '--swarming-targets-file', '/tmp/swarming_targets', 294 '--swarming-targets-file', '/tmp/swarming_targets',
226 '//out/Default'], mbw=mbw, ret=0) 295 '//out/Default'], mbw=mbw, ret=0)
227 self.assertIn('/fake_src/out/Default/base_unittests.isolate', 296 self.assertIn('/fake_src/out/Default/base_unittests.isolate',
228 mbw.files) 297 mbw.files)
229 self.assertIn('/fake_src/out/Default/base_unittests.isolated.gen.json', 298 self.assertIn('/fake_src/out/Default/base_unittests.isolated.gen.json',
230 mbw.files) 299 mbw.files)
231 300
232 def test_gn_lookup(self): 301 def test_gn_lookup(self):
233 self.check(['lookup', '-c', 'gn_debug'], ret=0) 302 self.check(['lookup', '-c', 'gn_debug'], ret=0)
234 303
235 def test_gn_lookup_goma_dir_expansion(self): 304 def test_gn_lookup_goma_dir_expansion(self):
236 self.check(['lookup', '-c', 'gn_rel_bot', '-g', '/foo'], ret=0, 305 self.check(['lookup', '-c', 'gn_rel_bot', '-g', '/foo'], ret=0,
237 out=("/fake_src/buildtools/linux64/gn gen '<path>' " 306 out=("/fake_src/buildtools/linux64/gn gen _path_ "
238 "'--args=is_debug=false use_goma=true " 307 "'--args=is_debug=false use_goma=true "
239 "goma_dir=\"/foo\"'\n" )) 308 "goma_dir=\"/foo\"'\n" ))
240 309
241 def test_gyp_analyze(self): 310 def test_gyp_analyze(self):
242 self.check(['analyze', '-c', 'gyp_rel_bot', '//out/Release', 311 mbw = self.check(['analyze', '-c', 'gyp_rel_bot', '//out/Release',
243 '/tmp/in.json', '/tmp/out.json'], 312 '/tmp/in.json', '/tmp/out.json'],
244 ret=0) 313 ret=0)
314 self.assertIn('analyzer', mbw.calls[0])
315
316 def test_gyp_crosscompile(self):
317 mbw = self.fake_mbw()
318 self.check(['gen', '-c', 'private', '//out/Release'], mbw=mbw)
319 self.assertTrue(mbw.cross_compile)
245 320
246 def test_gyp_gen(self): 321 def test_gyp_gen(self):
247 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], ret=0) 322 self.check(['gen', '-c', 'gyp_rel_bot', '-g', '/goma', '//out/Release'],
323 ret=0,
324 out=("GYP_DEFINES='goma=1 gomadir=/goma'\n"
325 "python build/gyp_chromium -G output_dir=out\n"))
326
327 mbw = self.fake_mbw(win32=True)
328 self.check(['gen', '-c', 'gyp_rel_bot', '-g', 'c:\\goma', '//out/Release'],
329 mbw=mbw, ret=0,
330 out=("set GYP_DEFINES=goma=1 gomadir='c:\\goma'\n"
331 "python build\\gyp_chromium -G output_dir=out\n"))
248 332
249 def test_gyp_gen_fails(self): 333 def test_gyp_gen_fails(self):
250 mbw = self.fake_mbw() 334 mbw = self.fake_mbw()
251 mbw.Call = lambda cmd: (1, '', '') 335 mbw.Call = lambda cmd, env=None: (1, '', '')
252 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], mbw=mbw, ret=1) 336 self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], mbw=mbw, ret=1)
253 337
254 def test_gyp_lookup_goma_dir_expansion(self): 338 def test_gyp_lookup_goma_dir_expansion(self):
255 self.check(['lookup', '-c', 'gyp_rel_bot', '-g', '/foo'], ret=0, 339 self.check(['lookup', '-c', 'gyp_rel_bot', '-g', '/foo'], ret=0,
256 out=("python build/gyp_chromium -G 'output_dir=<path>' " 340 out=("GYP_DEFINES='goma=1 gomadir=/foo'\n"
257 "-G config=Release -D goma=1 -D gomadir=/foo\n")) 341 "python build/gyp_chromium -G output_dir=_path_\n"))
258 342
259 def test_help(self): 343 def test_help(self):
260 self.assertRaises(SystemExit, self.check, ['-h']) 344 orig_stdout = sys.stdout
261 self.assertRaises(SystemExit, self.check, ['help']) 345 try:
262 self.assertRaises(SystemExit, self.check, ['help', 'gen']) 346 sys.stdout = StringIO.StringIO()
347 self.assertRaises(SystemExit, self.check, ['-h'])
348 self.assertRaises(SystemExit, self.check, ['help'])
349 self.assertRaises(SystemExit, self.check, ['help', 'gen'])
350 finally:
351 sys.stdout = orig_stdout
352
263 353
264 def test_validate(self): 354 def test_validate(self):
265 self.check(['validate'], ret=0) 355 self.check(['validate'], ret=0)
266 356
267 357
268 if __name__ == '__main__': 358 if __name__ == '__main__':
269 unittest.main() 359 unittest.main()
OLDNEW
« no previous file with comments | « tools/mb/mb_config.pyl ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698