Converts monkey test to its own test type

NOTRY=True
BUG=223650, 263479

Review URL: https://chromiumcodereview.appspot.com/22617003

git-svn-id: http://src.chromium.org/svn/trunk/src/build@216343 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
gkanwar@chromium.org 2013-08-08 01:08:14 +00:00
Родитель 967be3def9
Коммит 40a653819f
6 изменённых файлов: 205 добавлений и 174 удалений

Просмотреть файл

Просмотреть файл

@ -0,0 +1,27 @@
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates test runner factory and tests for monkey tests."""
import test_runner
def Setup(test_options):
"""Create and return the test runner factory and tests.
Args:
test_options: A MonkeyOptions object.
Returns:
A tuple of (TestRunnerFactory, tests).
"""
# Token to replicate across devices as the "test". The TestRunner does all of
# the work to run the test.
tests = ['MonkeyTest']
def TestRunnerFactory(device, shard_index):
return test_runner.TestRunner(
test_options, device, shard_index)
return (TestRunnerFactory, tests)

Просмотреть файл

@ -0,0 +1,18 @@
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Defines the MonkeyOptions named tuple."""
import collections
MonkeyOptions = collections.namedtuple('MonkeyOptions', [
'build_type',
'verbose_count',
'package_name',
'activity_name',
'event_count',
'category',
'throttle',
'seed',
'extra_args'])

Просмотреть файл

