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 |
11 from pylib import forwarder | 11 from pylib import forwarder |
12 from pylib.utils import reraiser_thread | 12 from pylib.utils import reraiser_thread |
13 | 13 |
14 import test_result | 14 import base_test_result |
15 | 15 |
16 | 16 |
17 class _ThreadSafeCounter(object): | 17 class _ThreadSafeCounter(object): |
18 """A threadsafe counter.""" | 18 """A threadsafe counter.""" |
19 def __init__(self): | 19 def __init__(self): |
20 self._lock = threading.Lock() | 20 self._lock = threading.Lock() |
21 self._value = 0 | 21 self._value = 0 |
22 | 22 |
23 def GetAndIncrement(self): | 23 def GetAndIncrement(self): |
24 """Get the current value and increment it atomically. | 24 """Get the current value and increment it atomically. |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 while True: | 105 while True: |
106 r = self._pop() | 106 r = self._pop() |
107 if r is None: | 107 if r is None: |
108 break | 108 break |
109 yield r | 109 yield r |
110 | 110 |
111 | 111 |
112 def _RunTestsFromQueue(runner, test_collection, out_results): | 112 def _RunTestsFromQueue(runner, test_collection, out_results): |
113 """Runs tests from the test_collection until empty using the given runner. | 113 """Runs tests from the test_collection until empty using the given runner. |
114 | 114 |
115 Adds TestResults objects to the out_results list and may add tests to the | 115 Adds TestRunResults objects to the out_results list and may add tests to the |
116 out_retry list. | 116 out_retry list. |
117 | 117 |
118 Args: | 118 Args: |
119 runner: A TestRunner object used to run the tests. | 119 runner: A TestRunner object used to run the tests. |
120 test_collection: A _TestCollection from which to get _Test objects to run. | 120 test_collection: A _TestCollection from which to get _Test objects to run. |
121 out_results: A list to add TestResults to. | 121 out_results: A list to add TestRunResults to. |
122 """ | 122 """ |
123 for test in test_collection: | 123 for test in test_collection: |
124 try: | 124 try: |
125 if not android_commands.IsDeviceAttached(runner.device): | 125 if not android_commands.IsDeviceAttached(runner.device): |
126 # Device is unresponsive, stop handling tests on this device. | 126 # Device is unresponsive, stop handling tests on this device. |
127 msg = 'Device %s is unresponsive.' % runner.device | 127 msg = 'Device %s is unresponsive.' % runner.device |
128 logging.warning(msg) | 128 logging.warning(msg) |
129 raise android_commands.errors.DeviceUnresponsiveError(msg) | 129 raise android_commands.errors.DeviceUnresponsiveError(msg) |
130 result, retry = runner.RunTest(test.test) | 130 result, retry = runner.RunTest(test.test) |
131 test.tries += 1 | 131 test.tries += 1 |
132 if retry and test.tries <= 3: | 132 if retry and test.tries <= 3: |
133 # Retry non-passing results, only record passing results. | 133 # Retry non-passing results, only record passing results. |
134 out_results.append(test_result.TestResults.FromRun(ok=result.ok)) | 134 pass_results = base_test_result.TestRunResults() |
| 135 pass_results.AddResults(result.GetPass()) |
| 136 out_results.append(pass_results) |
135 logging.warning('****Will retry test, try #%s.' % test.tries) | 137 logging.warning('****Will retry test, try #%s.' % test.tries) |
136 test_collection.add(_Test(test=retry, tries=test.tries)) | 138 test_collection.add(_Test(test=retry, tries=test.tries)) |
137 else: | 139 else: |
138 # All tests passed or retry limit reached. Either way, record results. | 140 # All tests passed or retry limit reached. Either way, record results. |
139 out_results.append(result) | 141 out_results.append(result) |
140 except android_commands.errors.DeviceUnresponsiveError: | 142 except android_commands.errors.DeviceUnresponsiveError: |
141 # Device is unresponsive, stop handling tests on this device and ensure | 143 # Device is unresponsive, stop handling tests on this device and ensure |
142 # current test gets runs by another device. Don't reraise this exception | 144 # current test gets runs by another device. Don't reraise this exception |
143 # on the main thread. | 145 # on the main thread. |
144 test_collection.add(test) | 146 test_collection.add(test) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 | 179 |
178 | 180 |
179 def _RunAllTests(runners, tests): | 181 def _RunAllTests(runners, tests): |
180 """Run all tests using the given TestRunners. | 182 """Run all tests using the given TestRunners. |
181 | 183 |
182 Args: | 184 Args: |
183 runners: a list of TestRunner objects. | 185 runners: a list of TestRunner objects. |
184 tests: a list of Tests to run using the given TestRunners. | 186 tests: a list of Tests to run using the given TestRunners. |
185 | 187 |
186 Returns: | 188 Returns: |
187 A TestResults object. | 189 A TestRunResults object. |
188 """ | 190 """ |
189 logging.warning('****Running %s tests with %s test runners.' % | 191 logging.warning('****Running %s tests with %s test runners.' % |
190 (len(tests), len(runners))) | 192 (len(tests), len(runners))) |
191 tests_collection = _TestCollection([_Test(t) for t in tests]) | 193 tests_collection = _TestCollection([_Test(t) for t in tests]) |
192 results = [] | 194 results = [] |
193 workers = reraiser_thread.ReraiserThreadGroup([reraiser_thread.ReraiserThread( | 195 workers = reraiser_thread.ReraiserThreadGroup([reraiser_thread.ReraiserThread( |
194 _RunTestsFromQueue, [r, tests_collection, results]) for r in runners]) | 196 _RunTestsFromQueue, [r, tests_collection, results]) for r in runners]) |
195 workers.StartAll() | 197 workers.StartAll() |
196 workers.JoinAll() | 198 workers.JoinAll() |
197 return test_result.TestResults.FromTestResults(results) | 199 run_results = base_test_result.TestRunResults() |
| 200 for r in results: |
| 201 run_results.AddTestRunResults(r) |
| 202 return run_results |
198 | 203 |
199 | 204 |
200 def _CreateRunners(runner_factory, devices): | 205 def _CreateRunners(runner_factory, devices): |
201 """Creates a test runner for each device and calls SetUp() in parallel. | 206 """Creates a test runner for each device and calls SetUp() in parallel. |
202 | 207 |
203 Note: if a device is unresponsive the corresponding TestRunner will not be | 208 Note: if a device is unresponsive the corresponding TestRunner will not be |
204 included in the returned list. | 209 included in the returned list. |
205 | 210 |
206 Args: | 211 Args: |
207 runner_factory: callable that takes a device and index and returns a | 212 runner_factory: callable that takes a device and index and returns a |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 """Run all tests on attached devices, retrying tests that don't pass. | 244 """Run all tests on attached devices, retrying tests that don't pass. |
240 | 245 |
241 Args: | 246 Args: |
242 runner_factory: callable that takes a device and index and returns a | 247 runner_factory: callable that takes a device and index and returns a |
243 TestRunner object. | 248 TestRunner object. |
244 devices: list of attached device serial numbers as strings. | 249 devices: list of attached device serial numbers as strings. |
245 tests: list of tests to run. | 250 tests: list of tests to run. |
246 build_type: either 'Debug' or 'Release'. | 251 build_type: either 'Debug' or 'Release'. |
247 | 252 |
248 Returns: | 253 Returns: |
249 A test_result.TestResults object. | 254 A base_test_result.TestRunResults object. |
250 """ | 255 """ |
251 forwarder.Forwarder.KillHost(build_type) | 256 forwarder.Forwarder.KillHost(build_type) |
252 runners = _CreateRunners(runner_factory, devices) | 257 runners = _CreateRunners(runner_factory, devices) |
253 try: | 258 try: |
254 return _RunAllTests(runners, tests) | 259 return _RunAllTests(runners, tests) |
255 finally: | 260 finally: |
256 try: | 261 try: |
257 _TearDownRunners(runners) | 262 _TearDownRunners(runners) |
258 except android_commands.errors.DeviceUnresponsiveError as e: | 263 except android_commands.errors.DeviceUnresponsiveError as e: |
259 logging.warning('****Device unresponsive during TearDown: [%s]', e) | 264 logging.warning('****Device unresponsive during TearDown: [%s]', e) |
260 finally: | 265 finally: |
261 forwarder.Forwarder.KillHost(build_type) | 266 forwarder.Forwarder.KillHost(build_type) |
OLD | NEW |