1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Runs a monkey test on a single device."""
6
7import logging
8import random
9
10from pylib import constants
11from pylib.base import base_test_result
12from pylib.base import base_test_runner
13from pylib.device import intent
14
15class TestRunner(base_test_runner.BaseTestRunner):
16  """A TestRunner instance runs a monkey test on a single device."""
17
18  def __init__(self, test_options, device, _):
19    super(TestRunner, self).__init__(device, None)
20    self._options = test_options
21    self._package = constants.PACKAGE_INFO[self._options.package].package
22    self._activity = constants.PACKAGE_INFO[self._options.package].activity
23
24  def _LaunchMonkeyTest(self):
25    """Runs monkey test for a given package.
26
27    Returns:
28      Output from the monkey command on the device.
29    """
30
31    timeout_ms = self._options.event_count * self._options.throttle * 1.5
32
33    cmd = ['monkey',
34           '-p %s' % self._package,
35           ' '.join(['-c %s' % c for c in self._options.category]),
36           '--throttle %d' % self._options.throttle,
37           '-s %d' % (self._options.seed or random.randint(1, 100)),
38           '-v ' * self._options.verbose_count,
39           '--monitor-native-crashes',
40           '--kill-process-after-error',
41           self._options.extra_args,
42           '%d' % self._options.event_count]
43    return self.device.RunShellCommand(' '.join(cmd), timeout=timeout_ms)
44
45  def RunTest(self, test_name):
46    """Run a Monkey test on the device.
47
48    Args:
49      test_name: String to use for logging the test result.
50
51    Returns:
52      A tuple of (TestRunResults, retry).
53    """
54    self.device.StartActivity(
55        intent.Intent(package=self._package, activity=self._activity,
56                      action='android.intent.action.MAIN'),
57        blocking=True, force_stop=True)
58
59    # Chrome crashes are not always caught by Monkey test runner.
60    # Verify Chrome has the same PID before and after the test.
61    before_pids = self.device.GetPids(self._package)
62
63    # Run the test.
64    output = ''
65    if before_pids:
66      output = '\n'.join(self._LaunchMonkeyTest())
67      after_pids = self.device.GetPids(self._package)
68
69    crashed = True
70    if not self._package in before_pids:
71      logging.error('Failed to start the process.')
72    elif not self._package in after_pids:
73      logging.error('Process %s has died.', before_pids[self._package])
74    elif before_pids[self._package] != after_pids[self._package]:
75      logging.error('Detected process restart %s -> %s',
76                    before_pids[self._package], after_pids[self._package])
77    else:
78      crashed = False
79
80    results = base_test_result.TestRunResults()
81    success_pattern = 'Events injected: %d' % self._options.event_count
82    if success_pattern in output and not crashed:
83      result = base_test_result.BaseTestResult(
84          test_name, base_test_result.ResultType.PASS, log=output)
85    else:
86      result = base_test_result.BaseTestResult(
87          test_name, base_test_result.ResultType.FAIL, log=output)
88      if 'chrome' in self._options.package:
89        logging.warning('Starting MinidumpUploadService...')
90        try:
91          self.device.old_interface.StartCrashUploadService(self._package)
92        except AssertionError as e:
93          logging.error('Failed to start MinidumpUploadService: %s', e)
94    results.AddResult(result)
95    return results, False
96