@ -0,0 +1,77 @@
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Runs a monkey test on a single device."""
import random
from pylib.base import base_test_result
from pylib.base import base_test_runner
class TestRunner(base_test_runner.BaseTestRunner):
"""A TestRunner instance runs a monkey test on a single device."""
def __init__(self, test_options, device, shard_index):
super(TestRunner, self).__init__(device, None, test_options.build_type)
self.options = test_options
def _LaunchMonkeyTest(self):
"""Runs monkey test for a given package.
Returns:
Output from the monkey command on the device.
"""
timeout_ms = self.options.event_count * self.options.throttle * 1.5
cmd = ['monkey',
'-p %s' % self.options.package_name,
' '.join(['-c %s' % c for c in self.options.category]),
'--throttle %d' % self.options.throttle,
'-s %d' % (self.options.seed or random.randint(1, 100)),
'-v ' * self.options.verbose_count,
'--monitor-native-crashes',
'--kill-process-after-error',
self.options.extra_args,
'%d' % self.options.event_count]
return self.adb.RunShellCommand(' '.join(cmd), timeout_time=timeout_ms)
def RunTest(self, test_name):
"""Run a Monkey test on the device.
Args:
test_name: String to use for logging the test result.
Returns:
A tuple of (TestRunResults, retry).
"""
self.adb.StartActivity(self.options.package_name,
self.options.activity_name,
wait_for_completion=True,
action='android.intent.action.MAIN',
force_stop=True)
# Chrome crashes are not always caught by Monkey test runner.
# Verify Chrome has the same PID before and after the test.
before_pids = self.adb.ExtractPid(self.options.package_name)
# Run the test.
output = ''
if before_pids:
output = '\n'.join(self._LaunchMonkeyTest())
after_pids = self.adb.ExtractPid(self.options.package_name)
crashed = (not before_pids or not after_pids
or after_pids[0] != before_pids[0])
results = base_test_result.TestRunResults()
if 'Monkey finished' in output and not crashed:
result = base_test_result.BaseTestResult(
test_name, base_test_result.ResultType.PASS, log=output)
else:
result = base_test_result.BaseTestResult(
test_name, base_test_result.ResultType.FAIL, log=output)
results.AddResult(result)
return results, False

Просмотреть файл

@ -1,170 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Runs the Monkey tests on one or more devices."""
import logging
import optparse
import random
import sys
from pylib.base import base_test_result
from pylib.base import test_dispatcher
from pylib.host_driven import test_case
from pylib.host_driven import test_runner
from pylib.utils import report_results
from pylib.utils import test_options_parser
class MonkeyTest(test_case.HostDrivenTestCase):
def __init__(self, test_name, package_name, activity_name, category, seed,
throttle, event_count, verbosity, extra_args):
"""Create a MonkeyTest object.
Args:
test_name: Name of the method to run for this test object.
package_name: Allowed package.
activity_name: Name of the activity to start.
category: A list of allowed categories.
seed: Seed value for pseduo-random generator. Same seed value
generates the same sequence of events. Seed is randomized by default.
throttle: Delay between events (ms).
event_count: Number of events to generate.
verbosity: Verbosity level [0-3].
extra_args: A string of other args to pass to the command verbatim.
"""
super(MonkeyTest, self).__init__(test_name)
self.package_name = package_name
self.activity_name = activity_name
self.category = category
self.seed = seed or random.randint(1, 100)
self.throttle = throttle
self.event_count = event_count
self.verbosity = verbosity
self.extra_args = extra_args
def testMonkey(self):
# Launch and wait for Chrome to launch.
self.adb.StartActivity(self.package_name,
self.activity_name,
wait_for_completion=True,
action='android.intent.action.MAIN',
force_stop=True)
# Chrome crashes are not always caught by Monkey test runner.
# Verify Chrome has the same PID before and after the test.
before_pids = self.adb.ExtractPid(self.package_name)
# Run the test.
output = ''
if before_pids:
output = '\n'.join(self._LaunchMonkeyTest())
after_pids = self.adb.ExtractPid(self.package_name)
crashed = (not before_pids or not after_pids
or after_pids[0] != before_pids[0])
results = base_test_result.TestRunResults()
if 'Monkey finished' in output and not crashed:
result = base_test_result.BaseTestResult(
self.tagged_name, base_test_result.ResultType.PASS, log=output)
else:
result = base_test_result.BaseTestResult(
self.tagged_name, base_test_result.ResultType.FAIL, log=output)
results.AddResult(result)
return results
def _LaunchMonkeyTest(self):
"""Runs monkey test for a given package.
Returns:
Output from the monkey command on the device.
"""
timeout_ms = self.event_count * self.throttle * 1.5
cmd = ['monkey',
'-p %s' % self.package_name,
' '.join(['-c %s' % c for c in self.category]),
'--throttle %d' % self.throttle,
'-s %d' % self.seed,
'-v ' * self.verbosity,
'--monitor-native-crashes',
'--kill-process-after-error',
self.extra_args,
'%d' % self.event_count]
return self.adb.RunShellCommand(' '.join(cmd), timeout_time=timeout_ms)
def RunMonkeyTests(options):
"""Runs the Monkey tests, replicating it if there multiple devices."""
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# Actually run the tests.
logging.debug('Running monkey tests.')
available_tests = [
MonkeyTest('testMonkey', options.package_name, options.activity_name,
category=options.category, seed=options.seed,
throttle=options.throttle, event_count=options.event_count,
verbosity=options.verbosity, extra_args=options.extra_args)]
def TestRunnerFactory(device, shard_index):
return test_runner.HostDrivenTestRunner(
device, shard_index, '', options.build_type, False, False)
results, exit_code = test_dispatcher.RunTests(
available_tests, TestRunnerFactory, False, None, shard=False,
build_type=options.build_type, num_retries=0)
report_results.LogFull(
results=results,
test_type='Monkey',
test_package='Monkey',
build_type=options.build_type)
return exit_code
def main():
desc = 'Run the Monkey tests on 1 or more devices.'
parser = optparse.OptionParser(description=desc)
test_options_parser.AddBuildTypeOption(parser)
parser.add_option('--package-name', help='Allowed package.')
parser.add_option('--activity-name',
default='com.google.android.apps.chrome.Main',
help='Name of the activity to start [default: %default].')
parser.add_option('--category', default='',
help='A list of allowed categories [default: %default].')
parser.add_option('--throttle', default=100, type='int',
help='Delay between events (ms) [default: %default]. ')
parser.add_option('--seed', type='int',
help=('Seed value for pseudo-random generator. Same seed '
'value generates the same sequence of events. Seed '
'is randomized by default.'))
parser.add_option('--event-count', default=10000, type='int',
help='Number of events to generate [default: %default].')
parser.add_option('--verbosity', default=1, type='int',
help='Verbosity level [0-3] [default: %default].')
parser.add_option('--extra-args', default='',
help=('String of other args to pass to the command verbatim'
' [default: "%default"].'))
(options, args) = parser.parse_args()
if args:
parser.print_help(sys.stderr)
parser.error('Unknown arguments: %s' % args)
if not options.package_name:
parser.print_help(sys.stderr)
parser.error('Missing package name')
if options.category:
options.category = options.category.split(',')
RunMonkeyTests(options)
if __name__ == '__main__':
main()

