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

Side by Side Diff: build/android/test_runner.py

Issue 19537004: [Android] Converts host driven tests to common test_dispatcher (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@sharding_refactoring
Patch Set: Merges instrumentation_test_case back into test_case Created 7 years, 4 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
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2013 The Chromium Authors. All rights reserved. 3 # Copyright 2013 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Runs all types of tests from one unified interface. 7 """Runs all types of tests from one unified interface.
8 8
9 TODO(gkanwar): 9 TODO(gkanwar):
10 * Add options to run Monkey tests. 10 * Add options to run Monkey tests.
11 """ 11 """
12 12
13 import collections 13 import collections
14 import optparse 14 import optparse
15 import os 15 import os
16 import shutil 16 import shutil
17 import sys 17 import sys
18 18
19 from pylib import constants 19 from pylib import constants
20 from pylib import ports 20 from pylib import ports
21 from pylib.base import base_test_result 21 from pylib.base import base_test_result
22 from pylib.base import test_dispatcher 22 from pylib.base import test_dispatcher
23 from pylib.gtest import gtest_config 23 from pylib.gtest import gtest_config
24 from pylib.gtest import setup as gtest_setup 24 from pylib.gtest import setup as gtest_setup
25 from pylib.gtest import test_options as gtest_test_options 25 from pylib.gtest import test_options as gtest_test_options
26 from pylib.host_driven import run_python_tests as python_dispatch 26 from pylib.host_driven import setup as host_driven_setup
27 from pylib.instrumentation import setup as instrumentation_setup 27 from pylib.instrumentation import setup as instrumentation_setup
28 from pylib.instrumentation import test_options as instrumentation_test_options 28 from pylib.instrumentation import test_options as instrumentation_test_options
29 from pylib.uiautomator import setup as uiautomator_setup 29 from pylib.uiautomator import setup as uiautomator_setup
30 from pylib.uiautomator import test_options as uiautomator_test_options 30 from pylib.uiautomator import test_options as uiautomator_test_options
31 from pylib.utils import report_results 31 from pylib.utils import report_results
32 from pylib.utils import run_tests_helper 32 from pylib.utils import run_tests_helper
33 33
34 34
35 _SDK_OUT_DIR = os.path.join(constants.DIR_SOURCE_ROOT, 'out') 35 _SDK_OUT_DIR = os.path.join(constants.DIR_SOURCE_ROOT, 'out')
36 36
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 option_parser.add_option( 152 option_parser.add_option(
153 '-A', '--annotation', dest='annotation_str', 153 '-A', '--annotation', dest='annotation_str',
154 help=('Comma-separated list of annotations. Run only tests with any of ' 154 help=('Comma-separated list of annotations. Run only tests with any of '
155 'the given annotations. An annotation can be either a key or a ' 155 'the given annotations. An annotation can be either a key or a '
156 'key-values pair. A test that has no annotation is considered ' 156 'key-values pair. A test that has no annotation is considered '
157 '"SmallTest".')) 157 '"SmallTest".'))
158 option_parser.add_option( 158 option_parser.add_option(
159 '-E', '--exclude-annotation', dest='exclude_annotation_str', 159 '-E', '--exclude-annotation', dest='exclude_annotation_str',
160 help=('Comma-separated list of annotations. Exclude tests with these ' 160 help=('Comma-separated list of annotations. Exclude tests with these '
161 'annotations.')) 161 'annotations.'))
162 option_parser.add_option('-j', '--java_only', action='store_true',
163 default=False, help='Run only the Java tests.')
164 option_parser.add_option('-p', '--python_only', action='store_true',
165 default=False,
166 help='Run only the host-driven tests.')
167 option_parser.add_option('--screenshot', dest='screenshot_failures', 162 option_parser.add_option('--screenshot', dest='screenshot_failures',
168 action='store_true', 163 action='store_true',
169 help='Capture screenshots of test failures') 164 help='Capture screenshots of test failures')
170 option_parser.add_option('--save-perf-json', action='store_true', 165 option_parser.add_option('--save-perf-json', action='store_true',
171 help='Saves the JSON file for each UI Perf test.') 166 help='Saves the JSON file for each UI Perf test.')
172 option_parser.add_option('--official-build', help='Run official build tests.') 167 option_parser.add_option('--official-build', help='Run official build tests.')
173 option_parser.add_option('--python_test_root',
174 help='Root of the host-driven tests.')
175 option_parser.add_option('--keep_test_server_ports', 168 option_parser.add_option('--keep_test_server_ports',
176 action='store_true', 169 action='store_true',
177 help=('Indicates the test server ports must be ' 170 help=('Indicates the test server ports must be '
178 'kept. When this is run via a sharder ' 171 'kept. When this is run via a sharder '
179 'the test server ports should be kept and ' 172 'the test server ports should be kept and '
180 'should not be reset.')) 173 'should not be reset.'))
181 # TODO(gkanwar): This option is deprecated. Remove it in the future. 174 # TODO(gkanwar): This option is deprecated. Remove it in the future.
182 option_parser.add_option('--disable_assertions', action='store_true', 175 option_parser.add_option('--disable_assertions', action='store_true',
183 help=('(DEPRECATED) Run with java assertions ' 176 help=('(DEPRECATED) Run with java assertions '
184 'disabled.')) 177 'disabled.'))
185 option_parser.add_option('--test_data', action='append', default=[], 178 option_parser.add_option('--test_data', action='append', default=[],
186 help=('Each instance defines a directory of test ' 179 help=('Each instance defines a directory of test '
187 'data that should be copied to the target(s) ' 180 'data that should be copied to the target(s) '
188 'before running the tests. The argument ' 181 'before running the tests. The argument '
189 'should be of the form <target>:<source>, ' 182 'should be of the form <target>:<source>, '
190 '<target> is relative to the device data' 183 '<target> is relative to the device data'
191 'directory, and <source> is relative to the ' 184 'directory, and <source> is relative to the '
192 'chromium build directory.')) 185 'chromium build directory.'))
193 186
194 187
195 def ProcessJavaTestOptions(options, error_func): 188 def ProcessJavaTestOptions(options, error_func):
196 """Processes options/arguments and populates |options| with defaults.""" 189 """Processes options/arguments and populates |options| with defaults."""
197 190
198 if options.java_only and options.python_only:
199 error_func('Options java_only (-j) and python_only (-p) '
200 'are mutually exclusive.')
201 options.run_java_tests = True
202 options.run_python_tests = True
203 if options.java_only:
204 options.run_python_tests = False
205 elif options.python_only:
206 options.run_java_tests = False
207
208 if not options.python_test_root:
209 options.run_python_tests = False
210
211 if options.annotation_str: 191 if options.annotation_str:
212 options.annotations = options.annotation_str.split(',') 192 options.annotations = options.annotation_str.split(',')
213 elif options.test_filter: 193 elif options.test_filter:
214 options.annotations = [] 194 options.annotations = []
215 else: 195 else:
216 options.annotations = ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest', 196 options.annotations = ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
217 'EnormousTest'] 197 'EnormousTest']
218 198
219 if options.exclude_annotation_str: 199 if options.exclude_annotation_str:
220 options.exclude_annotations = options.exclude_annotation_str.split(',') 200 options.exclude_annotations = options.exclude_annotation_str.split(',')
221 else: 201 else:
222 options.exclude_annotations = [] 202 options.exclude_annotations = []
223 203
224 if not options.keep_test_server_ports: 204 if not options.keep_test_server_ports:
225 if not ports.ResetTestServerPortAllocation(): 205 if not ports.ResetTestServerPortAllocation():
226 raise Exception('Failed to reset test server port.') 206 raise Exception('Failed to reset test server port.')
227 207
228 208
229 def AddInstrumentationTestOptions(option_parser): 209 def AddInstrumentationTestOptions(option_parser):
230 """Adds Instrumentation test options to |option_parser|.""" 210 """Adds Instrumentation test options to |option_parser|."""
231 211
232 option_parser.usage = '%prog instrumentation [options]' 212 option_parser.usage = '%prog instrumentation [options]'
233 option_parser.command_list = [] 213 option_parser.command_list = []
234 option_parser.example = ('%prog instrumentation ' 214 option_parser.example = ('%prog instrumentation '
235 '--test-apk=ChromiumTestShellTest') 215 '--test-apk=ChromiumTestShellTest')
236 216
237 AddJavaTestOptions(option_parser) 217 AddJavaTestOptions(option_parser)
238 AddCommonOptions(option_parser) 218 AddCommonOptions(option_parser)
239 219
220 option_parser.add_option('-j', '--java_only', action='store_true',
221 default=False, help='Run only the Java tests.')
222 option_parser.add_option('-p', '--python_only', action='store_true',
223 default=False,
224 help='Run only the host-driven tests.')
225 option_parser.add_option('--python_test_root',
226 help='Root of the host-driven tests.')
240 option_parser.add_option('-w', '--wait_debugger', dest='wait_for_debugger', 227 option_parser.add_option('-w', '--wait_debugger', dest='wait_for_debugger',
241 action='store_true', 228 action='store_true',
242 help='Wait for debugger.') 229 help='Wait for debugger.')
243 #TODO(craigdh): Remove option once -I is no longer passed downstream. 230 #TODO(craigdh): Remove option once -I is no longer passed downstream.
244 option_parser.add_option('-I', dest='install_apk', action='store_true', 231 option_parser.add_option('-I', dest='install_apk', action='store_true',
245 help='(DEPRECATED) Install the test apk.') 232 help='(DEPRECATED) Install the test apk.')
246 option_parser.add_option( 233 option_parser.add_option(
247 '--test-apk', dest='test_apk', 234 '--test-apk', dest='test_apk',
248 help=('The name of the apk containing the tests ' 235 help=('The name of the apk containing the tests '
249 '(without the .apk extension; e.g. "ContentShellTest"). ' 236 '(without the .apk extension; e.g. "ContentShellTest"). '
250 'Alternatively, this can be a full path to the apk.')) 237 'Alternatively, this can be a full path to the apk.'))
251 238
252 239
253 def ProcessInstrumentationOptions(options, error_func): 240 def ProcessInstrumentationOptions(options, error_func):
254 """Processes options/arguments and populate |options| with defaults. 241 """Processes options/arguments and populate |options| with defaults.
255 242
256 Args: 243 Args:
257 options: optparse.Options object. 244 options: optparse.Options object.
258 error_func: Function to call with the error message in case of an error. 245 error_func: Function to call with the error message in case of an error.
259 246
260 Returns: 247 Returns:
261 An InstrumentationOptions named tuple which contains all options relevant to 248 An InstrumentationOptions named tuple which contains all options relevant to
262 instrumentation tests. 249 instrumentation tests.
263 """ 250 """
264 251
265 ProcessJavaTestOptions(options, error_func) 252 ProcessJavaTestOptions(options, error_func)
266 253
254 if options.java_only and options.python_only:
255 error_func('Options java_only (-j) and python_only (-p) '
256 'are mutually exclusive.')
257 options.run_java_tests = True
258 options.run_python_tests = True
259 if options.java_only:
260 options.run_python_tests = False
261 elif options.python_only:
262 options.run_java_tests = False
263
264 if not options.python_test_root:
265 options.run_python_tests = False
266
267 if not options.test_apk: 267 if not options.test_apk:
268 error_func('--test-apk must be specified.') 268 error_func('--test-apk must be specified.')
269 269
270 if os.path.exists(options.test_apk): 270 if os.path.exists(options.test_apk):
271 # The APK is fully qualified, assume the JAR lives along side. 271 # The APK is fully qualified, assume the JAR lives along side.
272 options.test_apk_path = options.test_apk 272 options.test_apk_path = options.test_apk
273 options.test_apk_jar_path = (os.path.splitext(options.test_apk_path)[0] + 273 options.test_apk_jar_path = (os.path.splitext(options.test_apk_path)[0] +
274 '.jar') 274 '.jar')
275 else: 275 else:
276 options.test_apk_path = os.path.join(_SDK_OUT_DIR, 276 options.test_apk_path = os.path.join(_SDK_OUT_DIR,
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 tests, runner_factory, options.wait_for_debugger, 424 tests, runner_factory, options.wait_for_debugger,
425 options.test_device, 425 options.test_device,
426 shard=True, 426 shard=True,
427 build_type=options.build_type, 427 build_type=options.build_type,
428 test_timeout=None, 428 test_timeout=None,
429 num_retries=options.num_retries) 429 num_retries=options.num_retries)
430 430
431 results.AddTestRunResults(test_results) 431 results.AddTestRunResults(test_results)
432 432
433 if options.run_python_tests: 433 if options.run_python_tests:
434 test_results, test_exit_code = ( 434 runner_factory, tests = host_driven_setup.InstrumentationSetup(
435 python_dispatch.DispatchPythonTests(options)) 435 options.python_test_root, options.official_build,
436 instrumentation_options)
437
438 test_results, test_exit_code = test_dispatcher.RunTests(
439 tests, runner_factory, False,
440 options.test_device,
441 shard=True,
442 build_type=options.build_type,
443 test_timeout=None,
444 num_retries=options.num_retries)
436 445
437 results.AddTestRunResults(test_results) 446 results.AddTestRunResults(test_results)
438 447
439 # Only allow exit code escalation 448 # Only allow exit code escalation
440 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: 449 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
441 exit_code = test_exit_code 450 exit_code = test_exit_code
442 451
443 report_results.LogFull( 452 report_results.LogFull(
444 results=results, 453 results=results,
445 test_type='Instrumentation', 454 test_type='Instrumentation',
446 test_package=os.path.basename(options.test_apk), 455 test_package=os.path.basename(options.test_apk),
447 annotation=options.annotations, 456 annotation=options.annotations,
448 build_type=options.build_type, 457 build_type=options.build_type,
449 flakiness_server=options.flakiness_dashboard_server) 458 flakiness_server=options.flakiness_dashboard_server)
450 459
451 return exit_code 460 return exit_code
452 461
453 462
454 def _RunUIAutomatorTests(options, error_func): 463 def _RunUIAutomatorTests(options, error_func):
455 """Subcommand of RunTestsCommands which runs uiautomator tests.""" 464 """Subcommand of RunTestsCommands which runs uiautomator tests."""
456 uiautomator_options = ProcessUIAutomatorOptions(options, error_func) 465 uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
457 466
458 results = base_test_result.TestRunResults() 467 results = base_test_result.TestRunResults()
459 exit_code = 0 468 exit_code = 0
460 469
461 if options.run_java_tests: 470 runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
462 runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
463 471
464 test_results, exit_code = test_dispatcher.RunTests( 472 results, exit_code = test_dispatcher.RunTests(
465 tests, runner_factory, False, options.test_device, 473 tests, runner_factory, False, options.test_device,
466 shard=True, 474 shard=True,
467 build_type=options.build_type, 475 build_type=options.build_type,
468 test_timeout=None, 476 test_timeout=None,
469 num_retries=options.num_retries) 477 num_retries=options.num_retries)
470
471 results.AddTestRunResults(test_results)
472
473 if options.run_python_tests:
474 test_results, test_exit_code = (
475 python_dispatch.DispatchPythonTests(options))
476
477 results.AddTestRunResults(test_results)
478
479 # Only allow exit code escalation
480 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
481 exit_code = test_exit_code
482 478
483 report_results.LogFull( 479 report_results.LogFull(
484 results=results, 480 results=results,
485 test_type='UIAutomator', 481 test_type='UIAutomator',
486 test_package=os.path.basename(options.test_jar), 482 test_package=os.path.basename(options.test_jar),
487 annotation=options.annotations, 483 annotation=options.annotations,
488 build_type=options.build_type, 484 build_type=options.build_type,
489 flakiness_server=options.flakiness_dashboard_server) 485 flakiness_server=options.flakiness_dashboard_server)
490 486
491 return exit_code 487 return exit_code
(...skipping 26 matching lines...) Expand all
518 514
519 if command == 'gtest': 515 if command == 'gtest':
520 return _RunGTests(options, option_parser.error) 516 return _RunGTests(options, option_parser.error)
521 elif command == 'instrumentation': 517 elif command == 'instrumentation':
522 return _RunInstrumentationTests(options, option_parser.error) 518 return _RunInstrumentationTests(options, option_parser.error)
523 elif command == 'uiautomator': 519 elif command == 'uiautomator':
524 return _RunUIAutomatorTests(options, option_parser.error) 520 return _RunUIAutomatorTests(options, option_parser.error)
525 else: 521 else:
526 raise Exception('Unknown test type.') 522 raise Exception('Unknown test type.')
527 523
528 return exit_code
529
530 524
531 def HelpCommand(command, options, args, option_parser): 525 def HelpCommand(command, options, args, option_parser):
532 """Display help for a certain command, or overall help. 526 """Display help for a certain command, or overall help.
533 527
534 Args: 528 Args:
535 command: String indicating the command that was received to trigger 529 command: String indicating the command that was received to trigger
536 this function. 530 this function.
537 options: optparse options dictionary. 531 options: optparse options dictionary.
538 args: List of extra args from optparse. 532 args: List of extra args from optparse.
539 option_parser: optparse.OptionParser object. 533 option_parser: optparse.OptionParser object.
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 return 0 615 return 0
622 command = argv[1] 616 command = argv[1]
623 VALID_COMMANDS[command].add_options_func(option_parser) 617 VALID_COMMANDS[command].add_options_func(option_parser)
624 options, args = option_parser.parse_args(argv) 618 options, args = option_parser.parse_args(argv)
625 return VALID_COMMANDS[command].run_command_func( 619 return VALID_COMMANDS[command].run_command_func(
626 command, options, args, option_parser) 620 command, options, args, option_parser)
627 621
628 622
629 if __name__ == '__main__': 623 if __name__ == '__main__':
630 sys.exit(main(sys.argv)) 624 sys.exit(main(sys.argv))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698