Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: build/android/pylib/base/test_dispatcher.py

Issue 2039363002: [Android] Ensure perf test runner does not create shards for blacklisted devices. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix whitespace Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | build/android/test_runner.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 devil.android import device_blacklist
24 from devil.android import device_errors 25 from devil.android import device_errors
25 from devil.utils import reraiser_thread 26 from devil.utils import reraiser_thread
26 from devil.utils import watchdog_timer 27 from devil.utils import watchdog_timer
27 from pylib import constants 28 from pylib import constants
28 from pylib.base import base_test_result 29 from pylib.base import base_test_result
29 from pylib.base import test_collection 30 from pylib.base import test_collection
30 31
31 32
32 DEFAULT_TIMEOUT = 7 * 60 # seven minutes 33 DEFAULT_TIMEOUT = 7 * 60 # seven minutes
33 34
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 except: 124 except:
124 # An unhandleable exception, ensure tests get run by another device and 125 # An unhandleable exception, ensure tests get run by another device and
125 # reraise this exception on the main thread. 126 # reraise this exception on the main thread.
126 collection.add(test) 127 collection.add(test)
127 raise 128 raise
128 finally: 129 finally:
129 # Retries count as separate tasks so always mark the popped test as done. 130 # Retries count as separate tasks so always mark the popped test as done.
130 collection.test_completed() 131 collection.test_completed()
131 132
132 133
133 def _SetUp(runner_factory, device, out_runners, threadsafe_counter): 134 def _SetUp(runner_factory, device, out_runners, threadsafe_counter,
135 blacklist_file=None):
134 """Creates a test runner for each device and calls SetUp() in parallel. 136 """Creates a test runner for each device and calls SetUp() in parallel.
135 137
136 Note: if a device is unresponsive the corresponding TestRunner will not be 138 Note: if a device is unresponsive the corresponding TestRunner will not be
137 added to out_runners. 139 added to out_runners.
138 140
139 Args: 141 Args:
140 runner_factory: Callable that takes a device and index and returns a 142 runner_factory: Callable that takes a device and index and returns a
141 TestRunner object. 143 TestRunner object.
142 device: The device serial number to set up. 144 device: The device serial number to set up.
143 out_runners: List to add the successfully set up TestRunner object. 145 out_runners: List to add the successfully set up TestRunner object.
144 threadsafe_counter: A _ThreadSafeCounter object used to get shard indices. 146 threadsafe_counter: A _ThreadSafeCounter object used to get shard indices.
147 blacklist_file: Path to device blacklist.
145 """ 148 """
146 try: 149 try:
147 index = threadsafe_counter.GetAndIncrement() 150 index = threadsafe_counter.GetAndIncrement()
148 logging.warning('Creating shard %s for device %s.', index, device) 151 logging.warning('Creating shard %s for device %s.', index, device)
152
153 blacklist = (device_blacklist.Blacklist(blacklist_file).Read()
jbudorick 2016/06/06 22:52:27 This isn't the right place to do this; it'll get r
rnephew (Reviews Here) 2016/06/06 23:33:21 Yeah, that makes for a much much simpler solution.
154 if blacklist_file
155 else None)
156 if blacklist and str(device) in blacklist:
157 logging.info('Device %s is in blacklist. Not creating shard %s',
158 str(device), index)
159 return
160
149 runner = runner_factory(device, index) 161 runner = runner_factory(device, index)
150 runner.SetUp() 162 runner.SetUp()
151 out_runners.append(runner) 163 out_runners.append(runner)
152 except (device_errors.CommandFailedError, 164 except (device_errors.CommandFailedError,
153 device_errors.CommandTimeoutError, 165 device_errors.CommandTimeoutError,
154 device_errors.DeviceUnreachableError): 166 device_errors.DeviceUnreachableError):
155 logging.exception('Failed to create shard for %s', str(device)) 167 logging.exception('Failed to create shard for %s', str(device))
156 168
157 169
158 def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None, 170 def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 run_results.AddResults(base_test_result.BaseTestResult( 219 run_results.AddResults(base_test_result.BaseTestResult(
208 t, base_test_result.ResultType.UNKNOWN) for t in tc.test_names()) 220 t, base_test_result.ResultType.UNKNOWN) for t in tc.test_names())
209 221
210 for r in results: 222 for r in results:
211 run_results.AddTestRunResults(r) 223 run_results.AddTestRunResults(r)
212 if not run_results.DidRunPass(): 224 if not run_results.DidRunPass():
213 exit_code = constants.ERROR_EXIT_CODE 225 exit_code = constants.ERROR_EXIT_CODE
214 return (run_results, exit_code) 226 return (run_results, exit_code)
215 227
216 228
217 def _CreateRunners(runner_factory, devices, timeout=None): 229 def _CreateRunners(runner_factory, devices, timeout=None, blacklist_file=None):
218 """Creates a test runner for each device and calls SetUp() in parallel. 230 """Creates a test runner for each device and calls SetUp() in parallel.
219 231
220 Note: if a device is unresponsive the corresponding TestRunner will not be 232 Note: if a device is unresponsive the corresponding TestRunner will not be
221 included in the returned list. 233 included in the returned list.
222 234
223 Args: 235 Args:
224 runner_factory: Callable that takes a device and index and returns a 236 runner_factory: Callable that takes a device and index and returns a
225 TestRunner object. 237 TestRunner object.
226 devices: List of device serial numbers as strings. 238 devices: List of device serial numbers as strings.
227 timeout: Watchdog timeout in seconds, defaults to the default timeout. 239 timeout: Watchdog timeout in seconds, defaults to the default timeout.
240 blacklist_file: Path to device blacklist file.
228 241
229 Returns: 242 Returns:
230 A list of TestRunner objects. 243 A list of TestRunner objects.
231 """ 244 """
232 logging.warning('Creating %s test %s.', len(devices), 245 logging.warning('Creating %s test %s.', len(devices),
233 'runners' if len(devices) != 1 else 'runner') 246 'runners' if len(devices) != 1 else 'runner')
234 runners = [] 247 runners = []
235 counter = _ThreadSafeCounter() 248 counter = _ThreadSafeCounter()
236 threads = reraiser_thread.ReraiserThreadGroup( 249 threads = reraiser_thread.ReraiserThreadGroup(
237 [reraiser_thread.ReraiserThread(_SetUp, 250 [reraiser_thread.ReraiserThread(_SetUp,
238 [runner_factory, d, runners, counter], 251 [runner_factory, d, runners, counter,
252 blacklist_file],
239 name=str(d)[-4:]) 253 name=str(d)[-4:])
240 for d in devices]) 254 for d in devices])
241 threads.StartAll() 255 threads.StartAll()
242 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) 256 threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
243 return runners 257 return runners
244 258
245 259
246 def _TearDownRunners(runners, timeout=None): 260 def _TearDownRunners(runners, timeout=None):
247 """Calls TearDown() for each test runner in parallel. 261 """Calls TearDown() for each test runner in parallel.
248 262
(...skipping 25 matching lines...) Expand all
274 tests_expanded.append(test_group) 288 tests_expanded.append(test_group)
275 else: 289 else:
276 test_split = test_group.split(':') 290 test_split = test_group.split(':')
277 for i in range(0, len(test_split), max_per_run): 291 for i in range(0, len(test_split), max_per_run):
278 tests_expanded.append(':'.join(test_split[i:i+max_per_run])) 292 tests_expanded.append(':'.join(test_split[i:i+max_per_run]))
279 return tests_expanded 293 return tests_expanded
280 294
281 295
282 def RunTests(tests, runner_factory, devices, shard=True, 296 def RunTests(tests, runner_factory, devices, shard=True,
283 test_timeout=DEFAULT_TIMEOUT, setup_timeout=DEFAULT_TIMEOUT, 297 test_timeout=DEFAULT_TIMEOUT, setup_timeout=DEFAULT_TIMEOUT,
284 num_retries=2, max_per_run=256): 298 num_retries=2, max_per_run=256, blacklist_file=None):
285 """Run all tests on attached devices, retrying tests that don't pass. 299 """Run all tests on attached devices, retrying tests that don't pass.
286 300
287 Args: 301 Args:
288 tests: List of tests to run. 302 tests: List of tests to run.
289 runner_factory: Callable that takes a device and index and returns a 303 runner_factory: Callable that takes a device and index and returns a
290 TestRunner object. 304 TestRunner object.
291 devices: List of attached devices. 305 devices: List of attached devices.
292 shard: True if we should shard, False if we should replicate tests. 306 shard: True if we should shard, False if we should replicate tests.
293 - Sharding tests will distribute tests across all test runners through a 307 - Sharding tests will distribute tests across all test runners through a
294 shared test collection. 308 shared test collection.
295 - Replicating tests will copy all tests to each test runner through a 309 - Replicating tests will copy all tests to each test runner through a
296 unique test collection for each test runner. 310 unique test collection for each test runner.
297 test_timeout: Watchdog timeout in seconds for running tests. 311 test_timeout: Watchdog timeout in seconds for running tests.
298 setup_timeout: Watchdog timeout in seconds for creating and cleaning up 312 setup_timeout: Watchdog timeout in seconds for creating and cleaning up
299 test runners. 313 test runners.
300 num_retries: Number of retries for a test. 314 num_retries: Number of retries for a test.
301 max_per_run: Maximum number of tests to run in any group. 315 max_per_run: Maximum number of tests to run in any group.
316 blacklist_file: Path to blacklist file.
302 317
303 Returns: 318 Returns:
304 A tuple of (base_test_result.TestRunResults object, exit code). 319 A tuple of (base_test_result.TestRunResults object, exit code).
305 """ 320 """
306 if not tests: 321 if not tests:
307 logging.critical('No tests to run.') 322 logging.critical('No tests to run.')
308 return (base_test_result.TestRunResults(), constants.ERROR_EXIT_CODE) 323 return (base_test_result.TestRunResults(), constants.ERROR_EXIT_CODE)
309 324
310 tests_expanded = ApplyMaxPerRun(tests, max_per_run) 325 tests_expanded = ApplyMaxPerRun(tests, max_per_run)
311 if shard: 326 if shard:
312 # Generate a shared TestCollection object for all test runners, so they 327 # Generate a shared TestCollection object for all test runners, so they
313 # draw from a common pool of tests. 328 # draw from a common pool of tests.
314 shared_test_collection = test_collection.TestCollection( 329 shared_test_collection = test_collection.TestCollection(
315 [_Test(t) for t in tests_expanded]) 330 [_Test(t) for t in tests_expanded])
316 test_collection_factory = lambda: shared_test_collection 331 test_collection_factory = lambda: shared_test_collection
317 tag_results_with_device = False 332 tag_results_with_device = False
318 log_string = 'sharded across devices' 333 log_string = 'sharded across devices'
319 else: 334 else:
320 # Generate a unique TestCollection object for each test runner, but use 335 # Generate a unique TestCollection object for each test runner, but use
321 # the same set of tests. 336 # the same set of tests.
322 test_collection_factory = lambda: test_collection.TestCollection( 337 test_collection_factory = lambda: test_collection.TestCollection(
323 [_Test(t) for t in tests_expanded]) 338 [_Test(t) for t in tests_expanded])
324 tag_results_with_device = True 339 tag_results_with_device = True
325 log_string = 'replicated on each device' 340 log_string = 'replicated on each device'
326 341
327 logging.info('Will run %d tests (%s): %s', 342 logging.info('Will run %d tests (%s): %s',
328 len(tests_expanded), log_string, str(tests_expanded)) 343 len(tests_expanded), log_string, str(tests_expanded))
329 runners = _CreateRunners(runner_factory, devices, setup_timeout) 344 runners = _CreateRunners(runner_factory, devices, setup_timeout,
345 blacklist_file=blacklist_file)
330 try: 346 try:
331 return _RunAllTests(runners, test_collection_factory, 347 return _RunAllTests(runners, test_collection_factory,
332 num_retries, test_timeout, tag_results_with_device) 348 num_retries, test_timeout, tag_results_with_device)
333 finally: 349 finally:
334 try: 350 try:
335 _TearDownRunners(runners, setup_timeout) 351 _TearDownRunners(runners, setup_timeout)
336 except device_errors.DeviceUnreachableError as e: 352 except device_errors.DeviceUnreachableError as e:
337 logging.warning('Device unresponsive during TearDown: [%s]', e) 353 logging.warning('Device unresponsive during TearDown: [%s]', e)
338 except Exception: # pylint: disable=broad-except 354 except Exception: # pylint: disable=broad-except
339 logging.exception('Unexpected exception caught during TearDown') 355 logging.exception('Unexpected exception caught during TearDown')
OLDNEW
« no previous file with comments | « no previous file | build/android/test_runner.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698