| #!/usr/bin/env python |
| # |
| # Copyright 2017, The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| import sys |
| import subprocess |
| import os |
| import argparse |
| |
| # Registered host based unit tests |
| # Must have 'host_supported: true' |
| HOST_TESTS = [ |
| 'bluetooth_test_common', |
| 'bluetoothtbd_test', |
| 'net_test_avrcp', |
| 'net_test_btcore', |
| 'net_test_types', |
| 'net_test_btpackets', |
| ] |
| |
| SOONG_UI_BASH = 'build/soong/soong_ui.bash' |
| |
| def str2bool(argument, default=False): |
| """ Convert a string to a booleen value. """ |
| argument = str(argument) |
| if argument.lower() in ['0', 'f', 'false', 'off', 'no', 'n']: |
| return False |
| elif argument.lower() in ['1', 't', 'true', 'on', 'yes', 'y']: |
| return True |
| return default |
| |
| |
| def check_dir_exists(dir, dirname): |
| if not os.path.isdir(dir): |
| print "Couldn't find %s (%s)!" % (dirname, dir) |
| sys.exit(0) |
| |
| |
| def get_output_from_command(cmd): |
| try: |
| return subprocess.check_output(cmd).strip() |
| except subprocess.CalledProcessError as e: |
| print 'Failed to call {cmd}, return code {code}'.format(cmd=cmd, |
| code=e.returncode) |
| print e |
| return None |
| |
| |
| def get_android_root_or_die(): |
| value = os.environ.get('ANDROID_BUILD_TOP') |
| if not value: |
| # Try to find build/soong/soong_ui.bash upwards until root directory |
| current_path = os.path.abspath(os.getcwd()) |
| while current_path and os.path.isdir(current_path): |
| soong_ui_bash_path = os.path.join(current_path, SOONG_UI_BASH) |
| if os.path.isfile(soong_ui_bash_path): |
| # Use value returned from Soong UI instead in case definition to TOP |
| # changes in the future |
| value = get_output_from_command((soong_ui_bash_path, |
| '--dumpvar-mode', |
| '--abs', |
| 'TOP')) |
| break |
| parent_path = os.path.abspath(os.path.join(current_path, os.pardir)) |
| if parent_path == current_path: |
| current_path = None |
| else: |
| current_path = parent_path |
| if not value: |
| print 'Cannot determine ANDROID_BUILD_TOP' |
| sys.exit(1) |
| check_dir_exists(value, '$ANDROID_BUILD_TOP') |
| return value |
| |
| |
| def get_android_host_out_or_die(): |
| value = os.environ.get('ANDROID_HOST_OUT') |
| if not value: |
| ANDROID_BUILD_TOP = get_android_root_or_die() |
| value = get_output_from_command((os.path.join(ANDROID_BUILD_TOP, |
| SOONG_UI_BASH), |
| '--dumpvar-mode', |
| '--abs', |
| 'HOST_OUT')) |
| if not value: |
| print 'Cannot determine ANDROID_HOST_OUT' |
| sys.exit(1) |
| check_dir_exists(value, '$ANDROID_HOST_OUT') |
| return value |
| |
| |
| def get_android_dist_dir_or_die(): |
| # Check if $DIST_DIR is predefined as environment variable |
| value = os.environ.get('DIST_DIR') |
| if not value: |
| # If not use the default path |
| ANDROID_BUILD_TOP = get_android_root_or_die() |
| value = os.path.join(os.path.join(ANDROID_BUILD_TOP, 'out'), 'dist') |
| if not os.path.isdir(value): |
| if os.path.exists(value): |
| print '%s is not a directory!' % (value) |
| sys.exit(1) |
| os.makedirs(value) |
| return value |
| |
| |
| def get_native_test_root_or_die(): |
| android_host_out = get_android_host_out_or_die() |
| test_root = os.path.join(android_host_out, 'nativetest64') |
| if not os.path.isdir(test_root): |
| test_root = os.path.join(android_host_out, 'nativetest') |
| if not os.path.isdir(test_root): |
| print 'Neither nativetest64 nor nativetest directory exist,' \ |
| ' please compile first' |
| sys.exit(1) |
| return test_root |
| |
| |
| def get_test_cmd_or_die(test_root, test_name, enable_xml, test_filter): |
| test_path = os.path.join(os.path.join(test_root, test_name), test_name) |
| if not os.path.isfile(test_path): |
| print 'Cannot find: ' + test_path |
| sys.exit(1) |
| cmd = [test_path] |
| if enable_xml: |
| dist_dir = get_android_dist_dir_or_die() |
| log_output_path = os.path.join(dist_dir, 'gtest/{0}_test_details.xml' |
| .format(test_name)) |
| cmd.append('--gtest_output=xml:{0}'.format(log_output_path)) |
| if test_filter: |
| cmd.append('--gtest_filter=%s' % test_filter) |
| return cmd |
| |
| |
| # path is relative to Android build top |
| def build_target(target, num_tasks): |
| ANDROID_BUILD_TOP = get_android_root_or_die() |
| build_cmd = [SOONG_UI_BASH, '--make-mode'] |
| if num_tasks > 1: |
| build_cmd.append('-j' + str(num_tasks)) |
| build_cmd.append(target) |
| p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy()) |
| return_code = p.wait() |
| if return_code != 0: |
| print 'BUILD FAILED, return code: {0}'.format(str(return_code)) |
| sys.exit(1) |
| return |
| |
| |
| def main(): |
| """ run_host_unit_tests.py - Run registered host based unit tests |
| """ |
| parser = argparse.ArgumentParser(description='Run host based unit tests.') |
| parser.add_argument( |
| '--enable_xml', |
| type=str2bool, |
| dest='enable_xml', |
| nargs='?', |
| const=True, |
| default=False, |
| help= |
| 'Whether to output structured XML log output in out/dist/gtest directory') |
| parser.add_argument( |
| '-j', |
| type=int, |
| nargs='?', |
| dest='num_tasks', |
| const=-1, |
| default=-1, |
| help='Number of tasks to run at the same time') |
| parser.add_argument( |
| 'rest', |
| nargs=argparse.REMAINDER, |
| help='-- args, other gtest arguments for each individual test') |
| args = parser.parse_args() |
| |
| build_target('MODULES-IN-system-bt', args.num_tasks) |
| TEST_ROOT = get_native_test_root_or_die() |
| test_results = [] |
| for test in HOST_TESTS: |
| test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest) |
| if subprocess.call(test_cmd) != 0: |
| test_results.append(False) |
| else: |
| test_results.append(True) |
| if not all(test_results): |
| failures = [i for i, x in enumerate(test_results) if not x] |
| for index in failures: |
| print 'TEST FAILLED: ' + HOST_TESTS[index] |
| sys.exit(0) |
| print 'TEST PASSED ' + str(len(test_results)) + ' tests were run' |
| |
| dist_dir = get_android_dist_dir_or_die() |
| log_output_path = os.path.join(dist_dir, 'gtest/coverage') |
| cmd_path = os.path.join(get_android_root_or_die(), 'system/bt/test') |
| print cmd_path |
| cmd = [ |
| os.path.join(cmd_path, 'gen_coverage.py'), |
| '--skip-html', |
| '--json-file', |
| '-o', |
| log_output_path, |
| ] |
| subprocess.call(cmd) |
| |
| sys.exit(0) |
| |
| |
| if __name__ == '__main__': |
| main() |