Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # |
| 3 | # Copyright 2017, The Android Open Source Project |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | import sys |
| 17 | import subprocess |
| 18 | import os |
| 19 | import argparse |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 20 | |
| 21 | # Registered host based unit tests |
| 22 | # Must have 'host_supported: true' |
| 23 | HOST_TESTS = [ |
Jack He | c27d257 | 2018-07-25 12:02:22 -0700 | [diff] [blame] | 24 | 'bluetooth_test_common', |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 25 | 'bluetoothtbd_test', |
Ajay Panicker | 2c822c9 | 2018-02-21 21:04:24 -0800 | [diff] [blame] | 26 | 'net_test_avrcp', |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 27 | 'net_test_btcore', |
| 28 | 'net_test_types', |
Ajay Panicker | 341ab2b | 2018-01-03 14:23:44 -0800 | [diff] [blame] | 29 | 'net_test_btpackets', |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 30 | ] |
| 31 | |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 32 | SOONG_UI_BASH = 'build/soong/soong_ui.bash' |
| 33 | |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 34 | def str2bool(argument, default=False): |
| 35 | """ Convert a string to a booleen value. """ |
| 36 | argument = str(argument) |
| 37 | if argument.lower() in ['0', 'f', 'false', 'off', 'no', 'n']: |
| 38 | return False |
| 39 | elif argument.lower() in ['1', 't', 'true', 'on', 'yes', 'y']: |
| 40 | return True |
| 41 | return default |
| 42 | |
| 43 | |
| 44 | def check_dir_exists(dir, dirname): |
| 45 | if not os.path.isdir(dir): |
| 46 | print "Couldn't find %s (%s)!" % (dirname, dir) |
| 47 | sys.exit(0) |
| 48 | |
| 49 | |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 50 | def get_output_from_command(cmd): |
| 51 | try: |
| 52 | return subprocess.check_output(cmd).strip() |
| 53 | except subprocess.CalledProcessError as e: |
| 54 | print 'Failed to call {cmd}, return code {code}'.format(cmd=cmd, |
| 55 | code=e.returncode) |
| 56 | print e |
| 57 | return None |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 58 | |
| 59 | |
| 60 | def get_android_root_or_die(): |
| 61 | value = os.environ.get('ANDROID_BUILD_TOP') |
| 62 | if not value: |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 63 | # Try to find build/soong/soong_ui.bash upwards until root directory |
| 64 | current_path = os.path.abspath(os.getcwd()) |
| 65 | while current_path and os.path.isdir(current_path): |
| 66 | soong_ui_bash_path = os.path.join(current_path, SOONG_UI_BASH) |
| 67 | if os.path.isfile(soong_ui_bash_path): |
| 68 | # Use value returned from Soong UI instead in case definition to TOP |
| 69 | # changes in the future |
| 70 | value = get_output_from_command((soong_ui_bash_path, |
| 71 | '--dumpvar-mode', |
| 72 | '--abs', |
| 73 | 'TOP')) |
| 74 | break |
| 75 | parent_path = os.path.abspath(os.path.join(current_path, os.pardir)) |
| 76 | if parent_path == current_path: |
| 77 | current_path = None |
| 78 | else: |
| 79 | current_path = parent_path |
| 80 | if not value: |
| 81 | print 'Cannot determine ANDROID_BUILD_TOP' |
Jack He | b738576 | 2017-10-25 10:14:53 -0700 | [diff] [blame] | 82 | sys.exit(1) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 83 | check_dir_exists(value, '$ANDROID_BUILD_TOP') |
| 84 | return value |
| 85 | |
| 86 | |
| 87 | def get_android_host_out_or_die(): |
| 88 | value = os.environ.get('ANDROID_HOST_OUT') |
| 89 | if not value: |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 90 | ANDROID_BUILD_TOP = get_android_root_or_die() |
| 91 | value = get_output_from_command((os.path.join(ANDROID_BUILD_TOP, |
| 92 | SOONG_UI_BASH), |
| 93 | '--dumpvar-mode', |
| 94 | '--abs', |
| 95 | 'HOST_OUT')) |
| 96 | if not value: |
| 97 | print 'Cannot determine ANDROID_HOST_OUT' |
Jack He | b738576 | 2017-10-25 10:14:53 -0700 | [diff] [blame] | 98 | sys.exit(1) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 99 | check_dir_exists(value, '$ANDROID_HOST_OUT') |
| 100 | return value |
| 101 | |
| 102 | |
| 103 | def get_android_dist_dir_or_die(): |
Jack He | 11f1e93 | 2017-10-17 12:01:39 -0700 | [diff] [blame] | 104 | # Check if $DIST_DIR is predefined as environment variable |
| 105 | value = os.environ.get('DIST_DIR') |
| 106 | if not value: |
| 107 | # If not use the default path |
| 108 | ANDROID_BUILD_TOP = get_android_root_or_die() |
| 109 | value = os.path.join(os.path.join(ANDROID_BUILD_TOP, 'out'), 'dist') |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 110 | if not os.path.isdir(value): |
| 111 | if os.path.exists(value): |
| 112 | print '%s is not a directory!' % (value) |
Jack He | b738576 | 2017-10-25 10:14:53 -0700 | [diff] [blame] | 113 | sys.exit(1) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 114 | os.makedirs(value) |
| 115 | return value |
| 116 | |
| 117 | |
| 118 | def get_native_test_root_or_die(): |
| 119 | android_host_out = get_android_host_out_or_die() |
| 120 | test_root = os.path.join(android_host_out, 'nativetest64') |
| 121 | if not os.path.isdir(test_root): |
| 122 | test_root = os.path.join(android_host_out, 'nativetest') |
| 123 | if not os.path.isdir(test_root): |
| 124 | print 'Neither nativetest64 nor nativetest directory exist,' \ |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 125 | ' please compile first' |
Jack He | b738576 | 2017-10-25 10:14:53 -0700 | [diff] [blame] | 126 | sys.exit(1) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 127 | return test_root |
| 128 | |
| 129 | |
| 130 | def get_test_cmd_or_die(test_root, test_name, enable_xml, test_filter): |
| 131 | test_path = os.path.join(os.path.join(test_root, test_name), test_name) |
| 132 | if not os.path.isfile(test_path): |
| 133 | print 'Cannot find: ' + test_path |
Jack He | b738576 | 2017-10-25 10:14:53 -0700 | [diff] [blame] | 134 | sys.exit(1) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 135 | cmd = [test_path] |
| 136 | if enable_xml: |
| 137 | dist_dir = get_android_dist_dir_or_die() |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 138 | log_output_path = os.path.join(dist_dir, 'gtest/{0}_test_details.xml' |
| 139 | .format(test_name)) |
| 140 | cmd.append('--gtest_output=xml:{0}'.format(log_output_path)) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 141 | if test_filter: |
| 142 | cmd.append('--gtest_filter=%s' % test_filter) |
| 143 | return cmd |
| 144 | |
| 145 | |
| 146 | # path is relative to Android build top |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 147 | def build_target(target, num_tasks): |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 148 | ANDROID_BUILD_TOP = get_android_root_or_die() |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 149 | build_cmd = [SOONG_UI_BASH, '--make-mode'] |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 150 | if num_tasks > 1: |
| 151 | build_cmd.append('-j' + str(num_tasks)) |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 152 | build_cmd.append(target) |
| 153 | p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy()) |
Jack He | b738576 | 2017-10-25 10:14:53 -0700 | [diff] [blame] | 154 | return_code = p.wait() |
| 155 | if return_code != 0: |
| 156 | print 'BUILD FAILED, return code: {0}'.format(str(return_code)) |
| 157 | sys.exit(1) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 158 | return |
| 159 | |
| 160 | |
| 161 | def main(): |
| 162 | """ run_host_unit_tests.py - Run registered host based unit tests |
| 163 | """ |
| 164 | parser = argparse.ArgumentParser(description='Run host based unit tests.') |
| 165 | parser.add_argument( |
| 166 | '--enable_xml', |
| 167 | type=str2bool, |
| 168 | dest='enable_xml', |
| 169 | nargs='?', |
| 170 | const=True, |
| 171 | default=False, |
| 172 | help= |
| 173 | 'Whether to output structured XML log output in out/dist/gtest directory') |
| 174 | parser.add_argument( |
| 175 | '-j', |
| 176 | type=int, |
| 177 | nargs='?', |
| 178 | dest='num_tasks', |
| 179 | const=-1, |
| 180 | default=-1, |
| 181 | help='Number of tasks to run at the same time') |
| 182 | parser.add_argument( |
| 183 | 'rest', |
| 184 | nargs=argparse.REMAINDER, |
| 185 | help='-- args, other gtest arguments for each individual test') |
| 186 | args = parser.parse_args() |
| 187 | |
Jack He | 39555a3 | 2017-10-23 13:28:59 -0700 | [diff] [blame] | 188 | build_target('MODULES-IN-system-bt', args.num_tasks) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 189 | TEST_ROOT = get_native_test_root_or_die() |
| 190 | test_results = [] |
| 191 | for test in HOST_TESTS: |
| 192 | test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest) |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 193 | if subprocess.call(test_cmd) != 0: |
| 194 | test_results.append(False) |
| 195 | else: |
| 196 | test_results.append(True) |
| 197 | if not all(test_results): |
| 198 | failures = [i for i, x in enumerate(test_results) if not x] |
| 199 | for index in failures: |
| 200 | print 'TEST FAILLED: ' + HOST_TESTS[index] |
| 201 | sys.exit(0) |
| 202 | print 'TEST PASSED ' + str(len(test_results)) + ' tests were run' |
Ajay Panicker | ff48ce8 | 2018-09-20 14:39:00 -0700 | [diff] [blame] | 203 | |
| 204 | dist_dir = get_android_dist_dir_or_die() |
| 205 | log_output_path = os.path.join(dist_dir, 'gtest/coverage') |
| 206 | cmd_path = os.path.join(get_android_root_or_die(), 'system/bt/test') |
| 207 | print cmd_path |
| 208 | cmd = [ |
| 209 | os.path.join(cmd_path, 'gen_coverage.py'), |
| 210 | '--skip-html', |
| 211 | '--json-file', |
| 212 | '-o', |
| 213 | log_output_path, |
| 214 | ] |
| 215 | subprocess.call(cmd) |
| 216 | |
Jack He | aba81f4 | 2017-09-28 18:41:28 -0700 | [diff] [blame] | 217 | sys.exit(0) |
| 218 | |
| 219 | |
| 220 | if __name__ == '__main__': |
| 221 | main() |