15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch"""Defines TestPackageExecutable to help run stand-alone executables."""
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from pylib import cmd_helper
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from pylib import constants
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pylib import pexpect
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)from pylib.device import device_errors
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from pylib.gtest.test_package import TestPackage
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestPackageExecutable(TestPackage):
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """A helper class for running stand-alone executables."""
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _TEST_RUNNER_RET_VAL_FILE = 'gtest_retval'
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def __init__(self, suite_name):
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
27fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch      suite_name: Name of the test suite (e.g. base_unittests).
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
29fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    TestPackage.__init__(self, suite_name)
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self.suite_path = os.path.join(constants.GetOutDirectory(), suite_name)
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._symbols_dir = os.path.join(constants.GetOutDirectory(),
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                     'lib.target')
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  #override
35a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def GetGTestReturnCode(self, device):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = None
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret_code = 1  # Assume failure if we can't find it
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret_code_file = tempfile.NamedTemporaryFile()
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if not device.PullFile(
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          constants.TEST_EXECUTABLE_DIR + '/' +
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ret_code_file.name):
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.critical('Unable to pull gtest ret val file %s',
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ret_code_file.name)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise ValueError
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret_code = file(ret_code_file.name).read()
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = int(ret_code)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except ValueError:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.critical('Error reading gtest ret val file %s [%s]',
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       ret_code_file.name, ret_code)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = 1
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  @staticmethod
56a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def _AddNativeCoverageExports(device):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # export GCOV_PREFIX set the path for native coverage results
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # export GCOV_PREFIX_STRIP indicates how many initial directory
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #                          names to strip off the hardwired absolute paths.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #                          This value is calculated in buildbot.sh and
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #                          depends on where the tree is built.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ex: /usr/local/google/code/chrome will become
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     /code/chrome if GCOV_PREFIX_STRIP=3
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      depth = os.environ['NATIVE_COVERAGE_DEPTH_STRIP']
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      export_string = ('export GCOV_PREFIX="%s/gcov"\n' %
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       device.GetExternalStoragePath())
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      export_string += 'export GCOV_PREFIX_STRIP=%s\n' % depth
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return export_string
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except KeyError:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info('NATIVE_COVERAGE_DEPTH_STRIP is not defined: '
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'No native coverage.')
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ''
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    except device_errors.CommandFailedError:
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      logging.info('No external storage found: No native coverage.')
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return ''
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  #override
79a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def ClearApplicationState(self, device):
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    try:
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # We don't expect the executable to be running, so we don't attempt
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # to retry on failure.
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      device.KillAll(self.suite_name, blocking=True, timeout=30, retries=0)
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    except device_errors.CommandFailedError:
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # KillAll raises an exception if it can't find a process with the given
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # name. We only care that there is no process with the given name, so
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # we can safely eat the exception.
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pass
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  #override
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tool_wrapper = self.tool.GetTestWrapper()
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sh_script_file = tempfile.NamedTemporaryFile()
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # We need to capture the exit status from the script since adb shell won't
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # propagate to us.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sh_script_file.write('cd %s\n'
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '%s'
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '%s %s/%s --gtest_filter=%s %s\n'
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         'echo $? > %s' %
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         (constants.TEST_EXECUTABLE_DIR,
101a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                          self._AddNativeCoverageExports(device),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          tool_wrapper, constants.TEST_EXECUTABLE_DIR,
103fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch                          self.suite_name,
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          test_filter, test_arguments,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE))
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sh_script_file.flush()
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_helper.RunCmd(['chmod', '+x', sh_script_file.name])
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    device.PushChangedFiles(
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        sh_script_file.name,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh')
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info('Conents of the test runner script: ')
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for line in open(sh_script_file.name).readlines():
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info('  ' + line.rstrip())
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  #override
116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def GetAllTests(self, device):
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    all_tests = device.RunShellCommand(
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        '%s %s/%s --gtest_list_tests' %
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        (self.tool.GetTestWrapper(),
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch         constants.TEST_EXECUTABLE_DIR,
121fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch         self.suite_name))
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._ParseGTestListTests(all_tests)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  #override
125a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def SpawnTestProcess(self, device):
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    args = ['adb', '-s', str(device), 'shell', 'sh',
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh']
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info(args)
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return pexpect.spawn(args[0], args[1:], logfile=sys.stdout)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  #override
132a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def Install(self, device):
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.tool.NeedsDebugInfo():
134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      target_name = self.suite_path
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      target_name = self.suite_path + '_stripped'
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if not os.path.isfile(target_name):
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        raise Exception('Did not find %s, build target %s' %
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        (target_name, self.suite_name + '_stripped'))
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      target_mtime = os.stat(target_name).st_mtime
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      source_mtime = os.stat(self.suite_path).st_mtime
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if target_mtime < source_mtime:
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        raise Exception(
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'stripped binary (%s, timestamp %d) older than '
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'source binary (%s, timestamp %d), build target %s' %
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            (target_name, target_mtime, self.suite_path, source_mtime,
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             self.suite_name + '_stripped'))
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
150fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    test_binary = constants.TEST_EXECUTABLE_DIR + '/' + self.suite_name
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    device.PushChangedFiles(target_name, test_binary)
152