Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 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 import copy | 5 import copy |
| 6 import fnmatch | 6 import fnmatch |
| 7 import glob | |
| 7 import logging | 8 import logging |
| 8 import os | 9 import os |
| 10 import shutil | |
| 9 | 11 |
| 10 from pylib import android_commands | 12 from pylib import android_commands |
| 11 from pylib import cmd_helper | 13 from pylib import cmd_helper |
| 12 from pylib import constants | 14 from pylib import constants |
| 13 from pylib import ports | 15 from pylib import ports |
| 14 from pylib.base import shard | 16 from pylib.base import shard |
| 15 from pylib.utils import emulator | 17 from pylib.utils import emulator |
| 16 from pylib.utils import report_results | 18 from pylib.utils import report_results |
| 17 from pylib.utils import xvfb | 19 from pylib.utils import xvfb |
| 18 | 20 |
| 19 import gtest_config | 21 import gtest_config |
| 20 import test_runner | 22 import test_runner |
| 21 | 23 |
| 22 | 24 |
| 25 # TODO(frankf): Enable the use of the remaining isolate files | |
| 26 # after making sure we don't blow up the dependency size (and | |
| 27 # the world). | |
| 28 _ISOLATE_FILE_PATHS = { | |
| 29 'base_unittests': 'base/base_unittests.isolate', | |
| 30 'unit_tests': 'chrome/unit_tests.isolate', | |
| 31 #'net_unittests': 'net/net_unittests.isolate', | |
|
M-A Ruel
2013/07/08 17:56:02
I'd recommend to keep the keys sorted even if the
frankf
2013/07/09 01:09:35
Done.
| |
| 32 #'content_browsertests': 'content/content_browsertests.isolate', | |
| 33 #'content_unittests': 'content/content_unittests.isolate', | |
| 34 } | |
| 35 # Used for filtering large data deps at a finer grain than what's allowed in | |
|
M-A Ruel
2013/07/08 17:56:02
Add at least one whitespace between a variable and
frankf
2013/07/09 01:09:35
Done.
| |
| 36 # isolate files since pushing deps to devices is expensive. | |
| 37 _DEPS_EXCLUSION_LIST = [ | |
| 38 'chrome/test/data/extensions/api_test', | |
| 39 'chrome/test/data/extensions/secure_shell', | |
| 40 'chrome/test/data/firefox*', | |
| 41 'chrome/test/data/image_decoding', | |
| 42 'chrome/test/data/import', | |
| 43 'chrome/test/data/page_cycler', | |
| 44 'chrome/test/data/perf', | |
| 45 'chrome/test/data/pyauto_private', | |
| 46 'chrome/test/data/safari_import', | |
| 47 'chrome/test/data/scroll', | |
| 48 'chrome/test/data/third_party', | |
| 49 'third_party/hunspell_dictionaries/*.dic', | |
| 50 ] | |
| 51 _ISOLATE_SCRIPT = os.path.join( | |
| 52 constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py') | |
| 53 | |
| 54 | |
| 55 def _GenerateDepsDirUsingIsolate(test_suite, build_type): | |
| 56 """Generate the dependency dir for the test suite using isolate. | |
| 57 | |
| 58 Args: | |
| 59 test_suite: The test suite basename (e.g. base_unittests). | |
| 60 build_type: Release/Debug | |
| 61 | |
| 62 Returns: | |
| 63 If an isolate file exists, returns path to dependency dir on the host. | |
| 64 Otherwise, returns False. | |
| 65 """ | |
| 66 product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) | |
| 67 assert os.path.isabs(product_dir) | |
| 68 isolate_rel_path = _ISOLATE_FILE_PATHS.get(test_suite) | |
| 69 if not isolate_rel_path: | |
| 70 return False | |
| 71 | |
| 72 isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path) | |
| 73 isolated_abs_path = os.path.join( | |
| 74 product_dir, '%s.isolated' % test_suite) | |
| 75 assert os.path.exists(isolate_abs_path) | |
| 76 deps_dir = os.path.join(product_dir, 'isolate_deps_dir') | |
| 77 if os.path.isdir(deps_dir): | |
| 78 shutil.rmtree(deps_dir) | |
| 79 # We're relying on the fact that timestamps are preserved | |
| 80 # by the remap command (hardlinked). Otherwise, all the data | |
|
csharp
2013/07/04 13:23:16
I'm a bit concerned about this code relying on rem
M-A Ruel
2013/07/08 17:56:02
Or add a unit test for remap to ensure this assump
frankf
2013/07/09 01:09:35
Done. I'm checking that the first file we hit duri
| |
| 81 # will be pushed to the device once we move to using time diff | |
| 82 # instead of md5sum. | |
| 83 isolate_cmd = [ | |
| 84 'python', _ISOLATE_SCRIPT, | |
| 85 'remap', | |
| 86 '--isolate=%s' % isolate_abs_path, | |
|
M-A Ruel
2013/07/08 17:56:02
'--isolate', isolate_abs_path,
same for --isolate
frankf
2013/07/09 01:09:35
Done.
| |
| 87 '--isolated=%s' % isolated_abs_path, | |
| 88 '-V', 'PRODUCT_DIR=%s' % product_dir, | |
| 89 '-V', 'OS=android', | |
| 90 '--outdir=%s' % deps_dir, | |
| 91 ] | |
| 92 assert not cmd_helper.RunCmd(isolate_cmd) | |
| 93 | |
| 94 # Delete excluded files as defined by _DEPS_EXCLUSION_LIST. | |
| 95 old_cwd = os.getcwd() | |
| 96 os.chdir(deps_dir) | |
|
M-A Ruel
2013/07/08 17:56:02
try/finally
frankf
2013/07/09 01:09:35
Done.
| |
| 97 excluded_paths = [x for y in _DEPS_EXCLUSION_LIST for x in glob.glob(y)] | |
| 98 if excluded_paths: | |
| 99 logging.warning('Excluding the following from dependency list: %s', | |
| 100 excluded_paths) | |
| 101 for p in excluded_paths: | |
| 102 if os.path.isdir(p): | |
| 103 shutil.rmtree(p) | |
| 104 else: | |
| 105 os.remove(p) | |
| 106 os.chdir(old_cwd) | |
| 107 | |
| 108 # On Android, all pak files need to be in the top-level 'paks' directory. | |
| 109 paks_dir = os.path.join(deps_dir, 'paks') | |
| 110 os.mkdir(paks_dir) | |
| 111 for root, _, filenames in os.walk(os.path.join(deps_dir, 'out')): | |
| 112 for filename in fnmatch.filter(filenames, '*.pak'): | |
| 113 shutil.move(os.path.join(root, filename), paks_dir) | |
| 114 | |
| 115 # Move everything in PRODUCT_DIR to top level. | |
| 116 deps_product_dir = os.path.join(deps_dir, 'out', build_type) | |
| 117 if os.path.isdir(deps_product_dir): | |
| 118 for p in os.listdir(deps_product_dir): | |
| 119 shutil.move(os.path.join(deps_product_dir, p), deps_dir) | |
| 120 | |
| 121 return deps_dir | |
| 122 | |
| 123 | |
| 23 def _FullyQualifiedTestSuites(exe, option_test_suite, build_type): | 124 def _FullyQualifiedTestSuites(exe, option_test_suite, build_type): |
| 24 """Get a list of absolute paths to test suite targets. | 125 """Get a list of absolute paths to test suite targets. |
| 25 | 126 |
| 26 Args: | 127 Args: |
| 27 exe: if True, use the executable-based test runner. | 128 exe: if True, use the executable-based test runner. |
| 28 option_test_suite: the test_suite specified as an option. | 129 option_test_suite: the test_suite specified as an option. |
| 29 build_type: 'Release' or 'Debug'. | 130 build_type: 'Release' or 'Debug'. |
| 30 | 131 |
| 31 Returns: | 132 Returns: |
| 32 A list of tuples containing the suite and absolute path. | 133 A list of tuples containing the suite and absolute path. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 attached_devices = android_commands.GetAttachedDevices() | 232 attached_devices = android_commands.GetAttachedDevices() |
| 132 | 233 |
| 133 if not attached_devices: | 234 if not attached_devices: |
| 134 raise Exception('A device must be attached and online.') | 235 raise Exception('A device must be attached and online.') |
| 135 | 236 |
| 136 # Reset the test port allocation. It's important to do it before starting | 237 # Reset the test port allocation. It's important to do it before starting |
| 137 # to dispatch any tests. | 238 # to dispatch any tests. |
| 138 if not ports.ResetTestServerPortAllocation(): | 239 if not ports.ResetTestServerPortAllocation(): |
| 139 raise Exception('Failed to reset test server port.') | 240 raise Exception('Failed to reset test server port.') |
| 140 | 241 |
| 242 deps_dir = _GenerateDepsDirUsingIsolate(suite_name, options.build_type) | |
| 243 | |
| 141 # Constructs a new TestRunner with the current options. | 244 # Constructs a new TestRunner with the current options. |
| 142 def RunnerFactory(device, shard_index): | 245 def RunnerFactory(device, shard_index): |
| 143 return test_runner.TestRunner( | 246 return test_runner.TestRunner( |
| 144 device, | 247 device, |
| 145 options.test_suite, | 248 options.test_suite, |
| 146 options.test_arguments, | 249 options.test_arguments, |
| 147 options.timeout, | 250 options.timeout, |
| 148 options.cleanup_test_files, | 251 options.cleanup_test_files, |
| 149 options.tool, | 252 options.tool, |
| 150 options.build_type, | 253 options.build_type, |
| 151 options.webkit, | 254 options.webkit, |
| 152 options.push_deps, | 255 options.push_deps, |
| 153 constants.GTEST_TEST_PACKAGE_NAME, | 256 constants.GTEST_TEST_PACKAGE_NAME, |
| 154 constants.GTEST_TEST_ACTIVITY_NAME, | 257 constants.GTEST_TEST_ACTIVITY_NAME, |
| 155 constants.GTEST_COMMAND_LINE_FILE) | 258 constants.GTEST_COMMAND_LINE_FILE, |
| 259 deps_dir=deps_dir) | |
| 156 | 260 |
| 157 # Get tests and split them up based on the number of devices. | 261 # Get tests and split them up based on the number of devices. |
| 158 if options.gtest_filter: | 262 if options.gtest_filter: |
| 159 all_tests = [t for t in options.gtest_filter.split(':') if t] | 263 all_tests = [t for t in options.gtest_filter.split(':') if t] |
| 160 else: | 264 else: |
| 161 all_tests = GetAllEnabledTests(RunnerFactory, attached_devices) | 265 all_tests = GetAllEnabledTests(RunnerFactory, attached_devices) |
| 162 num_devices = len(attached_devices) | 266 num_devices = len(attached_devices) |
| 163 tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)] | 267 tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)] |
| 164 tests = [t for t in tests if t] | 268 tests = [t for t in tests if t] |
| 165 | 269 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 failures = 0 | 318 failures = 0 |
| 215 for suite_name, suite_path in all_test_suites: | 319 for suite_name, suite_path in all_test_suites: |
| 216 # Give each test suite its own copy of options. | 320 # Give each test suite its own copy of options. |
| 217 test_options = copy.deepcopy(options) | 321 test_options = copy.deepcopy(options) |
| 218 test_options.test_suite = suite_path | 322 test_options.test_suite = suite_path |
| 219 failures += _RunATestSuite(test_options, suite_name) | 323 failures += _RunATestSuite(test_options, suite_name) |
| 220 | 324 |
| 221 if options.use_xvfb: | 325 if options.use_xvfb: |
| 222 framebuffer.Stop() | 326 framebuffer.Stop() |
| 223 return failures | 327 return failures |
| OLD | NEW |