| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Generates test runner factory and tests for GTests.""" | 5 """Generates test runner factory and tests for GTests.""" |
| 6 # pylint: disable=W0212 | 6 # pylint: disable=W0212 |
| 7 | 7 |
| 8 import logging | 8 import logging |
| 9 import os | 9 import os |
| 10 import sys | 10 import sys |
| 11 | 11 |
| 12 from pylib import constants | 12 from pylib import constants |
| 13 from pylib import valgrind_tools | |
| 14 | 13 |
| 14 from pylib.base import base_setup |
| 15 from pylib.base import base_test_result | 15 from pylib.base import base_test_result |
| 16 from pylib.base import test_dispatcher | 16 from pylib.base import test_dispatcher |
| 17 from pylib.device import device_utils | 17 from pylib.device import device_utils |
| 18 from pylib.gtest import test_package_apk | 18 from pylib.gtest import test_package_apk |
| 19 from pylib.gtest import test_package_exe | 19 from pylib.gtest import test_package_exe |
| 20 from pylib.gtest import test_runner | 20 from pylib.gtest import test_runner |
| 21 from pylib.utils import isolator | |
| 22 | 21 |
| 23 sys.path.insert(0, | 22 sys.path.insert(0, |
| 24 os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', | 23 os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', |
| 25 'common')) | 24 'common')) |
| 26 import unittest_util # pylint: disable=F0401 | 25 import unittest_util # pylint: disable=F0401 |
| 27 | 26 |
| 28 | 27 |
| 29 _ISOLATE_FILE_PATHS = { | 28 ISOLATE_FILE_PATHS = { |
| 30 'base_unittests': 'base/base_unittests.isolate', | 29 'base_unittests': 'base/base_unittests.isolate', |
| 31 'blink_heap_unittests': | 30 'blink_heap_unittests': |
| 32 'third_party/WebKit/Source/platform/heap/BlinkHeapUnitTests.isolate', | 31 'third_party/WebKit/Source/platform/heap/BlinkHeapUnitTests.isolate', |
| 33 'breakpad_unittests': 'breakpad/breakpad_unittests.isolate', | 32 'breakpad_unittests': 'breakpad/breakpad_unittests.isolate', |
| 34 'cc_perftests': 'cc/cc_perftests.isolate', | 33 'cc_perftests': 'cc/cc_perftests.isolate', |
| 35 'components_unittests': 'components/components_unittests.isolate', | 34 'components_unittests': 'components/components_unittests.isolate', |
| 36 'content_browsertests': 'content/content_browsertests.isolate', | 35 'content_browsertests': 'content/content_browsertests.isolate', |
| 37 'content_unittests': 'content/content_unittests.isolate', | 36 'content_unittests': 'content/content_unittests.isolate', |
| 38 'media_perftests': 'media/media_perftests.isolate', | 37 'media_perftests': 'media/media_perftests.isolate', |
| 39 'media_unittests': 'media/media_unittests.isolate', | 38 'media_unittests': 'media/media_unittests.isolate', |
| 40 'net_unittests': 'net/net_unittests.isolate', | 39 'net_unittests': 'net/net_unittests.isolate', |
| 41 'sql_unittests': 'sql/sql_unittests.isolate', | 40 'sql_unittests': 'sql/sql_unittests.isolate', |
| 42 'ui_base_unittests': 'ui/base/ui_base_tests.isolate', | 41 'ui_base_unittests': 'ui/base/ui_base_tests.isolate', |
| 43 'unit_tests': 'chrome/unit_tests.isolate', | 42 'unit_tests': 'chrome/unit_tests.isolate', |
| 44 'webkit_unit_tests': | 43 'webkit_unit_tests': |
| 45 'third_party/WebKit/Source/web/WebKitUnitTests.isolate', | 44 'third_party/WebKit/Source/web/WebKitUnitTests.isolate', |
| 46 } | 45 } |
| 47 | 46 |
| 48 # Used for filtering large data deps at a finer grain than what's allowed in | 47 # Used for filtering large data deps at a finer grain than what's allowed in |
| 49 # isolate files since pushing deps to devices is expensive. | 48 # isolate files since pushing deps to devices is expensive. |
| 50 # Wildcards are allowed. | 49 # Wildcards are allowed. |
| 51 _DEPS_EXCLUSION_LIST = [ | 50 DEPS_EXCLUSION_LIST = [ |
| 52 'chrome/test/data/extensions/api_test', | 51 'chrome/test/data/extensions/api_test', |
| 53 'chrome/test/data/extensions/secure_shell', | 52 'chrome/test/data/extensions/secure_shell', |
| 54 'chrome/test/data/firefox*', | 53 'chrome/test/data/firefox*', |
| 55 'chrome/test/data/gpu', | 54 'chrome/test/data/gpu', |
| 56 'chrome/test/data/image_decoding', | 55 'chrome/test/data/image_decoding', |
| 57 'chrome/test/data/import', | 56 'chrome/test/data/import', |
| 58 'chrome/test/data/page_cycler', | 57 'chrome/test/data/page_cycler', |
| 59 'chrome/test/data/perf', | 58 'chrome/test/data/perf', |
| 60 'chrome/test/data/pyauto_private', | 59 'chrome/test/data/pyauto_private', |
| 61 'chrome/test/data/safari_import', | 60 'chrome/test/data/safari_import', |
| 62 'chrome/test/data/scroll', | 61 'chrome/test/data/scroll', |
| 63 'chrome/test/data/third_party', | 62 'chrome/test/data/third_party', |
| 64 'third_party/hunspell_dictionaries/*.dic', | 63 'third_party/hunspell_dictionaries/*.dic', |
| 65 # crbug.com/258690 | 64 # crbug.com/258690 |
| 66 'webkit/data/bmp_decoder', | 65 'webkit/data/bmp_decoder', |
| 67 'webkit/data/ico_decoder', | 66 'webkit/data/ico_decoder', |
| 68 ] | 67 ] |
| 69 | 68 |
| 70 | 69 |
| 71 def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None): | |
| 72 """Generate the dependency dir for the test suite using isolate. | |
| 73 | |
| 74 Args: | |
| 75 suite_name: Name of the test suite (e.g. base_unittests). | |
| 76 isolate_file_path: .isolate file path to use. If there is a default .isolate | |
| 77 file path for the suite_name, this will override it. | |
| 78 """ | |
| 79 if isolate_file_path: | |
| 80 if os.path.isabs(isolate_file_path): | |
| 81 isolate_abs_path = isolate_file_path | |
| 82 else: | |
| 83 isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, | |
| 84 isolate_file_path) | |
| 85 else: | |
| 86 isolate_rel_path = _ISOLATE_FILE_PATHS.get(suite_name) | |
| 87 if not isolate_rel_path: | |
| 88 logging.info('Did not find an isolate file for the test suite.') | |
| 89 return | |
| 90 isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path) | |
| 91 | |
| 92 isolated_abs_path = os.path.join( | |
| 93 constants.GetOutDirectory(), '%s.isolated' % suite_name) | |
| 94 assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path | |
| 95 | |
| 96 i = isolator.Isolator(constants.ISOLATE_DEPS_DIR) | |
| 97 i.Clear() | |
| 98 i.Remap(isolate_abs_path, isolated_abs_path) | |
| 99 # We're relying on the fact that timestamps are preserved | |
| 100 # by the remap command (hardlinked). Otherwise, all the data | |
| 101 # will be pushed to the device once we move to using time diff | |
| 102 # instead of md5sum. Perform a sanity check here. | |
| 103 i.VerifyHardlinks() | |
| 104 i.PurgeExcluded(_DEPS_EXCLUSION_LIST) | |
| 105 i.MoveOutputDeps() | |
| 106 | |
| 107 | |
| 108 def _GetDisabledTestsFilterFromFile(suite_name): | 70 def _GetDisabledTestsFilterFromFile(suite_name): |
| 109 """Returns a gtest filter based on the *_disabled file. | 71 """Returns a gtest filter based on the *_disabled file. |
| 110 | 72 |
| 111 Args: | 73 Args: |
| 112 suite_name: Name of the test suite (e.g. base_unittests). | 74 suite_name: Name of the test suite (e.g. base_unittests). |
| 113 | 75 |
| 114 Returns: | 76 Returns: |
| 115 A gtest filter which excludes disabled tests. | 77 A gtest filter which excludes disabled tests. |
| 116 Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc' | 78 Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc' |
| 117 """ | 79 """ |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 List of tests remaining. | 173 List of tests remaining. |
| 212 """ | 174 """ |
| 213 tests = _FilterTestsUsingPrefixes( | 175 tests = _FilterTestsUsingPrefixes( |
| 214 tests, has_gtest_filter, has_gtest_filter) | 176 tests, has_gtest_filter, has_gtest_filter) |
| 215 tests = unittest_util.FilterTestNames( | 177 tests = unittest_util.FilterTestNames( |
| 216 tests, _GetDisabledTestsFilterFromFile(suite_name)) | 178 tests, _GetDisabledTestsFilterFromFile(suite_name)) |
| 217 | 179 |
| 218 return tests | 180 return tests |
| 219 | 181 |
| 220 | 182 |
| 221 def PushDataDeps(device, test_options, test_package): | |
| 222 valgrind_tools.PushFilesForTool(test_options.tool, device) | |
| 223 if os.path.exists(constants.ISOLATE_DEPS_DIR): | |
| 224 device_dir = ( | |
| 225 constants.TEST_EXECUTABLE_DIR | |
| 226 if test_package.suite_name == 'breakpad_unittests' | |
| 227 else device.GetExternalStoragePath()) | |
| 228 device.PushChangedFiles([ | |
| 229 (os.path.join(constants.ISOLATE_DEPS_DIR, p), | |
| 230 '%s/%s' % (device_dir, p)) | |
| 231 for p in os.listdir(constants.ISOLATE_DEPS_DIR)]) | |
| 232 | |
| 233 | |
| 234 def Setup(test_options, devices): | 183 def Setup(test_options, devices): |
| 235 """Create the test runner factory and tests. | 184 """Create the test runner factory and tests. |
| 236 | 185 |
| 237 Args: | 186 Args: |
| 238 test_options: A GTestOptions object. | 187 test_options: A GTestOptions object. |
| 239 devices: A list of attached devices. | 188 devices: A list of attached devices. |
| 240 | 189 |
| 241 Returns: | 190 Returns: |
| 242 A tuple of (TestRunnerFactory, tests). | 191 A tuple of (TestRunnerFactory, tests). |
| 243 """ | 192 """ |
| 244 test_package = test_package_apk.TestPackageApk(test_options.suite_name) | 193 test_package = test_package_apk.TestPackageApk(test_options.suite_name) |
| 245 if not os.path.exists(test_package.suite_path): | 194 if not os.path.exists(test_package.suite_path): |
| 246 exe_test_package = test_package_exe.TestPackageExecutable( | 195 exe_test_package = test_package_exe.TestPackageExecutable( |
| 247 test_options.suite_name) | 196 test_options.suite_name) |
| 248 if not os.path.exists(exe_test_package.suite_path): | 197 if not os.path.exists(exe_test_package.suite_path): |
| 249 raise Exception( | 198 raise Exception( |
| 250 'Did not find %s target. Ensure it has been built.\n' | 199 'Did not find %s target. Ensure it has been built.\n' |
| 251 '(not found at %s or %s)' | 200 '(not found at %s or %s)' |
| 252 % (test_options.suite_name, | 201 % (test_options.suite_name, |
| 253 test_package.suite_path, | 202 test_package.suite_path, |
| 254 exe_test_package.suite_path)) | 203 exe_test_package.suite_path)) |
| 255 test_package = exe_test_package | 204 test_package = exe_test_package |
| 256 logging.warning('Found target %s', test_package.suite_path) | 205 logging.warning('Found target %s', test_package.suite_path) |
| 257 | 206 |
| 258 _GenerateDepsDirUsingIsolate(test_options.suite_name, | 207 base_setup.GenerateDepsDirUsingIsolate(test_options.suite_name, |
| 259 test_options.isolate_file_path) | 208 test_options.isolate_file_path, |
| 260 | 209 ISOLATE_FILE_PATHS, |
| 261 device_utils.DeviceUtils.parallel(devices).pMap( | 210 DEPS_EXCLUSION_LIST) |
| 262 PushDataDeps, test_options, test_package) | 211 def push_data_deps_to_device_dir(device): |
| 212 device_dir = (constants.TEST_EXECUTABLE_DIR |
| 213 if test_package.suite_name == 'breakpad_unittests' |
| 214 else device.GetExternalStoragePath()) |
| 215 base_setup.PushDataDeps(device, device_dir, test_options) |
| 216 device_utils.DeviceUtils.parallel(devices).pMap(push_data_deps_to_device_dir) |
| 263 | 217 |
| 264 tests = _GetTests(test_options, test_package, devices) | 218 tests = _GetTests(test_options, test_package, devices) |
| 265 | 219 |
| 266 # Constructs a new TestRunner with the current options. | 220 # Constructs a new TestRunner with the current options. |
| 267 def TestRunnerFactory(device, _shard_index): | 221 def TestRunnerFactory(device, _shard_index): |
| 268 return test_runner.TestRunner( | 222 return test_runner.TestRunner( |
| 269 test_options, | 223 test_options, |
| 270 device, | 224 device, |
| 271 test_package) | 225 test_package) |
| 272 | 226 |
| 273 if test_options.run_disabled: | 227 if test_options.run_disabled: |
| 274 test_options = test_options._replace( | 228 test_options = test_options._replace( |
| 275 test_arguments=('%s --gtest_also_run_disabled_tests' % | 229 test_arguments=('%s --gtest_also_run_disabled_tests' % |
| 276 test_options.test_arguments)) | 230 test_options.test_arguments)) |
| 277 else: | 231 else: |
| 278 tests = _FilterDisabledTests(tests, test_options.suite_name, | 232 tests = _FilterDisabledTests(tests, test_options.suite_name, |
| 279 bool(test_options.gtest_filter)) | 233 bool(test_options.gtest_filter)) |
| 280 if test_options.gtest_filter: | 234 if test_options.gtest_filter: |
| 281 tests = unittest_util.FilterTestNames(tests, test_options.gtest_filter) | 235 tests = unittest_util.FilterTestNames(tests, test_options.gtest_filter) |
| 282 | 236 |
| 283 # Coalesce unit tests into a single test per device | 237 # Coalesce unit tests into a single test per device |
| 284 if test_options.suite_name != 'content_browsertests': | 238 if test_options.suite_name != 'content_browsertests': |
| 285 num_devices = len(devices) | 239 num_devices = len(devices) |
| 286 tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] | 240 tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] |
| 287 tests = [t for t in tests if t] | 241 tests = [t for t in tests if t] |
| 288 | 242 |
| 289 return (TestRunnerFactory, tests) | 243 return (TestRunnerFactory, tests) |
| OLD | NEW |