diff options
Diffstat (limited to 'third_party/libwebrtc/tools_webrtc/mb/mb_unittest.py')
-rwxr-xr-x | third_party/libwebrtc/tools_webrtc/mb/mb_unittest.py | 728 |
1 files changed, 728 insertions, 0 deletions
diff --git a/third_party/libwebrtc/tools_webrtc/mb/mb_unittest.py b/third_party/libwebrtc/tools_webrtc/mb/mb_unittest.py new file mode 100755 index 0000000000..583fefd87e --- /dev/null +++ b/third_party/libwebrtc/tools_webrtc/mb/mb_unittest.py @@ -0,0 +1,728 @@ +#!/usr/bin/env vpython3 + +# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +"""Tests for mb.py.""" + +import ast +import os +import re +import sys +import tempfile +import unittest + +_SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) +_SRC_DIR = os.path.dirname(os.path.dirname(_SCRIPT_DIR)) +sys.path.insert(0, _SRC_DIR) + +from tools_webrtc.mb import mb + + +class FakeMBW(mb.WebRTCMetaBuildWrapper): + 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_webrtc\\mb\\mb_config.pyl' + self.default_isolate_map = ('c:\\fake_src\\testing\\buildbot\\' + 'gn_isolate_map.pyl') + self.platform = 'win32' + self.executable = 'c:\\python\\vpython3.exe' + self.sep = '\\' + self.cwd = 'c:\\fake_src\\out\\Default' + else: + self.chromium_src_dir = '/fake_src' + self.default_config = '/fake_src/tools_webrtc/mb/mb_config.pyl' + self.default_isolate_map = '/fake_src/testing/buildbot/gn_isolate_map.pyl' + self.executable = '/usr/bin/vpython3' + self.platform = 'linux2' + 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): + # pylint: disable=no-self-use + 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): + # pylint: disable=redefined-builtin + 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 = os.path.join(tempfile.gettempdir(), 'mb_test') + self.dirs.add(tmp_dir) + return tmp_dir + + def TempFile(self, mode='w'): + 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: + # pylint: disable=invalid-name + 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_group': { + 'fake_builder': 'rel_bot', + 'fake_debug_builder': 'debug_goma', + 'fake_args_bot': 'fake_args_bot', + 'fake_multi_phase': { 'phase_1': 'phase_1', 'phase_2': 'phase_2'}, + 'fake_android_bot': 'android_bot', + 'fake_args_file': 'args_file_goma', + 'fake_ios_error': 'ios_error', + }, + }, + 'configs': { + 'args_file_goma': ['fake_args_bot', 'goma'], + 'fake_args_bot': ['fake_args_bot'], + 'rel_bot': ['rel', 'goma', 'fake_feature1'], + 'debug_goma': ['debug', 'goma'], + 'phase_1': ['rel', 'phase_1'], + 'phase_2': ['rel', 'phase_2'], + 'android_bot': ['android'], + 'ios_error': ['error'], + }, + 'mixins': { + 'error': { + 'gn_args': 'error', + }, + 'fake_args_bot': { + 'args_file': '//build/args/bots/fake_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', + }, + 'debug': { + 'gn_args': 'is_debug=true', + }, + 'android': { + 'gn_args': 'target_os="android" dcheck_always_on=false', + } + }, +} +""" + + +def CreateFakeMBW(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_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 list(files.items()): + mbw.files[path] = contents + if path.endswith('.runtime_deps'): + + def FakeCall(cmd, env=None, capture_output=True, stdin=None): + # pylint: disable=cell-var-from-loop + del cmd + del env + del capture_output + del stdin + mbw.files[path] = contents + return 0, '', '' + + # pylint: disable=invalid-name + mbw.Call = FakeCall + return mbw + + +class UnitTest(unittest.TestCase): + # pylint: disable=invalid-name + def check(self, + args, + mbw=None, + files=None, + out=None, + err=None, + ret=None, + env=None): + if not mbw: + mbw = CreateFakeMBW(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_gen_swarming(self): + files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'raw'," + " 'args': []," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + mbw = CreateFakeMBW(files) + self.check([ + 'gen', '-c', 'debug_goma', '--swarming-targets-file', + '/tmp/swarming_targets', '//out/Default' + ], + mbw=mbw, + ret=0) + self.assertIn('/fake_src/out/Default/foo_unittests.isolate', mbw.files) + self.assertIn('/fake_src/out/Default/foo_unittests.isolated.gen.json', + mbw.files) + + def test_gen_swarming_android(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'console_test_launcher'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + mbw = self.check([ + 'gen', '-c', 'android_bot', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual( + files, + ['../../.vpython3', '../../testing/test_env.py', 'foo_unittests']) + self.assertEqual(command, [ + 'luci-auth', + 'context', + '--', + 'vpython3', + '../../build/android/test_wrapper/logdog_wrapper.py', + '--target', + 'foo_unittests', + '--logdog-bin-cmd', + '../../.task_template_packages/logdog_butler', + '--logcat-output-file', + '${ISOLATED_OUTDIR}/logcats', + '--store-tombstones', + ]) + + def test_gen_swarming_android_junit_test(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'junit_test'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + mbw = self.check([ + 'gen', '-c', 'android_bot', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual( + files, + ['../../.vpython3', '../../testing/test_env.py', 'foo_unittests']) + self.assertEqual(command, [ + 'luci-auth', + 'context', + '--', + 'vpython3', + '../../build/android/test_wrapper/logdog_wrapper.py', + '--target', + 'foo_unittests', + '--logdog-bin-cmd', + '../../.task_template_packages/logdog_butler', + '--logcat-output-file', + '${ISOLATED_OUTDIR}/logcats', + '--store-tombstones', + ]) + + def test_gen_script(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests_script\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests_script': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'script'," + " 'script': '//foo/foo_unittests_script.py'," + "}}\n"), + '/fake_src/out/Default/foo_unittests_script.runtime_deps': + ("foo_unittests\n" + "foo_unittests_script.py\n"), + } + mbw = self.check([ + 'gen', '-c', 'debug_goma', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = ( + mbw.files['/fake_src/out/Default/foo_unittests_script.isolate']) + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + 'foo_unittests', + 'foo_unittests_script.py', + ]) + self.assertEqual(command, [ + 'vpython3', + '../../foo/foo_unittests_script.py', + ]) + + def test_gen_raw(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'raw'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + mbw = self.check([ + 'gen', '-c', 'debug_goma', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + 'foo_unittests', + ]) + self.assertEqual(command, ['bin/run_foo_unittests']) + + def test_gen_non_parallel_console_test_launcher(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'non_parallel_console_test_launcher'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + mbw = self.check([ + 'gen', '-c', 'debug_goma', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + '../../third_party/gtest-parallel/gtest-parallel', + '../../third_party/gtest-parallel/gtest_parallel.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + 'foo_unittests', + ]) + self.assertEqual(command, [ + 'vpython3', + '../../testing/test_env.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + '--output_dir=${ISOLATED_OUTDIR}/test_logs', + '--gtest_color=no', + '--workers=1', + '--retry_failed=3', + './foo_unittests', + '--asan=0', + '--lsan=0', + '--msan=0', + '--tsan=0', + ]) + + def test_isolate_windowed_test_launcher_linux(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'windowed_test_launcher'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': + ("foo_unittests\n" + "some_resource_file\n"), + } + mbw = self.check([ + 'gen', '-c', 'debug_goma', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + '../../testing/xvfb.py', + '../../third_party/gtest-parallel/gtest-parallel', + '../../third_party/gtest-parallel/gtest_parallel.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + 'foo_unittests', + 'some_resource_file', + ]) + self.assertEqual(command, [ + 'vpython3', + '../../testing/xvfb.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + '--output_dir=${ISOLATED_OUTDIR}/test_logs', + '--gtest_color=no', + '--retry_failed=3', + './foo_unittests', + '--asan=0', + '--lsan=0', + '--msan=0', + '--tsan=0', + ]) + + def test_gen_windowed_test_launcher_win(self): + files = { + 'c:\\fake_src\\out\\Default\\tmp\\swarming_targets': + 'unittests\n', + 'c:\\fake_src\\testing\\buildbot\\gn_isolate_map.pyl': + ("{'unittests': {" + " 'label': '//somewhere:unittests'," + " 'type': 'windowed_test_launcher'," + "}}\n"), + r'c:\fake_src\out\Default\unittests.exe.runtime_deps': + ("unittests.exe\n" + "some_dependency\n"), + } + mbw = CreateFakeMBW(files=files, win32=True) + self.check([ + 'gen', '-c', 'debug_goma', '--swarming-targets-file', + 'c:\\fake_src\\out\\Default\\tmp\\swarming_targets', + '--isolate-map-file', + 'c:\\fake_src\\testing\\buildbot\\gn_isolate_map.pyl', '//out/Default' + ], + mbw=mbw, + ret=0) + + isolate_file = mbw.files['c:\\fake_src\\out\\Default\\unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + '../../third_party/gtest-parallel/gtest-parallel', + '../../third_party/gtest-parallel/gtest_parallel.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + 'some_dependency', + 'unittests.exe', + ]) + self.assertEqual(command, [ + 'vpython3', + '../../testing/test_env.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + '--output_dir=${ISOLATED_OUTDIR}/test_logs', + '--gtest_color=no', + '--retry_failed=3', + r'.\unittests.exe', + '--asan=0', + '--lsan=0', + '--msan=0', + '--tsan=0', + ]) + + def test_gen_console_test_launcher(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'console_test_launcher'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + mbw = self.check([ + 'gen', '-c', 'debug_goma', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + '../../third_party/gtest-parallel/gtest-parallel', + '../../third_party/gtest-parallel/gtest_parallel.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + 'foo_unittests', + ]) + self.assertEqual(command, [ + 'vpython3', + '../../testing/test_env.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + '--output_dir=${ISOLATED_OUTDIR}/test_logs', + '--gtest_color=no', + '--retry_failed=3', + './foo_unittests', + '--asan=0', + '--lsan=0', + '--msan=0', + '--tsan=0', + ]) + + def test_isolate_test_launcher_with_webcam(self): + test_files = { + '/tmp/swarming_targets': + 'foo_unittests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'console_test_launcher'," + " 'use_webcam': True," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': + ("foo_unittests\n" + "some_resource_file\n"), + } + mbw = self.check([ + 'gen', '-c', 'debug_goma', '//out/Default', '--swarming-targets-file', + '/tmp/swarming_targets', '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl' + ], + files=test_files, + ret=0) + + isolate_file = mbw.files['/fake_src/out/Default/foo_unittests.isolate'] + isolate_file_contents = ast.literal_eval(isolate_file) + files = isolate_file_contents['variables']['files'] + command = isolate_file_contents['variables']['command'] + + self.assertEqual(files, [ + '../../.vpython3', + '../../testing/test_env.py', + '../../third_party/gtest-parallel/gtest-parallel', + '../../third_party/gtest-parallel/gtest_parallel.py', + '../../tools_webrtc/ensure_webcam_is_running.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + 'foo_unittests', + 'some_resource_file', + ]) + self.assertEqual(command, [ + 'vpython3', + '../../tools_webrtc/ensure_webcam_is_running.py', + 'vpython3', + '../../testing/test_env.py', + '../../tools_webrtc/gtest-parallel-wrapper.py', + '--output_dir=${ISOLATED_OUTDIR}/test_logs', + '--gtest_color=no', + '--retry_failed=3', + './foo_unittests', + '--asan=0', + '--lsan=0', + '--msan=0', + '--tsan=0', + ]) + + def test_isolate(self): + files = { + '/fake_src/out/Default/toolchain.ninja': + "", + '/fake_src/testing/buildbot/gn_isolate_map.pyl': + ("{'foo_unittests': {" + " 'label': '//foo:foo_unittests'," + " 'type': 'non_parallel_console_test_launcher'," + "}}\n"), + '/fake_src/out/Default/foo_unittests.runtime_deps': ("foo_unittests\n"), + } + self.check( + ['isolate', '-c', 'debug_goma', '//out/Default', 'foo_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', 'foo_unittests'], + files=files, + ret=0) + files['/fake_src/out/Default/mb_type'] = 'gn\n' + self.check(['isolate', '//out/Default', 'foo_unittests'], + files=files, + ret=0) + +if __name__ == '__main__': + unittest.main() |