| 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 """Dispatches tests, either sharding or replicating them. | 5 """Dispatches tests, either sharding or replicating them. |
| 6 | 6 |
| 7 Performs the following steps: | 7 Performs the following steps: |
| 8 * Create a test collection factory, using the given tests | 8 * Create a test collection factory, using the given tests |
| 9 - If sharding: test collection factory returns the same shared test collection | 9 - If sharding: test collection factory returns the same shared test collection |
| 10 to all test runners | 10 to all test runners |
| 11 - If replciating: test collection factory returns a unique test collection to | 11 - If replciating: test collection factory returns a unique test collection to |
| 12 each test runner, with the same set of tests in each. | 12 each test runner, with the same set of tests in each. |
| 13 * Create a test runner for each device. | 13 * Create a test runner for each device. |
| 14 * Run each test runner in its own thread, grabbing tests from the test | 14 * Run each test runner in its own thread, grabbing tests from the test |
| 15 collection until there are no tests left. | 15 collection until there are no tests left. |
| 16 """ | 16 """ |
| 17 | 17 |
| 18 # TODO(jbudorick) Deprecate and remove this class after any relevant parts have | 18 # TODO(jbudorick) Deprecate and remove this class after any relevant parts have |
| 19 # been ported to the new environment / test instance model. | 19 # been ported to the new environment / test instance model. |
| 20 | 20 |
| 21 import logging | 21 import logging |
| 22 import threading | 22 import threading |
| 23 | 23 |
| 24 from pylib import android_commands |
| 24 from pylib import constants | 25 from pylib import constants |
| 25 from pylib.base import base_test_result | 26 from pylib.base import base_test_result |
| 26 from pylib.base import test_collection | 27 from pylib.base import test_collection |
| 27 from pylib.device import device_errors | 28 from pylib.device import device_errors |
| 28 from pylib.utils import reraiser_thread | 29 from pylib.utils import reraiser_thread |
| 29 from pylib.utils import watchdog_timer | 30 from pylib.utils import watchdog_timer |
| 30 | 31 |
| 31 | 32 |
| 32 DEFAULT_TIMEOUT = 7 * 60 # seven minutes | 33 DEFAULT_TIMEOUT = 7 * 60 # seven minutes |
| 33 | 34 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 new_test_run_results = base_test_result.TestRunResults() | 95 new_test_run_results = base_test_result.TestRunResults() |
| 95 for test_result in test_run_results.GetAll(): | 96 for test_result in test_run_results.GetAll(): |
| 96 test_result.SetName('%s_%s' % (runner.device_serial[-4:], | 97 test_result.SetName('%s_%s' % (runner.device_serial[-4:], |
| 97 test_result.GetName())) | 98 test_result.GetName())) |
| 98 new_test_run_results.AddResult(test_result) | 99 new_test_run_results.AddResult(test_result) |
| 99 return new_test_run_results | 100 return new_test_run_results |
| 100 | 101 |
| 101 for test in collection: | 102 for test in collection: |
| 102 watcher.Reset() | 103 watcher.Reset() |
| 103 try: | 104 try: |
| 104 if not runner.device.IsOnline(): | 105 if runner.device_serial not in android_commands.GetAttachedDevices(): |
| 105 # Device is unresponsive, stop handling tests on this device. | 106 # Device is unresponsive, stop handling tests on this device. |
| 106 msg = 'Device %s is unresponsive.' % runner.device_serial | 107 msg = 'Device %s is unresponsive.' % runner.device_serial |
| 107 logging.warning(msg) | 108 logging.warning(msg) |
| 108 raise device_errors.DeviceUnreachableError(msg) | 109 raise device_errors.DeviceUnreachableError(msg) |
| 109 result, retry = runner.RunTest(test.test) | 110 result, retry = runner.RunTest(test.test) |
| 110 if tag_results_with_device: | 111 if tag_results_with_device: |
| 111 result = TagTestRunResults(result) | 112 result = TagTestRunResults(result) |
| 112 test.tries += 1 | 113 test.tries += 1 |
| 113 if retry and test.tries <= num_retries: | 114 if retry and test.tries <= num_retries: |
| 114 # Retry non-passing results, only record passing results. | 115 # Retry non-passing results, only record passing results. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 142 device: The device serial number to set up. | 143 device: The device serial number to set up. |
| 143 out_runners: List to add the successfully set up TestRunner object. | 144 out_runners: List to add the successfully set up TestRunner object. |
| 144 threadsafe_counter: A _ThreadSafeCounter object used to get shard indices. | 145 threadsafe_counter: A _ThreadSafeCounter object used to get shard indices. |
| 145 """ | 146 """ |
| 146 try: | 147 try: |
| 147 index = threadsafe_counter.GetAndIncrement() | 148 index = threadsafe_counter.GetAndIncrement() |
| 148 logging.warning('Creating shard %s for device %s.', index, device) | 149 logging.warning('Creating shard %s for device %s.', index, device) |
| 149 runner = runner_factory(device, index) | 150 runner = runner_factory(device, index) |
| 150 runner.SetUp() | 151 runner.SetUp() |
| 151 out_runners.append(runner) | 152 out_runners.append(runner) |
| 152 except device_errors.DeviceUnreachableError as e: | 153 except (device_errors.DeviceUnreachableError, |
| 154 # TODO(jbudorick) Remove this once the underlying implementations |
| 155 # for the above are switched or wrapped. |
| 156 android_commands.errors.DeviceUnresponsiveError) as e: |
| 153 logging.warning('Failed to create shard for %s: [%s]', device, e) | 157 logging.warning('Failed to create shard for %s: [%s]', device, e) |
| 154 | 158 |
| 155 | 159 |
| 156 def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None, | 160 def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None, |
| 157 tag_results_with_device=False): | 161 tag_results_with_device=False): |
| 158 """Run all tests using the given TestRunners. | 162 """Run all tests using the given TestRunners. |
| 159 | 163 |
| 160 Args: | 164 Args: |
| 161 runners: A list of TestRunner objects. | 165 runners: A list of TestRunner objects. |
| 162 test_collection_factory: A callable to generate a TestCollection object for | 166 test_collection_factory: A callable to generate a TestCollection object for |
| (...skipping 21 matching lines...) Expand all Loading... |
| 184 [r, tc, results, watcher, num_retries, tag_results_with_device], | 188 [r, tc, results, watcher, num_retries, tag_results_with_device], |
| 185 name=r.device_serial[-4:]) | 189 name=r.device_serial[-4:]) |
| 186 for r, tc in zip(runners, test_collections)] | 190 for r, tc in zip(runners, test_collections)] |
| 187 | 191 |
| 188 workers = reraiser_thread.ReraiserThreadGroup(threads) | 192 workers = reraiser_thread.ReraiserThreadGroup(threads) |
| 189 workers.StartAll() | 193 workers.StartAll() |
| 190 | 194 |
| 191 # Catch DeviceUnreachableErrors and set a warning exit code | 195 # Catch DeviceUnreachableErrors and set a warning exit code |
| 192 try: | 196 try: |
| 193 workers.JoinAll(watcher) | 197 workers.JoinAll(watcher) |
| 194 except device_errors.DeviceUnreachableError as e: | 198 except (device_errors.DeviceUnreachableError, |
| 199 # TODO(jbudorick) Remove this once the underlying implementations |
| 200 # for the above are switched or wrapped. |
| 201 android_commands.errors.DeviceUnresponsiveError) as e: |
| 195 logging.error(e) | 202 logging.error(e) |
| 196 | 203 |
| 197 if not all((len(tc) == 0 for tc in test_collections)): | 204 if not all((len(tc) == 0 for tc in test_collections)): |
| 198 logging.error('Only ran %d tests (all devices are likely offline).' % | 205 logging.error('Only ran %d tests (all devices are likely offline).' % |
| 199 len(results)) | 206 len(results)) |
| 200 for tc in test_collections: | 207 for tc in test_collections: |
| 201 run_results.AddResults(base_test_result.BaseTestResult( | 208 run_results.AddResults(base_test_result.BaseTestResult( |
| 202 t, base_test_result.ResultType.UNKNOWN) for t in tc.test_names()) | 209 t, base_test_result.ResultType.UNKNOWN) for t in tc.test_names()) |
| 203 | 210 |
| 204 for r in results: | 211 for r in results: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 222 | 229 |
| 223 Returns: | 230 Returns: |
| 224 A list of TestRunner objects. | 231 A list of TestRunner objects. |
| 225 """ | 232 """ |
| 226 logging.warning('Creating %s test runners.' % len(devices)) | 233 logging.warning('Creating %s test runners.' % len(devices)) |
| 227 runners = [] | 234 runners = [] |
| 228 counter = _ThreadSafeCounter() | 235 counter = _ThreadSafeCounter() |
| 229 threads = reraiser_thread.ReraiserThreadGroup( | 236 threads = reraiser_thread.ReraiserThreadGroup( |
| 230 [reraiser_thread.ReraiserThread(_SetUp, | 237 [reraiser_thread.ReraiserThread(_SetUp, |
| 231 [runner_factory, d, runners, counter], | 238 [runner_factory, d, runners, counter], |
| 232 name=str(d)[-4:]) | 239 name=d[-4:]) |
| 233 for d in devices]) | 240 for d in devices]) |
| 234 threads.StartAll() | 241 threads.StartAll() |
| 235 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) | 242 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) |
| 236 return runners | 243 return runners |
| 237 | 244 |
| 238 | 245 |
| 239 def _TearDownRunners(runners, timeout=None): | 246 def _TearDownRunners(runners, timeout=None): |
| 240 """Calls TearDown() for each test runner in parallel. | 247 """Calls TearDown() for each test runner in parallel. |
| 241 | 248 |
| 242 Args: | 249 Args: |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 | 326 |
| 320 logging.info('Will run %d tests (%s): %s', | 327 logging.info('Will run %d tests (%s): %s', |
| 321 len(tests_expanded), log_string, str(tests_expanded)) | 328 len(tests_expanded), log_string, str(tests_expanded)) |
| 322 runners = _CreateRunners(runner_factory, devices, setup_timeout) | 329 runners = _CreateRunners(runner_factory, devices, setup_timeout) |
| 323 try: | 330 try: |
| 324 return _RunAllTests(runners, test_collection_factory, | 331 return _RunAllTests(runners, test_collection_factory, |
| 325 num_retries, test_timeout, tag_results_with_device) | 332 num_retries, test_timeout, tag_results_with_device) |
| 326 finally: | 333 finally: |
| 327 try: | 334 try: |
| 328 _TearDownRunners(runners, setup_timeout) | 335 _TearDownRunners(runners, setup_timeout) |
| 329 except device_errors.DeviceUnreachableError as e: | 336 except (device_errors.DeviceUnreachableError, |
| 337 # TODO(jbudorick) Remove this once the underlying implementations |
| 338 # for the above are switched or wrapped. |
| 339 android_commands.errors.DeviceUnresponsiveError) as e: |
| 330 logging.warning('Device unresponsive during TearDown: [%s]', e) | 340 logging.warning('Device unresponsive during TearDown: [%s]', e) |
| 331 except Exception as e: | 341 except Exception as e: |
| 332 logging.error('Unexpected exception caught during TearDown: %s' % str(e)) | 342 logging.error('Unexpected exception caught during TearDown: %s' % str(e)) |
| OLD | NEW |