| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from collections import namedtuple |
| import logging |
| import os |
| |
| import common |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server import site_gtest_runner |
| from autotest_lib.server import test |
| |
| |
| NATIVE_TESTS_PATH = '/data/nativetest' |
| WHITELIST_FILE = '/data/nativetest/tests.txt' |
| LIST_TEST_BINARIES_TEMPLATE = ( |
| 'find %(path)s -type f -mindepth 2 -maxdepth 2 ' |
| '\( -perm -100 -o -perm -010 -o -perm -001 \)') |
| |
| GtestSuite = namedtuple('GtestSuite', ['path', 'run_as_root']) |
| |
| class brillo_Gtests(test.test): |
| """Run one or more native gTest Suites.""" |
| version = 1 |
| |
| |
| def _get_whitelisted_tests(self, whitelist_path): |
| """Return the list of whitelisted tests. |
| |
| The whitelist is expected to be a two column CSV file containing the |
| test name and "yes" or "no" whether the test should be run as root or |
| not. |
| Anything after a # on a line is considered to be a comment and ignored. |
| |
| @param whitelist_path: Path to the whitelist. |
| |
| @return a list of GtestSuite tuples. |
| """ |
| suites = [] |
| for line in self.host.run_output( |
| 'cat %s' % whitelist_path).splitlines(): |
| # Remove anything after the first # (comments). |
| line = line.split('#')[0] |
| if line.strip() == '': |
| continue |
| |
| parts = line.split(',') |
| if len(parts) != 2: |
| logging.error('badly formatted line in %s: %s', whitelist_path, |
| line) |
| continue |
| |
| name = parts[0].strip() |
| path = os.path.join(NATIVE_TESTS_PATH, name, name) |
| suites.append(GtestSuite(path, parts[1].strip() == 'yes')) |
| return suites |
| |
| |
| def _find_all_gtestsuites(self, use_whitelist=False): |
| """Find all the gTest Suites installed on the DUT. |
| |
| @param use_whitelist: Only whitelisted tests found on the system will |
| be used. |
| """ |
| list_cmd = LIST_TEST_BINARIES_TEMPLATE % {'path': NATIVE_TESTS_PATH} |
| gtest_suites_path = self.host.run_output(list_cmd).splitlines() |
| gtest_suites = [GtestSuite(path, True) for path in gtest_suites_path] |
| |
| if use_whitelist: |
| try: |
| whitelisted = self._get_whitelisted_tests(WHITELIST_FILE) |
| gtest_suites = [t for t in whitelisted |
| if t.path in gtest_suites_path] |
| except error.AutoservRunError: |
| logging.error('Failed to read whitelist %s', WHITELIST_FILE) |
| |
| if not gtest_suites: |
| raise error.TestWarn('No test executables found on the DUT') |
| logging.debug('Test executables found:\n%s', |
| '\n'.join([str(t) for t in gtest_suites])) |
| return gtest_suites |
| |
| |
| def run_gtestsuite(self, gtestSuite): |
| """Run a gTest Suite. |
| |
| @param gtestSuite: GtestSuite tuple. |
| |
| @return True if the all the tests in the gTest Suite pass. False |
| otherwise. |
| """ |
| # Make sure the gTest Suite exists. |
| result = self.host.run('test -e %s' % gtestSuite.path, |
| ignore_status=True) |
| if not result.exit_status == 0: |
| logging.error('Unable to find %s', gtestSuite.path) |
| return False |
| |
| result = self.host.run('test -x %s' % gtestSuite.path, |
| ignore_status=True) |
| if not result.exit_status == 0: |
| self.host.run('chmod +x %s' % gtestSuite.path) |
| |
| logging.debug('Running: %s', gtestSuite) |
| command = gtestSuite.path |
| if not gtestSuite.run_as_root: |
| command = 'su shell %s' % command |
| |
| result = self.host.run(command, ignore_status=True) |
| logging.debug(result.stdout) |
| |
| parser = site_gtest_runner.gtest_parser() |
| for line in result.stdout.splitlines(): |
| parser.ProcessLogLine(line) |
| passed_tests = parser.PassedTests() |
| if passed_tests: |
| logging.debug('Passed Tests: %s', passed_tests) |
| failed_tests = parser.FailedTests(include_fails=True, |
| include_flaky=True) |
| if failed_tests: |
| logging.error('Failed Tests: %s', failed_tests) |
| for test in failed_tests: |
| logging.error('Test %s failed:\n%s', test, |
| parser.FailureDescription(test)) |
| return False |
| if result.exit_status != 0: |
| logging.error('%s exited with exit code: %s', |
| gtestSuite, result.exit_status) |
| return False |
| return True |
| |
| |
| def run_once(self, host=None, gtest_suites=None, use_whitelist=False): |
| """Run gTest Suites on the DUT. |
| |
| @param host: host object representing the device under test. |
| @param gtest_suites: List of gTest suites to run. Default is to run |
| every gTest suite on the host. |
| @param use_whitelist: If gTestSuites is not passed in and use_whitelist |
| is true, only whitelisted tests found on the |
| system will be used. |
| |
| @raise TestFail: The test failed. |
| """ |
| self.host = host |
| if not gtest_suites: |
| gtest_suites = self._find_all_gtestsuites( |
| use_whitelist=use_whitelist) |
| |
| failed_gtest_suites = [] |
| for gtestSuite in gtest_suites: |
| if not self.run_gtestsuite(gtestSuite): |
| failed_gtest_suites.append(gtestSuite) |
| |
| if failed_gtest_suites: |
| logging.error( |
| 'The following gTest Suites failed: \n %s', |
| '\n'.join([str(t) for t in failed_gtest_suites])) |
| raise error.TestFail( |
| 'Not all gTest Suites completed successfully. ' |
| '%s out of %s suites failed. ' |
| 'Failed Suites: %s' |
| % (len(failed_gtest_suites), |
| len(gtest_suites), |
| failed_gtest_suites)) |