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

Side by Side Diff: build/android/buildbot/bb_device_steps.py

Issue 11857014: Move android reboot step into python (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed multiprocessing comment Created 7 years, 11 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
« no previous file with comments | « build/android/PRESUBMIT.py ('k') | build/android/buildbot/bb_run_bot.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 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import collections 6 import collections
7 import glob 7 import glob
8 import json 8 import json
9 import multiprocessing
9 import optparse 10 import optparse
10 import os 11 import os
11 import pipes 12 import pipes
12 import shutil 13 import shutil
13 import subprocess 14 import subprocess
14 import sys 15 import sys
15 16
16 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 17 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
18 from pylib import android_commands
17 from pylib import buildbot_report 19 from pylib import buildbot_report
18 from pylib import constants 20 from pylib import constants
19 from pylib.gtest import gtest_config 21 from pylib.gtest import gtest_config
20 22
23 sys.path.append(os.path.join(
24 constants.CHROME_DIR, 'third_party', 'android_testrunner'))
25 import errors
26
21 27
22 TESTING = 'BUILDBOT_TESTING' in os.environ 28 TESTING = 'BUILDBOT_TESTING' in os.environ
23 29
24 CHROME_SRC = constants.CHROME_DIR 30 CHROME_SRC = constants.CHROME_DIR
25 31
26 # Describes an instrumation test suite: 32 # Describes an instrumation test suite:
27 # test: Name of test we're running. 33 # test: Name of test we're running.
28 # apk: apk to be installed. 34 # apk: apk to be installed.
29 # apk_package: package for the apk to be installed. 35 # apk_package: package for the apk to be installed.
30 # test_apk: apk to run tests on. 36 # test_apk: apk to run tests on.
(...skipping 15 matching lines...) Expand all
46 I_TEST('AndroidWebView', 52 I_TEST('AndroidWebView',
47 'AndroidWebView.apk', 53 'AndroidWebView.apk',
48 'org.chromium.android_webview', 54 'org.chromium.android_webview',
49 'AndroidWebViewTest', 55 'AndroidWebViewTest',
50 'webview:android_webview/test/data/device_files'), 56 'webview:android_webview/test/data/device_files'),
51 ]) 57 ])
52 58
53 VALID_TESTS = set(['ui', 'unit', 'webkit', 'webkit_layout']) 59 VALID_TESTS = set(['ui', 'unit', 'webkit', 'webkit_layout'])
54 60
55 61
62
56 def SpawnCmd(command): 63 def SpawnCmd(command):
57 """Spawn a process without waiting for termination.""" 64 """Spawn a process without waiting for termination."""
58 # Add adb binary to path. In the future, might use build_internal copy.
59 env = dict(os.environ)
60 env['PATH'] = os.pathsep.join([
61 env['PATH'], os.path.join(constants.ANDROID_SDK_ROOT, 'platform-tools')])
62 print '>', ' '.join(map(pipes.quote, command)) 65 print '>', ' '.join(map(pipes.quote, command))
63 sys.stdout.flush() 66 sys.stdout.flush()
64 if TESTING: 67 if TESTING:
65 class MockPopen(object): 68 class MockPopen(object):
66 @staticmethod 69 @staticmethod
67 def wait(): 70 def wait():
68 return 0 71 return 0
69 return MockPopen() 72 return MockPopen()
70 73
71 return subprocess.Popen(command, cwd=CHROME_SRC, env=env) 74 return subprocess.Popen(command, cwd=CHROME_SRC)
72 75
73 def RunCmd(command, flunk_on_failure=True): 76 def RunCmd(command, flunk_on_failure=True):
74 """Run a command relative to the chrome source root.""" 77 """Run a command relative to the chrome source root."""
75 code = SpawnCmd(command).wait() 78 code = SpawnCmd(command).wait()
76 print '<', ' '.join(map(pipes.quote, command)) 79 print '<', ' '.join(map(pipes.quote, command))
77 if code != 0: 80 if code != 0:
78 print 'ERROR: non-zero status %d from %s' % (code, command) 81 print 'ERROR: process exited with code %d' % code
79 if flunk_on_failure: 82 if flunk_on_failure:
80 buildbot_report.PrintError() 83 buildbot_report.PrintError()
81 else: 84 else:
82 buildbot_report.PrintWarning() 85 buildbot_report.PrintWarning()
83 return code 86 return code
84 87
85 88
89 # multiprocessing map_async requires a top-level function for pickle library.
90 def RebootDeviceSafe(device):
91 """Reboot a device, wait for it to start, and squelch timeout exceptions."""
92 try:
93 android_commands.AndroidCommands(device).Reboot(True)
94 except errors.DeviceUnresponsiveError as e:
95 return e
96
97
98 def RebootDevices():
99 """Reboot all attached and online devices."""
100 buildbot_report.PrintNamedStep('Reboot devices')
101 devices = android_commands.GetAttachedDevices()
102 print 'Rebooting: %s' % devices
103 if devices and not TESTING:
104 pool = multiprocessing.Pool(len(devices))
105 results = pool.map_async(RebootDeviceSafe, devices).get(99999)
106
107 for device, result in zip(devices, results):
108 if result:
109 print '%s failed to startup.' % device
110
111 if any(results):
112 buildbot_report.PrintWarning()
113 else:
114 print 'Reboots complete.'
115
116
86 def RunTestSuites(options, suites): 117 def RunTestSuites(options, suites):
87 """Manages an invocation of run_tests.py. 118 """Manages an invocation of run_tests.py.
88 119
89 Args: 120 Args:
90 options: options object. 121 options: options object.
91 suites: List of suites to run. 122 suites: List of suites to run.
92 """ 123 """
93 args = ['--verbose'] 124 args = ['--verbose']
94 if options.target == 'Release': 125 if options.target == 'Release':
95 args.append('--release') 126 args.append('--release')
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 '--builder-name', options.build_properties.get('buildername', ''), 193 '--builder-name', options.build_properties.get('buildername', ''),
163 '--build-number', options.build_properties.get('buildnumber', ''), 194 '--build-number', options.build_properties.get('buildnumber', ''),
164 '--master-name', options.build_properties.get('mastername', ''), 195 '--master-name', options.build_properties.get('mastername', ''),
165 '--build-name', options.build_properties.get('buildername', ''), 196 '--build-name', options.build_properties.get('buildername', ''),
166 '--platform=chromium-android', 197 '--platform=chromium-android',
167 '--test-results-server', 198 '--test-results-server',
168 options.factory_properties.get('test_results_server', '')]) 199 options.factory_properties.get('test_results_server', '')])
169 200
170 201
171 def MainTestWrapper(options): 202 def MainTestWrapper(options):
203 # Restart adb to work around bugs, sleep to wait for usb discovery.
204 RunCmd(['adb', 'kill-server'])
205 RunCmd(['adb', 'start-server'])
206 RunCmd(['sleep', '1'])
207
208 # Spawn logcat monitor
209 logcat_dir = os.path.join(CHROME_SRC, 'out/logcat')
210 shutil.rmtree(logcat_dir, ignore_errors=True)
211 SpawnCmd(['build/android/adb_logcat_monitor.py', logcat_dir])
212
213 # Wait for logcat_monitor to pull existing logcat
214 RunCmd(['sleep', '5'])
215
216 if options.reboot:
217 RebootDevices()
218
172 # Device check and alert emails 219 # Device check and alert emails
173 buildbot_report.PrintNamedStep('device_status_check') 220 buildbot_report.PrintNamedStep('device_status_check')
174 RunCmd(['build/android/device_status_check.py'], flunk_on_failure=False) 221 RunCmd(['build/android/device_status_check.py'], flunk_on_failure=False)
175 222
176 if options.install: 223 if options.install:
177 test_obj = INSTRUMENTATION_TESTS[options.install] 224 test_obj = INSTRUMENTATION_TESTS[options.install]
178 InstallApk(options, test_obj, print_step=True) 225 InstallApk(options, test_obj, print_step=True)
179 226
180 if not options.test_filter:
181 return
182
183 # Spawn logcat monitor
184 logcat_dir = os.path.join(CHROME_SRC, 'out/logcat')
185 shutil.rmtree(logcat_dir, ignore_errors=True)
186 SpawnCmd(['build/android/adb_logcat_monitor.py', logcat_dir])
187
188 if 'unit' in options.test_filter: 227 if 'unit' in options.test_filter:
189 RunTestSuites(options, gtest_config.STABLE_TEST_SUITES) 228 RunTestSuites(options, gtest_config.STABLE_TEST_SUITES)
190 if 'ui' in options.test_filter: 229 if 'ui' in options.test_filter:
191 for test in INSTRUMENTATION_TESTS.itervalues(): 230 for test in INSTRUMENTATION_TESTS.itervalues():
192 RunInstrumentationSuite(options, test) 231 RunInstrumentationSuite(options, test)
193 if 'webkit' in options.test_filter: 232 if 'webkit' in options.test_filter:
194 RunTestSuites(options, ['webkit_unit_tests', 'TestWebKitAPI']) 233 RunTestSuites(options, ['webkit_unit_tests', 'TestWebKitAPI'])
195 RunWebkitLint(options.target) 234 RunWebkitLint(options.target)
196 if 'webkit_layout' in options.test_filter: 235 if 'webkit_layout' in options.test_filter:
197 RunWebkitLayoutTests(options) 236 RunWebkitLayoutTests(options)
198 237
199 if options.experimental: 238 if options.experimental:
200 RunTestSuites(options, gtest_config.EXPERIMENTAL_TEST_SUITES) 239 RunTestSuites(options, gtest_config.EXPERIMENTAL_TEST_SUITES)
201 240
202 # Print logcat, kill logcat monitor 241 # Print logcat, kill logcat monitor
203 buildbot_report.PrintNamedStep('logcat_dump') 242 buildbot_report.PrintNamedStep('logcat_dump')
204 RunCmd(['build/android/adb_logcat_printer.py', logcat_dir]) 243 RunCmd(['build/android/adb_logcat_printer.py', logcat_dir])
205 244
206 buildbot_report.PrintNamedStep('test_report') 245 buildbot_report.PrintNamedStep('test_report')
207 for report in glob.glob( 246 for report in glob.glob(
208 os.path.join(CHROME_SRC, 'out', options.target, 'test_logs', '*.log')): 247 os.path.join(CHROME_SRC, 'out', options.target, 'test_logs', '*.log')):
209 subprocess.Popen(['cat', report]).wait() 248 RunCmd(['cat', report])
210 os.remove(report) 249 os.remove(report)
211 250
212 251
213 def main(argv): 252 def main(argv):
214 parser = optparse.OptionParser() 253 parser = optparse.OptionParser()
215 254
216 def convert_json(option, _, value, parser): 255 def convert_json(option, _, value, parser):
217 setattr(parser.values, option.dest, json.loads(value)) 256 setattr(parser.values, option.dest, json.loads(value))
218 257
219 parser.add_option('--build-properties', action='callback', 258 parser.add_option('--build-properties', action='callback',
220 callback=convert_json, type='string', default={}, 259 callback=convert_json, type='string', default={},
221 help='build properties in JSON format') 260 help='build properties in JSON format')
222 parser.add_option('--factory-properties', action='callback', 261 parser.add_option('--factory-properties', action='callback',
223 callback=convert_json, type='string', default={}, 262 callback=convert_json, type='string', default={},
224 help='factory properties in JSON format') 263 help='factory properties in JSON format')
225 parser.add_option('--slave-properties', action='callback', 264 parser.add_option('--slave-properties', action='callback',
226 callback=convert_json, type='string', default={}, 265 callback=convert_json, type='string', default={},
227 help='Properties set by slave script in JSON format') 266 help='Properties set by slave script in JSON format')
228 parser.add_option('--experimental', action='store_true', 267 parser.add_option('--experimental', action='store_true',
229 help='Run experiemental tests') 268 help='Run experiemental tests')
230 parser.add_option('-f', '--test-filter', metavar='<filter>', default=[], 269 parser.add_option('-f', '--test-filter', metavar='<filter>', default=[],
231 action='append', 270 action='append',
232 help=('Run a test suite. Test suites: "%s"' % 271 help=('Run a test suite. Test suites: "%s"' %
233 '", "'.join(VALID_TESTS))) 272 '", "'.join(VALID_TESTS)))
234 parser.add_option('--asan', action='store_true', help='Run tests with asan.') 273 parser.add_option('--asan', action='store_true', help='Run tests with asan.')
235 parser.add_option('--install', metavar='<apk name>', 274 parser.add_option('--install', metavar='<apk name>',
236 help='Install an apk by name') 275 help='Install an apk by name')
276 parser.add_option('--reboot', action='store_true',
277 help='Reboot devices before running tests')
237 options, args = parser.parse_args(argv[1:]) 278 options, args = parser.parse_args(argv[1:])
238 279
239 def ParserError(msg): 280 def ParserError(msg):
240 """We avoid parser.error because it calls sys.exit.""" 281 """We avoid parser.error because it calls sys.exit."""
241 parser.print_help() 282 parser.print_help()
242 print >> sys.stderr, '\nERROR:', msg 283 print >> sys.stderr, '\nERROR:', msg
243 return 1 284 return 1
244 285
245 if args: 286 if args:
246 return ParserError('Unused args %s' % args) 287 return ParserError('Unused args %s' % args)
247 288
248 unknown_tests = set(options.test_filter) - VALID_TESTS 289 unknown_tests = set(options.test_filter) - VALID_TESTS
249 if unknown_tests: 290 if unknown_tests:
250 return ParserError('Unknown tests %s' % list(unknown_tests)) 291 return ParserError('Unknown tests %s' % list(unknown_tests))
251 292
252 setattr(options, 'target', options.factory_properties.get('target', 'Debug')) 293 setattr(options, 'target', options.factory_properties.get('target', 'Debug'))
253 294
295 # Add adb binary and chromium-source platform-tools to tip of PATH variable.
296 android_paths = [os.path.join(constants.ANDROID_SDK_ROOT, 'platform-tools')]
297
298 # Bots checkout chrome in /b/build/slave/<name>/build/src
299 build_internal_android = os.path.abspath(os.path.join(
300 CHROME_SRC, '..', '..', '..', '..', '..', 'build_internal', 'scripts',
301 'slave', 'android'))
302 if os.path.exists(build_internal_android):
303 android_paths.insert(0, build_internal_android)
304 os.environ['PATH'] = os.pathsep.join(android_paths + [os.environ['PATH']])
305
254 MainTestWrapper(options) 306 MainTestWrapper(options)
255 307
256 308
257 if __name__ == '__main__': 309 if __name__ == '__main__':
258 sys.exit(main(sys.argv)) 310 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « build/android/PRESUBMIT.py ('k') | build/android/buildbot/bb_run_bot.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698