• 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
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