1 # Copyright 2015 The Chromium OS 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 from collections import namedtuple 6 import logging 7 import os 8 9 import common 10 from autotest_lib.client.common_lib import error 11 from autotest_lib.server import site_gtest_runner 12 from autotest_lib.server import test 13 14 15 NATIVE_TESTS_PATH = '/data/nativetest' 16 WHITELIST_FILE = '/data/nativetest/tests.txt' 17 LIST_TEST_BINARIES_TEMPLATE = ( 18 'find %(path)s -type f -mindepth 2 -maxdepth 2 ' 19 '\( -perm -100 -o -perm -010 -o -perm -001 \)') 20 21 GtestSuite = namedtuple('GtestSuite', ['path', 'run_as_root']) 22 23 class brillo_Gtests(test.test): 24 """Run one or more native gTest Suites.""" 25 version = 1 26 27 28 def _get_whitelisted_tests(self, whitelist_path): 29 """Return the list of whitelisted tests. 30 31 The whitelist is expected to be a two column CSV file containing the 32 test name and "yes" or "no" whether the test should be run as root or 33 not. 34 Anything after a # on a line is considered to be a comment and ignored. 35 36 @param whitelist_path: Path to the whitelist. 37 38 @return a list of GtestSuite tuples. 39 """ 40 suites = [] 41 for line in self.host.run_output( 42 'cat %s' % whitelist_path).splitlines(): 43 # Remove anything after the first # (comments). 44 line = line.split('#')[0] 45 if line.strip() == '': 46 continue 47 48 parts = line.split(',') 49 if len(parts) != 2: 50 logging.error('badly formatted line in %s: %s', whitelist_path, 51 line) 52 continue 53 54 name = parts[0].strip() 55 path = os.path.join(NATIVE_TESTS_PATH, name, name) 56 suites.append(GtestSuite(path, parts[1].strip() == 'yes')) 57 return suites 58 59 60 def _find_all_gtestsuites(self, use_whitelist=False): 61 """Find all the gTest Suites installed on the DUT. 62 63 @param use_whitelist: Only whitelisted tests found on the system will 64 be used. 65 """ 66 list_cmd = LIST_TEST_BINARIES_TEMPLATE % {'path': NATIVE_TESTS_PATH} 67 gtest_suites_path = self.host.run_output(list_cmd).splitlines() 68 gtest_suites = [GtestSuite(path, True) for path in gtest_suites_path] 69 70 if use_whitelist: 71 try: 72 whitelisted = self._get_whitelisted_tests(WHITELIST_FILE) 73 gtest_suites = [t for t in whitelisted 74 if t.path in gtest_suites_path] 75 except error.AutoservRunError: 76 logging.error('Failed to read whitelist %s', WHITELIST_FILE) 77 78 if not gtest_suites: 79 raise error.TestWarn('No test executables found on the DUT') 80 logging.debug('Test executables found:\n%s', 81 '\n'.join([str(t) for t in gtest_suites])) 82 return gtest_suites 83 84 85 def run_gtestsuite(self, gtestSuite): 86 """Run a gTest Suite. 87 88 @param gtestSuite: GtestSuite tuple. 89 90 @return True if the all the tests in the gTest Suite pass. False 91 otherwise. 92 """ 93 # Make sure the gTest Suite exists. 94 result = self.host.run('test -e %s' % gtestSuite.path, 95 ignore_status=True) 96 if not result.exit_status == 0: 97 logging.error('Unable to find %s', gtestSuite.path) 98 return False 99 100 result = self.host.run('test -x %s' % gtestSuite.path, 101 ignore_status=True) 102 if not result.exit_status == 0: 103 self.host.run('chmod +x %s' % gtestSuite.path) 104 105 logging.debug('Running: %s', gtestSuite) 106 command = gtestSuite.path 107 if not gtestSuite.run_as_root: 108 command = 'su shell %s' % command 109 110 result = self.host.run(command, ignore_status=True) 111 logging.debug(result.stdout) 112 113 parser = site_gtest_runner.gtest_parser() 114 for line in result.stdout.splitlines(): 115 parser.ProcessLogLine(line) 116 passed_tests = parser.PassedTests() 117 if passed_tests: 118 logging.debug('Passed Tests: %s', passed_tests) 119 failed_tests = parser.FailedTests(include_fails=True, 120 include_flaky=True) 121 if failed_tests: 122 logging.error('Failed Tests: %s', failed_tests) 123 for test in failed_tests: 124 logging.error('Test %s failed:\n%s', test, 125 parser.FailureDescription(test)) 126 return False 127 if result.exit_status != 0: 128 logging.error('%s exited with exit code: %s', 129 gtestSuite, result.exit_status) 130 return False 131 return True 132 133 134 def run_once(self, host=None, gtest_suites=None, use_whitelist=False): 135 """Run gTest Suites on the DUT. 136 137 @param host: host object representing the device under test. 138 @param gtest_suites: List of gTest suites to run. Default is to run 139 every gTest suite on the host. 140 @param use_whitelist: If gTestSuites is not passed in and use_whitelist 141 is true, only whitelisted tests found on the 142 system will be used. 143 144 @raise TestFail: The test failed. 145 """ 146 self.host = host 147 if not gtest_suites: 148 gtest_suites = self._find_all_gtestsuites( 149 use_whitelist=use_whitelist) 150 151 failed_gtest_suites = [] 152 for gtestSuite in gtest_suites: 153 if not self.run_gtestsuite(gtestSuite): 154 failed_gtest_suites.append(gtestSuite) 155 156 if failed_gtest_suites: 157 logging.error( 158 'The following gTest Suites failed: \n %s', 159 '\n'.join([str(t) for t in failed_gtest_suites])) 160 raise error.TestFail( 161 'Not all gTest Suites completed successfully. ' 162 '%s out of %s suites failed. ' 163 'Failed Suites: %s' 164 % (len(failed_gtest_suites), 165 len(gtest_suites), 166 failed_gtest_suites)) 167