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