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

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

Issue 12278020: [Android] Re-write the gtest TestRunner and introduce a new generic sharder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: more frank nits Created 7 years, 10 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 # found in the LICENSE file.
4
5 """Implements test sharding logic."""
6
7 import logging
8 import sys
9 import threading
10
11 from pylib import android_commands
12 from pylib import forwarder
13
14 import test_result
15
16
17 class _Worker(threading.Thread):
18 """Runs tests from the test_queue using the given runner in a separate thread.
19
20 Places results in the out_results.
21 """
22 def __init__(self, runner, test_queue, out_results, out_retry):
23 """Initializes the worker.
24
25 Args:
26 runner: A TestRunner object used to run the tests.
27 test_queue: A list from which to get tests to run.
28 out_results: A list to add TestResults to.
29 out_retry: A list to add tests to retry.
30 """
31 super(_Worker, self).__init__()
32 self.daemon = True
33 self._exc_info = None
34 self._runner = runner
35 self._test_queue = test_queue
36 self._out_results = out_results
37 self._out_retry = out_retry
38
39 #override
40 def run(self):
41 """Run tests from the queue in a seperate thread until it is empty.
42
43 Adds TestResults objects to the out_results list and may add tests to the
44 out_retry list.
45 """
46 try:
47 while True:
48 test = self._test_queue.pop()
49 result, retry = self._runner.Run(test)
50 self._out_results.append(result)
51 if retry:
52 self._out_retry.append(retry)
53 except IndexError:
54 pass
55 except:
56 self._exc_info = sys.exc_info()
57 raise
58
59 def ReraiseIfException(self):
60 """Reraise exception if an exception was raised in the thread."""
61 if self._exc_info:
62 raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
63
64
65 def _RunAllTests(runners, tests):
66 """Run all tests using the given TestRunners.
67
68 Args:
69 runners: a list of TestRunner objects.
70 tests: a list of Tests to run using the given TestRunners.
71
72 Returns:
73 Tuple: (list of TestResults, list of tests to retry)
74 """
75 tests_queue = list(tests)
76 workers = []
77 results = []
78 retry = []
79 for r in runners:
80 worker = _Worker(r, tests_queue, results, retry)
81 worker.start()
82 workers.append(worker)
83 while workers:
84 for w in workers[:]:
85 # Allow the main thread to periodically check for keyboard interrupts.
86 w.join(0.1)
87 if not w.isAlive():
88 w.ReraiseIfException()
89 workers.remove(w)
90 return (results, retry)
91
92
93 def _CreateRunners(runner_factory, devices):
94 """Creates a test runner for each device.
95
96 Note: if a device is unresponsive the corresponding TestRunner will not be
97 included in the returned list.
98
99 Args:
100 runner_factory: callable that takes a device and returns a TestRunner.
101 devices: list of device serial numbers as strings.
102
103 Returns:
104 A list of TestRunner objects.
105 """
106 test_runners = []
107 for index, device in enumerate(devices):
108 logging.warning('*' * 80)
109 logging.warning('Creating shard %d for %s', index, device)
110 logging.warning('*' * 80)
111 try:
112 test_runners.append(runner_factory(device))
113 except android_commands.errors.DeviceUnresponsiveError as e:
114 logging.warning('****Failed to create a shard: [%s]', e)
115 return test_runners
116
117
118 def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug',
119 tries=3):
120 """Run all tests on attached devices, retrying tests that don't pass.
121
122 Args:
123 runner_factory: callable that takes a device and returns a TestRunner.
124 devices: list of attached device serial numbers as strings.
125 tests: list of tests to run.
126 build_type: either 'Debug' or 'Release'.
127 tries: number of tries before accepting failure.
128
129 Returns:
130 A test_result.TestResults object.
131 """
132 final_results = test_result.TestResults()
133 results = test_result.TestResults()
134 forwarder.Forwarder.KillHost(build_type)
135 try_count = 0
136 while tests:
137 devices = set(devices).intersection(android_commands.GetAttachedDevices())
138 if not devices:
139 # There are no visible devices attached, this is unrecoverable.
140 msg = 'No devices attached and visible to run tests!'
141 logging.critical(msg)
142 raise Exception(msg)
143 if try_count >= tries:
144 # We've retried too many times, return the TestResults up to this point.
145 results.ok = final_results.ok
146 final_results = results
147 break
148 try_count += 1
149 runners = _CreateRunners(runner_factory, devices)
150 try:
151 results_list, tests = _RunAllTests(runners, tests)
152 results = test_result.TestResults.FromTestResults(results_list)
153 final_results.ok += results.ok
154 except android_commands.errors.DeviceUnresponsiveError as e:
155 logging.warning('****Failed to run test: [%s]', e)
156 forwarder.Forwarder.KillHost(build_type)
157 return final_results
OLDNEW
« no previous file with comments | « build/android/pylib/base/new_base_test_runner.py ('k') | build/android/pylib/base/shard_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698