Index: build/android/buildbot/bb_device_steps.py |
diff --git a/build/android/buildbot/bb_tests.py b/build/android/buildbot/bb_device_steps.py |
similarity index 79% |
rename from build/android/buildbot/bb_tests.py |
rename to build/android/buildbot/bb_device_steps.py |
index 094d6fb8ef1502c2604e2b826478fb645484a67e..b68928dab9d66227045dceb0eba08ed6482dac01 100755 |
--- a/build/android/buildbot/bb_tests.py |
+++ b/build/android/buildbot/bb_device_steps.py |
@@ -6,6 +6,7 @@ |
import collections |
import glob |
import json |
+import multiprocessing |
import optparse |
import os |
import pipes |
@@ -14,10 +15,15 @@ import subprocess |
import sys |
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) |
+from pylib import android_commands |
from pylib import buildbot_report |
from pylib import constants |
from pylib.gtest import gtest_config |
+sys.path.append(os.path.join( |
+ constants.CHROME_DIR, 'third_party', 'android_testrunner')) |
+import errors |
+ |
TESTING = 'BUILDBOT_TESTING' in os.environ |
@@ -53,12 +59,9 @@ INSTRUMENTATION_TESTS = dict((suite.name, suite) for suite in [ |
VALID_TESTS = set(['ui', 'unit', 'webkit', 'webkit_layout']) |
+ |
def SpawnCmd(command): |
"""Spawn a process without waiting for termination.""" |
- # Add adb binary to path. In the future, might use build_internal copy. |
- env = dict(os.environ) |
- env['PATH'] = os.pathsep.join([ |
- env['PATH'], os.path.join(constants.ANDROID_SDK_ROOT, 'platform-tools')]) |
print '>', ' '.join(map(pipes.quote, command)) |
sys.stdout.flush() |
if TESTING: |
@@ -68,14 +71,14 @@ def SpawnCmd(command): |
return 0 |
return MockPopen() |
- return subprocess.Popen(command, cwd=CHROME_SRC, env=env) |
+ return subprocess.Popen(command, cwd=CHROME_SRC) |
def RunCmd(command, flunk_on_failure=True): |
"""Run a command relative to the chrome source root.""" |
code = SpawnCmd(command).wait() |
print '<', ' '.join(map(pipes.quote, command)) |
if code != 0: |
- print 'ERROR: non-zero status %d from %s' % (code, command) |
+ print 'ERROR: process exited with code %d' % code |
if flunk_on_failure: |
buildbot_report.PrintError() |
else: |
@@ -83,6 +86,34 @@ def RunCmd(command, flunk_on_failure=True): |
return code |
+# multiprocessing map_async requires a top-level function for pickle library. |
+def RebootDeviceSafe(device): |
+ """Reboot a device, wait for it to start, and squelch timeout exceptions.""" |
+ try: |
+ android_commands.AndroidCommands(device).Reboot(True) |
+ except errors.DeviceUnresponsiveError as e: |
+ return e |
+ |
+ |
+def RebootDevices(): |
+ """Reboot all attached and online devices.""" |
+ buildbot_report.PrintNamedStep('Reboot devices') |
+ devices = android_commands.GetAttachedDevices() |
+ print 'Rebooting: %s' % devices |
+ if devices and not TESTING: |
+ pool = multiprocessing.Pool(len(devices)) |
+ results = pool.map_async(RebootDeviceSafe, devices).get(99999) |
+ |
+ for device, result in zip(devices, results): |
+ if result: |
+ print '%s failed to startup.' % device |
+ |
+ if any(results): |
+ buildbot_report.PrintWarning() |
+ else: |
+ print 'Reboots complete.' |
+ |
+ |
def RunTestSuites(options, suites): |
"""Manages an invocation of run_tests.py. |
@@ -169,6 +200,22 @@ def RunWebkitLayoutTests(options): |
def MainTestWrapper(options): |
+ # Restart adb to work around bugs, sleep to wait for usb discovery. |
+ RunCmd(['adb', 'kill-server']) |
+ RunCmd(['adb', 'start-server']) |
+ RunCmd(['sleep', '1']) |
+ |
+ # Spawn logcat monitor |
+ logcat_dir = os.path.join(CHROME_SRC, 'out/logcat') |
+ shutil.rmtree(logcat_dir, ignore_errors=True) |
+ SpawnCmd(['build/android/adb_logcat_monitor.py', logcat_dir]) |
+ |
+ # Wait for logcat_monitor to pull existing logcat |
+ RunCmd(['sleep', '5']) |
+ |
+ if options.reboot: |
+ RebootDevices() |
+ |
# Device check and alert emails |
buildbot_report.PrintNamedStep('device_status_check') |
RunCmd(['build/android/device_status_check.py'], flunk_on_failure=False) |
@@ -177,14 +224,6 @@ def MainTestWrapper(options): |
test_obj = INSTRUMENTATION_TESTS[options.install] |
InstallApk(options, test_obj, print_step=True) |
- if not options.test_filter: |
- return |
- |
- # Spawn logcat monitor |
- logcat_dir = os.path.join(CHROME_SRC, 'out/logcat') |
- shutil.rmtree(logcat_dir, ignore_errors=True) |
- SpawnCmd(['build/android/adb_logcat_monitor.py', logcat_dir]) |
- |
if 'unit' in options.test_filter: |
RunTestSuites(options, gtest_config.STABLE_TEST_SUITES) |
if 'ui' in options.test_filter: |
@@ -206,7 +245,7 @@ def MainTestWrapper(options): |
buildbot_report.PrintNamedStep('test_report') |
for report in glob.glob( |
os.path.join(CHROME_SRC, 'out', options.target, 'test_logs', '*.log')): |
- subprocess.Popen(['cat', report]).wait() |
+ RunCmd(['cat', report]) |
os.remove(report) |
@@ -234,6 +273,8 @@ def main(argv): |
parser.add_option('--asan', action='store_true', help='Run tests with asan.') |
parser.add_option('--install', metavar='<apk name>', |
help='Install an apk by name') |
+ parser.add_option('--reboot', action='store_true', |
+ help='Reboot devices before running tests') |
options, args = parser.parse_args(argv[1:]) |
def ParserError(msg): |
@@ -251,6 +292,17 @@ def main(argv): |
setattr(options, 'target', options.factory_properties.get('target', 'Debug')) |
+ # Add adb binary and chromium-source platform-tools to tip of PATH variable. |
+ android_paths = [os.path.join(constants.ANDROID_SDK_ROOT, 'platform-tools')] |
+ |
+ # Bots checkout chrome in /b/build/slave/<name>/build/src |
+ build_internal_android = os.path.abspath(os.path.join( |
+ CHROME_SRC, '..', '..', '..', '..', '..', 'build_internal', 'scripts', |
+ 'slave', 'android')) |
+ if os.path.exists(build_internal_android): |
+ android_paths.insert(0, build_internal_android) |
+ os.environ['PATH'] = os.pathsep.join(android_paths + [os.environ['PATH']]) |
+ |
MainTestWrapper(options) |