Index: build/android/pylib/base/shard.py |
diff --git a/build/android/pylib/base/shard.py b/build/android/pylib/base/shard.py |
index 94591aef7720000e3abb7f79b93a0139de27f146..aaa3975cebfcabcf58a929bcc89cf161e49dba9d 100644 |
--- a/build/android/pylib/base/shard.py |
+++ b/build/android/pylib/base/shard.py |
@@ -10,12 +10,17 @@ import threading |
from pylib import android_commands |
from pylib import forwarder |
from pylib.utils import reraiser_thread |
+from pylib.utils import watchdog_timer |
import base_test_result |
+DEFAULT_TIMEOUT = 7 * 60 # seven minutes |
+ |
+ |
class _ThreadSafeCounter(object): |
"""A threadsafe counter.""" |
+ |
def __init__(self): |
self._lock = threading.Lock() |
self._value = 0 |
@@ -34,6 +39,7 @@ class _ThreadSafeCounter(object): |
class _Test(object): |
"""Holds a test with additional metadata.""" |
+ |
def __init__(self, test, tries=0): |
"""Initializes the _Test object. |
@@ -51,6 +57,7 @@ class _TestCollection(object): |
Args: |
tests: list of tests to put in the collection. |
""" |
+ |
def __init__(self, tests=[]): |
self._lock = threading.Lock() |
self._tests = [] |
@@ -109,7 +116,7 @@ class _TestCollection(object): |
yield r |
-def _RunTestsFromQueue(runner, test_collection, out_results): |
+def _RunTestsFromQueue(runner, test_collection, out_results, watcher): |
"""Runs tests from the test_collection until empty using the given runner. |
Adds TestRunResults objects to the out_results list and may add tests to the |
@@ -119,8 +126,10 @@ def _RunTestsFromQueue(runner, test_collection, out_results): |
runner: A TestRunner object used to run the tests. |
test_collection: A _TestCollection from which to get _Test objects to run. |
out_results: A list to add TestRunResults to. |
+ watcher: A watchdog_timer.WatchdogTimer object, used as a shared timeout. |
""" |
for test in test_collection: |
+ watcher.Reset() |
try: |
if not android_commands.IsDeviceAttached(runner.device): |
# Device is unresponsive, stop handling tests on this device. |
@@ -178,12 +187,13 @@ def _SetUp(runner_factory, device, out_runners, threadsafe_counter): |
logging.warning('****Failed to create shard for %s: [%s]', device, e) |
-def _RunAllTests(runners, tests): |
+def _RunAllTests(runners, tests, timeout=None): |
"""Run all tests using the given TestRunners. |
Args: |
runners: a list of TestRunner objects. |
tests: a list of Tests to run using the given TestRunners. |
+ timeout: watchdog timeout in seconds, defaults to the default timeout. |
Returns: |
A TestRunResults object. |
@@ -192,17 +202,20 @@ def _RunAllTests(runners, tests): |
(len(tests), len(runners))) |
tests_collection = _TestCollection([_Test(t) for t in tests]) |
results = [] |
- workers = reraiser_thread.ReraiserThreadGroup([reraiser_thread.ReraiserThread( |
- _RunTestsFromQueue, [r, tests_collection, results]) for r in runners]) |
+ watcher = watchdog_timer.WatchdogTimer(timeout) |
+ workers = reraiser_thread.ReraiserThreadGroup( |
+ [reraiser_thread.ReraiserThread(_RunTestsFromQueue, |
+ [r, tests_collection, results, watcher]) |
+ for r in runners]) |
workers.StartAll() |
- workers.JoinAll() |
+ workers.JoinAll(watcher) |
run_results = base_test_result.TestRunResults() |
for r in results: |
run_results.AddTestRunResults(r) |
return run_results |
-def _CreateRunners(runner_factory, devices): |
+def _CreateRunners(runner_factory, devices, timeout=None): |
"""Creates a test runner for each device and calls SetUp() in parallel. |
Note: if a device is unresponsive the corresponding TestRunner will not be |
@@ -212,6 +225,7 @@ def _CreateRunners(runner_factory, devices): |
runner_factory: callable that takes a device and index and returns a |
TestRunner object. |
devices: list of device serial numbers as strings. |
+ timeout: watchdog timeout in seconds, defaults to the default timeout. |
Returns: |
A list of TestRunner objects. |
@@ -224,23 +238,26 @@ def _CreateRunners(runner_factory, devices): |
counter]) |
for d in devices]) |
threads.StartAll() |
- threads.JoinAll() |
+ threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) |
return runners |
-def _TearDownRunners(runners): |
+def _TearDownRunners(runners, timeout=None): |
"""Calls TearDown() for each test runner in parallel. |
Args: |
runners: a list of TestRunner objects. |
+ timeout: watchdog timeout in seconds, defaults to the default timeout. |
""" |
threads = reraiser_thread.ReraiserThreadGroup( |
[reraiser_thread.ReraiserThread(runner.TearDown) |
for runner in runners]) |
threads.StartAll() |
- threads.JoinAll() |
+ threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) |
-def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug'): |
+def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug', |
+ test_timeout=DEFAULT_TIMEOUT, |
+ setup_timeout=DEFAULT_TIMEOUT): |
"""Run all tests on attached devices, retrying tests that don't pass. |
Args: |
@@ -249,17 +266,21 @@ def ShardAndRunTests(runner_factory, devices, tests, build_type='Debug'): |
devices: list of attached device serial numbers as strings. |
tests: list of tests to run. |
build_type: either 'Debug' or 'Release'. |
+ test_timeout: watchdog timeout in seconds for running tests, defaults to the |
+ default timeout. |
+ setup_timeout: watchdog timeout in seconds for creating and cleaning up |
+ test runners, defaults to the default timeout. |
Returns: |
A base_test_result.TestRunResults object. |
""" |
forwarder.Forwarder.KillHost(build_type) |
- runners = _CreateRunners(runner_factory, devices) |
+ runners = _CreateRunners(runner_factory, devices, setup_timeout) |
try: |
- return _RunAllTests(runners, tests) |
+ return _RunAllTests(runners, tests, test_timeout) |
finally: |
try: |
- _TearDownRunners(runners) |
+ _TearDownRunners(runners, setup_timeout) |
except android_commands.errors.DeviceUnresponsiveError as e: |
logging.warning('****Device unresponsive during TearDown: [%s]', e) |
finally: |