test_package_apk.py revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1# Copyright (c) 2012 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"""Defines TestPackageApk to help run APK-based native tests."""
6# pylint: disable=W0212
7
8import logging
9import os
10import shlex
11import sys
12import tempfile
13import time
14
15from pylib import android_commands
16from pylib import constants
17from pylib import pexpect
18from pylib.device import device_errors
19from pylib.gtest.test_package import TestPackage
20
21
22class TestPackageApk(TestPackage):
23  """A helper class for running APK-based native tests."""
24
25  def __init__(self, suite_name):
26    """
27    Args:
28      suite_name: Name of the test suite (e.g. base_unittests).
29    """
30    TestPackage.__init__(self, suite_name)
31    if suite_name == 'content_browsertests':
32      self.suite_path = os.path.join(
33          constants.GetOutDirectory(), 'apks', '%s.apk' % suite_name)
34      self._package_info = constants.PACKAGE_INFO['content_browsertests']
35    else:
36      self.suite_path = os.path.join(
37          constants.GetOutDirectory(), '%s_apk' % suite_name,
38          '%s-debug.apk' % suite_name)
39      self._package_info = constants.PACKAGE_INFO['gtest']
40
41  def _CreateCommandLineFileOnDevice(self, device, options):
42    command_line_file = tempfile.NamedTemporaryFile()
43    # GTest expects argv[0] to be the executable path.
44    command_line_file.write(self.suite_name + ' ' + options)
45    command_line_file.flush()
46    device.old_interface.PushIfNeeded(
47        command_line_file.name,
48        self._package_info.cmdline_file)
49
50  def _GetFifo(self):
51    # The test.fifo path is determined by:
52    # testing/android/java/src/org/chromium/native_test/
53    #     ChromeNativeTestActivity.java and
54    # testing/android/native_test_launcher.cc
55    return '/data/data/' + self._package_info.package + '/files/test.fifo'
56
57  def _ClearFifo(self, device):
58    device.RunShellCommand('rm -f ' + self._GetFifo())
59
60  def _WatchFifo(self, device, timeout, logfile=None):
61    for i in range(10):
62      if device.old_interface.FileExistsOnDevice(self._GetFifo()):
63        logging.info('Fifo created.')
64        break
65      time.sleep(i)
66    else:
67      raise device_errors.DeviceUnreachableError(
68          'Unable to find fifo on device %s ' % self._GetFifo())
69    args = shlex.split(device.old_interface.Adb()._target_arg)
70    args += ['shell', 'cat', self._GetFifo()]
71    return pexpect.spawn('adb', args, timeout=timeout, logfile=logfile)
72
73  def _StartActivity(self, device):
74    device.old_interface.StartActivity(
75        self._package_info.package,
76        self._package_info.activity,
77        # No wait since the runner waits for FIFO creation anyway.
78        wait_for_completion=False,
79        action='android.intent.action.MAIN',
80        force_stop=True)
81
82  #override
83  def ClearApplicationState(self, device):
84    device.old_interface.ClearApplicationState(self._package_info.package)
85    # Content shell creates a profile on the sdscard which accumulates cache
86    # files over time.
87    if self.suite_name == 'content_browsertests':
88      try:
89        device.RunShellCommand(
90            'rm -r %s/content_shell' % device.GetExternalStoragePath(),
91            timeout=60 * 2)
92      except device_errors.CommandFailedError:
93        # TODO(jbudorick) Handle this exception appropriately once the
94        #                 conversions are done.
95        pass
96
97  #override
98  def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
99    self._CreateCommandLineFileOnDevice(
100        device, '--gtest_filter=%s %s' % (test_filter, test_arguments))
101
102  #override
103  def GetAllTests(self, device):
104    self._CreateCommandLineFileOnDevice(device, '--gtest_list_tests')
105    try:
106      self.tool.SetupEnvironment()
107      # Clear and start monitoring logcat.
108      self._ClearFifo(device)
109      self._StartActivity(device)
110      # Wait for native test to complete.
111      p = self._WatchFifo(device, timeout=30 * self.tool.GetTimeoutScale())
112      p.expect('<<ScopedMainEntryLogger')
113      p.close()
114    finally:
115      self.tool.CleanUpEnvironment()
116    # We need to strip the trailing newline.
117    content = [line.rstrip() for line in p.before.splitlines()]
118    return self._ParseGTestListTests(content)
119
120  #override
121  def SpawnTestProcess(self, device):
122    try:
123      self.tool.SetupEnvironment()
124      self._ClearFifo(device)
125      self._StartActivity(device)
126    finally:
127      self.tool.CleanUpEnvironment()
128    logfile = android_commands.NewLineNormalizer(sys.stdout)
129    return self._WatchFifo(device, timeout=10, logfile=logfile)
130
131  #override
132  def Install(self, device):
133    self.tool.CopyFiles()
134    device.Install(self.suite_path)
135