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