blob: f9f212fb95d87b912a74e45d1412e631aa8c933a [file] [log] [blame]
[email protected]fbe29322013-07-09 09:03:261#!/usr/bin/env python
2#
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
5# found in the LICENSE file.
6
7"""Runs all types of tests from one unified interface.
8
9TODO(gkanwar):
10* Add options to run Monkey tests.
11"""
12
13import collections
14import optparse
15import os
[email protected]6bc1bda22013-07-19 22:08:3716import shutil
[email protected]fbe29322013-07-09 09:03:2617import sys
18
[email protected]fbe29322013-07-09 09:03:2619from pylib import constants
20from pylib import ports
21from pylib.base import base_test_result
[email protected]6bc1bda22013-07-19 22:08:3722from pylib.base import test_dispatcher
[email protected]6bc1bda22013-07-19 22:08:3723from pylib.gtest import gtest_config
[email protected]2a684222013-08-01 16:59:2224from pylib.gtest import setup as gtest_setup
25from pylib.gtest import test_options as gtest_test_options
[email protected]37ee0c792013-08-06 19:10:1326from pylib.host_driven import setup as host_driven_setup
[email protected]6bc1bda22013-07-19 22:08:3727from pylib.instrumentation import setup as instrumentation_setup
[email protected]2a684222013-08-01 16:59:2228from pylib.instrumentation import test_options as instrumentation_test_options
[email protected]3dbdfa42013-08-08 01:08:1429from pylib.monkey import setup as monkey_setup
30from pylib.monkey import test_options as monkey_test_options
[email protected]ec3170b2013-08-14 14:39:4731from pylib.perf import setup as perf_setup
32from pylib.perf import test_options as perf_test_options
33from pylib.perf import test_runner as perf_test_runner
[email protected]6bc1bda22013-07-19 22:08:3734from pylib.uiautomator import setup as uiautomator_setup
[email protected]2a684222013-08-01 16:59:2235from pylib.uiautomator import test_options as uiautomator_test_options
[email protected]6bc1bda22013-07-19 22:08:3736from pylib.utils import report_results
37from pylib.utils import run_tests_helper
[email protected]fbe29322013-07-09 09:03:2638
39
40_SDK_OUT_DIR = os.path.join(constants.DIR_SOURCE_ROOT, 'out')
41
42
43def AddBuildTypeOption(option_parser):
44 """Adds the build type option to |option_parser|."""
45 default_build_type = 'Debug'
46 if 'BUILDTYPE' in os.environ:
47 default_build_type = os.environ['BUILDTYPE']
48 option_parser.add_option('--debug', action='store_const', const='Debug',
49 dest='build_type', default=default_build_type,
50 help=('If set, run test suites under out/Debug. '
51 'Default is env var BUILDTYPE or Debug.'))
52 option_parser.add_option('--release', action='store_const',
53 const='Release', dest='build_type',
54 help=('If set, run test suites under out/Release.'
55 ' Default is env var BUILDTYPE or Debug.'))
56
57
[email protected]fbe29322013-07-09 09:03:2658def AddCommonOptions(option_parser):
59 """Adds all common options to |option_parser|."""
60
61 AddBuildTypeOption(option_parser)
62
[email protected]fbe29322013-07-09 09:03:2663 option_parser.add_option('-c', dest='cleanup_test_files',
64 help='Cleanup test files on the device after run',
65 action='store_true')
66 option_parser.add_option('--num_retries', dest='num_retries', type='int',
67 default=2,
68 help=('Number of retries for a test before '
69 'giving up.'))
70 option_parser.add_option('-v',
71 '--verbose',
72 dest='verbose_count',
73 default=0,
74 action='count',
75 help='Verbose level (multiple times for more)')
[email protected]fbe29322013-07-09 09:03:2676 option_parser.add_option('--tool',
77 dest='tool',
78 help=('Run the test under a tool '
79 '(use --tool help to list them)'))
80 option_parser.add_option('--flakiness-dashboard-server',
81 dest='flakiness_dashboard_server',
82 help=('Address of the server that is hosting the '
83 'Chrome for Android flakiness dashboard.'))
84 option_parser.add_option('--skip-deps-push', dest='push_deps',
85 action='store_false', default=True,
86 help=('Do not push dependencies to the device. '
87 'Use this at own risk for speeding up test '
88 'execution on local machine.'))
[email protected]fbe29322013-07-09 09:03:2689 option_parser.add_option('-d', '--device', dest='test_device',
90 help=('Target device for the test suite '
91 'to run on.'))
92
93
94def ProcessCommonOptions(options):
95 """Processes and handles all common options."""
[email protected]fbe29322013-07-09 09:03:2696 run_tests_helper.SetLogLevel(options.verbose_count)
[email protected]14b3b1202013-08-15 22:25:2897 constants.SetBuildType(options.build_type)
[email protected]fbe29322013-07-09 09:03:2698
99
[email protected]fbe29322013-07-09 09:03:26100def AddGTestOptions(option_parser):
101 """Adds gtest options to |option_parser|."""
102
103 option_parser.usage = '%prog gtest [options]'
104 option_parser.command_list = []
105 option_parser.example = '%prog gtest -s base_unittests'
106
[email protected]6bc1bda22013-07-19 22:08:37107 # TODO(gkanwar): Make this option required
108 option_parser.add_option('-s', '--suite', dest='suite_name',
[email protected]fbe29322013-07-09 09:03:26109 help=('Executable name of the test suite to run '
110 '(use -s help to list them).'))
[email protected]9e689252013-07-30 20:14:36111 option_parser.add_option('-f', '--gtest_filter', dest='test_filter',
112 help='googletest-style filter string.')
113 option_parser.add_option('-a', '--test_arguments', dest='test_arguments',
114 help='Additional arguments to pass to the test.')
115 option_parser.add_option('-t', dest='timeout',
116 help='Timeout to wait for each test',
117 type='int',
118 default=60)
[email protected]fbe29322013-07-09 09:03:26119 # TODO(gkanwar): Move these to Common Options once we have the plumbing
120 # in our other test types to handle these commands
[email protected]fbe29322013-07-09 09:03:26121 AddCommonOptions(option_parser)
122
123
[email protected]6bc1bda22013-07-19 22:08:37124def ProcessGTestOptions(options):
125 """Intercept test suite help to list test suites.
126
127 Args:
128 options: Command line options.
[email protected]6bc1bda22013-07-19 22:08:37129 """
130 if options.suite_name == 'help':
131 print 'Available test suites are:'
[email protected]9e689252013-07-30 20:14:36132 for test_suite in (gtest_config.STABLE_TEST_SUITES +
133 gtest_config.EXPERIMENTAL_TEST_SUITES):
134 print test_suite
[email protected]2a684222013-08-01 16:59:22135 sys.exit(0)
[email protected]6bc1bda22013-07-19 22:08:37136
137 # Convert to a list, assuming all test suites if nothing was specified.
138 # TODO(gkanwar): Require having a test suite
139 if options.suite_name:
140 options.suite_name = [options.suite_name]
141 else:
[email protected]9e689252013-07-30 20:14:36142 options.suite_name = [s for s in gtest_config.STABLE_TEST_SUITES]
[email protected]6bc1bda22013-07-19 22:08:37143
144
[email protected]fbe29322013-07-09 09:03:26145def AddJavaTestOptions(option_parser):
146 """Adds the Java test options to |option_parser|."""
147
148 option_parser.add_option('-f', '--test_filter', dest='test_filter',
149 help=('Test filter (if not fully qualified, '
150 'will run all matches).'))
151 option_parser.add_option(
152 '-A', '--annotation', dest='annotation_str',
153 help=('Comma-separated list of annotations. Run only tests with any of '
154 'the given annotations. An annotation can be either a key or a '
155 'key-values pair. A test that has no annotation is considered '
156 '"SmallTest".'))
157 option_parser.add_option(
158 '-E', '--exclude-annotation', dest='exclude_annotation_str',
159 help=('Comma-separated list of annotations. Exclude tests with these '
160 'annotations.'))
[email protected]fbe29322013-07-09 09:03:26161 option_parser.add_option('--screenshot', dest='screenshot_failures',
162 action='store_true',
163 help='Capture screenshots of test failures')
164 option_parser.add_option('--save-perf-json', action='store_true',
165 help='Saves the JSON file for each UI Perf test.')
[email protected]37ee0c792013-08-06 19:10:13166 option_parser.add_option('--official-build', action='store_true',
167 help='Run official build tests.')
[email protected]fbe29322013-07-09 09:03:26168 option_parser.add_option('--keep_test_server_ports',
169 action='store_true',
170 help=('Indicates the test server ports must be '
171 'kept. When this is run via a sharder '
172 'the test server ports should be kept and '
173 'should not be reset.'))
[email protected]fbe29322013-07-09 09:03:26174 option_parser.add_option('--test_data', action='append', default=[],
175 help=('Each instance defines a directory of test '
176 'data that should be copied to the target(s) '
177 'before running the tests. The argument '
178 'should be of the form <target>:<source>, '
179 '<target> is relative to the device data'
180 'directory, and <source> is relative to the '
181 'chromium build directory.'))
182
183
184def ProcessJavaTestOptions(options, error_func):
185 """Processes options/arguments and populates |options| with defaults."""
186
[email protected]fbe29322013-07-09 09:03:26187 if options.annotation_str:
188 options.annotations = options.annotation_str.split(',')
189 elif options.test_filter:
190 options.annotations = []
191 else:
[email protected]6bc1bda22013-07-19 22:08:37192 options.annotations = ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
193 'EnormousTest']
[email protected]fbe29322013-07-09 09:03:26194
195 if options.exclude_annotation_str:
196 options.exclude_annotations = options.exclude_annotation_str.split(',')
197 else:
198 options.exclude_annotations = []
199
200 if not options.keep_test_server_ports:
201 if not ports.ResetTestServerPortAllocation():
202 raise Exception('Failed to reset test server port.')
203
204
205def AddInstrumentationTestOptions(option_parser):
206 """Adds Instrumentation test options to |option_parser|."""
207
208 option_parser.usage = '%prog instrumentation [options]'
209 option_parser.command_list = []
[email protected]fb7ab5e82013-07-26 18:31:20210 option_parser.example = ('%prog instrumentation '
[email protected]fbe29322013-07-09 09:03:26211 '--test-apk=ChromiumTestShellTest')
212
213 AddJavaTestOptions(option_parser)
214 AddCommonOptions(option_parser)
215
[email protected]37ee0c792013-08-06 19:10:13216 option_parser.add_option('-j', '--java_only', action='store_true',
217 default=False, help='Run only the Java tests.')
218 option_parser.add_option('-p', '--python_only', action='store_true',
219 default=False,
220 help='Run only the host-driven tests.')
[email protected]67954f822013-08-14 18:09:08221 option_parser.add_option('--python_test_root', '--host-driven-root',
222 dest='host_driven_root',
[email protected]37ee0c792013-08-06 19:10:13223 help='Root of the host-driven tests.')
[email protected]fbe29322013-07-09 09:03:26224 option_parser.add_option('-w', '--wait_debugger', dest='wait_for_debugger',
225 action='store_true',
226 help='Wait for debugger.')
[email protected]fbe29322013-07-09 09:03:26227 option_parser.add_option(
228 '--test-apk', dest='test_apk',
229 help=('The name of the apk containing the tests '
230 '(without the .apk extension; e.g. "ContentShellTest"). '
231 'Alternatively, this can be a full path to the apk.'))
232
233
234def ProcessInstrumentationOptions(options, error_func):
[email protected]2a684222013-08-01 16:59:22235 """Processes options/arguments and populate |options| with defaults.
236
237 Args:
238 options: optparse.Options object.
239 error_func: Function to call with the error message in case of an error.
240
241 Returns:
242 An InstrumentationOptions named tuple which contains all options relevant to
243 instrumentation tests.
244 """
[email protected]fbe29322013-07-09 09:03:26245
246 ProcessJavaTestOptions(options, error_func)
247
[email protected]37ee0c792013-08-06 19:10:13248 if options.java_only and options.python_only:
249 error_func('Options java_only (-j) and python_only (-p) '
250 'are mutually exclusive.')
251 options.run_java_tests = True
252 options.run_python_tests = True
253 if options.java_only:
254 options.run_python_tests = False
255 elif options.python_only:
256 options.run_java_tests = False
257
[email protected]67954f822013-08-14 18:09:08258 if not options.host_driven_root:
[email protected]37ee0c792013-08-06 19:10:13259 options.run_python_tests = False
260
[email protected]fbe29322013-07-09 09:03:26261 if not options.test_apk:
262 error_func('--test-apk must be specified.')
263
264 if os.path.exists(options.test_apk):
265 # The APK is fully qualified, assume the JAR lives along side.
266 options.test_apk_path = options.test_apk
267 options.test_apk_jar_path = (os.path.splitext(options.test_apk_path)[0] +
268 '.jar')
269 else:
270 options.test_apk_path = os.path.join(_SDK_OUT_DIR,
271 options.build_type,
272 constants.SDK_BUILD_APKS_DIR,
273 '%s.apk' % options.test_apk)
274 options.test_apk_jar_path = os.path.join(
275 _SDK_OUT_DIR, options.build_type, constants.SDK_BUILD_TEST_JAVALIB_DIR,
276 '%s.jar' % options.test_apk)
277
[email protected]2a684222013-08-01 16:59:22278 return instrumentation_test_options.InstrumentationOptions(
[email protected]2a684222013-08-01 16:59:22279 options.tool,
280 options.cleanup_test_files,
281 options.push_deps,
282 options.annotations,
283 options.exclude_annotations,
284 options.test_filter,
285 options.test_data,
286 options.save_perf_json,
287 options.screenshot_failures,
[email protected]2a684222013-08-01 16:59:22288 options.wait_for_debugger,
289 options.test_apk,
290 options.test_apk_path,
291 options.test_apk_jar_path)
292
[email protected]fbe29322013-07-09 09:03:26293
294def AddUIAutomatorTestOptions(option_parser):
295 """Adds UI Automator test options to |option_parser|."""
296
297 option_parser.usage = '%prog uiautomator [options]'
298 option_parser.command_list = []
299 option_parser.example = (
300 '%prog uiautomator --test-jar=chromium_testshell_uiautomator_tests'
301 ' --package-name=org.chromium.chrome.testshell')
302 option_parser.add_option(
303 '--package-name',
304 help='The package name used by the apk containing the application.')
305 option_parser.add_option(
306 '--test-jar', dest='test_jar',
307 help=('The name of the dexed jar containing the tests (without the '
308 '.dex.jar extension). Alternatively, this can be a full path '
309 'to the jar.'))
310
311 AddJavaTestOptions(option_parser)
312 AddCommonOptions(option_parser)
313
314
315def ProcessUIAutomatorOptions(options, error_func):
[email protected]2a684222013-08-01 16:59:22316 """Processes UIAutomator options/arguments.
317
318 Args:
319 options: optparse.Options object.
320 error_func: Function to call with the error message in case of an error.
321
322 Returns:
323 A UIAutomatorOptions named tuple which contains all options relevant to
[email protected]3dbdfa42013-08-08 01:08:14324 uiautomator tests.
[email protected]2a684222013-08-01 16:59:22325 """
[email protected]fbe29322013-07-09 09:03:26326
327 ProcessJavaTestOptions(options, error_func)
328
329 if not options.package_name:
330 error_func('--package-name must be specified.')
331
332 if not options.test_jar:
333 error_func('--test-jar must be specified.')
334
335 if os.path.exists(options.test_jar):
336 # The dexed JAR is fully qualified, assume the info JAR lives along side.
337 options.uiautomator_jar = options.test_jar
338 else:
339 options.uiautomator_jar = os.path.join(
340 _SDK_OUT_DIR, options.build_type, constants.SDK_BUILD_JAVALIB_DIR,
341 '%s.dex.jar' % options.test_jar)
342 options.uiautomator_info_jar = (
343 options.uiautomator_jar[:options.uiautomator_jar.find('.dex.jar')] +
344 '_java.jar')
345
[email protected]2a684222013-08-01 16:59:22346 return uiautomator_test_options.UIAutomatorOptions(
[email protected]2a684222013-08-01 16:59:22347 options.tool,
348 options.cleanup_test_files,
349 options.push_deps,
350 options.annotations,
351 options.exclude_annotations,
352 options.test_filter,
353 options.test_data,
354 options.save_perf_json,
355 options.screenshot_failures,
[email protected]2a684222013-08-01 16:59:22356 options.uiautomator_jar,
357 options.uiautomator_info_jar,
358 options.package_name)
359
[email protected]fbe29322013-07-09 09:03:26360
[email protected]3dbdfa42013-08-08 01:08:14361def AddMonkeyTestOptions(option_parser):
362 """Adds monkey test options to |option_parser|."""
[email protected]fb81b982013-08-09 00:07:12363
364 option_parser.usage = '%prog monkey [options]'
365 option_parser.command_list = []
366 option_parser.example = (
367 '%prog monkey --package-name=org.chromium.content_shell_apk'
368 ' --activity-name=.ContentShellActivity')
369
[email protected]3dbdfa42013-08-08 01:08:14370 option_parser.add_option('--package-name', help='Allowed package.')
371 option_parser.add_option(
[email protected]fb81b982013-08-09 00:07:12372 '--activity-name', help='Name of the activity to start.')
[email protected]3dbdfa42013-08-08 01:08:14373 option_parser.add_option(
374 '--event-count', default=10000, type='int',
375 help='Number of events to generate [default: %default].')
376 option_parser.add_option(
377 '--category', default='',
[email protected]fb81b982013-08-09 00:07:12378 help='A list of allowed categories.')
[email protected]3dbdfa42013-08-08 01:08:14379 option_parser.add_option(
380 '--throttle', default=100, type='int',
381 help='Delay between events (ms) [default: %default]. ')
382 option_parser.add_option(
383 '--seed', type='int',
384 help=('Seed value for pseudo-random generator. Same seed value generates '
385 'the same sequence of events. Seed is randomized by default.'))
386 option_parser.add_option(
387 '--extra-args', default='',
388 help=('String of other args to pass to the command verbatim '
389 '[default: "%default"].'))
390
391 AddCommonOptions(option_parser)
392
393
394def ProcessMonkeyTestOptions(options, error_func):
395 """Processes all monkey test options.
396
397 Args:
398 options: optparse.Options object.
399 error_func: Function to call with the error message in case of an error.
400
401 Returns:
402 A MonkeyOptions named tuple which contains all options relevant to
403 monkey tests.
404 """
405 if not options.package_name:
406 error_func('Package name is required.')
407
408 category = options.category
409 if category:
410 category = options.category.split(',')
411
412 return monkey_test_options.MonkeyOptions(
[email protected]3dbdfa42013-08-08 01:08:14413 options.verbose_count,
414 options.package_name,
415 options.activity_name,
416 options.event_count,
417 category,
418 options.throttle,
419 options.seed,
420 options.extra_args)
421
422
[email protected]ec3170b2013-08-14 14:39:47423def AddPerfTestOptions(option_parser):
424 """Adds perf test options to |option_parser|."""
425
426 option_parser.usage = '%prog perf [options]'
427 option_parser.command_list = []
428 option_parser.example = ('%prog perf --steps perf_steps.json')
429
430 option_parser.add_option('--steps', help='JSON file containing the list '
431 'of perf steps to run.')
432 option_parser.add_option('--flaky-steps',
433 help='A JSON file containing steps that are flaky '
434 'and will have its exit code ignored.')
435 option_parser.add_option('--print-step', help='The name of a previously '
436 'executed perf step to print.')
437
438 AddCommonOptions(option_parser)
439
440
441def ProcessPerfTestOptions(options, error_func):
442 """Processes all perf test options.
443
444 Args:
445 options: optparse.Options object.
446 error_func: Function to call with the error message in case of an error.
447
448 Returns:
449 A PerfOptions named tuple which contains all options relevant to
450 perf tests.
451 """
452 if not options.steps and not options.print_step:
453 error_func('Please specify --steps or --print-step')
454 return perf_test_options.PerfOptions(
455 options.steps, options.flaky_steps, options.print_step)
456
457
458
[email protected]6bc1bda22013-07-19 22:08:37459def _RunGTests(options, error_func):
460 """Subcommand of RunTestsCommands which runs gtests."""
[email protected]2a684222013-08-01 16:59:22461 ProcessGTestOptions(options)
[email protected]6bc1bda22013-07-19 22:08:37462
463 exit_code = 0
464 for suite_name in options.suite_name:
[email protected]2a684222013-08-01 16:59:22465 # TODO(gkanwar): Move this into ProcessGTestOptions once we require -s for
466 # the gtest command.
467 gtest_options = gtest_test_options.GTestOptions(
[email protected]2a684222013-08-01 16:59:22468 options.tool,
469 options.cleanup_test_files,
470 options.push_deps,
471 options.test_filter,
472 options.test_arguments,
473 options.timeout,
474 suite_name)
475 runner_factory, tests = gtest_setup.Setup(gtest_options)
[email protected]6bc1bda22013-07-19 22:08:37476
477 results, test_exit_code = test_dispatcher.RunTests(
478 tests, runner_factory, False, options.test_device,
479 shard=True,
[email protected]6bc1bda22013-07-19 22:08:37480 test_timeout=None,
481 num_retries=options.num_retries)
482
483 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
484 exit_code = test_exit_code
485
486 report_results.LogFull(
487 results=results,
488 test_type='Unit test',
489 test_package=suite_name,
[email protected]6bc1bda22013-07-19 22:08:37490 flakiness_server=options.flakiness_dashboard_server)
491
492 if os.path.isdir(constants.ISOLATE_DEPS_DIR):
493 shutil.rmtree(constants.ISOLATE_DEPS_DIR)
494
495 return exit_code
496
497
[email protected]6bc1bda22013-07-19 22:08:37498def _RunInstrumentationTests(options, error_func):
499 """Subcommand of RunTestsCommands which runs instrumentation tests."""
[email protected]2a684222013-08-01 16:59:22500 instrumentation_options = ProcessInstrumentationOptions(options, error_func)
[email protected]6bc1bda22013-07-19 22:08:37501
502 results = base_test_result.TestRunResults()
503 exit_code = 0
504
505 if options.run_java_tests:
[email protected]2a684222013-08-01 16:59:22506 runner_factory, tests = instrumentation_setup.Setup(instrumentation_options)
[email protected]6bc1bda22013-07-19 22:08:37507
508 test_results, exit_code = test_dispatcher.RunTests(
509 tests, runner_factory, options.wait_for_debugger,
510 options.test_device,
511 shard=True,
[email protected]6bc1bda22013-07-19 22:08:37512 test_timeout=None,
513 num_retries=options.num_retries)
514
515 results.AddTestRunResults(test_results)
516
517 if options.run_python_tests:
[email protected]37ee0c792013-08-06 19:10:13518 runner_factory, tests = host_driven_setup.InstrumentationSetup(
[email protected]67954f822013-08-14 18:09:08519 options.host_driven_root, options.official_build,
[email protected]37ee0c792013-08-06 19:10:13520 instrumentation_options)
521
[email protected]34020022013-08-06 23:35:34522 if tests:
523 test_results, test_exit_code = test_dispatcher.RunTests(
524 tests, runner_factory, False,
525 options.test_device,
526 shard=True,
[email protected]34020022013-08-06 23:35:34527 test_timeout=None,
528 num_retries=options.num_retries)
[email protected]6bc1bda22013-07-19 22:08:37529
[email protected]34020022013-08-06 23:35:34530 results.AddTestRunResults(test_results)
[email protected]6bc1bda22013-07-19 22:08:37531
[email protected]34020022013-08-06 23:35:34532 # Only allow exit code escalation
533 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
534 exit_code = test_exit_code
[email protected]6bc1bda22013-07-19 22:08:37535
536 report_results.LogFull(
537 results=results,
538 test_type='Instrumentation',
539 test_package=os.path.basename(options.test_apk),
540 annotation=options.annotations,
[email protected]6bc1bda22013-07-19 22:08:37541 flakiness_server=options.flakiness_dashboard_server)
542
543 return exit_code
544
545
546def _RunUIAutomatorTests(options, error_func):
547 """Subcommand of RunTestsCommands which runs uiautomator tests."""
[email protected]2a684222013-08-01 16:59:22548 uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
[email protected]6bc1bda22013-07-19 22:08:37549
[email protected]37ee0c792013-08-06 19:10:13550 runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
[email protected]6bc1bda22013-07-19 22:08:37551
[email protected]37ee0c792013-08-06 19:10:13552 results, exit_code = test_dispatcher.RunTests(
553 tests, runner_factory, False, options.test_device,
554 shard=True,
[email protected]37ee0c792013-08-06 19:10:13555 test_timeout=None,
556 num_retries=options.num_retries)
[email protected]6bc1bda22013-07-19 22:08:37557
558 report_results.LogFull(
559 results=results,
560 test_type='UIAutomator',
561 test_package=os.path.basename(options.test_jar),
562 annotation=options.annotations,
[email protected]6bc1bda22013-07-19 22:08:37563 flakiness_server=options.flakiness_dashboard_server)
564
565 return exit_code
566
567
[email protected]3dbdfa42013-08-08 01:08:14568def _RunMonkeyTests(options, error_func):
569 """Subcommand of RunTestsCommands which runs monkey tests."""
570 monkey_options = ProcessMonkeyTestOptions(options, error_func)
571
572 runner_factory, tests = monkey_setup.Setup(monkey_options)
573
574 results, exit_code = test_dispatcher.RunTests(
[email protected]78e1f6822013-08-12 21:09:44575 tests, runner_factory, False, None, shard=False, test_timeout=None)
[email protected]3dbdfa42013-08-08 01:08:14576
577 report_results.LogFull(
578 results=results,
579 test_type='Monkey',
[email protected]14b3b1202013-08-15 22:25:28580 test_package='Monkey')
[email protected]3dbdfa42013-08-08 01:08:14581
582 return exit_code
583
584
[email protected]ec3170b2013-08-14 14:39:47585def _RunPerfTests(options, error_func):
586 """Subcommand of RunTestsCommands which runs perf tests."""
587 perf_options = ProcessPerfTestOptions(options, error_func)
588 # Just print the results from a single previously executed step.
589 if perf_options.print_step:
590 return perf_test_runner.PrintTestOutput(perf_options.print_step)
591
592 runner_factory, tests = perf_setup.Setup(perf_options)
593
[email protected]86184c7b2013-08-15 15:06:57594 results, _ = test_dispatcher.RunTests(
[email protected]ec3170b2013-08-14 14:39:47595 tests, runner_factory, False, None, shard=True, test_timeout=None)
596
597 report_results.LogFull(
598 results=results,
599 test_type='Perf',
[email protected]865a47a2013-08-16 14:01:12600 test_package='Perf')
[email protected]86184c7b2013-08-15 15:06:57601 # Always return 0 on the sharding stage. Individual tests exit_code
602 # will be returned on the print_step stage.
603 return 0
[email protected]ec3170b2013-08-14 14:39:47604
[email protected]3dbdfa42013-08-08 01:08:14605
[email protected]fbe29322013-07-09 09:03:26606def RunTestsCommand(command, options, args, option_parser):
607 """Checks test type and dispatches to the appropriate function.
608
609 Args:
610 command: String indicating the command that was received to trigger
611 this function.
612 options: optparse options dictionary.
613 args: List of extra args from optparse.
614 option_parser: optparse.OptionParser object.
615
616 Returns:
617 Integer indicated exit code.
[email protected]b3873892013-07-10 04:57:10618
619 Raises:
620 Exception: Unknown command name passed in, or an exception from an
621 individual test runner.
[email protected]fbe29322013-07-09 09:03:26622 """
623
[email protected]d82f0252013-07-12 23:22:57624 # Check for extra arguments
625 if len(args) > 2:
626 option_parser.error('Unrecognized arguments: %s' % (' '.join(args[2:])))
627 return constants.ERROR_EXIT_CODE
628
[email protected]fbe29322013-07-09 09:03:26629 ProcessCommonOptions(options)
630
[email protected]fbe29322013-07-09 09:03:26631 if command == 'gtest':
[email protected]6bc1bda22013-07-19 22:08:37632 return _RunGTests(options, option_parser.error)
[email protected]fbe29322013-07-09 09:03:26633 elif command == 'instrumentation':
[email protected]6bc1bda22013-07-19 22:08:37634 return _RunInstrumentationTests(options, option_parser.error)
[email protected]fbe29322013-07-09 09:03:26635 elif command == 'uiautomator':
[email protected]6bc1bda22013-07-19 22:08:37636 return _RunUIAutomatorTests(options, option_parser.error)
[email protected]3dbdfa42013-08-08 01:08:14637 elif command == 'monkey':
638 return _RunMonkeyTests(options, option_parser.error)
[email protected]ec3170b2013-08-14 14:39:47639 elif command == 'perf':
640 return _RunPerfTests(options, option_parser.error)
[email protected]fbe29322013-07-09 09:03:26641 else:
[email protected]6bc1bda22013-07-19 22:08:37642 raise Exception('Unknown test type.')
[email protected]fbe29322013-07-09 09:03:26643
[email protected]fbe29322013-07-09 09:03:26644
645def HelpCommand(command, options, args, option_parser):
646 """Display help for a certain command, or overall help.
647
648 Args:
649 command: String indicating the command that was received to trigger
650 this function.
651 options: optparse options dictionary.
652 args: List of extra args from optparse.
653 option_parser: optparse.OptionParser object.
654
655 Returns:
656 Integer indicated exit code.
657 """
658 # If we don't have any args, display overall help
659 if len(args) < 3:
660 option_parser.print_help()
661 return 0
[email protected]d82f0252013-07-12 23:22:57662 # If we have too many args, print an error
663 if len(args) > 3:
664 option_parser.error('Unrecognized arguments: %s' % (' '.join(args[3:])))
665 return constants.ERROR_EXIT_CODE
[email protected]fbe29322013-07-09 09:03:26666
667 command = args[2]
668
669 if command not in VALID_COMMANDS:
670 option_parser.error('Unrecognized command.')
671
672 # Treat the help command as a special case. We don't care about showing a
673 # specific help page for itself.
674 if command == 'help':
675 option_parser.print_help()
676 return 0
677
678 VALID_COMMANDS[command].add_options_func(option_parser)
679 option_parser.usage = '%prog ' + command + ' [options]'
680 option_parser.command_list = None
681 option_parser.print_help()
682
683 return 0
684
685
686# Define a named tuple for the values in the VALID_COMMANDS dictionary so the
687# syntax is a bit prettier. The tuple is two functions: (add options, run
688# command).
689CommandFunctionTuple = collections.namedtuple(
690 'CommandFunctionTuple', ['add_options_func', 'run_command_func'])
691VALID_COMMANDS = {
692 'gtest': CommandFunctionTuple(AddGTestOptions, RunTestsCommand),
[email protected]fbe29322013-07-09 09:03:26693 'instrumentation': CommandFunctionTuple(
694 AddInstrumentationTestOptions, RunTestsCommand),
695 'uiautomator': CommandFunctionTuple(
696 AddUIAutomatorTestOptions, RunTestsCommand),
[email protected]3dbdfa42013-08-08 01:08:14697 'monkey': CommandFunctionTuple(
698 AddMonkeyTestOptions, RunTestsCommand),
[email protected]ec3170b2013-08-14 14:39:47699 'perf': CommandFunctionTuple(
700 AddPerfTestOptions, RunTestsCommand),
[email protected]fbe29322013-07-09 09:03:26701 'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand)
702 }
703
704
705class CommandOptionParser(optparse.OptionParser):
706 """Wrapper class for OptionParser to help with listing commands."""
707
708 def __init__(self, *args, **kwargs):
709 self.command_list = kwargs.pop('command_list', [])
710 self.example = kwargs.pop('example', '')
711 optparse.OptionParser.__init__(self, *args, **kwargs)
712
713 #override
714 def get_usage(self):
715 normal_usage = optparse.OptionParser.get_usage(self)
716 command_list = self.get_command_list()
717 example = self.get_example()
718 return self.expand_prog_name(normal_usage + example + command_list)
719
720 #override
721 def get_command_list(self):
722 if self.command_list:
723 return '\nCommands:\n %s\n' % '\n '.join(sorted(self.command_list))
724 return ''
725
726 def get_example(self):
727 if self.example:
728 return '\nExample:\n %s\n' % self.example
729 return ''
730
[email protected]b3873892013-07-10 04:57:10731
[email protected]fbe29322013-07-09 09:03:26732def main(argv):
733 option_parser = CommandOptionParser(
734 usage='Usage: %prog <command> [options]',
735 command_list=VALID_COMMANDS.keys())
736
737 if len(argv) < 2 or argv[1] not in VALID_COMMANDS:
[email protected]f8513e52013-08-09 01:08:52738 option_parser.error('Invalid command.')
[email protected]fbe29322013-07-09 09:03:26739 command = argv[1]
740 VALID_COMMANDS[command].add_options_func(option_parser)
741 options, args = option_parser.parse_args(argv)
[email protected]b3873892013-07-10 04:57:10742 return VALID_COMMANDS[command].run_command_func(
[email protected]fbe29322013-07-09 09:03:26743 command, options, args, option_parser)
744
[email protected]fbe29322013-07-09 09:03:26745
746if __name__ == '__main__':
747 sys.exit(main(sys.argv))