Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
michael@0 | 1 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
michael@0 | 2 | # Use of this source code is governed by a BSD-style license that can be |
michael@0 | 3 | # found in the LICENSE file. |
michael@0 | 4 | |
michael@0 | 5 | |
michael@0 | 6 | import logging |
michael@0 | 7 | import os |
michael@0 | 8 | import shutil |
michael@0 | 9 | import sys |
michael@0 | 10 | import tempfile |
michael@0 | 11 | |
michael@0 | 12 | import cmd_helper |
michael@0 | 13 | import constants |
michael@0 | 14 | from test_package import TestPackage |
michael@0 | 15 | from pylib import pexpect |
michael@0 | 16 | |
michael@0 | 17 | |
michael@0 | 18 | class TestPackageExecutable(TestPackage): |
michael@0 | 19 | """A helper class for running stand-alone executables.""" |
michael@0 | 20 | |
michael@0 | 21 | _TEST_RUNNER_RET_VAL_FILE = 'gtest_retval' |
michael@0 | 22 | |
michael@0 | 23 | def __init__(self, adb, device, test_suite, timeout, rebaseline, |
michael@0 | 24 | performance_test, cleanup_test_files, tool, dump_debug_info, |
michael@0 | 25 | symbols_dir=None): |
michael@0 | 26 | """ |
michael@0 | 27 | Args: |
michael@0 | 28 | adb: ADB interface the tests are using. |
michael@0 | 29 | device: Device to run the tests. |
michael@0 | 30 | test_suite: A specific test suite to run, empty to run all. |
michael@0 | 31 | timeout: Timeout for each test. |
michael@0 | 32 | rebaseline: Whether or not to run tests in isolation and update the |
michael@0 | 33 | filter. |
michael@0 | 34 | performance_test: Whether or not performance test(s). |
michael@0 | 35 | cleanup_test_files: Whether or not to cleanup test files on device. |
michael@0 | 36 | tool: Name of the Valgrind tool. |
michael@0 | 37 | dump_debug_info: A debug_info object. |
michael@0 | 38 | symbols_dir: Directory to put the stripped binaries. |
michael@0 | 39 | """ |
michael@0 | 40 | TestPackage.__init__(self, adb, device, test_suite, timeout, |
michael@0 | 41 | rebaseline, performance_test, cleanup_test_files, |
michael@0 | 42 | tool, dump_debug_info) |
michael@0 | 43 | self.symbols_dir = symbols_dir |
michael@0 | 44 | |
michael@0 | 45 | def _GetGTestReturnCode(self): |
michael@0 | 46 | ret = None |
michael@0 | 47 | ret_code = 1 # Assume failure if we can't find it |
michael@0 | 48 | ret_code_file = tempfile.NamedTemporaryFile() |
michael@0 | 49 | try: |
michael@0 | 50 | if not self.adb.Adb().Pull( |
michael@0 | 51 | self.adb.GetExternalStorage() + '/' + |
michael@0 | 52 | TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE, |
michael@0 | 53 | ret_code_file.name): |
michael@0 | 54 | logging.critical('Unable to pull gtest ret val file %s', |
michael@0 | 55 | ret_code_file.name) |
michael@0 | 56 | raise ValueError |
michael@0 | 57 | ret_code = file(ret_code_file.name).read() |
michael@0 | 58 | ret = int(ret_code) |
michael@0 | 59 | except ValueError: |
michael@0 | 60 | logging.critical('Error reading gtest ret val file %s [%s]', |
michael@0 | 61 | ret_code_file.name, ret_code) |
michael@0 | 62 | ret = 1 |
michael@0 | 63 | return ret |
michael@0 | 64 | |
michael@0 | 65 | def _AddNativeCoverageExports(self): |
michael@0 | 66 | # export GCOV_PREFIX set the path for native coverage results |
michael@0 | 67 | # export GCOV_PREFIX_STRIP indicates how many initial directory |
michael@0 | 68 | # names to strip off the hardwired absolute paths. |
michael@0 | 69 | # This value is calculated in buildbot.sh and |
michael@0 | 70 | # depends on where the tree is built. |
michael@0 | 71 | # Ex: /usr/local/google/code/chrome will become |
michael@0 | 72 | # /code/chrome if GCOV_PREFIX_STRIP=3 |
michael@0 | 73 | try: |
michael@0 | 74 | depth = os.environ['NATIVE_COVERAGE_DEPTH_STRIP'] |
michael@0 | 75 | except KeyError: |
michael@0 | 76 | logging.info('NATIVE_COVERAGE_DEPTH_STRIP is not defined: ' |
michael@0 | 77 | 'No native coverage.') |
michael@0 | 78 | return '' |
michael@0 | 79 | export_string = ('export GCOV_PREFIX="%s/gcov"\n' % |
michael@0 | 80 | self.adb.GetExternalStorage()) |
michael@0 | 81 | export_string += 'export GCOV_PREFIX_STRIP=%s\n' % depth |
michael@0 | 82 | return export_string |
michael@0 | 83 | |
michael@0 | 84 | def GetAllTests(self): |
michael@0 | 85 | """Returns a list of all tests available in the test suite.""" |
michael@0 | 86 | all_tests = self.adb.RunShellCommand( |
michael@0 | 87 | '%s %s/%s --gtest_list_tests' % |
michael@0 | 88 | (self.tool.GetTestWrapper(), |
michael@0 | 89 | constants.TEST_EXECUTABLE_DIR, |
michael@0 | 90 | self.test_suite_basename)) |
michael@0 | 91 | return self._ParseGTestListTests(all_tests) |
michael@0 | 92 | |
michael@0 | 93 | def CreateTestRunnerScript(self, gtest_filter, test_arguments): |
michael@0 | 94 | """Creates a test runner script and pushes to the device. |
michael@0 | 95 | |
michael@0 | 96 | Args: |
michael@0 | 97 | gtest_filter: A gtest_filter flag. |
michael@0 | 98 | test_arguments: Additional arguments to pass to the test binary. |
michael@0 | 99 | """ |
michael@0 | 100 | tool_wrapper = self.tool.GetTestWrapper() |
michael@0 | 101 | sh_script_file = tempfile.NamedTemporaryFile() |
michael@0 | 102 | # We need to capture the exit status from the script since adb shell won't |
michael@0 | 103 | # propagate to us. |
michael@0 | 104 | sh_script_file.write('cd %s\n' |
michael@0 | 105 | '%s' |
michael@0 | 106 | '%s %s/%s --gtest_filter=%s %s\n' |
michael@0 | 107 | 'echo $? > %s' % |
michael@0 | 108 | (constants.TEST_EXECUTABLE_DIR, |
michael@0 | 109 | self._AddNativeCoverageExports(), |
michael@0 | 110 | tool_wrapper, constants.TEST_EXECUTABLE_DIR, |
michael@0 | 111 | self.test_suite_basename, |
michael@0 | 112 | gtest_filter, test_arguments, |
michael@0 | 113 | TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE)) |
michael@0 | 114 | sh_script_file.flush() |
michael@0 | 115 | cmd_helper.RunCmd(['chmod', '+x', sh_script_file.name]) |
michael@0 | 116 | self.adb.PushIfNeeded( |
michael@0 | 117 | sh_script_file.name, |
michael@0 | 118 | constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh') |
michael@0 | 119 | logging.info('Conents of the test runner script: ') |
michael@0 | 120 | for line in open(sh_script_file.name).readlines(): |
michael@0 | 121 | logging.info(' ' + line.rstrip()) |
michael@0 | 122 | |
michael@0 | 123 | def RunTestsAndListResults(self): |
michael@0 | 124 | """Runs all the tests and checks for failures. |
michael@0 | 125 | |
michael@0 | 126 | Returns: |
michael@0 | 127 | A TestResults object. |
michael@0 | 128 | """ |
michael@0 | 129 | args = ['adb', '-s', self.device, 'shell', 'sh', |
michael@0 | 130 | constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh'] |
michael@0 | 131 | logging.info(args) |
michael@0 | 132 | p = pexpect.spawn(args[0], args[1:], logfile=sys.stdout) |
michael@0 | 133 | return self._WatchTestOutput(p) |
michael@0 | 134 | |
michael@0 | 135 | def StripAndCopyExecutable(self): |
michael@0 | 136 | """Strips and copies the executable to the device.""" |
michael@0 | 137 | if self.tool.NeedsDebugInfo(): |
michael@0 | 138 | target_name = self.test_suite |
michael@0 | 139 | else: |
michael@0 | 140 | target_name = self.test_suite + '_' + self.device + '_stripped' |
michael@0 | 141 | should_strip = True |
michael@0 | 142 | if os.path.isfile(target_name): |
michael@0 | 143 | logging.info('Found target file %s' % target_name) |
michael@0 | 144 | target_mtime = os.stat(target_name).st_mtime |
michael@0 | 145 | source_mtime = os.stat(self.test_suite).st_mtime |
michael@0 | 146 | if target_mtime > source_mtime: |
michael@0 | 147 | logging.info('Target mtime (%d) is newer than source (%d), assuming ' |
michael@0 | 148 | 'no change.' % (target_mtime, source_mtime)) |
michael@0 | 149 | should_strip = False |
michael@0 | 150 | |
michael@0 | 151 | if should_strip: |
michael@0 | 152 | logging.info('Did not find up-to-date stripped binary. Generating a ' |
michael@0 | 153 | 'new one (%s).' % target_name) |
michael@0 | 154 | # Whenever we generate a stripped binary, copy to the symbols dir. If we |
michael@0 | 155 | # aren't stripping a new binary, assume it's there. |
michael@0 | 156 | if self.symbols_dir: |
michael@0 | 157 | if not os.path.exists(self.symbols_dir): |
michael@0 | 158 | os.makedirs(self.symbols_dir) |
michael@0 | 159 | shutil.copy(self.test_suite, self.symbols_dir) |
michael@0 | 160 | strip = os.environ['STRIP'] |
michael@0 | 161 | cmd_helper.RunCmd([strip, self.test_suite, '-o', target_name]) |
michael@0 | 162 | test_binary = constants.TEST_EXECUTABLE_DIR + '/' + self.test_suite_basename |
michael@0 | 163 | self.adb.PushIfNeeded(target_name, test_binary) |
michael@0 | 164 | |
michael@0 | 165 | def _GetTestSuiteBaseName(self): |
michael@0 | 166 | """Returns the base name of the test suite.""" |
michael@0 | 167 | return os.path.basename(self.test_suite) |