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 """Implements test sharding logic.""" | 5 """Implements test sharding logic.""" |
| 6 | 6 |
| 7 import logging | 7 import logging |
| 8 import threading | 8 import threading |
| 9 | 9 |
| 10 from pylib import android_commands | 10 from pylib import android_commands |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 | 109 |
| 110 def __iter__(self): | 110 def __iter__(self): |
| 111 """Iterate through tests in the collection until all have been handled.""" | 111 """Iterate through tests in the collection until all have been handled.""" |
| 112 while True: | 112 while True: |
| 113 r = self._pop() | 113 r = self._pop() |
| 114 if r is None: | 114 if r is None: |
| 115 break | 115 break |
| 116 yield r | 116 yield r |
| 117 | 117 |
| 118 | 118 |
| 119 def _RunTestsFromQueue(runner, test_collection, out_results, watcher): | 119 def _RunTestsFromQueue(runner, test_collection, out_results, watcher, |
| 120 num_retries): | |
| 120 """Runs tests from the test_collection until empty using the given runner. | 121 """Runs tests from the test_collection until empty using the given runner. |
| 121 | 122 |
| 122 Adds TestRunResults objects to the out_results list and may add tests to the | 123 Adds TestRunResults objects to the out_results list and may add tests to the |
| 123 out_retry list. | 124 out_retry list. |
| 124 | 125 |
| 125 Args: | 126 Args: |
| 126 runner: A TestRunner object used to run the tests. | 127 runner: A TestRunner object used to run the tests. |
| 127 test_collection: A _TestCollection from which to get _Test objects to run. | 128 test_collection: A _TestCollection from which to get _Test objects to run. |
| 128 out_results: A list to add TestRunResults to. | 129 out_results: A list to add TestRunResults to. |
| 129 watcher: A watchdog_timer.WatchdogTimer object, used as a shared timeout. | 130 watcher: A watchdog_timer.WatchdogTimer object, used as a shared timeout. |
| 131 num_retries: Number of retries for a test. | |
| 130 """ | 132 """ |
| 131 for test in test_collection: | 133 for test in test_collection: |
| 132 watcher.Reset() | 134 watcher.Reset() |
| 133 try: | 135 try: |
| 134 if not android_commands.IsDeviceAttached(runner.device): | 136 if not android_commands.IsDeviceAttached(runner.device): |
| 135 # Device is unresponsive, stop handling tests on this device. | 137 # Device is unresponsive, stop handling tests on this device. |
| 136 msg = 'Device %s is unresponsive.' % runner.device | 138 msg = 'Device %s is unresponsive.' % runner.device |
| 137 logging.warning(msg) | 139 logging.warning(msg) |
| 138 raise android_commands.errors.DeviceUnresponsiveError(msg) | 140 raise android_commands.errors.DeviceUnresponsiveError(msg) |
| 139 result, retry = runner.RunTest(test.test) | 141 result, retry = runner.RunTest(test.test) |
| 140 test.tries += 1 | 142 test.tries += 1 |
| 141 if retry and test.tries <= 3: | 143 if retry and test.tries <= num_retries: |
| 142 # Retry non-passing results, only record passing results. | 144 # Retry non-passing results, only record passing results. |
| 143 pass_results = base_test_result.TestRunResults() | 145 pass_results = base_test_result.TestRunResults() |
| 144 pass_results.AddResults(result.GetPass()) | 146 pass_results.AddResults(result.GetPass()) |
| 145 out_results.append(pass_results) | 147 out_results.append(pass_results) |
| 146 logging.warning('Will retry test, try #%s.' % test.tries) | 148 logging.warning('Will retry test, try #%s.' % test.tries) |
| 147 test_collection.add(_Test(test=retry, tries=test.tries)) | 149 test_collection.add(_Test(test=retry, tries=test.tries)) |
| 148 else: | 150 else: |
| 149 # All tests passed or retry limit reached. Either way, record results. | 151 # All tests passed or retry limit reached. Either way, record results. |
| 150 out_results.append(result) | 152 out_results.append(result) |
| 151 except android_commands.errors.DeviceUnresponsiveError: | 153 except android_commands.errors.DeviceUnresponsiveError: |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 180 try: | 182 try: |
| 181 index = threadsafe_counter.GetAndIncrement() | 183 index = threadsafe_counter.GetAndIncrement() |
| 182 logging.warning('Creating shard %s for device %s.', index, device) | 184 logging.warning('Creating shard %s for device %s.', index, device) |
| 183 runner = runner_factory(device, index) | 185 runner = runner_factory(device, index) |
| 184 runner.SetUp() | 186 runner.SetUp() |
| 185 out_runners.append(runner) | 187 out_runners.append(runner) |
| 186 except android_commands.errors.DeviceUnresponsiveError as e: | 188 except android_commands.errors.DeviceUnresponsiveError as e: |
| 187 logging.warning('Failed to create shard for %s: [%s]', device, e) | 189 logging.warning('Failed to create shard for %s: [%s]', device, e) |
| 188 | 190 |
| 189 | 191 |
| 190 def _RunAllTests(runners, tests, timeout=None): | 192 def _RunAllTests(runners, tests, num_retries, timeout=None): |
| 191 """Run all tests using the given TestRunners. | 193 """Run all tests using the given TestRunners. |
| 192 | 194 |
| 193 Args: | 195 Args: |
| 194 runners: a list of TestRunner objects. | 196 runners: a list of TestRunner objects. |
| 195 tests: a list of Tests to run using the given TestRunners. | 197 tests: a list of Tests to run using the given TestRunners. |
| 196 timeout: watchdog timeout in seconds, defaults to the default timeout. | 198 timeout: watchdog timeout in seconds, defaults to the default timeout. |
| 197 | 199 |
| 198 Returns: | 200 Returns: |
| 199 A TestRunResults object. | 201 A TestRunResults object. |
| 200 """ | 202 """ |
| 201 logging.warning('Running %s tests with %s test runners.' % | 203 logging.warning('Running %s tests with %s test runners.' % |
| 202 (len(tests), len(runners))) | 204 (len(tests), len(runners))) |
| 203 tests_collection = _TestCollection([_Test(t) for t in tests]) | 205 tests_collection = _TestCollection([_Test(t) for t in tests]) |
| 204 results = [] | 206 results = [] |
| 205 watcher = watchdog_timer.WatchdogTimer(timeout) | 207 watcher = watchdog_timer.WatchdogTimer(timeout) |
| 206 workers = reraiser_thread.ReraiserThreadGroup( | 208 workers = reraiser_thread.ReraiserThreadGroup( |
| 207 [reraiser_thread.ReraiserThread(_RunTestsFromQueue, | 209 [reraiser_thread.ReraiserThread( |
| 208 [r, tests_collection, results, watcher], | 210 _RunTestsFromQueue, |
| 209 name=r.device[-4:]) | 211 [r, tests_collection, results, watcher, num_retries], |
| 212 name=r.device[-4:]) | |
| 210 for r in runners]) | 213 for r in runners]) |
| 211 workers.StartAll() | 214 workers.StartAll() |
| 212 workers.JoinAll(watcher) | 215 workers.JoinAll(watcher) |
| 213 run_results = base_test_result.TestRunResults() | 216 run_results = base_test_result.TestRunResults() |
| 214 for r in results: | 217 for r in results: |
| 215 run_results.AddTestRunResults(r) | 218 run_results.AddTestRunResults(r) |
| 216 return run_results | 219 return run_results |
| 217 | 220 |
| 218 | 221 |
| 219 def _CreateRunners(runner_factory, devices, timeout=None): | 222 def _CreateRunners(runner_factory, devices, timeout=None): |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 """ | 255 """ |
| 253 threads = reraiser_thread.ReraiserThreadGroup( | 256 threads = reraiser_thread.ReraiserThreadGroup( |
| 254 [reraiser_thread.ReraiserThread(r.TearDown, name=r.device[-4:]) | 257 [reraiser_thread.ReraiserThread(r.TearDown, name=r.device[-4:]) |
| 255 for r in runners]) | 258 for r in runners]) |
| 256 threads.StartAll() | 259 threads.StartAll() |
| 257 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) | 260 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) |
| 258 | 261 |
| 259 | 262 |
| 260 def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug', | 263 def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug', |
| 261 test_timeout=DEFAULT_TIMEOUT, | 264 test_timeout=DEFAULT_TIMEOUT, |
| 262 setup_timeout=DEFAULT_TIMEOUT): | 265 setup_timeout=DEFAULT_TIMEOUT, |
| 266 num_retries=2): | |
|
craigdh
2013/04/12 21:20:35
add documentation for the new arg
nilesh
2013/04/12 21:42:55
Done.
| |
| 263 """Run all tests on attached devices, retrying tests that don't pass. | 267 """Run all tests on attached devices, retrying tests that don't pass. |
| 264 | 268 |
| 265 Args: | 269 Args: |
| 266 runner_factory: callable that takes a device and index and returns a | 270 runner_factory: callable that takes a device and index and returns a |
| 267 TestRunner object. | 271 TestRunner object. |
| 268 devices: list of attached device serial numbers as strings. | 272 devices: list of attached device serial numbers as strings. |
| 269 tests: list of tests to run. | 273 tests: list of tests to run. |
| 270 build_type: either 'Debug' or 'Release'. | 274 build_type: either 'Debug' or 'Release'. |
| 271 test_timeout: watchdog timeout in seconds for running tests, defaults to the | 275 test_timeout: watchdog timeout in seconds for running tests, defaults to the |
| 272 default timeout. | 276 default timeout. |
| 273 setup_timeout: watchdog timeout in seconds for creating and cleaning up | 277 setup_timeout: watchdog timeout in seconds for creating and cleaning up |
| 274 test runners, defaults to the default timeout. | 278 test runners, defaults to the default timeout. |
| 275 | 279 |
| 276 Returns: | 280 Returns: |
| 277 A base_test_result.TestRunResults object. | 281 A base_test_result.TestRunResults object. |
| 278 """ | 282 """ |
| 279 forwarder.Forwarder.KillHost(build_type) | 283 forwarder.Forwarder.KillHost(build_type) |
| 280 runners = _CreateRunners(runner_factory, devices, setup_timeout) | 284 runners = _CreateRunners(runner_factory, devices, setup_timeout) |
| 281 try: | 285 try: |
| 282 return _RunAllTests(runners, tests, test_timeout) | 286 return _RunAllTests(runners, tests, num_retries, test_timeout) |
| 283 finally: | 287 finally: |
| 284 try: | 288 try: |
| 285 _TearDownRunners(runners, setup_timeout) | 289 _TearDownRunners(runners, setup_timeout) |
| 286 except android_commands.errors.DeviceUnresponsiveError as e: | 290 except android_commands.errors.DeviceUnresponsiveError as e: |
| 287 logging.warning('Device unresponsive during TearDown: [%s]', e) | 291 logging.warning('Device unresponsive during TearDown: [%s]', e) |
| 288 finally: | 292 finally: |
| 289 forwarder.Forwarder.KillHost(build_type) | 293 forwarder.Forwarder.KillHost(build_type) |
| OLD | NEW |