| 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 """Base class representing GTest test packages.""" |
| 5 | 6 |
| 6 import logging | |
| 7 import os | 7 import os |
| 8 import re | |
| 9 | 8 |
| 10 from pylib import constants | 9 from pylib import constants |
| 11 from pylib import pexpect | |
| 12 from pylib.android_commands import errors | |
| 13 from pylib.base import base_test_result | |
| 14 from pylib.perf_tests_helper import PrintPerfResult | |
| 15 | 10 |
| 16 | 11 |
| 17 class TestPackage(object): | 12 class TestPackage(object): |
| 18 """A helper base class for both APK and stand-alone executables. | 13 """A helper base class for both APK and stand-alone executables. |
| 19 | 14 |
| 20 Args: | 15 Args: |
| 21 adb: ADB interface the tests are using. | 16 adb: ADB interface the tests are using. |
| 22 device: Device to run the tests. | 17 device: Device to run the tests. |
| 23 test_suite: A specific test suite to run, empty to run all. | 18 test_suite: A specific test suite to run, empty to run all. |
| 24 timeout: Timeout for each test. | |
| 25 cleanup_test_files: Whether or not to cleanup test files on device. | |
| 26 tool: Name of the Valgrind tool. | 19 tool: Name of the Valgrind tool. |
| 27 """ | 20 """ |
| 28 | 21 |
| 29 def __init__(self, adb, device, test_suite, timeout, | 22 def __init__(self, adb, device, test_suite, tool): |
| 30 cleanup_test_files, tool): | |
| 31 self.adb = adb | 23 self.adb = adb |
| 32 self.device = device | 24 self.device = device |
| 33 self.test_suite_full = test_suite | 25 self.test_suite_full = test_suite |
| 34 self.test_suite = os.path.splitext(test_suite)[0] | 26 self.test_suite = os.path.splitext(test_suite)[0] |
| 35 self.test_suite_basename = self._GetTestSuiteBaseName() | 27 self.test_suite_basename = self._GetTestSuiteBaseName() |
| 36 self.test_suite_dirname = os.path.dirname( | 28 self.test_suite_dirname = os.path.dirname( |
| 37 self.test_suite.split(self.test_suite_basename)[0]) | 29 self.test_suite.split(self.test_suite_basename)[0]) |
| 38 self.cleanup_test_files = cleanup_test_files | |
| 39 self.tool = tool | 30 self.tool = tool |
| 40 if timeout == 0: | |
| 41 timeout = 60 | |
| 42 # On a VM (e.g. chromium buildbots), this timeout is way too small. | |
| 43 if os.environ.get('BUILDBOT_SLAVENAME'): | |
| 44 timeout = timeout * 2 | |
| 45 self.timeout = timeout * self.tool.GetTimeoutScale() | |
| 46 | 31 |
| 47 def ClearApplicationState(self): | 32 def ClearApplicationState(self): |
| 48 """Clears the application state.""" | 33 """Clears the application state.""" |
| 49 raise NotImplementedError('Method must be overriden.') | 34 raise NotImplementedError('Method must be overriden.') |
| 50 | 35 |
| 36 def CreateCommandLineFileOnDevice(self, test_filter, test_arguments): |
| 37 """Creates a test runner script and pushes to the device. |
| 38 |
| 39 Args: |
| 40 test_filter: A test_filter flag. |
| 41 test_arguments: Additional arguments to pass to the test binary. |
| 42 """ |
| 43 raise NotImplementedError('Method must be overriden.') |
| 44 |
| 45 def GetAllTests(self): |
| 46 """Returns a list of all tests available in the test suite.""" |
| 47 raise NotImplementedError('Method must be overriden.') |
| 48 |
| 49 def GetGTestReturnCode(self): |
| 50 return None |
| 51 |
| 52 def SpawnTestProcess(self): |
| 53 """Spawn the test process. |
| 54 |
| 55 Returns: |
| 56 An instance of pexpect spawn class. |
| 57 """ |
| 58 raise NotImplementedError('Method must be overriden.') |
| 59 |
| 60 def Install(self): |
| 61 """Install the test package to the device.""" |
| 62 raise NotImplementedError('Method must be overriden.') |
| 63 |
| 51 def GetDisabledPrefixes(self): | 64 def GetDisabledPrefixes(self): |
| 52 return ['DISABLED_', 'FLAKY_', 'FAILS_'] | 65 return ['DISABLED_', 'FLAKY_', 'FAILS_'] |
| 53 | 66 |
| 54 def _ParseGTestListTests(self, all_tests): | 67 def _ParseGTestListTests(self, all_tests): |
| 55 """Parses and filters the raw test lists. | 68 """Parses and filters the raw test lists. |
| 56 | 69 |
| 57 Args: | 70 Args: |
| 58 all_tests: The raw test listing with the following format: | 71 all_tests: The raw test listing with the following format: |
| 59 | 72 |
| 60 IPCChannelTest. | 73 IPCChannelTest. |
| 61 SendMessageInChannelConnected | 74 SendMessageInChannelConnected |
| 62 IPCSyncChannelTest. | 75 IPCSyncChannelTest. |
| 63 Simple | 76 Simple |
| 64 DISABLED_SendWithTimeoutMixedOKAndTimeout | 77 DISABLED_SendWithTimeoutMixedOKAndTimeout |
| 65 | 78 |
| 66 Returns: | 79 Returns: |
| 67 A list of non-disabled tests. For the above raw listing: | 80 A list of non-disabled tests. For the above raw listing: |
| 68 | 81 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 79 continue | 92 continue |
| 80 if test[0] != ' ' and test.endswith('.'): | 93 if test[0] != ' ' and test.endswith('.'): |
| 81 current = test | 94 current = test |
| 82 continue | 95 continue |
| 83 if 'YOU HAVE' in test: | 96 if 'YOU HAVE' in test: |
| 84 break | 97 break |
| 85 test_name = test[2:] | 98 test_name = test[2:] |
| 86 if not any([test_name.startswith(x) for x in disabled_prefixes]): | 99 if not any([test_name.startswith(x) for x in disabled_prefixes]): |
| 87 ret += [current + test_name] | 100 ret += [current + test_name] |
| 88 return ret | 101 return ret |
| 89 | |
| 90 def _WatchTestOutput(self, p): | |
| 91 """Watches the test output. | |
| 92 | |
| 93 Args: | |
| 94 p: the process generating output as created by pexpect.spawn. | |
| 95 | |
| 96 Returns: | |
| 97 A TestRunResults object. | |
| 98 """ | |
| 99 results = base_test_result.TestRunResults() | |
| 100 | |
| 101 # Test case statuses. | |
| 102 re_run = re.compile('\[ RUN \] ?(.*)\r\n') | |
| 103 re_fail = re.compile('\[ FAILED \] ?(.*)\r\n') | |
| 104 re_ok = re.compile('\[ OK \] ?(.*?) .*\r\n') | |
| 105 | |
| 106 # Test run statuses. | |
| 107 re_passed = re.compile('\[ PASSED \] ?(.*)\r\n') | |
| 108 re_runner_fail = re.compile('\[ RUNNER_FAILED \] ?(.*)\r\n') | |
| 109 # Signal handlers are installed before starting tests | |
| 110 # to output the CRASHED marker when a crash happens. | |
| 111 re_crash = re.compile('\[ CRASHED \](.*)\r\n') | |
| 112 | |
| 113 log = '' | |
| 114 try: | |
| 115 while True: | |
| 116 full_test_name = None | |
| 117 found = p.expect([re_run, re_passed, re_runner_fail], | |
| 118 timeout=self.timeout) | |
| 119 if found == 1: # re_passed | |
| 120 break | |
| 121 elif found == 2: # re_runner_fail | |
| 122 break | |
| 123 else: # re_run | |
| 124 full_test_name = p.match.group(1).replace('\r', '') | |
| 125 found = p.expect([re_ok, re_fail, re_crash], timeout=self.timeout) | |
| 126 log = p.before.replace('\r', '') | |
| 127 if found == 0: # re_ok | |
| 128 if full_test_name == p.match.group(1).replace('\r', ''): | |
| 129 results.AddResult(base_test_result.BaseTestResult( | |
| 130 full_test_name, base_test_result.ResultType.PASS, | |
| 131 log=log)) | |
| 132 elif found == 2: # re_crash | |
| 133 results.AddResult(base_test_result.BaseTestResult( | |
| 134 full_test_name, base_test_result.ResultType.CRASH, | |
| 135 log=log)) | |
| 136 break | |
| 137 else: # re_fail | |
| 138 results.AddResult(base_test_result.BaseTestResult( | |
| 139 full_test_name, base_test_result.ResultType.FAIL, log=log)) | |
| 140 except pexpect.EOF: | |
| 141 logging.error('Test terminated - EOF') | |
| 142 # We're here because either the device went offline, or the test harness | |
| 143 # crashed without outputting the CRASHED marker (crbug.com/175538). | |
| 144 if not self.adb.IsOnline(): | |
| 145 raise errors.DeviceUnresponsiveError('Device %s went offline.' % | |
| 146 self.device) | |
| 147 if full_test_name: | |
| 148 results.AddResult(base_test_result.BaseTestResult( | |
| 149 full_test_name, base_test_result.ResultType.CRASH, | |
| 150 log=p.before.replace('\r', ''))) | |
| 151 except pexpect.TIMEOUT: | |
| 152 logging.error('Test terminated after %d second timeout.', | |
| 153 self.timeout) | |
| 154 if full_test_name: | |
| 155 results.AddResult(base_test_result.BaseTestResult( | |
| 156 full_test_name, base_test_result.ResultType.TIMEOUT, | |
| 157 log=p.before.replace('\r', ''))) | |
| 158 finally: | |
| 159 p.close() | |
| 160 | |
| 161 ret_code = self._GetGTestReturnCode() | |
| 162 if ret_code: | |
| 163 logging.critical( | |
| 164 'gtest exit code: %d\npexpect.before: %s\npexpect.after: %s', | |
| 165 ret_code, p.before, p.after) | |
| 166 | |
| 167 return results | |
| OLD | NEW |