1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 |
- #!/usr/bin/env python3
- # Copyright 2020 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- """Tests for mb.py."""
- from __future__ import print_function
- from __future__ import absolute_import
- import json
- import os
- import re
- import sys
- import tempfile
- import unittest
- if sys.version_info.major == 2:
- from StringIO import StringIO
- else:
- from io import StringIO
- sys.path.insert(
- 0,
- os.path.abspath(
- os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')))
- from mb import mb
- # Call has argument input to match subprocess.run
- # pylint: disable=redefined-builtin
- class FakeMBW(mb.MetaBuildWrapper):
- def __init__(self, win32=False):
- super().__init__()
- # Override vars for test portability.
- if win32:
- self.chromium_src_dir = 'c:\\fake_src'
- self.default_config = 'c:\\fake_src\\tools\\mb\\mb_config.pyl'
- self.default_isolate_map = ('c:\\fake_src\\testing\\buildbot\\'
- 'gn_isolate_map.pyl')
- self.temp = 'c:\\temp'
- self.platform = 'win32'
- self.executable = 'c:\\python\\python.exe'
- self.sep = '\\'
- self.cwd = 'c:\\fake_src\\out\\Default'
- else:
- self.chromium_src_dir = '/fake_src'
- self.default_config = '/fake_src/tools/mb/mb_config.pyl'
- self.default_isolate_map = '/fake_src/testing/buildbot/gn_isolate_map.pyl'
- self.temp = '/tmp'
- self.platform = 'linux'
- self.executable = '/usr/bin/python'
- self.sep = '/'
- self.cwd = '/fake_src/out/Default'
- self.files = {}
- self.dirs = set()
- self.calls = []
- self.cmds = []
- self.cross_compile = None
- self.out = ''
- self.err = ''
- self.rmdirs = []
- def ExpandUser(self, path):
- return '$HOME/%s' % path
- def Exists(self, path):
- abs_path = self._AbsPath(path)
- return (self.files.get(abs_path) is not None or abs_path in self.dirs)
- def ListDir(self, path):
- dir_contents = []
- for f in list(self.files.keys()) + list(self.dirs):
- head, _ = os.path.split(f)
- if head == path:
- dir_contents.append(f)
- return dir_contents
- def MaybeMakeDirectory(self, path):
- abpath = self._AbsPath(path)
- self.dirs.add(abpath)
- def PathJoin(self, *comps):
- return self.sep.join(comps)
- def ReadFile(self, path):
- try:
- return self.files[self._AbsPath(path)]
- except KeyError as e:
- raise IOError('%s not found' % path) from e
- def WriteFile(self, path, contents, force_verbose=False):
- if self.args.dryrun or self.args.verbose or force_verbose:
- self.Print('\nWriting """\\\n%s""" to %s.\n' % (contents, path))
- abpath = self._AbsPath(path)
- self.files[abpath] = contents
- def Call(self, cmd, env=None, capture_output=True, input=None):
- # Avoid unused-argument warnings from Pylint
- del env
- del capture_output
- del input
- self.calls.append(cmd)
- if self.cmds:
- return self.cmds.pop(0)
- return 0, '', ''
- def Print(self, *args, **kwargs):
- sep = kwargs.get('sep', ' ')
- end = kwargs.get('end', '\n')
- f = kwargs.get('file', sys.stdout)
- if f == sys.stderr:
- self.err += sep.join(args) + end
- else:
- self.out += sep.join(args) + end
- def TempDir(self):
- tmp_dir = self.temp + self.sep + 'mb_test'
- self.dirs.add(tmp_dir)
- return tmp_dir
- def TempFile(self, mode='w'):
- # Avoid unused-argument warnings from Pylint
- del mode
- return FakeFile(self.files)
- def RemoveFile(self, path):
- abpath = self._AbsPath(path)
- self.files[abpath] = None
- def RemoveDirectory(self, abs_path):
- # Normalize the passed-in path to handle different working directories
- # used during unit testing.
- abs_path = self._AbsPath(abs_path)
- self.rmdirs.append(abs_path)
- files_to_delete = [f for f in self.files if f.startswith(abs_path)]
- for f in files_to_delete:
- self.files[f] = None
- def _AbsPath(self, path):
- if not ((self.platform == 'win32' and path.startswith('c:')) or
- (self.platform != 'win32' and path.startswith('/'))):
- path = self.PathJoin(self.cwd, path)
- if self.sep == '\\':
- return re.sub(r'\\+', r'\\', path)
- return re.sub('/+', '/', path)
- class FakeFile:
- def __init__(self, files):
- self.name = '/tmp/file'
- self.buf = ''
- self.files = files
- def write(self, contents):
- self.buf += contents
- def close(self):
- self.files[self.name] = self.buf
- TEST_CONFIG = """\
- {
- 'builder_groups': {
- 'chromium': {},
- 'fake_builder_group': {
- 'fake_args_bot': 'fake_args_bot',
- 'fake_args_file': 'args_file_goma',
- 'fake_builder': 'rel_bot',
- 'fake_debug_builder': 'debug_goma',
- 'fake_ios_error': 'ios_error',
- 'fake_multi_phase': { 'phase_1': 'phase_1', 'phase_2': 'phase_2'},
- },
- },
- 'configs': {
- 'args_file_goma': ['fake_args_bot', 'goma'],
- 'debug_goma': ['debug', 'goma'],
- 'fake_args_bot': ['fake_args_bot'],
- 'ios_error': ['error'],
- 'phase_1': ['rel', 'phase_1'],
- 'phase_2': ['rel', 'phase_2'],
- 'rel_bot': ['rel', 'goma', 'fake_feature1'],
- },
- 'mixins': {
- 'debug': {
- 'gn_args': 'is_debug=true',
- },
- 'error': {
- 'gn_args': 'error',
- },
- 'fake_args_bot': {
- 'args_file': '//build/args/bots/fake_builder_group/fake_args_bot.gn',
- },
- 'fake_feature1': {
- 'gn_args': 'enable_doom_melon=true',
- },
- 'goma': {
- 'gn_args': 'use_goma=true',
- },
- 'phase_1': {
- 'gn_args': 'phase=1',
- },
- 'phase_2': {
- 'gn_args': 'phase=2',
- },
- 'rel': {
- 'gn_args': 'is_debug=false dcheck_always_on=false',
- },
- },
- }
- """
- TEST_BAD_CONFIG = """\
- {
- 'configs': {
- 'rel_bot_1': ['rel', 'chrome_with_codecs'],
- 'rel_bot_2': ['rel', 'bad_nested_config'],
- },
- 'builder_groups': {
- 'chromium': {
- 'a': 'rel_bot_1',
- 'b': 'rel_bot_2',
- },
- },
- 'mixins': {
- 'chrome_with_codecs': {
- 'gn_args': 'proprietary_codecs=true',
- },
- 'bad_nested_config': {
- 'mixins': ['chrome_with_codecs'],
- },
- 'rel': {
- 'gn_args': 'is_debug=false',
- },
- },
- }
- """
- TEST_ARGS_FILE_TWICE_CONFIG = """\
- {
- 'builder_groups': {
- 'chromium': {},
- 'fake_builder_group': {
- 'fake_args_file_twice': 'args_file_twice',
- },
- },
- 'configs': {
- 'args_file_twice': ['args_file', 'args_file'],
- },
- 'mixins': {
- 'args_file': {
- 'args_file': '//build/args/fake.gn',
- },
- },
- }
- """
- TEST_DUP_CONFIG = """\
- {
- 'builder_groups': {
- 'chromium': {},
- 'fake_builder_group': {
- 'fake_builder': 'some_config',
- 'other_builder': 'some_other_config',
- },
- },
- 'configs': {
- 'some_config': ['args_file'],
- 'some_other_config': ['args_file'],
- },
- 'mixins': {
- 'args_file': {
- 'args_file': '//build/args/fake.gn',
- },
- },
- }
- """
- TRYSERVER_CONFIG = """\
- {
- 'builder_groups': {
- 'not_a_tryserver': {
- 'fake_builder': 'fake_config',
- },
- 'tryserver.chromium.linux': {
- 'try_builder': 'fake_config',
- },
- 'tryserver.chromium.mac': {
- 'try_builder2': 'fake_config',
- },
- },
- 'configs': {},
- 'mixins': {},
- }
- """
- class UnitTest(unittest.TestCase):
- maxDiff = None
- def fake_mbw(self, files=None, win32=False):
- mbw = FakeMBW(win32=win32)
- mbw.files.setdefault(mbw.default_config, TEST_CONFIG)
- mbw.files.setdefault(
- mbw.ToAbsPath('//testing/buildbot/gn_isolate_map.pyl'),
- '''{
- "foo_unittests": {
- "label": "//foo:foo_unittests",
- "type": "console_test_launcher",
- "args": [],
- },
- }''')
- mbw.files.setdefault(
- mbw.ToAbsPath('//build/args/bots/fake_builder_group/fake_args_bot.gn'),
- 'is_debug = false\ndcheck_always_on=false\n')
- mbw.files.setdefault(mbw.ToAbsPath('//tools/mb/rts_banned_suites.json'),
- '{}')
- if files:
- for path, contents in files.items():
- mbw.files[path] = contents
- return mbw
- def check(self, args, mbw=None, files=None, out=None, err=None, ret=None,
- env=None):
- if not mbw:
- mbw = self.fake_mbw(files)
- try:
- prev_env = os.environ.copy()
- os.environ = env if env else prev_env
- actual_ret = mbw.Main(args)
- finally:
- os.environ = prev_env
- self.assertEqual(
- actual_ret, ret,
- "ret: %s, out: %s, err: %s" % (actual_ret, mbw.out, mbw.err))
- if out is not None:
- self.assertEqual(mbw.out, out)
- if err is not None:
- self.assertEqual(mbw.err, err)
- return mbw
- def test_analyze(self):
- files = {'/tmp/in.json': '''{\
- "files": ["foo/foo_unittest.cc"],
- "test_targets": ["foo_unittests"],
- "additional_compile_targets": ["all"]
- }''',
- '/tmp/out.json.gn': '''{\
- "status": "Found dependency",
- "compile_targets": ["//foo:foo_unittests"],
- "test_targets": ["//foo:foo_unittests"]
- }'''}
- mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, capture_output=True, input='': (0, '', '')
- self.check(['analyze', '-c', 'debug_goma', '//out/Default',
- '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
- out = json.loads(mbw.files['/tmp/out.json'])
- self.assertEqual(out, {
- 'status': 'Found dependency',
- 'compile_targets': ['foo:foo_unittests'],
- 'test_targets': ['foo_unittests']
- })
- def test_analyze_optimizes_compile_for_all(self):
- files = {'/tmp/in.json': '''{\
- "files": ["foo/foo_unittest.cc"],
- "test_targets": ["foo_unittests"],
- "additional_compile_targets": ["all"]
- }''',
- '/tmp/out.json.gn': '''{\
- "status": "Found dependency",
- "compile_targets": ["//foo:foo_unittests", "all"],
- "test_targets": ["//foo:foo_unittests"]
- }'''}
- mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, capture_output=True, input='': (0, '', '')
- self.check(['analyze', '-c', 'debug_goma', '//out/Default',
- '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
- out = json.loads(mbw.files['/tmp/out.json'])
- # check that 'foo_unittests' is not in the compile_targets
- self.assertEqual(['all'], out['compile_targets'])
- def test_analyze_handles_other_toolchains(self):
- files = {'/tmp/in.json': '''{\
- "files": ["foo/foo_unittest.cc"],
- "test_targets": ["foo_unittests"],
- "additional_compile_targets": ["all"]
- }''',
- '/tmp/out.json.gn': '''{\
- "status": "Found dependency",
- "compile_targets": ["//foo:foo_unittests",
- "//foo:foo_unittests(bar)"],
- "test_targets": ["//foo:foo_unittests"]
- }'''}
- mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, capture_output=True, input='': (0, '', '')
- self.check(['analyze', '-c', 'debug_goma', '//out/Default',
- '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
- out = json.loads(mbw.files['/tmp/out.json'])
- # crbug.com/736215: If GN returns a label containing a toolchain,
- # MB (and Ninja) don't know how to handle it; to work around this,
- # we give up and just build everything we were asked to build. The
- # output compile_targets should include all of the input test_targets and
- # additional_compile_targets.
- self.assertEqual(['all', 'foo_unittests'], out['compile_targets'])
- def test_analyze_handles_way_too_many_results(self):
- too_many_files = ', '.join(['"//foo:foo%d"' % i for i in range(40 * 1024)])
- files = {'/tmp/in.json': '''{\
- "files": ["foo/foo_unittest.cc"],
- "test_targets": ["foo_unittests"],
- "additional_compile_targets": ["all"]
- }''',
- '/tmp/out.json.gn': '''{\
- "status": "Found dependency",
- "compile_targets": [''' + too_many_files + '''],
- "test_targets": ["//foo:foo_unittests"]
- }'''}
- mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, capture_output=True, input='': (0, '', '')
- self.check(['analyze', '-c', 'debug_goma', '//out/Default',
- '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
- out = json.loads(mbw.files['/tmp/out.json'])
- # If GN returns so many compile targets that we might have command-line
- # issues, we should give up and just build everything we were asked to
- # build. The output compile_targets should include all of the input
- # test_targets and additional_compile_targets.
- self.assertEqual(['all', 'foo_unittests'], out['compile_targets'])
- def test_gen(self):
- mbw = self.fake_mbw()
- self.check(['gen', '-c', 'debug_goma', '//out/Default', '-g', '/goma'],
- mbw=mbw, ret=0)
- self.assertMultiLineEqual(mbw.files['/fake_src/out/Default/args.gn'],
- ('goma_dir = "/goma"\n'
- 'is_debug = true\n'
- 'use_goma = true\n'))
- # Make sure we log both what is written to args.gn and the command line.
- self.assertIn('Writing """', mbw.out)
- self.assertIn('/fake_src/buildtools/linux64/gn gen //out/Default --check',
- mbw.out)
- mbw = self.fake_mbw(win32=True)
- self.check(['gen', '-c', 'debug_goma', '-g', 'c:\\goma', '//out/Debug'],
- mbw=mbw, ret=0)
- self.assertMultiLineEqual(mbw.files['c:\\fake_src\\out\\Debug\\args.gn'],
- ('goma_dir = "c:\\\\goma"\n'
- 'is_debug = true\n'
- 'use_goma = true\n'))
- self.assertIn(
- 'c:\\fake_src\\buildtools\\win\\gn.exe gen //out/Debug '
- '--check', mbw.out)
- mbw = self.fake_mbw()
- self.check(['gen', '-m', 'fake_builder_group', '-b', 'fake_args_bot',
- '//out/Debug'],
- mbw=mbw, ret=0)
- # TODO(https://crbug.com/1093038): This assert is inappropriately failing.
- # self.assertEqual(
- # mbw.files['/fake_src/out/Debug/args.gn'],
- # 'import("//build/args/bots/fake_builder_group/fake_args_bot.gn")\n')
- def test_gen_args_file_mixins(self):
- mbw = self.fake_mbw()
- self.check(['gen', '-m', 'fake_builder_group', '-b', 'fake_args_file',
- '//out/Debug'], mbw=mbw, ret=0)
- self.assertEqual(
- mbw.files['/fake_src/out/Debug/args.gn'],
- ('import("//build/args/bots/fake_builder_group/fake_args_bot.gn")\n'
- 'use_goma = true\n'))
- def test_gen_args_file_twice(self):
- mbw = self.fake_mbw()
- mbw.files[mbw.default_config] = TEST_ARGS_FILE_TWICE_CONFIG
- self.check(['gen', '-m', 'fake_builder_group', '-b', 'fake_args_file_twice',
- '//out/Debug'], mbw=mbw, ret=1)
- def test_gen_fails(self):
- mbw = self.fake_mbw()
- mbw.Call = lambda cmd, env=None, capture_output=True, input='': (1, '', '')
- self.check(['gen', '-c', 'debug_goma', '//out/Default'], mbw=mbw, ret=1)
- def test_gen_swarming(self):
- files = {
- '/tmp/swarming_targets':
- 'base_unittests\n',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- }
- mbw = self.fake_mbw(files)
- def fake_call(cmd, env=None, capture_output=True, input=''):
- del cmd
- del env
- del capture_output
- del input
- mbw.files['/fake_src/out/Default/base_unittests.runtime_deps'] = (
- 'base_unittests\n')
- return 0, '', ''
- mbw.Call = fake_call
- self.check(['gen',
- '-c', 'debug_goma',
- '--swarming-targets-file', '/tmp/swarming_targets',
- '//out/Default'], mbw=mbw, ret=0)
- self.assertIn('/fake_src/out/Default/base_unittests.isolate',
- mbw.files)
- self.assertIn('/fake_src/out/Default/base_unittests.isolated.gen.json',
- mbw.files)
- def test_gen_swarming_script(self):
- files = {
- '/tmp/swarming_targets': 'cc_perftests\n',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl': (
- "{'cc_perftests': {"
- " 'label': '//cc:cc_perftests',"
- " 'type': 'script',"
- " 'script': '/fake_src/out/Default/test_script.py',"
- "}}\n"
- ),
- }
- mbw = self.fake_mbw(files=files)
- def fake_call(cmd, env=None, capture_output=True, input=''):
- del cmd
- del env
- del capture_output
- del input
- mbw.files['/fake_src/out/Default/cc_perftests.runtime_deps'] = (
- 'cc_perftests\n')
- return 0, '', ''
- mbw.Call = fake_call
- self.check(['gen',
- '-c', 'debug_goma',
- '--swarming-targets-file', '/tmp/swarming_targets',
- '--isolate-map-file',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl',
- '//out/Default'], mbw=mbw, ret=0)
- self.assertIn('/fake_src/out/Default/cc_perftests.isolate',
- mbw.files)
- self.assertIn('/fake_src/out/Default/cc_perftests.isolated.gen.json',
- mbw.files)
- def test_multiple_isolate_maps(self):
- files = {
- '/tmp/swarming_targets':
- 'cc_perftests\n',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'cc_perftests': {"
- " 'label': '//cc:cc_perftests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- '/fake_src/testing/buildbot/gn_isolate_map2.pyl':
- ("{'cc_perftests2': {"
- " 'label': '//cc:cc_perftests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- }
- mbw = self.fake_mbw(files=files)
- def fake_call(cmd, env=None, capture_output=True, input=''):
- del cmd
- del env
- del capture_output
- del input
- mbw.files['/fake_src/out/Default/cc_perftests.runtime_deps'] = (
- 'cc_perftests_fuzzer\n')
- return 0, '', ''
- mbw.Call = fake_call
- self.check(['gen',
- '-c', 'debug_goma',
- '--swarming-targets-file', '/tmp/swarming_targets',
- '--isolate-map-file',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl',
- '--isolate-map-file',
- '/fake_src/testing/buildbot/gn_isolate_map2.pyl',
- '//out/Default'], mbw=mbw, ret=0)
- self.assertIn('/fake_src/out/Default/cc_perftests.isolate',
- mbw.files)
- self.assertIn('/fake_src/out/Default/cc_perftests.isolated.gen.json',
- mbw.files)
- def test_duplicate_isolate_maps(self):
- files = {
- '/tmp/swarming_targets':
- 'cc_perftests\n',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'cc_perftests': {"
- " 'label': '//cc:cc_perftests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- '/fake_src/testing/buildbot/gn_isolate_map2.pyl':
- ("{'cc_perftests': {"
- " 'label': '//cc:cc_perftests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- 'c:\\fake_src\out\Default\cc_perftests.exe.runtime_deps':
- ("cc_perftests\n"),
- }
- mbw = self.fake_mbw(files=files, win32=True)
- # Check that passing duplicate targets into mb fails.
- self.check(['gen',
- '-c', 'debug_goma',
- '--swarming-targets-file', '/tmp/swarming_targets',
- '--isolate-map-file',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl',
- '--isolate-map-file',
- '/fake_src/testing/buildbot/gn_isolate_map2.pyl',
- '//out/Default'], mbw=mbw, ret=1)
- def test_isolate(self):
- files = {
- '/fake_src/out/Default/toolchain.ninja':
- "",
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- '/fake_src/out/Default/base_unittests.runtime_deps':
- ("base_unittests\n"),
- }
- self.check(['isolate', '-c', 'debug_goma', '//out/Default',
- 'base_unittests'], files=files, ret=0)
- # test running isolate on an existing build_dir
- files['/fake_src/out/Default/args.gn'] = 'is_debug = true\n'
- self.check(['isolate', '//out/Default', 'base_unittests'],
- files=files, ret=0)
- self.check(['isolate', '//out/Default', 'base_unittests'],
- files=files, ret=0)
- # Existing build dir that uses a .gni import.
- files['/fake_src/out/Default/args.gn'] = 'import("//import/args.gni")\n'
- files['/fake_src/import/args.gni'] = 'is_debug = true\n'
- self.check(['isolate', '//out/Default', 'base_unittests'],
- files=files,
- ret=0)
- def test_dedup_runtime_deps(self):
- files = {
- '/tmp/swarming_targets':
- 'base_unittests\n',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- }
- mbw = self.fake_mbw(files)
- def fake_call(cmd, env=None, capture_output=True, input=''):
- del cmd
- del env
- del capture_output
- del input
- mbw.files['/fake_src/out/Default/base_unittests.runtime_deps'] = (
- 'base_unittests\n'
- '../../filters/some_filter/\n'
- '../../filters/some_filter/foo\n'
- '../../filters/another_filter/hoo\n')
- return 0, '', ''
- mbw.Call = fake_call
- self.check([
- 'gen', '-c', 'debug_goma', '--swarming-targets-file',
- '/tmp/swarming_targets', '//out/Default'
- ],
- mbw=mbw,
- ret=0)
- self.assertIn('/fake_src/out/Default/base_unittests.isolate', mbw.files)
- files = mbw.files.get('/fake_src/out/Default/base_unittests.isolate')
- self.assertIn('../../filters/some_filter', files)
- self.assertNotIn('../../filters/some_filter/foo', files)
- self.assertIn('../../filters/another_filter/hoo', files)
- def test_isolate_dir(self):
- files = {
- '/fake_src/out/Default/toolchain.ninja':
- "",
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- }
- mbw = self.fake_mbw(files=files)
- mbw.cmds.append((0, '', '')) # Result of `gn gen`
- mbw.cmds.append((0, '', '')) # Result of `autoninja`
- # Result of `gn desc runtime_deps`
- mbw.cmds.append((0, 'base_unitests\n../../test_data/\n', ''))
- self.check(['isolate', '-c', 'debug_goma', '//out/Default',
- 'base_unittests'], mbw=mbw, ret=0, err='')
- def test_isolate_generated_dir(self):
- files = {
- '/fake_src/out/Default/toolchain.ninja':
- "",
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- }
- mbw = self.fake_mbw(files=files)
- mbw.cmds.append((0, '', '')) # Result of `gn gen`
- mbw.cmds.append((0, '', '')) # Result of `autoninja`
- # Result of `gn desc runtime_deps`
- mbw.cmds.append((0, 'base_unitests\ntest_data/\n', ''))
- expected_err = ('error: gn `data` items may not list generated directories;'
- ' list files in directory instead for:\n'
- '//out/Default/test_data/\n')
- self.check(['isolate', '-c', 'debug_goma', '//out/Default',
- 'base_unittests'], mbw=mbw, ret=1)
- self.assertEqual(mbw.out[-len(expected_err):], expected_err)
- def test_run(self):
- files = {
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- '/fake_src/out/Default/base_unittests.runtime_deps':
- ("base_unittests\n"),
- }
- mbw = self.check(['run', '-c', 'debug_goma', '//out/Default',
- 'base_unittests'], files=files, ret=0)
- # pylint: disable=line-too-long
- self.assertEqual(
- mbw.files['/fake_src/out/Default/base_unittests.isolate'],
- '{"variables": {"command": ["vpython3", "../../testing/test_env.py", "./base_unittests", "--test-launcher-bot-mode", "--asan=0", "--lsan=0", "--msan=0", "--tsan=0", "--cfi-diag=0"], "files": ["../../.vpython3", "../../testing/test_env.py"]}}\n')
- # pylint: enable=line-too-long
- def test_run_swarmed(self):
- files = {
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- '/fake_src/out/Default/base_unittests.runtime_deps':
- ("base_unittests\n"),
- '/fake_src/out/Default/base_unittests.archive.json':
- ("{\"base_unittests\":\"fake_hash\"}"),
- '/fake_src/third_party/depot_tools/cipd_manifest.txt':
- ("# vpython\n"
- "/some/vpython/pkg git_revision:deadbeef\n"),
- }
- task_json = json.dumps({'tasks': [{'task_id': '00000'}]})
- collect_json = json.dumps({'00000': {'results': {}}})
- mbw = self.fake_mbw(files=files)
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'task.json')] = task_json
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'collect_output.json')] = collect_json
- original_impl = mbw.ToSrcRelPath
- def to_src_rel_path_stub(path):
- if path.endswith('base_unittests.archive.json'):
- return 'base_unittests.archive.json'
- return original_impl(path)
- mbw.ToSrcRelPath = to_src_rel_path_stub
- self.check(['run', '-s', '-c', 'debug_goma', '//out/Default',
- 'base_unittests'], mbw=mbw, ret=0)
- mbw = self.fake_mbw(files=files)
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'task.json')] = task_json
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'collect_output.json')] = collect_json
- mbw.ToSrcRelPath = to_src_rel_path_stub
- self.check(['run', '-s', '-c', 'debug_goma', '-d', 'os', 'Win7',
- '//out/Default', 'base_unittests'], mbw=mbw, ret=0)
- def test_run_swarmed_task_failure(self):
- files = {
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ("{'base_unittests': {"
- " 'label': '//base:base_unittests',"
- " 'type': 'console_test_launcher',"
- "}}\n"),
- '/fake_src/out/Default/base_unittests.runtime_deps':
- ("base_unittests\n"),
- '/fake_src/out/Default/base_unittests.archive.json':
- ("{\"base_unittests\":\"fake_hash\"}"),
- '/fake_src/third_party/depot_tools/cipd_manifest.txt':
- ("# vpython\n"
- "/some/vpython/pkg git_revision:deadbeef\n"),
- }
- task_json = json.dumps({'tasks': [{'task_id': '00000'}]})
- collect_json = json.dumps({'00000': {'results': {'exit_code': 1}}})
- mbw = self.fake_mbw(files=files)
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'task.json')] = task_json
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'collect_output.json')] = collect_json
- original_impl = mbw.ToSrcRelPath
- def to_src_rel_path_stub(path):
- if path.endswith('base_unittests.archive.json'):
- return 'base_unittests.archive.json'
- return original_impl(path)
- mbw.ToSrcRelPath = to_src_rel_path_stub
- self.check(
- ['run', '-s', '-c', 'debug_goma', '//out/Default', 'base_unittests'],
- mbw=mbw,
- ret=1)
- mbw = self.fake_mbw(files=files)
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'task.json')] = task_json
- mbw.files[mbw.PathJoin(mbw.TempDir(), 'collect_output.json')] = collect_json
- mbw.ToSrcRelPath = to_src_rel_path_stub
- self.check([
- 'run', '-s', '-c', 'debug_goma', '-d', 'os', 'Win7', '//out/Default',
- 'base_unittests'
- ],
- mbw=mbw,
- ret=1)
- def test_lookup(self):
- self.check(['lookup', '-c', 'debug_goma'], ret=0,
- out=('\n'
- 'Writing """\\\n'
- 'is_debug = true\n'
- 'use_goma = true\n'
- '""" to _path_/args.gn.\n\n'
- '/fake_src/buildtools/linux64/gn gen _path_\n'))
- def test_quiet_lookup(self):
- self.check(['lookup', '-c', 'debug_goma', '--quiet'], ret=0,
- out=('is_debug = true\n'
- 'use_goma = true\n'))
- def test_lookup_goma_dir_expansion(self):
- self.check(['lookup', '-c', 'rel_bot', '-g', '/foo'],
- ret=0,
- out=('\n'
- 'Writing """\\\n'
- 'dcheck_always_on = false\n'
- 'enable_doom_melon = true\n'
- 'goma_dir = "/foo"\n'
- 'is_debug = false\n'
- 'use_goma = true\n'
- '""" to _path_/args.gn.\n\n'
- '/fake_src/buildtools/linux64/gn gen _path_\n'))
- def test_help(self):
- orig_stdout = sys.stdout
- try:
- sys.stdout = StringIO()
- self.assertRaises(SystemExit, self.check, ['-h'])
- self.assertRaises(SystemExit, self.check, ['help'])
- self.assertRaises(SystemExit, self.check, ['help', 'gen'])
- finally:
- sys.stdout = orig_stdout
- def test_multiple_phases(self):
- # Check that not passing a --phase to a multi-phase builder fails.
- mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
- 'fake_multi_phase'], ret=1)
- self.assertIn('Must specify a build --phase', mbw.out)
- # Check that passing a --phase to a single-phase builder fails.
- mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
- 'fake_builder', '--phase', 'phase_1'], ret=1)
- self.assertIn('Must not specify a build --phase', mbw.out)
- # Check that passing a wrong phase key to a multi-phase builder fails.
- mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
- 'fake_multi_phase', '--phase', 'wrong_phase'], ret=1)
- self.assertIn('Phase wrong_phase doesn\'t exist', mbw.out)
- # Check that passing a correct phase key to a multi-phase builder passes.
- mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
- 'fake_multi_phase', '--phase', 'phase_1'], ret=0)
- self.assertIn('phase = 1', mbw.out)
- mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
- 'fake_multi_phase', '--phase', 'phase_2'], ret=0)
- self.assertIn('phase = 2', mbw.out)
- def test_recursive_lookup(self):
- files = {
- '/fake_src/build/args/fake.gn': (
- 'enable_doom_melon = true\n'
- 'enable_antidoom_banana = true\n'
- )
- }
- self.check([
- 'lookup', '-m', 'fake_builder_group', '-b', 'fake_args_file',
- '--recursive'
- ],
- files=files,
- ret=0,
- out=('dcheck_always_on = false\n'
- 'is_debug = false\n'
- 'use_goma = true\n'))
- def test_train(self):
- mbw = self.fake_mbw()
- temp_dir = mbw.TempDir()
- self.check(['train', '--expectations-dir', temp_dir], mbw=mbw, ret=0)
- self.assertIn(os.path.join(temp_dir, 'fake_builder_group.json'), mbw.files)
- def test_validate(self):
- mbw = self.fake_mbw()
- self.check(['validate'], mbw=mbw, ret=0)
- def test_bad_validate(self):
- mbw = self.fake_mbw()
- mbw.files[mbw.default_config] = TEST_BAD_CONFIG
- self.check(['validate', '-f', mbw.default_config], mbw=mbw, ret=1)
- def test_duplicate_validate(self):
- mbw = self.fake_mbw()
- mbw.files[mbw.default_config] = TEST_DUP_CONFIG
- self.check(['validate'], mbw=mbw, ret=1)
- self.assertIn(
- 'Duplicate configs detected. When evaluated fully, the '
- 'following configs are all equivalent: \'some_config\', '
- '\'some_other_config\'.', mbw.out)
- def test_good_expectations_validate(self):
- mbw = self.fake_mbw()
- # Train the expectations normally.
- temp_dir = mbw.TempDir()
- self.check(['train', '--expectations-dir', temp_dir], mbw=mbw, ret=0)
- # Immediately validating them should pass.
- self.check(['validate', '--expectations-dir', temp_dir], mbw=mbw, ret=0)
- def test_bad_expectations_validate(self):
- mbw = self.fake_mbw()
- # Train the expectations normally.
- temp_dir = mbw.TempDir()
- self.check(['train', '--expectations-dir', temp_dir], mbw=mbw, ret=0)
- # Remove one of the expectation files.
- mbw.files.pop(os.path.join(temp_dir, 'fake_builder_group.json'))
- # Now validating should fail.
- self.check(['validate', '--expectations-dir', temp_dir], mbw=mbw, ret=1)
- self.assertIn('Expectations out of date', mbw.out)
- def test_build_command_unix(self):
- files = {
- '/fake_src/out/Default/toolchain.ninja':
- '',
- '/fake_src/testing/buildbot/gn_isolate_map.pyl':
- ('{"base_unittests": {'
- ' "label": "//base:base_unittests",'
- ' "type": "console_test_launcher",'
- ' "args": [],'
- '}}\n')
- }
- mbw = self.fake_mbw(files)
- self.check(['run', '//out/Default', 'base_unittests'], mbw=mbw, ret=0)
- self.assertIn(['autoninja', '-C', 'out/Default', 'base_unittests'],
- mbw.calls)
- def test_build_command_windows(self):
- files = {
- 'c:\\fake_src\\out\\Default\\toolchain.ninja':
- '',
- 'c:\\fake_src\\testing\\buildbot\\gn_isolate_map.pyl':
- ('{"base_unittests": {'
- ' "label": "//base:base_unittests",'
- ' "type": "console_test_launcher",'
- ' "args": [],'
- '}}\n')
- }
- mbw = self.fake_mbw(files, True)
- self.check(['run', '//out/Default', 'base_unittests'], mbw=mbw, ret=0)
- self.assertIn(['autoninja.bat', '-C', 'out\\Default', 'base_unittests'],
- mbw.calls)
- def test_ios_error_config_with_ios_json(self):
- """Ensures that ios_error config finds the correct iOS JSON file for args"""
- files = {
- '/fake_src/ios/build/bots/fake_builder_group/fake_ios_error.json':
- ('{"gn_args": ["is_debug=true"]}\n')
- }
- mbw = self.fake_mbw(files)
- self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_ios_error'],
- mbw=mbw,
- ret=0,
- out=('\n'
- 'Writing """\\\n'
- 'is_debug = true\n'
- '""" to _path_/args.gn.\n\n'
- '/fake_src/buildtools/linux64/gn gen _path_\n'))
- def test_bot_definition_in_ios_json_only(self):
- """Ensures that logic checks iOS JSON file for args
- When builder definition is not present, ensure that ios/build/bots/ is
- checked.
- """
- files = {
- '/fake_src/ios/build/bots/fake_builder_group/fake_ios_bot.json':
- ('{"gn_args": ["is_debug=true"]}\n')
- }
- mbw = self.fake_mbw(files)
- self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_ios_bot'],
- mbw=mbw,
- ret=0,
- out=('\n'
- 'Writing """\\\n'
- 'is_debug = true\n'
- '""" to _path_/args.gn.\n\n'
- '/fake_src/buildtools/linux64/gn gen _path_\n'))
- def test_ios_error_config_missing_json_definition(self):
- """Ensures MBErr is thrown
- Expect MBErr with 'No iOS definition ...' for iOS bots when the bot config
- is ios_error, but there is no iOS JSON definition for it.
- """
- mbw = self.fake_mbw()
- self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_ios_error'],
- mbw=mbw,
- ret=1)
- self.assertIn('MBErr: No iOS definition was found.', mbw.out)
- def test_bot_missing_definition(self):
- """Ensures builder missing MBErr is thrown
- Expect the original MBErr to be thrown for iOS bots when the bot definition
- doesn't exist at all.
- """
- mbw = self.fake_mbw()
- self.check(['lookup', '-m', 'fake_builder_group', '-b', 'random_bot'],
- mbw=mbw,
- ret=1)
- self.assertIn('MBErr: Builder name "random_bot" not found under groups',
- mbw.out)
- if __name__ == '__main__':
- unittest.main()
|