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:
Родитель
967be3def9
Коммит
40a653819f
|
@ -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.host_driven import setup as host_driven_setup
|
||||||
from pylib.instrumentation import setup as instrumentation_setup
|
from pylib.instrumentation import setup as instrumentation_setup
|
||||||
from pylib.instrumentation import test_options as instrumentation_test_options
|
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 setup as uiautomator_setup
|
||||||
from pylib.uiautomator import test_options as uiautomator_test_options
|
from pylib.uiautomator import test_options as uiautomator_test_options
|
||||||
from pylib.utils import report_results
|
from pylib.utils import report_results
|
||||||
|
@ -315,7 +317,7 @@ def ProcessUIAutomatorOptions(options, error_func):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A UIAutomatorOptions named tuple which contains all options relevant to
|
A UIAutomatorOptions named tuple which contains all options relevant to
|
||||||
instrumentation tests.
|
uiautomator tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ProcessJavaTestOptions(options, error_func)
|
ProcessJavaTestOptions(options, error_func)
|
||||||
|
@ -353,6 +355,63 @@ def ProcessUIAutomatorOptions(options, error_func):
|
||||||
options.package_name)
|
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):
|
def _RunGTests(options, error_func):
|
||||||
"""Subcommand of RunTestsCommands which runs gtests."""
|
"""Subcommand of RunTestsCommands which runs gtests."""
|
||||||
ProcessGTestOptions(options)
|
ProcessGTestOptions(options)
|
||||||
|
@ -450,9 +509,6 @@ def _RunUIAutomatorTests(options, error_func):
|
||||||
"""Subcommand of RunTestsCommands which runs uiautomator tests."""
|
"""Subcommand of RunTestsCommands which runs uiautomator tests."""
|
||||||
uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
|
uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
|
||||||
|
|
||||||
results = base_test_result.TestRunResults()
|
|
||||||
exit_code = 0
|
|
||||||
|
|
||||||
runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
|
runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
|
||||||
|
|
||||||
results, exit_code = test_dispatcher.RunTests(
|
results, exit_code = test_dispatcher.RunTests(
|
||||||
|
@ -473,6 +529,25 @@ def _RunUIAutomatorTests(options, error_func):
|
||||||
return exit_code
|
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):
|
def RunTestsCommand(command, options, args, option_parser):
|
||||||
"""Checks test type and dispatches to the appropriate function.
|
"""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)
|
return _RunInstrumentationTests(options, option_parser.error)
|
||||||
elif command == 'uiautomator':
|
elif command == 'uiautomator':
|
||||||
return _RunUIAutomatorTests(options, option_parser.error)
|
return _RunUIAutomatorTests(options, option_parser.error)
|
||||||
|
elif command == 'monkey':
|
||||||
|
return _RunMonkeyTests(options, option_parser.error)
|
||||||
else:
|
else:
|
||||||
raise Exception('Unknown test type.')
|
raise Exception('Unknown test type.')
|
||||||
|
|
||||||
|
@ -560,6 +637,8 @@ VALID_COMMANDS = {
|
||||||
AddInstrumentationTestOptions, RunTestsCommand),
|
AddInstrumentationTestOptions, RunTestsCommand),
|
||||||
'uiautomator': CommandFunctionTuple(
|
'uiautomator': CommandFunctionTuple(
|
||||||
AddUIAutomatorTestOptions, RunTestsCommand),
|
AddUIAutomatorTestOptions, RunTestsCommand),
|
||||||
|
'monkey': CommandFunctionTuple(
|
||||||
|
AddMonkeyTestOptions, RunTestsCommand),
|
||||||
'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand)
|
'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче