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. |
| 198 num_retries: number of retries for a test. |
196 timeout: watchdog timeout in seconds, defaults to the default timeout. | 199 timeout: watchdog timeout in seconds, defaults to the default timeout. |
197 | 200 |
198 Returns: | 201 Returns: |
199 A TestRunResults object. | 202 A TestRunResults object. |
200 """ | 203 """ |
201 logging.warning('Running %s tests with %s test runners.' % | 204 logging.warning('Running %s tests with %s test runners.' % |
202 (len(tests), len(runners))) | 205 (len(tests), len(runners))) |
203 tests_collection = _TestCollection([_Test(t) for t in tests]) | 206 tests_collection = _TestCollection([_Test(t) for t in tests]) |
204 results = [] | 207 results = [] |
205 watcher = watchdog_timer.WatchdogTimer(timeout) | 208 watcher = watchdog_timer.WatchdogTimer(timeout) |
206 workers = reraiser_thread.ReraiserThreadGroup( | 209 workers = reraiser_thread.ReraiserThreadGroup( |
207 [reraiser_thread.ReraiserThread(_RunTestsFromQueue, | 210 [reraiser_thread.ReraiserThread( |
208 [r, tests_collection, results, watcher], | 211 _RunTestsFromQueue, |
209 name=r.device[-4:]) | 212 [r, tests_collection, results, watcher, num_retries], |
| 213 name=r.device[-4:]) |
210 for r in runners]) | 214 for r in runners]) |
211 workers.StartAll() | 215 workers.StartAll() |
212 workers.JoinAll(watcher) | 216 workers.JoinAll(watcher) |
213 run_results = base_test_result.TestRunResults() | 217 run_results = base_test_result.TestRunResults() |
214 for r in results: | 218 for r in results: |
215 run_results.AddTestRunResults(r) | 219 run_results.AddTestRunResults(r) |
216 return run_results | 220 return run_results |
217 | 221 |
218 | 222 |
219 def _CreateRunners(runner_factory, devices, timeout=None): | 223 def _CreateRunners(runner_factory, devices, timeout=None): |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 """ | 256 """ |
253 threads = reraiser_thread.ReraiserThreadGroup( | 257 threads = reraiser_thread.ReraiserThreadGroup( |
254 [reraiser_thread.ReraiserThread(r.TearDown, name=r.device[-4:]) | 258 [reraiser_thread.ReraiserThread(r.TearDown, name=r.device[-4:]) |
255 for r in runners]) | 259 for r in runners]) |
256 threads.StartAll() | 260 threads.StartAll() |
257 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) | 261 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) |
258 | 262 |
259 | 263 |
260 def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug', | 264 def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug', |
261 test_timeout=DEFAULT_TIMEOUT, | 265 test_timeout=DEFAULT_TIMEOUT, |
262 setup_timeout=DEFAULT_TIMEOUT): | 266 setup_timeout=DEFAULT_TIMEOUT, |
| 267 num_retries=2): |
263 """Run all tests on attached devices, retrying tests that don't pass. | 268 """Run all tests on attached devices, retrying tests that don't pass. |
264 | 269 |
265 Args: | 270 Args: |
266 runner_factory: callable that takes a device and index and returns a | 271 runner_factory: callable that takes a device and index and returns a |
267 TestRunner object. | 272 TestRunner object. |
268 devices: list of attached device serial numbers as strings. | 273 devices: list of attached device serial numbers as strings. |
269 tests: list of tests to run. | 274 tests: list of tests to run. |
270 build_type: either 'Debug' or 'Release'. | 275 build_type: either 'Debug' or 'Release'. |
271 test_timeout: watchdog timeout in seconds for running tests, defaults to the | 276 test_timeout: watchdog timeout in seconds for running tests, defaults to the |
272 default timeout. | 277 default timeout. |
273 setup_timeout: watchdog timeout in seconds for creating and cleaning up | 278 setup_timeout: watchdog timeout in seconds for creating and cleaning up |
274 test runners, defaults to the default timeout. | 279 test runners, defaults to the default timeout. |
| 280 num_retries: number of retries for a test. |
275 | 281 |
276 Returns: | 282 Returns: |
277 A base_test_result.TestRunResults object. | 283 A base_test_result.TestRunResults object. |
278 """ | 284 """ |
279 forwarder.Forwarder.KillHost(build_type) | 285 forwarder.Forwarder.KillHost(build_type) |
280 runners = _CreateRunners(runner_factory, devices, setup_timeout) | 286 runners = _CreateRunners(runner_factory, devices, setup_timeout) |
281 try: | 287 try: |
282 return _RunAllTests(runners, tests, test_timeout) | 288 return _RunAllTests(runners, tests, num_retries, test_timeout) |
283 finally: | 289 finally: |
284 try: | 290 try: |
285 _TearDownRunners(runners, setup_timeout) | 291 _TearDownRunners(runners, setup_timeout) |
286 except android_commands.errors.DeviceUnresponsiveError as e: | 292 except android_commands.errors.DeviceUnresponsiveError as e: |
287 logging.warning('Device unresponsive during TearDown: [%s]', e) | 293 logging.warning('Device unresponsive during TearDown: [%s]', e) |
288 finally: | 294 finally: |
289 forwarder.Forwarder.KillHost(build_type) | 295 forwarder.Forwarder.KillHost(build_type) |
OLD | NEW |