1#!/usr/bin/env python3 2# coding=utf-8 3 4# 5# Copyright (c) 2023 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19 20import os 21import json 22import shutil 23import shlex 24import subprocess 25import sys 26import stat 27 28FLAGS = os.O_WRONLY | os.O_APPEND | os.O_CREAT 29MODES = stat.S_IWUSR | stat.S_IRUSR 30 31# 子系统json目录 32SYSTEM_JSON = "build/subsystem_config.json" 33# 覆盖率gcda 34COVERAGE_GCDA_RESULTS = "test/localCoverage/codeCoverage/results/coverage/data/cxx" 35# 报告路径 36REPORT_PATH = "test/localCoverage/codeCoverage/results/coverage/reports/cxx" 37# llvm-gcov.sh 38LLVM_GCOV = "test/localCoverage/codeCoverage/llvm-gcov.sh" 39 40 41def _init_sys_config(): 42 sys.localcoverage_path = os.path.join(current_path, "..") 43 sys.path.insert(0, sys.localcoverage_path) 44 45 46def call(cmd_list, is_show_cmd=False, out=None, err=None): 47 return_flag = False 48 try: 49 if is_show_cmd: 50 print("execute command: {}".format(" ".join(cmd_list))) 51 if 0 == subprocess.call(cmd_list, shell=False, stdout=out, stderr=err): 52 return_flag = True 53 except Exception: 54 print("Error : command {} execute faild!".format(cmd_list)) 55 return_flag = False 56 return return_flag 57 58 59def execute_command(command, printflag=False): 60 try: 61 cmd_list = shlex.split(command) 62 coverage_log_path = os.path.join( 63 CODEPATH, "test/testfwk/developer_test/localCoverage", "coverage.log") 64 with os.fdopen(os.open(coverage_log_path, FLAGS, MODES), 'a') as fd: 65 call(cmd_list, printflag, fd, fd) 66 except IOError: 67 print("Error: Exception occur in open err") 68 69 70def get_subsystem_config_info(): 71 subsystem_info_dic = {} 72 subsystem_config_filepath = os.path.join(CODEPATH, SYSTEM_JSON) 73 if os.path.exists(subsystem_config_filepath): 74 data = None 75 with open(subsystem_config_filepath, 'r') as f: 76 data = json.load(f) 77 if not data: 78 print("subsystem config file error.") 79 for value in data.values(): 80 subsystem_name = value.get('name') 81 subsystem_dir = value.get('dir') 82 subsystem_path = value.get('path') 83 subsystem_project = value.get('project') 84 subsystem_rootpath = os.path.join(CODEPATH, subsystem_path) 85 subsystem_info_dic[subsystem_name] = [ 86 subsystem_project, subsystem_dir, 87 subsystem_path, subsystem_rootpath 88 ] 89 return subsystem_info_dic 90 91 92def get_subsystem_name_list(): 93 subsystem_name_list = [] 94 subsystem_info_dic = get_subsystem_config_info() 95 for key in subsystem_info_dic.keys(): 96 subsystem_rootpath = subsystem_info_dic[key][3] 97 if os.path.exists(subsystem_rootpath): 98 subsystem_name_list.append(key) 99 return subsystem_name_list 100 101 102def get_subsystem_rootpath(subsystem_name): 103 subsystem_path = "" 104 subsystem_rootpath = "" 105 subsystem_info_dic = get_subsystem_config_info() 106 for key in subsystem_info_dic.keys(): 107 if key == subsystem_name: 108 subsystem_path = subsystem_info_dic[key][2] 109 subsystem_rootpath = subsystem_info_dic[key][3] 110 break 111 return subsystem_path, subsystem_rootpath 112 113 114def is_filterout_dir(ignore_prefix, check_path): 115 # 屏蔽列表 116 filter_out_list = ["unittest", "third_party", "test"] 117 for item in filter_out_list: 118 check_list = check_path[len(ignore_prefix):].split("/") 119 if item in check_list: 120 return True 121 return False 122 123 124def rm_unnecessary_dir(cov_path): 125 topdir = os.path.join(cov_path, "obj") 126 for root, dirs, files in os.walk(topdir): 127 if is_filterout_dir(topdir, root): 128 shutil.rmtree(root) 129 130 131def get_files_from_dir(find_path, postfix=None): 132 names = os.listdir(find_path) 133 file_list = [] 134 for fn in names: 135 if not os.path.isfile(os.path.join(find_path, fn)): 136 continue 137 if postfix is not None: 138 if fn.endswith(postfix): 139 file_list.append(fn) 140 else: 141 file_list.append(fn) 142 return file_list 143 144 145def get_gcno_files(cov_path, dir_name): 146 gcda_strip_path = dir_name[len(cov_path) + 1:] 147 gcda_list = get_files_from_dir(dir_name, ".gcda") 148 for file_name in gcda_list: 149 gcno_name = f"{os.path.splitext(file_name)[0]}.gcno" 150 gcno_path = os.path.join( 151 os.path.join(CODEPATH, OUTPUT), gcda_strip_path, gcno_name) 152 if os.path.exists(gcno_path): 153 if os.path.exists(gcno_path): 154 shutil.copy(gcno_path, dir_name) 155 else: 156 print("%s not exists!", gcno_path) 157 158 159def get_module_gcno_files(cov_path, dir_name): 160 for root, dirs, files in os.walk(dir_name): 161 get_gcno_files(cov_path, root) 162 163 164def gen_subsystem_trace_info(subsystem, data_dir, test_dir): 165 src_dir = os.path.join(CODEPATH, OUTPUT) 166 single_info_path = os.path.join( 167 CODEPATH, REPORT_PATH, "single_test", test_dir) 168 if not os.path.exists(single_info_path): 169 os.makedirs(single_info_path) 170 output_name = os.path.join( 171 CODEPATH, single_info_path, f"{subsystem}_output.info") 172 if not os.path.exists(src_dir): 173 print("Sours path %s not exist!", src_dir) 174 return 175 cmd = "lcov -c -b {} -d {} --gcov-tool {} -o {} --ignore-errors source,gcov".format( 176 src_dir, data_dir, os.path.join(CODEPATH, LLVM_GCOV), output_name) 177 print(f"single_test**{cmd}") 178 execute_command(cmd) 179 180 181def cut_info(subsystem, test_dir): 182 trace_file = os.path.join( 183 CODEPATH, REPORT_PATH, "single_test", 184 test_dir, f"{subsystem}_output.info") 185 output_name = os.path.join( 186 CODEPATH, REPORT_PATH, "single_test", 187 test_dir, f"{subsystem}_strip.info") 188 remove = r"'*/unittest/*' '*/third_party/*' 'sdk/android-arm64/*'" 189 if not os.path.exists(trace_file): 190 print("Error: trace file %s not exisit!", trace_file) 191 return 192 cmd = "lcov --remove {} {} -o {}".format(trace_file, remove, output_name) 193 execute_command(cmd) 194 195 196def gen_info(cov_path, test_dir, subsystem_list): 197 if len(subsystem_list) == 0: 198 return 199 for subsystem in subsystem_list: 200 (subsystem_path, subsystem_rootpath) = get_subsystem_rootpath(subsystem) 201 subsystem_data_abspath = os.path.join(cov_path, "obj", subsystem_path) 202 if not os.path.exists(subsystem_data_abspath): 203 continue 204 get_module_gcno_files(cov_path, subsystem_data_abspath) 205 gen_subsystem_trace_info(subsystem, subsystem_data_abspath, test_dir) 206 cut_info(subsystem, test_dir) 207 208 209def gen_all_test_info(subsystem_list): 210 cov_path = os.path.join(CODEPATH, COVERAGE_GCDA_RESULTS) 211 single_test_dir_list = [] 212 for root, dirs, files in os.walk(cov_path): 213 single_test_dir_list = dirs 214 break 215 for index, cur_test_dir in enumerate(single_test_dir_list): 216 cur_test_abs_dir = os.path.join(cov_path, cur_test_dir) 217 rm_unnecessary_dir(cur_test_abs_dir) 218 gen_info(cur_test_abs_dir, cur_test_dir, subsystem_list) 219 220 221def merge_subsystem_info_from_all_test(subsystem): 222 single_test_info_path = os.path.join(CODEPATH, REPORT_PATH, "single_test") 223 subsystem_info_list = [] 224 subsystem_info_name = f"{subsystem}_strip.info" 225 for root, dirs, files in os.walk(single_test_info_path): 226 if subsystem_info_name in files: 227 subsystem_info_path_tmp = os.path.join( 228 single_test_info_path, root, subsystem_info_name) 229 subsystem_info_list.append(subsystem_info_path_tmp) 230 if len(subsystem_info_list) == 0: 231 return 232 info_output_name = os.path.join( 233 CODEPATH, REPORT_PATH, subsystem_info_name) 234 cmd = "lcov -a {} -o {}".format( 235 " -a ".join(subsystem_info_list), info_output_name) 236 execute_command(cmd) 237 238 239def merge_all_test_subsystem_info(subsystem_list): 240 single_test_info_path = os.path.join( 241 CODEPATH, REPORT_PATH, "single_test") 242 if not os.path.exists(single_test_info_path): 243 print("Error: the single test info path %s not exist", 244 single_test_info_path) 245 return 246 for subsystem in subsystem_list: 247 print("Merging all %s info from test data......", subsystem) 248 merge_subsystem_info_from_all_test(subsystem) 249 250 251def merge_info(report_dir): 252 if not os.path.exists(report_dir): 253 print("Error: report dir %s not exist", report_dir) 254 return 255 subsystem_name_list = get_files_from_dir(report_dir, "_strip.info") 256 if len(subsystem_name_list) == 0: 257 print("Error: get subsytem trace files in \report directory failed.") 258 return 259 trace_file_list = [] 260 for subsystem in subsystem_name_list: 261 trace_file_name = os.path.join(report_dir, subsystem) 262 trace_file_list.append(trace_file_name) 263 cmd = "lcov -a {} -o {}".format( 264 " -a ".join(trace_file_list), os.path.join(report_dir, "ohos_codeCoverage.info")) 265 execute_command(cmd) 266 267 268def merge_all_subsystem_info(): 269 print("Merging all the sysbsystem trace files......") 270 merge_info(os.path.join(CODEPATH, REPORT_PATH)) 271 272 273def gen_html(cov_path): 274 tracefile = os.path.join(CODEPATH, REPORT_PATH, "ohos_codeCoverage.info") 275 if not os.path.exists(tracefile): 276 print("Error: the trace file %s not exist", tracefile) 277 return 278 cmd = "genhtml --branch-coverage --demangle-cpp -o {} -p {} --ignore-errors source {}".format( 279 os.path.join(CODEPATH, REPORT_PATH, "html"), CODEPATH, tracefile) 280 execute_command(cmd) 281 282 283def gen_final_report(cov_path): 284 print("Generating the html report......") 285 gen_html(cov_path) 286 287 288if __name__ == "__main__": 289 current_path = os.path.abspath(os.path.dirname(__name__)) 290 CODEPATH = current_path.split("/test/testfwk/developer_test")[0] 291 _init_sys_config() 292 from localCoverage.utils import get_product_name 293 # 编译生成的out路径 294 OUTPUT = "out/{}".format(get_product_name(CODEPATH)) 295 296 gen_all_test_info(subsystem_list=get_subsystem_name_list()) 297 merge_all_test_subsystem_info(subsystem_list=get_subsystem_name_list()) 298 merge_all_subsystem_info() 299 gen_final_report(os.path.join(CODEPATH, COVERAGE_GCDA_RESULTS)) 300