OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import glob | 5 import glob |
6 import logging | 6 import logging |
7 import os | 7 import os |
8 import sys | |
9 | 8 |
10 from pylib import android_commands | 9 from pylib import android_commands |
11 from pylib import constants | 10 from pylib import constants |
12 from pylib import perf_tests_helper | 11 from pylib import perf_tests_helper |
13 from pylib.android_commands import errors | 12 from pylib.android_commands import errors |
14 from pylib.base.base_test_runner import BaseTestRunner | 13 from pylib.base import new_base_test_runner as base_test_runner |
15 from pylib.base.test_result import BaseTestResult, TestResults | 14 from pylib.base import test_result |
16 from pylib.utils import run_tests_helper | 15 from pylib.utils import run_tests_helper |
17 | 16 |
18 from test_package_apk import TestPackageApk | 17 import test_package_apk |
19 from test_package_executable import TestPackageExecutable | 18 import test_package_executable |
20 | |
21 | |
22 CURFILE_PATH = os.path.abspath(os.path.dirname(__file__)) | |
23 | 19 |
24 | 20 |
25 def _GetDataFilesForTestSuite(test_suite_basename): | 21 def _GetDataFilesForTestSuite(test_suite_basename): |
26 """Returns a list of data files/dirs needed by the test suite. | 22 """Returns a list of data files/dirs needed by the test suite. |
27 | 23 |
28 Args: | 24 Args: |
29 test_suite_basename: The test suite basename for which to return file paths. | 25 test_suite_basename: The test suite basename for which to return file paths. |
30 | 26 |
31 Returns: | 27 Returns: |
32 A list of test file and directory paths. | 28 A list of test file and directory paths. |
33 """ | 29 """ |
34 # Ideally, we'd just push all test data. However, it has >100MB, and a lot | 30 # Ideally, we'd just push all test data. However, it has >100MB, and a lot |
35 # of the files are not relevant (some are used for browser_tests, others for | 31 # of the files are not relevant (some are used for browser_tests, others for |
36 # features not supported, etc..). | 32 # features not supported, etc..). |
37 if test_suite_basename in ['base_unittests', | 33 if test_suite_basename in ['base_unittests', 'sql_unittests', 'unit_tests']: |
38 'sql_unittests', | |
39 'unit_tests']: | |
40 test_files = [ | 34 test_files = [ |
41 'base/data/file_util_unittest', | 35 'base/data/file_util_unittest', |
42 'base/data/json/bom_feff.json', | 36 'base/data/json/bom_feff.json', |
43 'base/prefs/test/data/pref_service', | 37 'base/prefs/test/data/pref_service', |
44 'chrome/test/data/download-test1.lib', | 38 'chrome/test/data/download-test1.lib', |
45 'chrome/test/data/extensions/bad_magic.crx', | 39 'chrome/test/data/extensions/bad_magic.crx', |
46 'chrome/test/data/extensions/good.crx', | 40 'chrome/test/data/extensions/good.crx', |
47 'chrome/test/data/extensions/icon1.png', | 41 'chrome/test/data/extensions/icon1.png', |
48 'chrome/test/data/extensions/icon2.png', | 42 'chrome/test/data/extensions/icon2.png', |
49 'chrome/test/data/extensions/icon3.png', | 43 'chrome/test/data/extensions/icon3.png', |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 return [ | 117 return [ |
124 'media/test/data', | 118 'media/test/data', |
125 ] | 119 ] |
126 elif test_suite_basename == 'cc_perftests': | 120 elif test_suite_basename == 'cc_perftests': |
127 return [ | 121 return [ |
128 'cc/test/data', | 122 'cc/test/data', |
129 ] | 123 ] |
130 return [] | 124 return [] |
131 | 125 |
132 | 126 |
133 class TestRunner(BaseTestRunner): | 127 def _TestSuiteRequiresMockTestServer(test_suite_basename): |
| 128 """Returns True if the test suite requires mock test server.""" |
| 129 tests_require_net_test_server = ['unit_tests', 'net_unittests', |
| 130 'content_unittests'] |
| 131 return (test_suite_basename in |
| 132 tests_require_net_test_server) |
| 133 |
| 134 |
| 135 class TestRunner(base_test_runner.BaseTestRunner): |
134 """Single test suite attached to a single device. | 136 """Single test suite attached to a single device. |
135 | 137 |
136 Args: | 138 Args: |
137 device: Device to run the tests. | 139 device: Device to run the tests. |
138 test_suite: A specific test suite to run, empty to run all. | 140 test_suite: A specific test suite to run, empty to run all. |
139 gtest_filter: A gtest_filter flag. | |
140 test_arguments: Additional arguments to pass to the test binary. | 141 test_arguments: Additional arguments to pass to the test binary. |
141 timeout: Timeout for each test. | 142 timeout: Timeout for each test. |
142 cleanup_test_files: Whether or not to cleanup test files on device. | 143 cleanup_test_files: Whether or not to cleanup test files on device. |
143 tool: Name of the Valgrind tool. | 144 tool_name: Name of the Valgrind tool. |
144 shard_index: index number of the shard on which the test suite will run. | |
145 build_type: 'Release' or 'Debug'. | 145 build_type: 'Release' or 'Debug'. |
146 in_webkit_checkout: Whether the suite is being run from a WebKit checkout. | 146 in_webkit_checkout: Whether the suite is being run from a WebKit checkout. |
147 """ | 147 """ |
148 | 148 |
149 def __init__(self, device, test_suite, gtest_filter, test_arguments, timeout, | 149 def __init__(self, device, test_suite, test_arguments, timeout, |
150 cleanup_test_files, tool_name, shard_index, build_type, | 150 cleanup_test_files, tool_name, build_type, |
151 in_webkit_checkout): | 151 in_webkit_checkout): |
152 BaseTestRunner.__init__(self, device, tool_name, shard_index, build_type) | 152 super(TestRunner, self).__init__(device, tool_name, build_type) |
153 self._running_on_emulator = self.device.startswith('emulator') | 153 self._running_on_emulator = self.device.startswith('emulator') |
154 self._gtest_filter = gtest_filter | |
155 self._test_arguments = test_arguments | 154 self._test_arguments = test_arguments |
156 self.test_results = TestResults() | |
157 self.in_webkit_checkout = in_webkit_checkout | 155 self.in_webkit_checkout = in_webkit_checkout |
| 156 self._cleanup_test_files = cleanup_test_files |
158 | 157 |
159 logging.warning('Test suite: ' + test_suite) | 158 logging.warning('Test suite: ' + test_suite) |
160 if os.path.splitext(test_suite)[1] == '.apk': | 159 if os.path.splitext(test_suite)[1] == '.apk': |
161 self.test_package = TestPackageApk( | 160 self.test_package = test_package_apk.TestPackageApk( |
162 self.adb, | 161 self.adb, |
163 device, | 162 device, |
164 test_suite, | 163 test_suite, |
165 timeout, | 164 timeout, |
166 cleanup_test_files, | 165 self._cleanup_test_files, |
167 self.tool) | 166 self.tool) |
168 else: | 167 else: |
169 # Put a copy into the android out/target directory, to allow stack trace | 168 # Put a copy into the android out/target directory, to allow stack trace |
170 # generation. | 169 # generation. |
171 symbols_dir = os.path.join(constants.CHROME_DIR, 'out', build_type, | 170 symbols_dir = os.path.join(constants.CHROME_DIR, 'out', build_type, |
172 'lib.target') | 171 'lib.target') |
173 self.test_package = TestPackageExecutable( | 172 self.test_package = test_package_executable.TestPackageExecutable( |
174 self.adb, | 173 self.adb, |
175 device, | 174 device, |
176 test_suite, timeout, | 175 test_suite, |
177 cleanup_test_files, | 176 timeout, |
| 177 self._cleanup_test_files, |
178 self.tool, | 178 self.tool, |
179 symbols_dir) | 179 symbols_dir) |
180 | 180 |
181 def _TestSuiteRequiresMockTestServer(self): | |
182 """Returns True if the test suite requires mock test server.""" | |
183 tests_require_net_test_server = ['unit_tests', 'net_unittests', | |
184 'content_unittests'] | |
185 return (self.test_package.test_suite_basename in | |
186 tests_require_net_test_server) | |
187 | |
188 def GetDisabledTests(self): | |
189 """Returns a list of disabled tests. | |
190 | |
191 Returns: | |
192 A list of disabled tests obtained from 'filter' subdirectory. | |
193 """ | |
194 gtest_filter_base_path = os.path.join( | |
195 CURFILE_PATH, 'filter', self.test_package.test_suite_basename) | |
196 disabled_tests = run_tests_helper.GetExpectations( | |
197 gtest_filter_base_path + '_disabled') | |
198 if self._running_on_emulator: | |
199 # Append emulator's filter file. | |
200 disabled_tests.extend(run_tests_helper.GetExpectations( | |
201 gtest_filter_base_path + '_emulator_additional_disabled')) | |
202 return disabled_tests | |
203 | |
204 def LaunchHelperToolsForTestSuite(self): | |
205 """Launches helper tools for the test suite. | |
206 | |
207 Sometimes one test may need to run some helper tools first in order to | |
208 successfully complete the test. | |
209 """ | |
210 if self._TestSuiteRequiresMockTestServer(): | |
211 self.LaunchChromeTestServerSpawner() | |
212 | 181 |
213 def StripAndCopyFiles(self): | 182 def StripAndCopyFiles(self): |
214 """Strips and copies the required data files for the test suite.""" | 183 """Strips and copies the required data files for the test suite.""" |
215 self.test_package.StripAndCopyExecutable() | 184 self.test_package.StripAndCopyExecutable() |
216 self.test_package.PushDataAndPakFiles() | 185 self.test_package.PushDataAndPakFiles() |
217 self.tool.CopyFiles() | 186 self.tool.CopyFiles() |
218 test_data = _GetDataFilesForTestSuite(self.test_package.test_suite_basename) | 187 test_data = _GetDataFilesForTestSuite(self.test_package.test_suite_basename) |
219 if test_data: | 188 if test_data: |
220 # Make sure SD card is ready. | 189 # Make sure SD card is ready. |
221 self.adb.WaitForSdCardReady(20) | 190 self.adb.WaitForSdCardReady(20) |
(...skipping 11 matching lines...) Expand all Loading... |
233 webkit_src = os.path.join(constants.CHROME_DIR, 'third_party', 'WebKit') | 202 webkit_src = os.path.join(constants.CHROME_DIR, 'third_party', 'WebKit') |
234 if self.in_webkit_checkout: | 203 if self.in_webkit_checkout: |
235 webkit_src = os.path.join(constants.CHROME_DIR, '..', '..', '..') | 204 webkit_src = os.path.join(constants.CHROME_DIR, '..', '..', '..') |
236 | 205 |
237 self.adb.PushIfNeeded( | 206 self.adb.PushIfNeeded( |
238 os.path.join(webkit_src, 'Source/WebKit/chromium/tests/data'), | 207 os.path.join(webkit_src, 'Source/WebKit/chromium/tests/data'), |
239 os.path.join( | 208 os.path.join( |
240 self.adb.GetExternalStorage(), | 209 self.adb.GetExternalStorage(), |
241 'third_party/WebKit/Source/WebKit/chromium/tests/data')) | 210 'third_party/WebKit/Source/WebKit/chromium/tests/data')) |
242 | 211 |
243 def RunTests(self): | 212 # TODO(craigdh): There is no reason for this to be part of TestRunner. |
244 """Runs tests on a single device. | 213 def GetDisabledTests(self): |
| 214 """Returns a list of disabled tests. |
245 | 215 |
246 Returns: | 216 Returns: |
247 A TestResults object. | 217 A list of disabled tests obtained from 'filter' subdirectory. |
248 """ | 218 """ |
249 if self._gtest_filter: | 219 gtest_filter_base_path = os.path.join( |
250 try: | 220 os.path.abspath(os.path.dirname(__file__)), |
251 self.test_package.CreateTestRunnerScript(self._gtest_filter, | 221 'filter', |
252 self._test_arguments) | 222 self.test_package.test_suite_basename) |
253 self.test_results = self.test_package.RunTestsAndListResults() | 223 disabled_tests = run_tests_helper.GetExpectations( |
254 except errors.DeviceUnresponsiveError as e: | 224 gtest_filter_base_path + '_disabled') |
255 # Make sure this device is not attached | 225 if self._running_on_emulator: |
256 logging.warning(e) | 226 # Append emulator's filter file. |
257 if android_commands.IsDeviceAttached(self.device): | 227 disabled_tests.extend(run_tests_helper.GetExpectations( |
258 raise e | 228 gtest_filter_base_path + '_emulator_additional_disabled')) |
259 self.test_results.device_exception = device_exception | 229 return disabled_tests |
260 # Calculate unknown test results. | 230 |
261 finally: | 231 def RunTest(self, test): |
262 # TODO(frankf): Do not break TestResults encapsulation. | 232 """Runs a test on a single device. |
263 all_tests = set(self._gtest_filter.split(':')) | 233 |
264 all_tests_ran = set([t.name for t in self.test_results.GetAll()]) | 234 Args: |
265 unknown_tests = all_tests - all_tests_ran | 235 test: a gtest filter string to run. |
266 self.test_results.unknown = [BaseTestResult(t, '') for t in | 236 |
267 unknown_tests] | 237 Returns: |
268 return self.test_results | 238 Tuple: (TestResults, test to retry or None) |
| 239 """ |
| 240 test_results = test_result.TestResults() |
| 241 if not test: |
| 242 return test_results, None |
| 243 |
| 244 try: |
| 245 self.test_package.CreateTestRunnerScript(test, self._test_arguments) |
| 246 test_results = self.test_package.RunTestsAndListResults() |
| 247 except errors.DeviceUnresponsiveError as e: |
| 248 # Make sure this device is not attached |
| 249 logging.warning(e) |
| 250 if android_commands.IsDeviceAttached(self.device): |
| 251 raise |
| 252 test_results.device_exception = device_exception |
| 253 # Calculate unknown test results. |
| 254 # TODO(frankf): Do not break TestResults encapsulation. |
| 255 all_tests = set(test.split(':')) |
| 256 all_tests_ran = set([t.name for t in test_results.GetAll()]) |
| 257 unknown_tests = all_tests - all_tests_ran |
| 258 test_results.unknown = [test_result.BaseTestResult(t, '') for t in |
| 259 unknown_tests] |
| 260 retry = ':'.join([t.name for t in test_results.GetAllBroken()]) |
| 261 return test_results, retry |
269 | 262 |
270 def SetUp(self): | 263 def SetUp(self): |
271 """Sets up necessary test enviroment for the test suite.""" | 264 """Sets up necessary test enviroment for the test suite.""" |
272 super(TestRunner, self).SetUp() | 265 super(TestRunner, self).SetUp() |
273 self.adb.ClearApplicationState(constants.CHROME_PACKAGE) | 266 self.adb.ClearApplicationState(constants.CHROME_PACKAGE) |
274 self.StripAndCopyFiles() | 267 self.StripAndCopyFiles() |
275 self.LaunchHelperToolsForTestSuite() | 268 if _TestSuiteRequiresMockTestServer(self.test_package.test_suite_basename): |
| 269 self.LaunchChromeTestServerSpawner() |
276 self.tool.SetupEnvironment() | 270 self.tool.SetupEnvironment() |
277 | 271 |
278 def TearDown(self): | 272 def TearDown(self): |
279 """Cleans up the test enviroment for the test suite.""" | 273 """Cleans up the test enviroment for the test suite.""" |
280 self.tool.CleanUpEnvironment() | 274 self.tool.CleanUpEnvironment() |
281 if self.test_package.cleanup_test_files: | 275 if self._cleanup_test_files: |
282 self.adb.RemovePushedFiles() | 276 self.adb.RemovePushedFiles() |
283 super(TestRunner, self).TearDown() | 277 super(TestRunner, self).TearDown() |
OLD | NEW |