Chromium Code Reviews| 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 'ui_unittests': 'ui/base/ui_base_tests.isolate', | 42 'ui_unittests': 'ui/base/ui_base_tests.isolate', |
| 44 'unit_tests': 'chrome/unit_tests.isolate', | 43 'unit_tests': 'chrome/unit_tests.isolate', |
| 45 'webkit_unit_tests': | 44 'webkit_unit_tests': |
| 46 'third_party/WebKit/Source/web/WebKitUnitTests.isolate', | 45 'third_party/WebKit/Source/web/WebKitUnitTests.isolate', |
| 47 } | 46 } |
| 48 | 47 |
| 49 # Used for filtering large data deps at a finer grain than what's allowed in | 48 # Used for filtering large data deps at a finer grain than what's allowed in |
| 50 # isolate files since pushing deps to devices is expensive. | 49 # isolate files since pushing deps to devices is expensive. |
| 51 # Wildcards are allowed. | 50 # Wildcards are allowed. |
| 52 _DEPS_EXCLUSION_LIST = [ | 51 DEPS_EXCLUSION_LIST = [ |
| 53 'chrome/test/data/extensions/api_test', | 52 'chrome/test/data/extensions/api_test', |
| 54 'chrome/test/data/extensions/secure_shell', | 53 'chrome/test/data/extensions/secure_shell', |
| 55 'chrome/test/data/firefox*', | 54 'chrome/test/data/firefox*', |
| 56 'chrome/test/data/gpu', | 55 'chrome/test/data/gpu', |
| 57 'chrome/test/data/image_decoding', | 56 'chrome/test/data/image_decoding', |
| 58 'chrome/test/data/import', | 57 'chrome/test/data/import', |
| 59 'chrome/test/data/page_cycler', | 58 'chrome/test/data/page_cycler', |
| 60 'chrome/test/data/perf', | 59 'chrome/test/data/perf', |
| 61 'chrome/test/data/pyauto_private', | 60 'chrome/test/data/pyauto_private', |
| 62 'chrome/test/data/safari_import', | 61 'chrome/test/data/safari_import', |
| 63 'chrome/test/data/scroll', | 62 'chrome/test/data/scroll', |
| 64 'chrome/test/data/third_party', | 63 'chrome/test/data/third_party', |
| 65 'third_party/hunspell_dictionaries/*.dic', | 64 'third_party/hunspell_dictionaries/*.dic', |
| 66 # crbug.com/258690 | 65 # crbug.com/258690 |
| 67 'webkit/data/bmp_decoder', | 66 'webkit/data/bmp_decoder', |
| 68 'webkit/data/ico_decoder', | 67 'webkit/data/ico_decoder', |
| 69 ] | 68 ] |
| 70 | 69 |
| 71 | 70 |
| 72 def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None): | |
| 73 """Generate the dependency dir for the test suite using isolate. | |
| 74 | |
| 75 Args: | |
| 76 suite_name: Name of the test suite (e.g. base_unittests). | |
| 77 isolate_file_path: .isolate file path to use. If there is a default .isolate | |
| 78 file path for the suite_name, this will override it. | |
| 79 """ | |
| 80 if isolate_file_path: | |
| 81 if os.path.isabs(isolate_file_path): | |
| 82 isolate_abs_path = isolate_file_path | |
| 83 else: | |
| 84 isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, | |
| 85 isolate_file_path) | |
| 86 else: | |
| 87 isolate_rel_path = _ISOLATE_FILE_PATHS.get(suite_name) | |
| 88 if not isolate_rel_path: | |
| 89 logging.info('Did not find an isolate file for the test suite.') | |
| 90 return | |
| 91 isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path) | |
| 92 | |
| 93 isolated_abs_path = os.path.join( | |
| 94 constants.GetOutDirectory(), '%s.isolated' % suite_name) | |
| 95 assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path | |
| 96 | |
| 97 i = isolator.Isolator(constants.ISOLATE_DEPS_DIR) | |
| 98 i.Clear() | |
| 99 i.Remap(isolate_abs_path, isolated_abs_path) | |
| 100 # We're relying on the fact that timestamps are preserved | |
| 101 # by the remap command (hardlinked). Otherwise, all the data | |
| 102 # will be pushed to the device once we move to using time diff | |
| 103 # instead of md5sum. Perform a sanity check here. | |
| 104 i.VerifyHardlinks() | |
| 105 i.PurgeExcluded(_DEPS_EXCLUSION_LIST) | |
| 106 i.MoveOutputDeps() | |
| 107 | |
| 108 | |
| 109 def _GetDisabledTestsFilterFromFile(suite_name): | 71 def _GetDisabledTestsFilterFromFile(suite_name): |
| 110 """Returns a gtest filter based on the *_disabled file. | 72 """Returns a gtest filter based on the *_disabled file. |
| 111 | 73 |
| 112 Args: | 74 Args: |
| 113 suite_name: Name of the test suite (e.g. base_unittests). | 75 suite_name: Name of the test suite (e.g. base_unittests). |
| 114 | 76 |
| 115 Returns: | 77 Returns: |
| 116 A gtest filter which excludes disabled tests. | 78 A gtest filter which excludes disabled tests. |
| 117 Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc' | 79 Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc' |
| 118 """ | 80 """ |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 List of tests remaining. | 169 List of tests remaining. |
| 208 """ | 170 """ |
| 209 tests = _FilterTestsUsingPrefixes( | 171 tests = _FilterTestsUsingPrefixes( |
| 210 tests, has_gtest_filter, has_gtest_filter) | 172 tests, has_gtest_filter, has_gtest_filter) |
| 211 tests = unittest_util.FilterTestNames( | 173 tests = unittest_util.FilterTestNames( |
| 212 tests, _GetDisabledTestsFilterFromFile(suite_name)) | 174 tests, _GetDisabledTestsFilterFromFile(suite_name)) |
| 213 | 175 |
| 214 return tests | 176 return tests |
| 215 | 177 |
| 216 | 178 |
| 217 def PushDataDeps(device, test_options, test_package): | |
| 218 valgrind_tools.PushFilesForTool(test_options.tool, device) | |
| 219 if os.path.exists(constants.ISOLATE_DEPS_DIR): | |
| 220 device_dir = ( | |
| 221 constants.TEST_EXECUTABLE_DIR | |
| 222 if test_package.suite_name == 'breakpad_unittests' | |
| 223 else device.GetExternalStoragePath()) | |
| 224 device.PushChangedFiles([ | |
| 225 (os.path.join(constants.ISOLATE_DEPS_DIR, p), | |
| 226 '%s/%s' % (device_dir, p)) | |
| 227 for p in os.listdir(constants.ISOLATE_DEPS_DIR)]) | |
| 228 | |
| 229 | |
| 230 def Setup(test_options, devices): | 179 def Setup(test_options, devices): |
| 231 """Create the test runner factory and tests. | 180 """Create the test runner factory and tests. |
| 232 | 181 |
| 233 Args: | 182 Args: |
| 234 test_options: A GTestOptions object. | 183 test_options: A GTestOptions object. |
| 235 devices: A list of attached devices. | 184 devices: A list of attached devices. |
| 236 | 185 |
| 237 Returns: | 186 Returns: |
| 238 A tuple of (TestRunnerFactory, tests). | 187 A tuple of (TestRunnerFactory, tests). |
| 239 """ | 188 """ |
| 240 test_package = test_package_apk.TestPackageApk(test_options.suite_name) | 189 test_package = test_package_apk.TestPackageApk(test_options.suite_name) |
| 241 if not os.path.exists(test_package.suite_path): | 190 if not os.path.exists(test_package.suite_path): |
| 242 exe_test_package = test_package_exe.TestPackageExecutable( | 191 exe_test_package = test_package_exe.TestPackageExecutable( |
| 243 test_options.suite_name) | 192 test_options.suite_name) |
| 244 if not os.path.exists(exe_test_package.suite_path): | 193 if not os.path.exists(exe_test_package.suite_path): |
| 245 raise Exception( | 194 raise Exception( |
| 246 'Did not find %s target. Ensure it has been built.\n' | 195 'Did not find %s target. Ensure it has been built.\n' |
| 247 '(not found at %s or %s)' | 196 '(not found at %s or %s)' |
| 248 % (test_options.suite_name, | 197 % (test_options.suite_name, |
| 249 test_package.suite_path, | 198 test_package.suite_path, |
| 250 exe_test_package.suite_path)) | 199 exe_test_package.suite_path)) |
| 251 test_package = exe_test_package | 200 test_package = exe_test_package |
| 252 logging.warning('Found target %s', test_package.suite_path) | 201 logging.warning('Found target %s', test_package.suite_path) |
| 253 | 202 |
| 254 _GenerateDepsDirUsingIsolate(test_options.suite_name, | 203 base_setup.GenerateDepsDirUsingIsolate(test_options.suite_name, |
| 255 test_options.isolate_file_path) | 204 test_options.isolate_file_path, |
| 256 | 205 ISOLATE_FILE_PATHS, |
| 206 DEPS_EXCLUSION_LIST) | |
| 207 def DeviceDir(device): | |
| 208 return (constants.TEST_EXECUTABLE_DIR | |
| 209 if test_package.suite_name == 'breakpad_unittests' | |
| 210 else device.GetExternalStoragePath()) | |
| 257 device_utils.DeviceUtils.parallel(devices).pMap( | 211 device_utils.DeviceUtils.parallel(devices).pMap( |
| 258 PushDataDeps, test_options, test_package) | 212 (lambda d, opts: base_setup.PushDataDeps(d, DeviceDir(d), opts)), |
|
jbudorick
2014/11/03 15:52:32
Instead of defining DeviceDir as a separate functi
mikecase (-- gone --)
2014/11/06 00:12:21
Done.
| |
| 213 test_options) | |
| 259 | 214 |
| 260 tests = _GetTests(test_options, test_package, devices) | 215 tests = _GetTests(test_options, test_package, devices) |
| 261 | 216 |
| 262 # Constructs a new TestRunner with the current options. | 217 # Constructs a new TestRunner with the current options. |
| 263 def TestRunnerFactory(device, _shard_index): | 218 def TestRunnerFactory(device, _shard_index): |
| 264 return test_runner.TestRunner( | 219 return test_runner.TestRunner( |
| 265 test_options, | 220 test_options, |
| 266 device, | 221 device, |
| 267 test_package) | 222 test_package) |
| 268 | 223 |
| 269 if test_options.run_disabled: | 224 if test_options.run_disabled: |
| 270 test_options = test_options._replace( | 225 test_options = test_options._replace( |
| 271 test_arguments=('%s --gtest_also_run_disabled_tests' % | 226 test_arguments=('%s --gtest_also_run_disabled_tests' % |
| 272 test_options.test_arguments)) | 227 test_options.test_arguments)) |
| 273 else: | 228 else: |
| 274 tests = _FilterDisabledTests(tests, test_options.suite_name, | 229 tests = _FilterDisabledTests(tests, test_options.suite_name, |
| 275 bool(test_options.gtest_filter)) | 230 bool(test_options.gtest_filter)) |
| 276 if test_options.gtest_filter: | 231 if test_options.gtest_filter: |
| 277 tests = unittest_util.FilterTestNames(tests, test_options.gtest_filter) | 232 tests = unittest_util.FilterTestNames(tests, test_options.gtest_filter) |
| 278 | 233 |
| 279 # Coalesce unit tests into a single test per device | 234 # Coalesce unit tests into a single test per device |
| 280 if test_options.suite_name != 'content_browsertests': | 235 if test_options.suite_name != 'content_browsertests': |
| 281 num_devices = len(devices) | 236 num_devices = len(devices) |
| 282 tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] | 237 tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] |
| 283 tests = [t for t in tests if t] | 238 tests = [t for t in tests if t] |
| 284 | 239 |
| 285 return (TestRunnerFactory, tests) | 240 return (TestRunnerFactory, tests) |
| OLD | NEW |