Просмотреть файл

@ -26,6 +26,8 @@ from pylib.gtest import test_options as gtest_test_options
from pylib.host_driven import setup as host_driven_setup
from pylib.instrumentation import setup as instrumentation_setup
from pylib.instrumentation import test_options as instrumentation_test_options
from pylib.monkey import setup as monkey_setup
from pylib.monkey import test_options as monkey_test_options
from pylib.uiautomator import setup as uiautomator_setup
from pylib.uiautomator import test_options as uiautomator_test_options
from pylib.utils import report_results
@ -315,7 +317,7 @@ def ProcessUIAutomatorOptions(options, error_func):
Returns:
A UIAutomatorOptions named tuple which contains all options relevant to
instrumentation tests.
uiautomator tests.
"""
ProcessJavaTestOptions(options, error_func)
@ -353,6 +355,63 @@ def ProcessUIAutomatorOptions(options, error_func):
options.package_name)
def AddMonkeyTestOptions(option_parser):
"""Adds monkey test options to |option_parser|."""
option_parser.add_option('--package-name', help='Allowed package.')
option_parser.add_option(
'--activity-name', default='com.google.android.apps.chrome.Main',
help='Name of the activity to start [default: %default].')
option_parser.add_option(
'--event-count', default=10000, type='int',
help='Number of events to generate [default: %default].')
option_parser.add_option(
'--category', default='',
help='A list of allowed categories [default: %default].')
option_parser.add_option(
'--throttle', default=100, type='int',
help='Delay between events (ms) [default: %default]. ')
option_parser.add_option(
'--seed', type='int',
help=('Seed value for pseudo-random generator. Same seed value generates '
'the same sequence of events. Seed is randomized by default.'))
option_parser.add_option(
'--extra-args', default='',
help=('String of other args to pass to the command verbatim '
'[default: "%default"].'))
AddCommonOptions(option_parser)
def ProcessMonkeyTestOptions(options, error_func):
"""Processes all monkey test options.
Args:
options: optparse.Options object.
error_func: Function to call with the error message in case of an error.
Returns:
A MonkeyOptions named tuple which contains all options relevant to
monkey tests.
"""
if not options.package_name:
error_func('Package name is required.')
category = options.category
if category:
category = options.category.split(',')
return monkey_test_options.MonkeyOptions(
options.build_type,
options.verbose_count,
options.package_name,
options.activity_name,
options.event_count,
category,
options.throttle,
options.seed,
options.extra_args)
def _RunGTests(options, error_func):
"""Subcommand of RunTestsCommands which runs gtests."""
ProcessGTestOptions(options)
@ -450,9 +509,6 @@ def _RunUIAutomatorTests(options, error_func):
"""Subcommand of RunTestsCommands which runs uiautomator tests."""
uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
results = base_test_result.TestRunResults()
exit_code = 0
runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
results, exit_code = test_dispatcher.RunTests(
@ -473,6 +529,25 @@ def _RunUIAutomatorTests(options, error_func):
return exit_code
def _RunMonkeyTests(options, error_func):
"""Subcommand of RunTestsCommands which runs monkey tests."""
monkey_options = ProcessMonkeyTestOptions(options, error_func)
runner_factory, tests = monkey_setup.Setup(monkey_options)
results, exit_code = test_dispatcher.RunTests(
tests, runner_factory, False, None, shard=False)
report_results.LogFull(
results=results,
test_type='Monkey',
test_package='Monkey',
build_type=options.build_type)
return exit_code
def RunTestsCommand(command, options, args, option_parser):
"""Checks test type and dispatches to the appropriate function.
@ -504,6 +579,8 @@ def RunTestsCommand(command, options, args, option_parser):
return _RunInstrumentationTests(options, option_parser.error)
elif command == 'uiautomator':
return _RunUIAutomatorTests(options, option_parser.error)
elif command == 'monkey':
return _RunMonkeyTests(options, option_parser.error)
else:
raise Exception('Unknown test type.')
@ -560,6 +637,8 @@ VALID_COMMANDS = {
AddInstrumentationTestOptions, RunTestsCommand),
'uiautomator': CommandFunctionTuple(
AddUIAutomatorTestOptions, RunTestsCommand),
'monkey': CommandFunctionTuple(
AddMonkeyTestOptions, RunTestsCommand),
'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand)
}