| 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 |