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 """Dispatches GTests.""" | 5 """Runs GTests.""" |
| 6 | 6 |
| 7 import copy | 7 import copy |
| 8 import fnmatch | 8 import fnmatch |
| 9 import glob | 9 import glob |
| 10 import logging | 10 import logging |
| 11 import os | 11 import os |
| 12 import shutil | 12 import shutil |
| 13 | 13 |
| 14 from pylib import android_commands | 14 from pylib import android_commands |
| 15 from pylib import cmd_helper | 15 from pylib import cmd_helper |
| 16 from pylib import constants | 16 from pylib import constants |
| 17 from pylib import dispatch | |
| 17 from pylib import ports | 18 from pylib import ports |
| 18 from pylib.base import base_test_result | 19 from pylib.base import base_test_result |
| 19 from pylib.base import shard | 20 from pylib.base import shard |
| 20 from pylib.utils import emulator | 21 from pylib.utils import emulator |
| 21 from pylib.utils import report_results | 22 from pylib.utils import report_results |
| 22 from pylib.utils import xvfb | |
| 23 | 23 |
| 24 import gtest_config | 24 import gtest_config |
| 25 import test_runner | 25 import test_runner |
| 26 | 26 |
| 27 | 27 |
| 28 # TODO(frankf): Add more test targets here after making sure we don't | 28 # TODO(frankf): Add more test targets here after making sure we don't |
| 29 # blow up the dependency size (and the world). | 29 # blow up the dependency size (and the world). |
| 30 _ISOLATE_FILE_PATHS = { | 30 _ISOLATE_FILE_PATHS = { |
| 31 'base_unittests': 'base/base_unittests.isolate', | 31 'base_unittests': 'base/base_unittests.isolate', |
| 32 'unit_tests': 'chrome/unit_tests.isolate', | 32 'unit_tests': 'chrome/unit_tests.isolate', |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 all_tests) | 200 all_tests) |
| 201 | 201 |
| 202 | 202 |
| 203 def GetAllEnabledTests(runner_factory, devices): | 203 def GetAllEnabledTests(runner_factory, devices): |
| 204 """Get all enabled tests. | 204 """Get all enabled tests. |
| 205 | 205 |
| 206 Obtains a list of enabled tests from the test package on the device, | 206 Obtains a list of enabled tests from the test package on the device, |
| 207 then filters it again using the disabled list on the host. | 207 then filters it again using the disabled list on the host. |
| 208 | 208 |
| 209 Args: | 209 Args: |
| 210 runner_factory: callable that takes a devices and returns a TestRunner. | 210 runner_factory: callable that takes devide and shard_index and returns |
|
frankf
2013/07/12 22:28:28
?
gkanwar
2013/07/12 22:53:34
s/devide/device/
Fixed.
| |
| 211 devices: list of devices. | 211 a TestRunner. |
| 212 | 212 |
| 213 Returns: | 213 Returns: |
| 214 List of all enabled tests. | 214 List of all enabled tests. |
| 215 | 215 |
| 216 Raises: | 216 Raises: |
| 217 Exception: If no devices available. | 217 Exception: If no devices available. |
| 218 """ | 218 """ |
| 219 for device in devices: | 219 for device in devices: |
| 220 try: | 220 try: |
| 221 logging.info('Obtaining tests from %s', device) | 221 logging.info('Obtaining tests from %s', device) |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 238 options: options for running the tests. | 238 options: options for running the tests. |
| 239 suite_name: name of the test suite being run. | 239 suite_name: name of the test suite being run. |
| 240 | 240 |
| 241 Returns: | 241 Returns: |
| 242 A tuple of (base_test_result.TestRunResult object, exit code). | 242 A tuple of (base_test_result.TestRunResult object, exit code). |
| 243 | 243 |
| 244 Raises: | 244 Raises: |
| 245 Exception: For various reasons including device failure or failing to reset | 245 Exception: For various reasons including device failure or failing to reset |
| 246 the test server port. | 246 the test server port. |
| 247 """ | 247 """ |
| 248 attached_devices = [] | |
| 249 buildbot_emulators = [] | |
| 250 | |
| 251 if options.use_emulator: | |
| 252 buildbot_emulators = emulator.LaunchEmulators(options.emulator_count, | |
| 253 options.abi, | |
| 254 wait_for_boot=True) | |
| 255 attached_devices = [e.device for e in buildbot_emulators] | |
| 256 elif options.test_device: | |
| 257 attached_devices = [options.test_device] | |
| 258 else: | |
| 259 attached_devices = android_commands.GetAttachedDevices() | |
| 260 | |
| 261 if not attached_devices: | |
| 262 raise Exception('A device must be attached and online.') | |
| 263 | 248 |
| 264 # Reset the test port allocation. It's important to do it before starting | 249 # Reset the test port allocation. It's important to do it before starting |
| 265 # to dispatch any tests. | 250 # to dispatch any tests. |
| 266 if not ports.ResetTestServerPortAllocation(): | 251 if not ports.ResetTestServerPortAllocation(): |
|
frankf
2013/07/12 22:28:28
There's still a lot of duplication in dispatch fil
gkanwar
2013/07/12 22:53:34
I think the only duplication that exists currently
| |
| 267 raise Exception('Failed to reset test server port.') | 252 raise Exception('Failed to reset test server port.') |
| 268 | 253 |
| 269 deps_dir = _GenerateDepsDirUsingIsolate(suite_name, options.build_type) | 254 deps_dir = _GenerateDepsDirUsingIsolate(suite_name, options.build_type) |
| 270 | 255 |
| 271 # Constructs a new TestRunner with the current options. | 256 # Constructs a new TestRunner with the current options. |
| 272 def RunnerFactory(device, shard_index): | 257 def TestRunnerFactory(device, shard_index): |
| 273 return test_runner.TestRunner( | 258 return test_runner.TestRunner( |
| 274 device, | 259 device, |
| 275 options.test_suite, | 260 options.test_suite, |
| 276 options.test_arguments, | 261 options.test_arguments, |
| 277 options.timeout, | 262 options.timeout, |
| 278 options.cleanup_test_files, | 263 options.cleanup_test_files, |
| 279 options.tool, | 264 options.tool, |
| 280 options.build_type, | 265 options.build_type, |
| 281 options.webkit, | 266 options.webkit, |
| 282 options.push_deps, | 267 options.push_deps, |
| 283 constants.GTEST_TEST_PACKAGE_NAME, | 268 constants.GTEST_TEST_PACKAGE_NAME, |
| 284 constants.GTEST_TEST_ACTIVITY_NAME, | 269 constants.GTEST_TEST_ACTIVITY_NAME, |
| 285 constants.GTEST_COMMAND_LINE_FILE, | 270 constants.GTEST_COMMAND_LINE_FILE, |
| 286 deps_dir=deps_dir) | 271 deps_dir=deps_dir) |
| 287 | 272 |
| 273 # TODO(gkanwar): This breaks the abstraction of having dispatch.Dispatch deal | |
| 274 # entirely with the devices. Can we do this another way? | |
| 275 attached_devices = android_commands.GetAttachedDevices() | |
| 288 # Get tests and split them up based on the number of devices. | 276 # Get tests and split them up based on the number of devices. |
| 289 if options.test_filter: | 277 if options.test_filter: |
| 290 all_tests = [t for t in options.test_filter.split(':') if t] | 278 all_tests = [t for t in options.test_filter.split(':') if t] |
| 291 else: | 279 else: |
| 292 all_tests = GetAllEnabledTests(RunnerFactory, attached_devices) | 280 all_tests = GetAllEnabledTests(TestRunnerFactory, attached_devices) |
| 293 num_devices = len(attached_devices) | 281 num_devices = len(attached_devices) |
| 294 tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)] | 282 tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)] |
| 295 tests = [t for t in tests if t] | 283 tests = [t for t in tests if t] |
| 296 | 284 |
| 297 # Run tests. | 285 # Run tests. |
| 298 test_results, exit_code = shard.ShardAndRunTests( | 286 test_results, exit_code = dispatch.Dispatch(options, tests, TestRunnerFactory, |
| 299 RunnerFactory, attached_devices, tests, options.build_type, | 287 sharding='distribute') |
| 300 test_timeout=None, num_retries=options.num_retries) | |
| 301 | 288 |
| 302 report_results.LogFull( | 289 report_results.LogFull( |
| 303 results=test_results, | 290 results=test_results, |
| 304 test_type='Unit test', | 291 test_type='Unit test', |
| 305 test_package=suite_name, | 292 test_package=suite_name, |
| 306 build_type=options.build_type, | 293 build_type=options.build_type, |
| 307 flakiness_server=options.flakiness_dashboard_server) | 294 flakiness_server=options.flakiness_dashboard_server) |
| 308 | 295 |
| 309 for buildbot_emulator in buildbot_emulators: | |
| 310 buildbot_emulator.Shutdown() | |
| 311 | 296 |
| 312 return (test_results, exit_code) | 297 return (test_results, exit_code) |
| 313 | 298 |
| 314 | 299 |
| 315 def _ListTestSuites(): | 300 def _ListTestSuites(): |
| 316 """Display a list of available test suites.""" | 301 """Display a list of available test suites.""" |
| 317 print 'Available test suites are:' | 302 print 'Available test suites are:' |
| 318 for test_suite in gtest_config.STABLE_TEST_SUITES: | 303 for test_suite in gtest_config.STABLE_TEST_SUITES: |
| 319 print test_suite | 304 print test_suite |
| 320 | 305 |
| 321 | 306 |
| 322 def Dispatch(options): | 307 def RunGTests(options): |
| 323 """Dispatches the tests, sharding if possible. | 308 """Runs the tests, sharding if possible. |
| 324 | 309 |
| 325 If options.use_emulator is True, all tests will be run in new emulator | 310 If options.use_emulator is True, all tests will be run in new emulator |
| 326 instance. | 311 instance. |
| 327 | 312 |
| 328 Args: | 313 Args: |
| 329 options: options for running the tests. | 314 options: options for running the tests. |
| 330 | 315 |
| 331 Returns: | 316 Returns: |
| 332 base_test_result.TestRunResults object with the results of running the tests | 317 base_test_result.TestRunResults object with the results of running the tests |
| 333 """ | 318 """ |
| 334 results = base_test_result.TestRunResults() | 319 results = base_test_result.TestRunResults() |
| 335 | 320 |
| 336 if options.test_suite == 'help': | 321 if options.test_suite == 'help': |
| 337 _ListTestSuites() | 322 _ListTestSuites() |
| 338 return (results, 0) | 323 return (results, 0) |
| 339 | 324 |
| 340 if options.use_xvfb: | |
| 341 framebuffer = xvfb.Xvfb() | |
| 342 framebuffer.Start() | |
| 343 | |
| 344 all_test_suites = _FullyQualifiedTestSuites(options.exe, options.test_suite, | 325 all_test_suites = _FullyQualifiedTestSuites(options.exe, options.test_suite, |
| 345 options.build_type) | 326 options.build_type) |
| 346 exit_code = 0 | 327 exit_code = 0 |
| 347 for suite_name, suite_path in all_test_suites: | 328 for suite_name, suite_path in all_test_suites: |
| 348 # Give each test suite its own copy of options. | 329 # Give each test suite its own copy of options. |
| 349 test_options = copy.deepcopy(options) | 330 test_options = copy.deepcopy(options) |
| 350 test_options.test_suite = suite_path | 331 test_options.test_suite = suite_path |
| 351 test_results, test_exit_code = _RunATestSuite(test_options, suite_name) | 332 test_results, test_exit_code = _RunATestSuite(test_options, suite_name) |
| 352 results.AddTestRunResults(test_results) | 333 results.AddTestRunResults(test_results) |
| 353 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: | 334 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: |
| 354 exit_code = test_exit_code | 335 exit_code = test_exit_code |
| 355 | 336 |
| 356 if options.use_xvfb: | |
| 357 framebuffer.Stop() | |
| 358 | |
| 359 return (results, exit_code) | 337 return (results, exit_code) |
| OLD | NEW |