run_host_unit_tests.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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
  20. # Registered host based unit tests
  21. # Must have 'host_supported: true'
  22. HOST_TESTS = [
  23. 'bluetooth_test_common',
  24. 'bluetoothtbd_test',
  25. 'net_test_avrcp',
  26. 'net_test_btcore',
  27. 'net_test_types',
  28. 'net_test_btpackets',
  29. ]
  30. SOONG_UI_BASH = 'build/soong/soong_ui.bash'
  31. def str2bool(argument, default=False):
  32. """ Convert a string to a booleen value. """
  33. argument = str(argument)
  34. if argument.lower() in ['0', 'f', 'false', 'off', 'no', 'n']:
  35. return False
  36. elif argument.lower() in ['1', 't', 'true', 'on', 'yes', 'y']:
  37. return True
  38. return default
  39. def check_dir_exists(dir, dirname):
  40. if not os.path.isdir(dir):
  41. print "Couldn't find %s (%s)!" % (dirname, dir)
  42. sys.exit(0)
  43. def get_output_from_command(cmd):
  44. try:
  45. return subprocess.check_output(cmd).strip()
  46. except subprocess.CalledProcessError as e:
  47. print 'Failed to call {cmd}, return code {code}'.format(cmd=cmd,
  48. code=e.returncode)
  49. print e
  50. return None
  51. def get_android_root_or_die():
  52. value = os.environ.get('ANDROID_BUILD_TOP')
  53. if not value:
  54. # Try to find build/soong/soong_ui.bash upwards until root directory
  55. current_path = os.path.abspath(os.getcwd())
  56. while current_path and os.path.isdir(current_path):
  57. soong_ui_bash_path = os.path.join(current_path, SOONG_UI_BASH)
  58. if os.path.isfile(soong_ui_bash_path):
  59. # Use value returned from Soong UI instead in case definition to TOP
  60. # changes in the future
  61. value = get_output_from_command((soong_ui_bash_path,
  62. '--dumpvar-mode',
  63. '--abs',
  64. 'TOP'))
  65. break
  66. parent_path = os.path.abspath(os.path.join(current_path, os.pardir))
  67. if parent_path == current_path:
  68. current_path = None
  69. else:
  70. current_path = parent_path
  71. if not value:
  72. print 'Cannot determine ANDROID_BUILD_TOP'
  73. sys.exit(1)
  74. check_dir_exists(value, '$ANDROID_BUILD_TOP')
  75. return value
  76. def get_android_host_out_or_die():
  77. value = os.environ.get('ANDROID_HOST_OUT')
  78. if not value:
  79. ANDROID_BUILD_TOP = get_android_root_or_die()
  80. value = get_output_from_command((os.path.join(ANDROID_BUILD_TOP,
  81. SOONG_UI_BASH),
  82. '--dumpvar-mode',
  83. '--abs',
  84. 'HOST_OUT'))
  85. if not value:
  86. print 'Cannot determine ANDROID_HOST_OUT'
  87. sys.exit(1)
  88. check_dir_exists(value, '$ANDROID_HOST_OUT')
  89. return value
  90. def get_android_dist_dir_or_die():
  91. # Check if $DIST_DIR is predefined as environment variable
  92. value = os.environ.get('DIST_DIR')
  93. if not value:
  94. # If not use the default path
  95. ANDROID_BUILD_TOP = get_android_root_or_die()
  96. value = os.path.join(os.path.join(ANDROID_BUILD_TOP, 'out'), 'dist')
  97. if not os.path.isdir(value):
  98. if os.path.exists(value):
  99. print '%s is not a directory!' % (value)
  100. sys.exit(1)
  101. os.makedirs(value)
  102. return value
  103. def get_native_test_root_or_die():
  104. android_host_out = get_android_host_out_or_die()
  105. test_root = os.path.join(android_host_out, 'nativetest64')
  106. if not os.path.isdir(test_root):
  107. test_root = os.path.join(android_host_out, 'nativetest')
  108. if not os.path.isdir(test_root):
  109. print 'Neither nativetest64 nor nativetest directory exist,' \
  110. ' please compile first'
  111. sys.exit(1)
  112. return test_root
  113. def get_test_cmd_or_die(test_root, test_name, enable_xml, test_filter):
  114. test_path = os.path.join(os.path.join(test_root, test_name), test_name)
  115. if not os.path.isfile(test_path):
  116. print 'Cannot find: ' + test_path
  117. sys.exit(1)
  118. cmd = [test_path]
  119. if enable_xml:
  120. dist_dir = get_android_dist_dir_or_die()
  121. log_output_path = os.path.join(dist_dir, 'gtest/{0}_test_details.xml'
  122. .format(test_name))
  123. cmd.append('--gtest_output=xml:{0}'.format(log_output_path))
  124. if test_filter:
  125. cmd.append('--gtest_filter=%s' % test_filter)
  126. return cmd
  127. # path is relative to Android build top
  128. def build_target(target, num_tasks):
  129. ANDROID_BUILD_TOP = get_android_root_or_die()
  130. build_cmd = [SOONG_UI_BASH, '--make-mode']
  131. if num_tasks > 1:
  132. build_cmd.append('-j' + str(num_tasks))
  133. build_cmd.append(target)
  134. p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy())
  135. return_code = p.wait()
  136. if return_code != 0:
  137. print 'BUILD FAILED, return code: {0}'.format(str(return_code))
  138. sys.exit(1)
  139. return
  140. def main():
  141. """ run_host_unit_tests.py - Run registered host based unit tests
  142. """
  143. parser = argparse.ArgumentParser(description='Run host based unit tests.')
  144. parser.add_argument(
  145. '--enable_xml',
  146. type=str2bool,
  147. dest='enable_xml',
  148. nargs='?',
  149. const=True,
  150. default=False,
  151. help=
  152. 'Whether to output structured XML log output in out/dist/gtest directory')
  153. parser.add_argument(
  154. '-j',
  155. type=int,
  156. nargs='?',
  157. dest='num_tasks',
  158. const=-1,
  159. default=-1,
  160. help='Number of tasks to run at the same time')
  161. parser.add_argument(
  162. 'rest',
  163. nargs=argparse.REMAINDER,
  164. help='-- args, other gtest arguments for each individual test')
  165. args = parser.parse_args()
  166. build_target('MODULES-IN-system-bt', args.num_tasks)
  167. TEST_ROOT = get_native_test_root_or_die()
  168. test_results = []
  169. for test in HOST_TESTS:
  170. test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest)
  171. if subprocess.call(test_cmd) != 0:
  172. test_results.append(False)
  173. else:
  174. test_results.append(True)
  175. if not all(test_results):
  176. failures = [i for i, x in enumerate(test_results) if not x]
  177. for index in failures:
  178. print 'TEST FAILLED: ' + HOST_TESTS[index]
  179. sys.exit(0)
  180. print 'TEST PASSED ' + str(len(test_results)) + ' tests were run'
  181. dist_dir = get_android_dist_dir_or_die()
  182. log_output_path = os.path.join(dist_dir, 'gtest/coverage')
  183. cmd_path = os.path.join(get_android_root_or_die(), 'system/bt/test')
  184. print cmd_path
  185. cmd = [
  186. os.path.join(cmd_path, 'gen_coverage.py'),
  187. '--skip-html',
  188. '--json-file',
  189. '-o',
  190. log_output_path,
  191. ]
  192. subprocess.call(cmd)
  193. sys.exit(0)
  194. if __name__ == '__main__':
  195. main()