openubmc-bingo 0.5.240__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of openubmc-bingo might be problematic. Click here for more details.
- bmcgo/__init__.py +12 -0
- bmcgo/bmcgo.py +22 -0
- bmcgo/bmcgo_config.py +176 -0
- bmcgo/cli/__init__.py +10 -0
- bmcgo/cli/cli.py +584 -0
- bmcgo/codegen/__init__.py +14 -0
- bmcgo/codegen/c/__init__.py +9 -0
- bmcgo/codegen/c/annotation.py +52 -0
- bmcgo/codegen/c/argument.py +42 -0
- bmcgo/codegen/c/codegen.py +153 -0
- bmcgo/codegen/c/comment.py +22 -0
- bmcgo/codegen/c/ctype_defination.py +353 -0
- bmcgo/codegen/c/helper.py +87 -0
- bmcgo/codegen/c/interface.py +63 -0
- bmcgo/codegen/c/method.py +82 -0
- bmcgo/codegen/c/property.py +180 -0
- bmcgo/codegen/c/renderer.py +21 -0
- bmcgo/codegen/c/signal.py +64 -0
- bmcgo/codegen/c/template/client.c.mako +145 -0
- bmcgo/codegen/c/template/client.h.mako +36 -0
- bmcgo/codegen/c/template/interface.c.mako +0 -0
- bmcgo/codegen/c/template/interface.introspect.xml.mako +99 -0
- bmcgo/codegen/c/template/micro_component.c.mako +32 -0
- bmcgo/codegen/c/template/public.c.mako +228 -0
- bmcgo/codegen/c/template/public.h.mako +128 -0
- bmcgo/codegen/c/template/server.c.mako +104 -0
- bmcgo/codegen/c/template/server.h.mako +36 -0
- bmcgo/codegen/lua/.lua-format +7 -0
- bmcgo/codegen/lua/Makefile +101 -0
- bmcgo/codegen/lua/__init__.py +9 -0
- bmcgo/codegen/lua/codegen.py +171 -0
- bmcgo/codegen/lua/proto/Makefile +87 -0
- bmcgo/codegen/lua/proto/ipmi_types.proto +17 -0
- bmcgo/codegen/lua/proto/types.proto +52 -0
- bmcgo/codegen/lua/script/check_intfs.py +161 -0
- bmcgo/codegen/lua/script/dto/__init__.py +11 -0
- bmcgo/codegen/lua/script/dto/exception.py +53 -0
- bmcgo/codegen/lua/script/dto/kepler_abstract.py +47 -0
- bmcgo/codegen/lua/script/dto/options.py +33 -0
- bmcgo/codegen/lua/script/dto/print_simple.py +19 -0
- bmcgo/codegen/lua/script/dto/redfish_api.py +241 -0
- bmcgo/codegen/lua/script/dto/url_route.py +195 -0
- bmcgo/codegen/lua/script/gen_db_json.py +444 -0
- bmcgo/codegen/lua/script/gen_depends.py +89 -0
- bmcgo/codegen/lua/script/gen_entry.py +263 -0
- bmcgo/codegen/lua/script/gen_feature_json.py +156 -0
- bmcgo/codegen/lua/script/gen_historical_local_db_json.py +88 -0
- bmcgo/codegen/lua/script/gen_intf_json.py +261 -0
- bmcgo/codegen/lua/script/gen_intf_rpc_json.py +575 -0
- bmcgo/codegen/lua/script/gen_ipmi_json.py +485 -0
- bmcgo/codegen/lua/script/gen_mdb_json.py +117 -0
- bmcgo/codegen/lua/script/gen_rpc_msg_json.py +487 -0
- bmcgo/codegen/lua/script/gen_schema.py +302 -0
- bmcgo/codegen/lua/script/ipmi_types_pb2.py +135 -0
- bmcgo/codegen/lua/script/loader/__init__.py +11 -0
- bmcgo/codegen/lua/script/loader/file_utils.py +33 -0
- bmcgo/codegen/lua/script/loader/kepler_abstract_collect.py +79 -0
- bmcgo/codegen/lua/script/loader/kepler_abstract_loader.py +47 -0
- bmcgo/codegen/lua/script/loader/redfish_loader.py +127 -0
- bmcgo/codegen/lua/script/lua_format.py +62 -0
- bmcgo/codegen/lua/script/mds_util.py +385 -0
- bmcgo/codegen/lua/script/merge_model.py +330 -0
- bmcgo/codegen/lua/script/merge_proto_algo.py +85 -0
- bmcgo/codegen/lua/script/proto_loader.py +47 -0
- bmcgo/codegen/lua/script/proto_plugin.py +140 -0
- bmcgo/codegen/lua/script/redfish_source_tree.py +118 -0
- bmcgo/codegen/lua/script/render_utils/__init__.py +38 -0
- bmcgo/codegen/lua/script/render_utils/base.py +25 -0
- bmcgo/codegen/lua/script/render_utils/client_lua.py +98 -0
- bmcgo/codegen/lua/script/render_utils/controller_lua.py +71 -0
- bmcgo/codegen/lua/script/render_utils/db_lua.py +224 -0
- bmcgo/codegen/lua/script/render_utils/error_lua.py +185 -0
- bmcgo/codegen/lua/script/render_utils/factory.py +52 -0
- bmcgo/codegen/lua/script/render_utils/ipmi_lua.py +159 -0
- bmcgo/codegen/lua/script/render_utils/ipmi_message_lua.py +24 -0
- bmcgo/codegen/lua/script/render_utils/mdb_lua.py +177 -0
- bmcgo/codegen/lua/script/render_utils/mdb_register.py +215 -0
- bmcgo/codegen/lua/script/render_utils/message_lua.py +26 -0
- bmcgo/codegen/lua/script/render_utils/messages_lua.py +156 -0
- bmcgo/codegen/lua/script/render_utils/model_lua.py +485 -0
- bmcgo/codegen/lua/script/render_utils/old_model_lua.py +429 -0
- bmcgo/codegen/lua/script/render_utils/plugin_lua.py +38 -0
- bmcgo/codegen/lua/script/render_utils/redfish_proto.py +86 -0
- bmcgo/codegen/lua/script/render_utils/request_lua.py +76 -0
- bmcgo/codegen/lua/script/render_utils/service_lua.py +130 -0
- bmcgo/codegen/lua/script/render_utils/utils_message_lua.py +125 -0
- bmcgo/codegen/lua/script/render_utils/validate_lua.py +221 -0
- bmcgo/codegen/lua/script/sep_ipmi_message_cmds.py +217 -0
- bmcgo/codegen/lua/script/template.py +166 -0
- bmcgo/codegen/lua/script/types_pb2.py +516 -0
- bmcgo/codegen/lua/script/utils.py +663 -0
- bmcgo/codegen/lua/script/validate.py +80 -0
- bmcgo/codegen/lua/script/yaml_to_json.py +73 -0
- bmcgo/codegen/lua/templates/Makefile +114 -0
- bmcgo/codegen/lua/templates/apps/Makefile +261 -0
- bmcgo/codegen/lua/templates/apps/Makefile.mdb.mk +64 -0
- bmcgo/codegen/lua/templates/apps/app.lua.mako +19 -0
- bmcgo/codegen/lua/templates/apps/class.lua.mako +35 -0
- bmcgo/codegen/lua/templates/apps/client.lua.mako +429 -0
- bmcgo/codegen/lua/templates/apps/controller.lua.mako +276 -0
- bmcgo/codegen/lua/templates/apps/datas.lua.mako +8 -0
- bmcgo/codegen/lua/templates/apps/db.lua.mako +89 -0
- bmcgo/codegen/lua/templates/apps/entry.lua.mako +128 -0
- bmcgo/codegen/lua/templates/apps/feature.lua.mako +37 -0
- bmcgo/codegen/lua/templates/apps/generate_route.mako +25 -0
- bmcgo/codegen/lua/templates/apps/impl_feature.lua.mako +72 -0
- bmcgo/codegen/lua/templates/apps/ipmi.lua.mako +97 -0
- bmcgo/codegen/lua/templates/apps/ipmi_cmd.lua.mako +18 -0
- bmcgo/codegen/lua/templates/apps/ipmi_message.lua.mako +36 -0
- bmcgo/codegen/lua/templates/apps/local_db.lua.mako +263 -0
- bmcgo/codegen/lua/templates/apps/main.lua.mako +25 -0
- bmcgo/codegen/lua/templates/apps/mc.lua.mako +77 -0
- bmcgo/codegen/lua/templates/apps/mdb.lua.mako +45 -0
- bmcgo/codegen/lua/templates/apps/mdb_interface.lua.mako +73 -0
- bmcgo/codegen/lua/templates/apps/message.lua.mako +38 -0
- bmcgo/codegen/lua/templates/apps/model.lua.mako +239 -0
- bmcgo/codegen/lua/templates/apps/orm_classes.lua.mako +16 -0
- bmcgo/codegen/lua/templates/apps/plugin.lua.mako +8 -0
- bmcgo/codegen/lua/templates/apps/redfish.proto.mako +47 -0
- bmcgo/codegen/lua/templates/apps/service.lua.mako +440 -0
- bmcgo/codegen/lua/templates/apps/signal_listen.lua.mako +19 -0
- bmcgo/codegen/lua/templates/apps/utils/default_intf.lua.mako +41 -0
- bmcgo/codegen/lua/templates/apps/utils/enum.mako +10 -0
- bmcgo/codegen/lua/templates/apps/utils/imports.mako +13 -0
- bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +25 -0
- bmcgo/codegen/lua/templates/apps/utils/mdb_obj.lua.mako +23 -0
- bmcgo/codegen/lua/templates/apps/utils/message.mako +160 -0
- bmcgo/codegen/lua/templates/apps/utils/request.lua.mako +59 -0
- bmcgo/codegen/lua/templates/apps/utils/validate.mako +83 -0
- bmcgo/codegen/lua/templates/errors.lua.mako +36 -0
- bmcgo/codegen/lua/templates/messages.lua.mako +32 -0
- bmcgo/codegen/lua/templates/new_app/.clang-format.mako +170 -0
- bmcgo/codegen/lua/templates/new_app/.gitignore.mako +26 -0
- bmcgo/codegen/lua/templates/new_app/CHANGELOG.md.mako +0 -0
- bmcgo/codegen/lua/templates/new_app/CMakeLists.txt.mako +29 -0
- bmcgo/codegen/lua/templates/new_app/Makefile.mako +25 -0
- bmcgo/codegen/lua/templates/new_app/README.md.mako +0 -0
- bmcgo/codegen/lua/templates/new_app/conanfile.py.mako +7 -0
- bmcgo/codegen/lua/templates/new_app/config.cfg.mako +6 -0
- bmcgo/codegen/lua/templates/new_app/mds/model.json.mako +3 -0
- bmcgo/codegen/lua/templates/new_app/mds/service.json.mako +21 -0
- bmcgo/codegen/lua/templates/new_app/permissions.ini.mako +16 -0
- bmcgo/codegen/lua/templates/new_app/src/lualib/${project_name}_app.lua.mako +16 -0
- bmcgo/codegen/lua/templates/new_app/src/service/main.lua.mako +25 -0
- bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.conf.mako +9 -0
- bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.lua.mako +47 -0
- bmcgo/codegen/lua/templates/new_app/test/unit/test.lua.mako +23 -0
- bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/${project_name}.service.mako +18 -0
- bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/multi-user.target.wants/${project_name}.service.link +1 -0
- bmcgo/component/__init__.py +10 -0
- bmcgo/component/analysis/analysis.py +183 -0
- bmcgo/component/analysis/build_deps.py +165 -0
- bmcgo/component/analysis/data_deps.py +333 -0
- bmcgo/component/analysis/dep-rules.json +912 -0
- bmcgo/component/analysis/dep_node.py +110 -0
- bmcgo/component/analysis/intf_deps.py +163 -0
- bmcgo/component/analysis/intf_validation.py +254 -0
- bmcgo/component/analysis/rule.py +211 -0
- bmcgo/component/analysis/smc_dfx_whitelist.json +11 -0
- bmcgo/component/analysis/sr_validation.py +391 -0
- bmcgo/component/build.py +222 -0
- bmcgo/component/component_dt_version_parse.py +348 -0
- bmcgo/component/component_helper.py +114 -0
- bmcgo/component/coverage/__init__.py +11 -0
- bmcgo/component/coverage/c_incremental_cov_report.template +53 -0
- bmcgo/component/coverage/incremental_cov.py +464 -0
- bmcgo/component/deploy.py +110 -0
- bmcgo/component/gen.py +169 -0
- bmcgo/component/package_info.py +236 -0
- bmcgo/component/template/conanbase.py.mako +278 -0
- bmcgo/component/template/conanfile.deploy.py.mako +40 -0
- bmcgo/component/test.py +947 -0
- bmcgo/errors.py +119 -0
- bmcgo/frame.py +217 -0
- bmcgo/functional/__init__.py +10 -0
- bmcgo/functional/analysis.py +96 -0
- bmcgo/functional/bmc_studio_action.py +98 -0
- bmcgo/functional/check.py +185 -0
- bmcgo/functional/conan_index_build.py +251 -0
- bmcgo/functional/config.py +332 -0
- bmcgo/functional/csr_build.py +724 -0
- bmcgo/functional/deploy.py +263 -0
- bmcgo/functional/diff.py +235 -0
- bmcgo/functional/fetch.py +235 -0
- bmcgo/functional/full_component.py +391 -0
- bmcgo/functional/maintain.py +381 -0
- bmcgo/functional/new.py +166 -0
- bmcgo/functional/schema_valid.py +111 -0
- bmcgo/functional/simple_sign.py +104 -0
- bmcgo/functional/upgrade.py +78 -0
- bmcgo/ipmigen/__init__.py +13 -0
- bmcgo/ipmigen/ctype_defination.py +82 -0
- bmcgo/ipmigen/ipmigen.py +309 -0
- bmcgo/ipmigen/template/cmd.c.mako +366 -0
- bmcgo/ipmigen/template/ipmi.c.mako +25 -0
- bmcgo/ipmigen/template/ipmi.h.mako +51 -0
- bmcgo/logger.py +176 -0
- bmcgo/misc.py +117 -0
- bmcgo/target/app.yml +17 -0
- bmcgo/target/install_sdk.yml +15 -0
- bmcgo/target/personal.yml +53 -0
- bmcgo/target/publish.yml +45 -0
- bmcgo/tasks/__init__.py +11 -0
- bmcgo/tasks/download_buildtools_hm.py +124 -0
- bmcgo/tasks/misc.py +15 -0
- bmcgo/tasks/task.py +354 -0
- bmcgo/tasks/task_build_conan.py +714 -0
- bmcgo/tasks/task_build_rootfs_img.py +595 -0
- bmcgo/tasks/task_buildgppbin.py +88 -0
- bmcgo/tasks/task_buildhpm_ext4.py +82 -0
- bmcgo/tasks/task_create_interface_config.py +122 -0
- bmcgo/tasks/task_download_buildtools.py +99 -0
- bmcgo/tasks/task_download_dependency.py +72 -0
- bmcgo/tasks/task_hpm_envir_prepare.py +112 -0
- bmcgo/tasks/task_packet_to_supporte.py +87 -0
- bmcgo/tasks/task_prepare.py +105 -0
- bmcgo/tasks/task_sign_and_pack_hpm.py +42 -0
- bmcgo/utils/__init__.py +10 -0
- bmcgo/utils/buffer.py +128 -0
- bmcgo/utils/combine_json_schemas.py +170 -0
- bmcgo/utils/component_post.py +54 -0
- bmcgo/utils/component_version_check.py +86 -0
- bmcgo/utils/config.py +1067 -0
- bmcgo/utils/fetch_component_code.py +232 -0
- bmcgo/utils/install_manager.py +61 -0
- bmcgo/utils/installations/__init__.py +10 -0
- bmcgo/utils/installations/base_installer.py +70 -0
- bmcgo/utils/installations/install_consts.py +30 -0
- bmcgo/utils/installations/install_plans/bingo.yml +11 -0
- bmcgo/utils/installations/install_workflow.py +50 -0
- bmcgo/utils/installations/installers/apt_installer.py +177 -0
- bmcgo/utils/installations/installers/pip_installer.py +46 -0
- bmcgo/utils/installations/version_util.py +100 -0
- bmcgo/utils/mapping_config_patch.py +443 -0
- bmcgo/utils/perf_analysis.py +114 -0
- bmcgo/utils/tools.py +704 -0
- bmcgo/worker.py +417 -0
- openubmc_bingo-0.5.240.dist-info/METADATA +30 -0
- openubmc_bingo-0.5.240.dist-info/RECORD +242 -0
- openubmc_bingo-0.5.240.dist-info/WHEEL +5 -0
- openubmc_bingo-0.5.240.dist-info/entry_points.txt +2 -0
- openubmc_bingo-0.5.240.dist-info/top_level.txt +1 -0
bmcgo/component/test.py
ADDED
|
@@ -0,0 +1,947 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
|
|
4
|
+
# openUBMC is licensed under Mulan PSL v2.
|
|
5
|
+
# You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
6
|
+
# You may obtain a copy of Mulan PSL v2 at:
|
|
7
|
+
# http://license.coscl.org.cn/MulanPSL2
|
|
8
|
+
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
9
|
+
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
10
|
+
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
11
|
+
# See the Mulan PSL v2 for more details.
|
|
12
|
+
import argparse
|
|
13
|
+
import datetime
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
import re
|
|
17
|
+
import subprocess
|
|
18
|
+
import stat
|
|
19
|
+
import textwrap
|
|
20
|
+
import xml.etree.ElementTree as ET
|
|
21
|
+
import shutil
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from bmcgo import misc
|
|
25
|
+
from bmcgo.logger import Logger
|
|
26
|
+
from bmcgo.component.deploy import DeployComp
|
|
27
|
+
from bmcgo.component.build import BuildComp
|
|
28
|
+
from bmcgo.component.package_info import InfoComp
|
|
29
|
+
from bmcgo.component.gen import GenComp
|
|
30
|
+
from bmcgo.codegen.c.helper import Helper
|
|
31
|
+
from bmcgo.component.component_dt_version_parse import ComponentDtVersionParse
|
|
32
|
+
from bmcgo.component.coverage.incremental_cov import IncrementalCov
|
|
33
|
+
from bmcgo.bmcgo_config import BmcgoConfig
|
|
34
|
+
from bmcgo.utils.tools import Tools
|
|
35
|
+
from bmcgo.errors import BmcGoException
|
|
36
|
+
|
|
37
|
+
log = Logger("comp_test")
|
|
38
|
+
cwd = os.getcwd()
|
|
39
|
+
cwd_script = os.path.split(os.path.realpath(__file__))[0]
|
|
40
|
+
TOTAL_TIME = "totaltime"
|
|
41
|
+
HIT_LINES = "hitlines"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestFailedError(OSError):
|
|
45
|
+
"""测试失败"""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TestComp():
|
|
49
|
+
def __init__(self, bconfig: BmcgoConfig, args=None):
|
|
50
|
+
self.bconfig = bconfig
|
|
51
|
+
self.folder = bconfig.component.folder
|
|
52
|
+
self.tools = Tools()
|
|
53
|
+
os.chdir(self.folder)
|
|
54
|
+
# 路径定义
|
|
55
|
+
self._path_define()
|
|
56
|
+
|
|
57
|
+
parser = self.arg_parser(True)
|
|
58
|
+
# 参数检查
|
|
59
|
+
dt_parser = ComponentDtVersionParse(parser=parser, args=args, serv_file=self.temp_service_json)
|
|
60
|
+
dt_parser.chose_dt_mode()
|
|
61
|
+
self.args, self.build_args = parser.parse_known_args(args)
|
|
62
|
+
if self.args.enable_luajit:
|
|
63
|
+
self.build_args.append("-jit")
|
|
64
|
+
self.build_args.append("-bt")
|
|
65
|
+
self.build_args.append("dt")
|
|
66
|
+
self.build_args.append("-r")
|
|
67
|
+
self.build_args.append(self.args.remote)
|
|
68
|
+
if self.args.coverage:
|
|
69
|
+
self.build_args.append("-cov")
|
|
70
|
+
if self.args.asan:
|
|
71
|
+
self.build_args.append("-as")
|
|
72
|
+
|
|
73
|
+
self.info = InfoComp(self.build_args, self.temp_service_json)
|
|
74
|
+
self.unit_test = self.args.unit_test
|
|
75
|
+
self.integration_test = self.args.integration_test
|
|
76
|
+
self.test_filter = self.args.test_filter
|
|
77
|
+
self.app = self.args.app
|
|
78
|
+
self.asan = self.args.asan
|
|
79
|
+
self.coverage = self.args.coverage # 根据入参配置是否显示覆盖率未
|
|
80
|
+
self.without_build = self.args.without_build
|
|
81
|
+
self.coverage_exclude = self.args.coverage_exclude
|
|
82
|
+
self.ut_output = None
|
|
83
|
+
self.it_output = None
|
|
84
|
+
self.fuzz_output = None
|
|
85
|
+
self.dt_result = {}
|
|
86
|
+
# 存在test_package目录的组件由conan拉起DT测试
|
|
87
|
+
self.test_by_conan = os.path.isdir("test_package")
|
|
88
|
+
# 文件名称定义
|
|
89
|
+
self.origin_cov = "luacov.stats.out"
|
|
90
|
+
self.cov_filter = "luacov.stats.filter"
|
|
91
|
+
self.cov_report = "luacov.report.html"
|
|
92
|
+
# dt-fuzz定义
|
|
93
|
+
self.fuzz_test = self.args.fuzz_test
|
|
94
|
+
self.fuzz_gen = self.args.fuzz_gen
|
|
95
|
+
self.fuzz_count = self.args.fuzz_count
|
|
96
|
+
self.dtframe = os.path.join(self.temp_path, "dtframeforlua")
|
|
97
|
+
|
|
98
|
+
# 构建阶段检查
|
|
99
|
+
self.remote_pkg_list = []
|
|
100
|
+
# prerelease默认为空
|
|
101
|
+
|
|
102
|
+
self.srv_file = os.path.join(cwd, "mds", "service.json")
|
|
103
|
+
|
|
104
|
+
# 获取包名,默认取deps目录下的第一个目录名
|
|
105
|
+
self.package_id = ""
|
|
106
|
+
log.info("===>>>包名: %s", self.info.package)
|
|
107
|
+
|
|
108
|
+
self.current_app = self.info.name
|
|
109
|
+
# 初始化DT字典
|
|
110
|
+
self.init_dt_result_dict()
|
|
111
|
+
|
|
112
|
+
# 构建和部署对象
|
|
113
|
+
self.build = BuildComp(bconfig, self.build_args, service_json=self.temp_service_json)
|
|
114
|
+
self.deploy = DeployComp(bconfig, self.build.info)
|
|
115
|
+
self.current_app = self.build.info.name
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def arg_parser(add_help=False):
|
|
119
|
+
pkg_parser = InfoComp.arg_parser()
|
|
120
|
+
parser = argparse.ArgumentParser(description="Test component", parents=[pkg_parser], add_help=add_help)
|
|
121
|
+
parser.add_argument("-ut", "--unit_test", help="Enable unit test", action=misc.STORE_TRUE)
|
|
122
|
+
parser.add_argument("-it", "--integration_test", help="Enable integration test", action=misc.STORE_TRUE)
|
|
123
|
+
parser.add_argument("-ft", "--fuzz_test", help="Enable fuzz test", action=misc.STORE_TRUE)
|
|
124
|
+
parser.add_argument("-fg", "--fuzz_gen", help="Generate fuzz case", action=misc.STORE_TRUE)
|
|
125
|
+
parser.add_argument("-cnt", "--fuzz_count", help="Fuzz count", required=False, type=int, default=100000)
|
|
126
|
+
parser.add_argument("-f", "--test_filter", help="Run unit test with a filter", required=False, default='.')
|
|
127
|
+
parser.add_argument("-a", "--app", help="App in hica", required=False, default='all')
|
|
128
|
+
parser.add_argument("-wb", "--without_build", help="测试时不重新构建", action=misc.STORE_TRUE)
|
|
129
|
+
parser.add_argument("--coverage_exclude", help="Specify coverage exclude file path of whitelist",
|
|
130
|
+
required=False, default="")
|
|
131
|
+
return parser
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def is_method_covered(next_line):
|
|
135
|
+
pattern = re.compile("data-hits")
|
|
136
|
+
match = re.search(pattern, next_line)
|
|
137
|
+
if match is not None:
|
|
138
|
+
return True
|
|
139
|
+
else:
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def find_method(line_str):
|
|
144
|
+
pattern = re.compile(":(Impl[\w]+)\(.*</span>")
|
|
145
|
+
match = re.search(pattern, line_str)
|
|
146
|
+
if match is not None:
|
|
147
|
+
return match.group(1)
|
|
148
|
+
else:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def search_test_config(test_path):
|
|
153
|
+
config_list = []
|
|
154
|
+
# 遍历路径, 搜索.conf文件
|
|
155
|
+
for path, _, files in os.walk(test_path):
|
|
156
|
+
for file in files:
|
|
157
|
+
if ".conf" in file:
|
|
158
|
+
config_file = os.path.join(path, file)
|
|
159
|
+
config_list.append(config_file)
|
|
160
|
+
return config_list
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def is_common_dep(dep, dt_common_deps):
|
|
164
|
+
for dt_dep in dt_common_deps:
|
|
165
|
+
if dt_dep.split("/")[0] in dep:
|
|
166
|
+
return True
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def reslove_gcov(html_report):
|
|
171
|
+
if not os.path.exists(html_report):
|
|
172
|
+
log.warning("覆盖率报告 %s 不存在, 未运行到C/C++代码, 或执行测试时未使能覆盖率功能", html_report)
|
|
173
|
+
return (0, 0, 0)
|
|
174
|
+
with open(html_report, "r", encoding="utf-8", errors="replace") as fp:
|
|
175
|
+
html_content = fp.read()
|
|
176
|
+
cov_pattern = re.compile(r'<td class="headerCovTableEntryLo">([\d.]+).*%</td>')
|
|
177
|
+
coverage_match = re.search(cov_pattern, html_content)
|
|
178
|
+
coverage = coverage_match.group(1) if coverage_match else 0
|
|
179
|
+
|
|
180
|
+
# 匹配total和hits
|
|
181
|
+
pattern = r'<td class="headerCovTableEntry">(\d+)</td>'
|
|
182
|
+
matches = re.findall(pattern, html_content)
|
|
183
|
+
if len(matches) >= 2:
|
|
184
|
+
first_number = int(matches[0])
|
|
185
|
+
second_number = int(matches[1])
|
|
186
|
+
# 较大的数字是 total_lines
|
|
187
|
+
total_lines = max(first_number, second_number)
|
|
188
|
+
# 较小的数字是 hit_lines
|
|
189
|
+
hit_lines = min(first_number, second_number)
|
|
190
|
+
else:
|
|
191
|
+
total_lines = 0
|
|
192
|
+
hit_lines = 0
|
|
193
|
+
missed_lines = total_lines - hit_lines
|
|
194
|
+
return (f"{coverage}%", hit_lines, missed_lines)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def _clear_result(file):
|
|
199
|
+
if not os.path.isfile(file):
|
|
200
|
+
return
|
|
201
|
+
fp = os.fdopen(os.open(file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
202
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w')
|
|
203
|
+
fp.close()
|
|
204
|
+
|
|
205
|
+
@staticmethod
|
|
206
|
+
def _get_c_test_results(output_xmls):
|
|
207
|
+
results = []
|
|
208
|
+
total = 0
|
|
209
|
+
failed = 0
|
|
210
|
+
duration = 0
|
|
211
|
+
status_dict = {"success": "ok", "failed": "not ok"}
|
|
212
|
+
ljust_width = 7
|
|
213
|
+
for output_xml in output_xmls:
|
|
214
|
+
tree = ET.parse(output_xml)
|
|
215
|
+
for testcase_element in tree.iter(tag="testcase"):
|
|
216
|
+
status_element = testcase_element.find("status")
|
|
217
|
+
if status_element is None:
|
|
218
|
+
continue
|
|
219
|
+
duration_element = testcase_element.find("duration")
|
|
220
|
+
name = testcase_element.get("path")
|
|
221
|
+
result = status_element.get("result")
|
|
222
|
+
duration += float(0 if duration_element is None else duration_element.text)
|
|
223
|
+
total += 1
|
|
224
|
+
test_result = str(status_dict.get(result, "")).ljust(ljust_width)
|
|
225
|
+
results.append(f"{test_result} {str(total).ljust(ljust_width)} {name}")
|
|
226
|
+
failed += 1 if result == "failed" else 0
|
|
227
|
+
error_element = testcase_element.find("error")
|
|
228
|
+
if error_element is not None:
|
|
229
|
+
error = error_element.text
|
|
230
|
+
results.append(f"# {error}")
|
|
231
|
+
if results:
|
|
232
|
+
summary = f"# Ran {total} tests in {duration:.3f} seconds, {total - failed} successes, {failed} failures"
|
|
233
|
+
results.append(summary)
|
|
234
|
+
|
|
235
|
+
return results
|
|
236
|
+
|
|
237
|
+
def get_excluded_files_on_key(self, lang):
|
|
238
|
+
if not self.coverage_exclude:
|
|
239
|
+
return []
|
|
240
|
+
|
|
241
|
+
component_name = self.current_app
|
|
242
|
+
cov_exclude_path = os.path.realpath(os.path.join(cwd, self.coverage_exclude))
|
|
243
|
+
try:
|
|
244
|
+
with open(cov_exclude_path, 'r') as file:
|
|
245
|
+
excluded_data = json.load(file)
|
|
246
|
+
except FileNotFoundError as exc:
|
|
247
|
+
raise BmcGoException(f"File not found: {cov_exclude_path}") from exc
|
|
248
|
+
except json.JSONDecodeError:
|
|
249
|
+
log.info(f"Failed to decode JSON from file: {cov_exclude_path}")
|
|
250
|
+
return []
|
|
251
|
+
|
|
252
|
+
# 基于语言筛选白名单文件
|
|
253
|
+
excluded_files = []
|
|
254
|
+
if component_name in excluded_data:
|
|
255
|
+
excluded_files.extend(excluded_data[component_name][lang])
|
|
256
|
+
|
|
257
|
+
return excluded_files
|
|
258
|
+
|
|
259
|
+
def write_commponent_deps(self, deps, dt_common_deps, mf_file, uc_code, prefix):
|
|
260
|
+
# 获取组件自身配置的依赖列表
|
|
261
|
+
for dep in deps:
|
|
262
|
+
conan = dep.get(misc.CONAN)
|
|
263
|
+
if conan is None:
|
|
264
|
+
log.error("依赖格式错误, 获取到: %s", dep)
|
|
265
|
+
elif not self.is_common_dep(conan, dt_common_deps):
|
|
266
|
+
# 写入组件配置的非DT公共依赖
|
|
267
|
+
if "@" not in conan:
|
|
268
|
+
write_dep = prefix + '"' + conan + uc_code + '"' + "\n"
|
|
269
|
+
else:
|
|
270
|
+
write_dep = prefix + '"' + conan + '"' + "\n"
|
|
271
|
+
mf_file.write(write_dep)
|
|
272
|
+
|
|
273
|
+
def build_and_deploy(self):
|
|
274
|
+
# 构建被测组件
|
|
275
|
+
self.build.run()
|
|
276
|
+
os.chdir(self.folder)
|
|
277
|
+
# 部署被测组件及其依赖到temp/rootfs目录
|
|
278
|
+
self.deploy.run()
|
|
279
|
+
os.chdir(self.folder)
|
|
280
|
+
|
|
281
|
+
def coverage_config(self, project_root, cov_path, app):
|
|
282
|
+
log.info("配置覆盖率报告选项")
|
|
283
|
+
if app is not None:
|
|
284
|
+
app_path = "apps/" + app + "/"
|
|
285
|
+
else:
|
|
286
|
+
app_path = ""
|
|
287
|
+
|
|
288
|
+
# 获取需要屏蔽的.lua文件
|
|
289
|
+
lua_exclusion = self.get_excluded_files_on_key("LUA_EXCLUDED")
|
|
290
|
+
lua_x = []
|
|
291
|
+
# luacov规则,移除.lua拓展名
|
|
292
|
+
for file in lua_exclusion:
|
|
293
|
+
if file.endswith('.lua'):
|
|
294
|
+
file = file[:-4]
|
|
295
|
+
lua_x.append(file)
|
|
296
|
+
|
|
297
|
+
# 默认屏蔽test和temp目录下的文件
|
|
298
|
+
lua_exclusions = [f'"{app_path}{file}"' for file in lua_x]
|
|
299
|
+
exclusions = [f'"{project_root}test/.*"', f'"{project_root}temp/.*"'] + lua_exclusions
|
|
300
|
+
|
|
301
|
+
# 用textwrap格式化配置信息
|
|
302
|
+
config_str = textwrap.dedent(f"""
|
|
303
|
+
return {{
|
|
304
|
+
include = {{"{app_path}src/.*"}},
|
|
305
|
+
exclude = {{{', '.join(exclusions)}}},
|
|
306
|
+
statsfile = "{cov_path}/{self.origin_cov}",
|
|
307
|
+
coverage_filter = "{cov_path}/{self.cov_filter}",
|
|
308
|
+
reporter = "html",
|
|
309
|
+
reportfile = "{cov_path}/{self.cov_report}",
|
|
310
|
+
includeuntestedfiles = {{"{project_root}/src"}}
|
|
311
|
+
}}
|
|
312
|
+
""").strip()
|
|
313
|
+
|
|
314
|
+
if not os.path.exists(cov_path):
|
|
315
|
+
os.makedirs(cov_path)
|
|
316
|
+
# 重写默认的defaults.lua文件
|
|
317
|
+
with os.fdopen(os.open(self.cov_config, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
318
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file:
|
|
319
|
+
file.write(config_str)
|
|
320
|
+
|
|
321
|
+
def prepare_dlclose(self):
|
|
322
|
+
stub_code = textwrap.dedent('''\
|
|
323
|
+
#include <stdio.h>
|
|
324
|
+
int dlclose(void *handle)
|
|
325
|
+
{
|
|
326
|
+
return 0;
|
|
327
|
+
}
|
|
328
|
+
''')
|
|
329
|
+
|
|
330
|
+
os.makedirs(self.asan_path, exist_ok=True)
|
|
331
|
+
source_file = os.path.join(self.asan_path, "dlclose.c")
|
|
332
|
+
# 创建打桩文件并编译为so
|
|
333
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
|
334
|
+
mode = stat.S_IRUSR | stat.S_IWUSR
|
|
335
|
+
with os.fdopen(os.open(source_file, flags, mode), 'w') as f:
|
|
336
|
+
f.write(stub_code)
|
|
337
|
+
cmd = ["gcc", source_file, "-shared", "-fPIC", "-o", self.dlclose_path]
|
|
338
|
+
subprocess.run(cmd)
|
|
339
|
+
|
|
340
|
+
def check_asan_log(self):
|
|
341
|
+
files = os.listdir(self.asan_path)
|
|
342
|
+
asanlog_exist = False
|
|
343
|
+
for f in files:
|
|
344
|
+
if "asan.log" in f:
|
|
345
|
+
asanlog_exist = True
|
|
346
|
+
asan_log = os.path.join(self.asan_path, f)
|
|
347
|
+
# 备份日志到coverage路径下,便于看板或门禁下载
|
|
348
|
+
shutil.copy(asan_log, self.cov_path)
|
|
349
|
+
log.warning("地址消毒检测到内存问题, 日志保存到 %s", asan_log)
|
|
350
|
+
if asanlog_exist:
|
|
351
|
+
raise OSError("检测到内存问题, 请检查地址消毒日志!")
|
|
352
|
+
|
|
353
|
+
def clear_asan_log(self):
|
|
354
|
+
files = os.listdir(self.asan_path)
|
|
355
|
+
for f in files:
|
|
356
|
+
if "asan.log" in f:
|
|
357
|
+
os.remove(os.path.join(self.asan_path, f))
|
|
358
|
+
|
|
359
|
+
def set_additional_env(self, test_env, project_root, project_name):
|
|
360
|
+
test_env["PROJECT_DIR"] = project_root
|
|
361
|
+
test_env["PROJECT_NAME"] = project_name
|
|
362
|
+
if self.fuzz_test:
|
|
363
|
+
test_env["LD_PRELOAD"] = self.preload_option
|
|
364
|
+
test_env["ASAN_OPTIONS"] = "detect_leaks=0"
|
|
365
|
+
if self.coverage:
|
|
366
|
+
test_env["LUA_PATH"] = self.luacov_env
|
|
367
|
+
test_env["LUA_CPATH"] = self.luafilesystem
|
|
368
|
+
if self.asan:
|
|
369
|
+
self.prepare_dlclose()
|
|
370
|
+
self.clear_asan_log()
|
|
371
|
+
test_env["LD_PRELOAD"] = self.preload_option
|
|
372
|
+
test_env["ASAN_OPTIONS"] = "halt_on_error=0:detect_leaks=1:log_path={}".format(self.asan_log)
|
|
373
|
+
|
|
374
|
+
def set_unit_test_cmd(self, test_entry):
|
|
375
|
+
if self.coverage:
|
|
376
|
+
ut_cmd = [self.lua_bin, "-lluacov", test_entry, "-v", "-o", "TAP", "-p", self.test_filter]
|
|
377
|
+
else:
|
|
378
|
+
ut_cmd = [self.lua_bin, test_entry, "-v", "-o", "TAP", "-p", self.test_filter]
|
|
379
|
+
return ut_cmd
|
|
380
|
+
|
|
381
|
+
def add_luacov_to_config(self):
|
|
382
|
+
log.info("添加 luacov 路径到 %s", self.test_config)
|
|
383
|
+
with open(self.test_config, "r") as file:
|
|
384
|
+
search_str = ' self:add_lua_path(self.apps_root .. "?/init.lua")\n'
|
|
385
|
+
insert_str = ' self:add_lua_path(self.bmc_root .. "lualib/luacov/?.lua")\n'
|
|
386
|
+
lines = file.readlines()
|
|
387
|
+
if insert_str in lines:
|
|
388
|
+
return
|
|
389
|
+
insert_index = lines.index(search_str)
|
|
390
|
+
lines.insert(insert_index + 1, insert_str)
|
|
391
|
+
write_str = "".join(lines)
|
|
392
|
+
with os.fdopen(os.open(self.test_config, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
393
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file:
|
|
394
|
+
file.write(write_str)
|
|
395
|
+
|
|
396
|
+
def add_luacov_to_preloader(self):
|
|
397
|
+
preloader_dir = os.path.dirname(self.preloader)
|
|
398
|
+
preloader_wrapper = "app_preloader_wrapper.lua"
|
|
399
|
+
preloader_wrapper_path = os.path.join(preloader_dir, preloader_wrapper)
|
|
400
|
+
log.info("添加 luacov 依赖到 %s", preloader_wrapper_path)
|
|
401
|
+
with os.fdopen(os.open(preloader_wrapper_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
402
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file:
|
|
403
|
+
preloader_path = Path(self.preloader)
|
|
404
|
+
preloader_name = preloader_path.stem
|
|
405
|
+
preloader_module_name = os.path.basename(preloader_path.parent)
|
|
406
|
+
# luacov 需要在最前面先加载
|
|
407
|
+
file.write("require 'luacov'\n")
|
|
408
|
+
file.write(f"require '{preloader_module_name}.{preloader_name}'\n")
|
|
409
|
+
|
|
410
|
+
preloader = os.path.basename(self.preloader)
|
|
411
|
+
log.info(f"{self.test_config}加载{preloader}替换为{preloader_wrapper}")
|
|
412
|
+
self.tools.run_command(f"sed -i 's#{preloader}#{preloader_wrapper}#g' {self.test_config}")
|
|
413
|
+
|
|
414
|
+
def run_cmd_and_save_result(self, cmd, env, savefile):
|
|
415
|
+
# 保存当前所在工作目录信息
|
|
416
|
+
where = os.getcwd()
|
|
417
|
+
if os.path.exists("apps"):
|
|
418
|
+
app_path = os.path.join(self.folder, "apps", self.current_app)
|
|
419
|
+
output_dir = os.path.join(self.cov_path, self.current_app, "output")
|
|
420
|
+
# 切换到apps目录下对应的app路径
|
|
421
|
+
os.chdir(app_path)
|
|
422
|
+
else:
|
|
423
|
+
output_dir = os.path.join(self.cov_path, "output")
|
|
424
|
+
if not os.path.exists(output_dir):
|
|
425
|
+
os.makedirs(output_dir)
|
|
426
|
+
try:
|
|
427
|
+
file = os.fdopen(os.open(savefile, os.O_WRONLY | os.O_CREAT | os.O_APPEND,
|
|
428
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w')
|
|
429
|
+
tail_p = subprocess.Popen(["/usr/bin/tail", "-f", savefile])
|
|
430
|
+
process = subprocess.run(cmd, env=env, stdout=file, universal_newlines=True,
|
|
431
|
+
encoding="utf-8", errors="replace")
|
|
432
|
+
finally:
|
|
433
|
+
tail_p.kill()
|
|
434
|
+
file.close()
|
|
435
|
+
if process.returncode != 0:
|
|
436
|
+
raise subprocess.CalledProcessError(process.returncode, process.args)
|
|
437
|
+
# 返回到之前工作目录(主要用于hica场景,独立仓不受影响)
|
|
438
|
+
os.chdir(where)
|
|
439
|
+
|
|
440
|
+
def init_dt_result_dict(self):
|
|
441
|
+
self.dt_result[self.current_app] = {}
|
|
442
|
+
self.dt_result[self.current_app][HIT_LINES] = 0
|
|
443
|
+
self.dt_result[self.current_app]["missedlines"] = 0
|
|
444
|
+
self.dt_result[self.current_app]["linecoverage"] = ""
|
|
445
|
+
self.dt_result[self.current_app]["tests"] = 0
|
|
446
|
+
self.dt_result[self.current_app]["failures"] = 0
|
|
447
|
+
self.dt_result[self.current_app]["successes"] = 0
|
|
448
|
+
self.dt_result[self.current_app][TOTAL_TIME] = 0
|
|
449
|
+
self.dt_result[self.current_app]["uttime"] = 0.0
|
|
450
|
+
self.dt_result[self.current_app]["ittime"] = 0
|
|
451
|
+
self.dt_result[self.current_app]["lua_hitlines"] = 0
|
|
452
|
+
self.dt_result[self.current_app]["lua_missedlines"] = 0
|
|
453
|
+
self.dt_result[self.current_app]["lua_linecoverage"] = ""
|
|
454
|
+
self.dt_result[self.current_app]["gcov_hitlines"] = 0
|
|
455
|
+
self.dt_result[self.current_app]["gcov_missedlines"] = 0
|
|
456
|
+
self.dt_result[self.current_app]["gcov_linecoverage"] = ""
|
|
457
|
+
self.dt_result[self.current_app]["method_coverage"] = ""
|
|
458
|
+
self.dt_result[self.current_app]["total_method_count"] = 0
|
|
459
|
+
self.dt_result[self.current_app]["covered_method"] = []
|
|
460
|
+
self.dt_result[self.current_app]["covered_method_count"] = 0
|
|
461
|
+
self.dt_result[self.current_app]["uncovered_method"] = []
|
|
462
|
+
self.dt_result[self.current_app]["uncovered_method_count"] = 0
|
|
463
|
+
|
|
464
|
+
def parse_ut_result(self):
|
|
465
|
+
with open(self.ut_output) as file:
|
|
466
|
+
pattern = re.compile("# Ran (.*) tests in (.*) seconds, (.*) success(?:es)?, (.*) failures")
|
|
467
|
+
lines = file.readlines()
|
|
468
|
+
match = re.search(pattern, lines[-1])
|
|
469
|
+
if match is not None:
|
|
470
|
+
self.dt_result[self.current_app]["tests"] = int(match.group(1))
|
|
471
|
+
self.dt_result[self.current_app]["uttime"] = float(match.group(2))
|
|
472
|
+
self.dt_result[self.current_app]["successes"] = int(match.group(3))
|
|
473
|
+
self.dt_result[self.current_app]["failures"] = int(match.group(4))
|
|
474
|
+
else:
|
|
475
|
+
log.info("分析单元测试结果失败!")
|
|
476
|
+
|
|
477
|
+
def save_dt_result(self, destdir):
|
|
478
|
+
dt_result = os.path.join(destdir, "dt_result.json")
|
|
479
|
+
if self.app != "all" and os.path.exists("apps"):
|
|
480
|
+
# hica单个app运行时进行结果追加
|
|
481
|
+
if os.path.exists(dt_result):
|
|
482
|
+
file = open(dt_result, "r")
|
|
483
|
+
current_json = json.load(file)
|
|
484
|
+
file.close()
|
|
485
|
+
else:
|
|
486
|
+
current_json = {}
|
|
487
|
+
current_json.update(self.dt_result)
|
|
488
|
+
json_str = json.dumps(current_json, indent=4)
|
|
489
|
+
else:
|
|
490
|
+
# 独立自仓或hica运行所有app时一次写入
|
|
491
|
+
json_str = json.dumps(self.dt_result, indent=4)
|
|
492
|
+
|
|
493
|
+
with os.fdopen(os.open(dt_result, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
494
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file:
|
|
495
|
+
file.write(json_str)
|
|
496
|
+
log.info("Dt 报告结果输出到 %s", dt_result)
|
|
497
|
+
|
|
498
|
+
def start_test_by_type(self, ut_cmd, config_list, test_env):
|
|
499
|
+
self.init_dt_result_dict()
|
|
500
|
+
cov_path = self.cov_path if not os.path.exists("apps") else os.path.join(self.cov_path, self.current_app)
|
|
501
|
+
output_dir = os.path.join(cov_path, "output")
|
|
502
|
+
self.ut_output = os.path.join(output_dir, "ut_output.txt")
|
|
503
|
+
self.it_output = os.path.join(output_dir, "it_output.txt")
|
|
504
|
+
self.fuzz_output = os.path.join(output_dir, "fuzz_output.txt")
|
|
505
|
+
|
|
506
|
+
# 根据测试类型启动DT测试
|
|
507
|
+
if self.unit_test and not self.integration_test:
|
|
508
|
+
self._clear_result(self.ut_output)
|
|
509
|
+
self.run_cmd_and_save_result(ut_cmd, test_env, self.ut_output)
|
|
510
|
+
self.parse_ut_result()
|
|
511
|
+
self.dt_result[self.current_app][TOTAL_TIME] = self.dt_result[self.current_app]["uttime"]
|
|
512
|
+
elif self.integration_test and not self.unit_test:
|
|
513
|
+
self._clear_result(self.ut_output)
|
|
514
|
+
# 集成测试存在多个conf文件场景
|
|
515
|
+
start = datetime.datetime.utcnow()
|
|
516
|
+
for config in config_list:
|
|
517
|
+
log.info("集成测试配置: %s", config)
|
|
518
|
+
self.run_cmd_and_save_result([self.skynet_path, config], test_env, self.it_output)
|
|
519
|
+
end = datetime.datetime.utcnow()
|
|
520
|
+
it_time = (end - start).seconds
|
|
521
|
+
self.dt_result[self.current_app]["ittime"] = it_time
|
|
522
|
+
self.dt_result[self.current_app][TOTAL_TIME] = it_time
|
|
523
|
+
elif self.integration_test and self.unit_test:
|
|
524
|
+
# 先运行单元测试
|
|
525
|
+
self._clear_result(self.ut_output)
|
|
526
|
+
self.run_cmd_and_save_result(ut_cmd, test_env, self.ut_output)
|
|
527
|
+
self.parse_ut_result()
|
|
528
|
+
# 再运行集成测试
|
|
529
|
+
self._clear_result(self.it_output)
|
|
530
|
+
log.info("================ 集成测试开始 ================")
|
|
531
|
+
start = datetime.datetime.utcnow()
|
|
532
|
+
for config in config_list:
|
|
533
|
+
log.info("集成测试配置: %s", config)
|
|
534
|
+
self.run_cmd_and_save_result([self.skynet_path, config], test_env, self.it_output)
|
|
535
|
+
end = datetime.datetime.utcnow()
|
|
536
|
+
it_time = (end - start).seconds
|
|
537
|
+
self.dt_result[self.current_app]["ittime"] = it_time
|
|
538
|
+
self.dt_result[self.current_app][TOTAL_TIME] = it_time + \
|
|
539
|
+
self.dt_result[self.current_app]["uttime"]
|
|
540
|
+
elif self.fuzz_test:
|
|
541
|
+
self._clear_result(self.fuzz_output)
|
|
542
|
+
fuzz_path = os.path.join(self.folder, "test/fuzz")
|
|
543
|
+
# Fuzz场景只有一个conf文件
|
|
544
|
+
fuzz_config = self.search_test_config(fuzz_path)[0]
|
|
545
|
+
fuzz_cmd = [self.skynet_path, fuzz_config]
|
|
546
|
+
self.run_cmd_and_save_result(fuzz_cmd, test_env, self.fuzz_output)
|
|
547
|
+
|
|
548
|
+
def get_method_coverage(self, lines, index, covered_method, uncovered_method):
|
|
549
|
+
method = self.find_method(lines[index])
|
|
550
|
+
if method is None:
|
|
551
|
+
return
|
|
552
|
+
if self.is_method_covered(lines[index + 1]):
|
|
553
|
+
covered_method.append(method)
|
|
554
|
+
else:
|
|
555
|
+
uncovered_method.append(method)
|
|
556
|
+
|
|
557
|
+
def get_lua_coverage(self, lines, index):
|
|
558
|
+
# 通过行偏移获取总体覆盖率数据
|
|
559
|
+
coverage = lines[index + 7]
|
|
560
|
+
hits = lines[index + 9]
|
|
561
|
+
missed = lines[index + 10]
|
|
562
|
+
pattern = re.compile("<strong>(.*)</strong>")
|
|
563
|
+
match = re.search(pattern, coverage)
|
|
564
|
+
coverage = match.group(1) if match is not None else None
|
|
565
|
+
match = re.search(pattern, hits)
|
|
566
|
+
hits = match.group(1) if match is not None else None
|
|
567
|
+
match = re.search(pattern, missed)
|
|
568
|
+
missed = match.group(1) if match is not None else None
|
|
569
|
+
self.dt_result[self.current_app]["lua_linecoverage"] = coverage
|
|
570
|
+
self.dt_result[self.current_app]["lua_hitlines"] += int(hits)
|
|
571
|
+
self.dt_result[self.current_app]["lua_missedlines"] += int(missed)
|
|
572
|
+
|
|
573
|
+
def reslove_luacov(self, html_report):
|
|
574
|
+
if not os.path.exists(html_report):
|
|
575
|
+
log.error("覆盖率报告 %s 不存在, 执行测试时, 请使能覆盖率功能", html_report)
|
|
576
|
+
return
|
|
577
|
+
covered_method = []
|
|
578
|
+
uncovered_method = []
|
|
579
|
+
with open(html_report, "r", encoding="utf-8", errors="replace") as file:
|
|
580
|
+
lines = file.readlines()
|
|
581
|
+
line_index = 0
|
|
582
|
+
for line in lines:
|
|
583
|
+
if '<main>' in line:
|
|
584
|
+
self.get_lua_coverage(lines, line_index)
|
|
585
|
+
self.get_method_coverage(lines, line_index, covered_method, uncovered_method)
|
|
586
|
+
line_index += 1
|
|
587
|
+
# 汇总method覆盖率信息
|
|
588
|
+
method_count = len(covered_method) + len(uncovered_method)
|
|
589
|
+
if method_count != 0:
|
|
590
|
+
self.dt_result[self.current_app]["method_coverage"] = '%.1d' % (len(covered_method) / method_count)
|
|
591
|
+
self.dt_result[self.current_app]["total_method_count"] = len(covered_method) + len(uncovered_method)
|
|
592
|
+
self.dt_result[self.current_app]["covered_method"] = covered_method
|
|
593
|
+
self.dt_result[self.current_app]["covered_method_count"] = len(covered_method)
|
|
594
|
+
self.dt_result[self.current_app]["uncovered_method"] = uncovered_method
|
|
595
|
+
self.dt_result[self.current_app]["uncovered_method_count"] = len(uncovered_method)
|
|
596
|
+
|
|
597
|
+
def generate_luacov(self, test_env):
|
|
598
|
+
subprocess.run([self.lua_bin, self.luacov_bin], env=test_env)
|
|
599
|
+
self.reslove_luacov(os.path.join(self.cov_path, self.cov_report))
|
|
600
|
+
|
|
601
|
+
def save_package_info(self):
|
|
602
|
+
# 保存package信息,多次构建情况下用于确定唯一的包名
|
|
603
|
+
package_path = os.path.join(self.temp_path, "package_info")
|
|
604
|
+
log.info("保存包信息到 %s", package_path)
|
|
605
|
+
with os.fdopen(os.open(package_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
606
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file:
|
|
607
|
+
file.write(self.info.package)
|
|
608
|
+
|
|
609
|
+
def generate_gcov(self):
|
|
610
|
+
if not self.test_by_conan:
|
|
611
|
+
if not os.path.exists("src/lualib-src"):
|
|
612
|
+
return
|
|
613
|
+
package_path = os.path.join(self.temp_path, "package_info")
|
|
614
|
+
with open(package_path, "r") as file:
|
|
615
|
+
lines = file.readlines()
|
|
616
|
+
package_path = lines[0].replace("@", "/")
|
|
617
|
+
else:
|
|
618
|
+
package_path = self.info.package.replace("@", "/")
|
|
619
|
+
base_dir = "%s/.conan/data/%s" % (os.path.expanduser('~'), package_path)
|
|
620
|
+
gcov_path = os.path.join(self.cov_path, "gcov")
|
|
621
|
+
if not os.path.exists(gcov_path):
|
|
622
|
+
os.makedirs(gcov_path)
|
|
623
|
+
info_file = os.path.join(gcov_path, "gcov.info")
|
|
624
|
+
self.dt_result[self.current_app]["gcov_linecoverage"] = 0
|
|
625
|
+
self.dt_result[self.current_app]["gcov_hitlines"] += 0
|
|
626
|
+
self.dt_result[self.current_app]["gcov_missedlines"] += 0
|
|
627
|
+
# 生成gcov覆盖率数据
|
|
628
|
+
cmd = [
|
|
629
|
+
"lcov",
|
|
630
|
+
"--base-directory",
|
|
631
|
+
base_dir,
|
|
632
|
+
"--directory",
|
|
633
|
+
base_dir,
|
|
634
|
+
"--capture",
|
|
635
|
+
"--output-file",
|
|
636
|
+
info_file,
|
|
637
|
+
"--ignore-errors",
|
|
638
|
+
"unused",
|
|
639
|
+
]
|
|
640
|
+
# exclude files
|
|
641
|
+
exclude = [
|
|
642
|
+
"--exclude=*include*",
|
|
643
|
+
"--exclude=*test*",
|
|
644
|
+
"--exclude=*.h",
|
|
645
|
+
"--exclude=*/service/cli/*",
|
|
646
|
+
"--exclude=*/gen/interface/*"
|
|
647
|
+
]
|
|
648
|
+
|
|
649
|
+
# 获取需要屏蔽的.c/cpp文件
|
|
650
|
+
c_exclusion = self.get_excluded_files_on_key("C_EXCLUDED")
|
|
651
|
+
for file in c_exclusion:
|
|
652
|
+
exclude.append(f"--exclude=*{file}*")
|
|
653
|
+
cmd.extend(exclude)
|
|
654
|
+
|
|
655
|
+
ret = Helper.run(cmd, check=False)
|
|
656
|
+
if ret != 0:
|
|
657
|
+
return
|
|
658
|
+
# 生成html覆盖率报告
|
|
659
|
+
cmd = ["genhtml", "--output-directory", gcov_path, info_file]
|
|
660
|
+
Helper.run(cmd, check=False)
|
|
661
|
+
if ret != 0:
|
|
662
|
+
return
|
|
663
|
+
# resolv coverage
|
|
664
|
+
ret = self.reslove_gcov(os.path.join(self.cov_path, "gcov/index.html"))
|
|
665
|
+
if ret is not None:
|
|
666
|
+
self.dt_result[self.current_app]["gcov_linecoverage"] = ret[0]
|
|
667
|
+
self.dt_result[self.current_app]["gcov_hitlines"] += int(ret[1])
|
|
668
|
+
self.dt_result[self.current_app]["gcov_missedlines"] += int(ret[2])
|
|
669
|
+
|
|
670
|
+
def combine_coverage(self):
|
|
671
|
+
# 将luacov和gcov数据汇总
|
|
672
|
+
self.dt_result[self.current_app][HIT_LINES] = self.dt_result[self.current_app]["lua_hitlines"] + \
|
|
673
|
+
self.dt_result[self.current_app]["gcov_hitlines"]
|
|
674
|
+
self.dt_result[self.current_app]["missedlines"] = self.dt_result[self.current_app]["lua_missedlines"] + \
|
|
675
|
+
self.dt_result[self.current_app]["gcov_missedlines"]
|
|
676
|
+
total_lines = self.dt_result[self.current_app][HIT_LINES] + self.dt_result[self.current_app]["missedlines"]
|
|
677
|
+
if total_lines != 0:
|
|
678
|
+
self.dt_result[self.current_app]["linecoverage"] = "{:.1%}".format(
|
|
679
|
+
self.dt_result[self.current_app][HIT_LINES] / total_lines)
|
|
680
|
+
|
|
681
|
+
def run_independent_test(self, test_env):
|
|
682
|
+
log.info("================ 测试 %s 开始 ================", self.current_app)
|
|
683
|
+
# 配置额外的环境变量
|
|
684
|
+
self.set_additional_env(test_env, self.folder, self.current_app)
|
|
685
|
+
test_entry = os.path.join(self.folder, "test/unit/test.lua")
|
|
686
|
+
itegration_path = os.path.join(self.folder, "test/integration")
|
|
687
|
+
# 获取集成测试配置文件列表
|
|
688
|
+
config_list = self.search_test_config(itegration_path)
|
|
689
|
+
# 设置覆盖率配置文件
|
|
690
|
+
if self.coverage:
|
|
691
|
+
self.coverage_config(self.folder, self.cov_path, None)
|
|
692
|
+
# 设置unit_test运行命令
|
|
693
|
+
ut_cmd = self.set_unit_test_cmd(test_entry)
|
|
694
|
+
# 集成测试场景修改config.cfg和app_preloader.lua
|
|
695
|
+
if (self.integration_test or self.fuzz_test) and self.coverage:
|
|
696
|
+
# config.cfg中增加luacov路径到LUA_PATH
|
|
697
|
+
self.add_luacov_to_config()
|
|
698
|
+
# app_preloader.lua中增加require 'luacov'
|
|
699
|
+
self.add_luacov_to_preloader()
|
|
700
|
+
# 启动DT测试
|
|
701
|
+
self.start_test_by_type(ut_cmd, config_list, test_env)
|
|
702
|
+
# 生成覆盖率报告
|
|
703
|
+
if self.coverage:
|
|
704
|
+
# 生成lua覆盖率报告
|
|
705
|
+
self.generate_luacov(test_env)
|
|
706
|
+
self.generate_gcov()
|
|
707
|
+
self.combine_coverage()
|
|
708
|
+
log.info("行覆盖率: %s, 命中: %s 行, 未命中: %s 行",
|
|
709
|
+
self.dt_result[self.current_app]["linecoverage"],
|
|
710
|
+
self.dt_result[self.current_app][HIT_LINES],
|
|
711
|
+
self.dt_result[self.current_app]["missedlines"])
|
|
712
|
+
log.info("覆盖率报告 %s 保存到 %s", self.cov_report, self.cov_path)
|
|
713
|
+
# 保存结果供jenkins工程解析
|
|
714
|
+
self.save_dt_result(self.cov_path)
|
|
715
|
+
# 检测是否存在asan日志
|
|
716
|
+
if self.asan:
|
|
717
|
+
self.check_asan_log()
|
|
718
|
+
|
|
719
|
+
def run_hica_test(self, test_env):
|
|
720
|
+
# 获取app列表
|
|
721
|
+
app_list = []
|
|
722
|
+
if self.app == "all":
|
|
723
|
+
dirs = os.listdir("apps")
|
|
724
|
+
app_list.extend(dirs)
|
|
725
|
+
else:
|
|
726
|
+
app_list.append(self.app)
|
|
727
|
+
|
|
728
|
+
# 集成测试场景修改config.cfg和app_preloader.lua
|
|
729
|
+
if self.integration_test and self.coverage:
|
|
730
|
+
# config.cfg中增加luacov路径到LUA_PATH
|
|
731
|
+
self.add_luacov_to_config()
|
|
732
|
+
# app_preloader.lua中增加require 'luacov'
|
|
733
|
+
self.add_luacov_to_preloader()
|
|
734
|
+
|
|
735
|
+
hica_cov = self.cov_path
|
|
736
|
+
for app in app_list:
|
|
737
|
+
self.current_app = app
|
|
738
|
+
banner = "单元测试: %s" % (app) if self.unit_test else "集成测试: %s" % (app)
|
|
739
|
+
log.info("================ %s 开始 ================", banner)
|
|
740
|
+
# 适配hica仓的app路径
|
|
741
|
+
project_root = os.path.join(self.folder, "apps/" + app)
|
|
742
|
+
app_cov_path = os.path.join(self.cov_path, app)
|
|
743
|
+
test_entry = os.path.join(project_root, "test/unit/test.lua")
|
|
744
|
+
itegration_path = os.path.join(project_root, "test/integration")
|
|
745
|
+
# 获取集成测试配置文件列表
|
|
746
|
+
config_list = self.search_test_config(itegration_path)
|
|
747
|
+
# 配置额外的环境变量
|
|
748
|
+
self.set_additional_env(test_env, project_root, self.current_app)
|
|
749
|
+
# 设置覆盖率配置文件
|
|
750
|
+
if self.coverage:
|
|
751
|
+
self.coverage_config(project_root, app_cov_path, app)
|
|
752
|
+
# 设置unit_test运行命令
|
|
753
|
+
ut_cmd = self.set_unit_test_cmd(test_entry)
|
|
754
|
+
# 启动DT测试
|
|
755
|
+
self.start_test_by_type(ut_cmd, config_list, test_env)
|
|
756
|
+
# 生成覆盖率报告
|
|
757
|
+
if self.coverage:
|
|
758
|
+
subprocess.run([self.lua_bin, self.luacov_bin], env=test_env)
|
|
759
|
+
ret = self.reslove_luacov(os.path.join(app_cov_path, self.cov_report))
|
|
760
|
+
if ret is not None:
|
|
761
|
+
self.dt_result[self.current_app]["linecoverage"] = ret[0]
|
|
762
|
+
self.dt_result[self.current_app][HIT_LINES] = int(ret[1])
|
|
763
|
+
self.dt_result[self.current_app]["missedlines"] = int(ret[2])
|
|
764
|
+
log.info("行覆盖率: %s, 命中: %s 行, 未命中: %s 行", ret[0], ret[1], ret[2])
|
|
765
|
+
log.info("覆盖率报告 %s 保存到 %s", self.cov_report, app_cov_path)
|
|
766
|
+
# 保存结果供jenkins工程解析
|
|
767
|
+
self.save_dt_result(hica_cov)
|
|
768
|
+
# 检测是否存在asan日志
|
|
769
|
+
if self.asan:
|
|
770
|
+
self.check_asan_log()
|
|
771
|
+
|
|
772
|
+
def generate_fuzz(self):
|
|
773
|
+
dtframe_gen = os.path.join(self.dtframe, "auto_gen_script/fuzz_build.py")
|
|
774
|
+
ipmi_source = os.path.join(self.folder, "mds", "ipmi.json")
|
|
775
|
+
ipmi_template = os.path.join(self.dtframe, "templates/ipmi.mako")
|
|
776
|
+
mdb_template = os.path.join(self.dtframe, "templates/mdb_interface.mako")
|
|
777
|
+
model_source = os.path.join(self.folder, "mds", "model.json")
|
|
778
|
+
mdb_interface_root = os.path.join(self.folder, "temp/opt/bmc/apps/mdb_interface")
|
|
779
|
+
fuzz_path = os.path.join(self.folder, "test/fuzz")
|
|
780
|
+
os.makedirs(fuzz_path, exist_ok=True)
|
|
781
|
+
os.chdir(fuzz_path)
|
|
782
|
+
Helper.run(["/usr/bin/env", "python3", dtframe_gen, "-s", ipmi_source, "-t",
|
|
783
|
+
ipmi_template, "-c", str(self.fuzz_count)])
|
|
784
|
+
Helper.run(["/usr/bin/env", "python3", dtframe_gen, "-s", model_source, "-t",
|
|
785
|
+
mdb_template, "-mp", mdb_interface_root, "-c", str(self.fuzz_count)])
|
|
786
|
+
|
|
787
|
+
def run_test(self):
|
|
788
|
+
log.info("================ 开发者测试开始 ================")
|
|
789
|
+
# 判断temp是否存在
|
|
790
|
+
if not os.path.exists(self.temp_path):
|
|
791
|
+
log.error("%s 不存在, 请先构建一次此工程", self.temp_path)
|
|
792
|
+
return
|
|
793
|
+
# 公共环境变量
|
|
794
|
+
test_env = {
|
|
795
|
+
"ROOT_DIR": self.temp_path,
|
|
796
|
+
"LD_LIBRARY_PATH": self.test_lib,
|
|
797
|
+
"CONFIG_FILE": self.test_config
|
|
798
|
+
}
|
|
799
|
+
# 适配hica仓
|
|
800
|
+
if os.path.exists("apps"):
|
|
801
|
+
self.run_hica_test(test_env)
|
|
802
|
+
else:
|
|
803
|
+
self.run_independent_test(test_env)
|
|
804
|
+
|
|
805
|
+
def print_build_menu(self):
|
|
806
|
+
log.info("================================ 构建菜单 ================================")
|
|
807
|
+
ljust_width = 30
|
|
808
|
+
log.info("%s %s", "单元测试(ut):".ljust(ljust_width), str(self.unit_test))
|
|
809
|
+
log.info("%s %s", "集成测试(it):".ljust(ljust_width), str(self.integration_test))
|
|
810
|
+
log.info("%s %s", "覆盖率:".ljust(ljust_width), str(self.coverage))
|
|
811
|
+
log.info("%s %s", "地址消毒:".ljust(ljust_width), str(self.asan))
|
|
812
|
+
log.info("============================================================================")
|
|
813
|
+
|
|
814
|
+
def test_c_component(self):
|
|
815
|
+
# 调用测试命令
|
|
816
|
+
try:
|
|
817
|
+
test_package_build_dir = os.path.join(self.folder, "test_package", "build")
|
|
818
|
+
if os.path.isdir(test_package_build_dir):
|
|
819
|
+
shutil.rmtree(test_package_build_dir)
|
|
820
|
+
self.build.test()
|
|
821
|
+
except OSError as e:
|
|
822
|
+
raise TestFailedError("执行测试任务失败, 退出") from e
|
|
823
|
+
finally:
|
|
824
|
+
self._save_c_test_result()
|
|
825
|
+
if self.ut_output:
|
|
826
|
+
self.parse_ut_result()
|
|
827
|
+
|
|
828
|
+
# C框架由构建时测试,仅需要统计覆盖率
|
|
829
|
+
if self.coverage:
|
|
830
|
+
self.generate_gcov()
|
|
831
|
+
self.combine_coverage()
|
|
832
|
+
result = self.dt_result[self.current_app]
|
|
833
|
+
log.info("覆盖率: %s, 命中: %s 行, 未命中: %s 行",
|
|
834
|
+
result["linecoverage"], result[HIT_LINES], result["missedlines"])
|
|
835
|
+
self.save_dt_result(self.cov_path)
|
|
836
|
+
log.info("覆盖率报告 %s 保存到 %s", self.cov_report, self.cov_path)
|
|
837
|
+
|
|
838
|
+
def check_folder(self):
|
|
839
|
+
test_package_folder = os.path.join(self.folder, "test_package")
|
|
840
|
+
test_folder = os.path.join(self.folder, "test")
|
|
841
|
+
if os.path.isdir(test_folder) or os.path.isdir(test_package_folder):
|
|
842
|
+
return True
|
|
843
|
+
return False
|
|
844
|
+
|
|
845
|
+
def incremental_cov(self):
|
|
846
|
+
temp_path = os.path.join(self.folder, "temp", "coverage")
|
|
847
|
+
cov_exclude_path = self.coverage_exclude
|
|
848
|
+
if self.coverage_exclude:
|
|
849
|
+
cov_exclude_path = os.path.realpath(os.path.join(cwd, self.coverage_exclude))
|
|
850
|
+
total_coverage, c_coverage, lua_coverage = IncrementalCov(
|
|
851
|
+
"HEAD~..HEAD", self.current_app, temp_path, 0.8, cov_exclude_path).calculate_cov()
|
|
852
|
+
log.info("增量总覆盖:%s, c代码覆盖: %s, lua代码覆盖: %s", total_coverage, c_coverage, lua_coverage)
|
|
853
|
+
log.info("增量覆盖率报告保存到 dt_result.json")
|
|
854
|
+
|
|
855
|
+
def run(self):
|
|
856
|
+
self.print_build_menu()
|
|
857
|
+
if not self.check_folder():
|
|
858
|
+
log.warning("当前组件不存在开发者测试的test文件夹或test_package文件夹,开发者测试终止!")
|
|
859
|
+
return
|
|
860
|
+
|
|
861
|
+
# -gen代码自动生成逻辑
|
|
862
|
+
if self.fuzz_gen:
|
|
863
|
+
self.generate_fuzz()
|
|
864
|
+
return
|
|
865
|
+
# 构建完后单独运行DT
|
|
866
|
+
has_dt_type = self.unit_test or self.integration_test or self.fuzz_test
|
|
867
|
+
if not has_dt_type:
|
|
868
|
+
self.unit_test = True
|
|
869
|
+
|
|
870
|
+
# 构建被测组件
|
|
871
|
+
if not self.without_build:
|
|
872
|
+
self.build_and_deploy()
|
|
873
|
+
|
|
874
|
+
ret = 0
|
|
875
|
+
try:
|
|
876
|
+
# 有test_package的由conan启动测试
|
|
877
|
+
if self.test_by_conan:
|
|
878
|
+
if self.info.language == "c":
|
|
879
|
+
args = ["-s", self.temp_service_json]
|
|
880
|
+
gen = GenComp(args)
|
|
881
|
+
gen.run()
|
|
882
|
+
self.test_c_component()
|
|
883
|
+
if self.coverage:
|
|
884
|
+
# 调用增量模块
|
|
885
|
+
self.incremental_cov()
|
|
886
|
+
self.print_build_menu()
|
|
887
|
+
else:
|
|
888
|
+
self.save_package_info()
|
|
889
|
+
self.run_test()
|
|
890
|
+
if self.coverage:
|
|
891
|
+
# 调用增量模块
|
|
892
|
+
self.incremental_cov()
|
|
893
|
+
self.print_build_menu()
|
|
894
|
+
except Exception as exp:
|
|
895
|
+
log.warning("===>>>> exception: %s", str(exp))
|
|
896
|
+
ret = -1
|
|
897
|
+
if ret == 0:
|
|
898
|
+
log.info("===>>>> 测试: %s 完成", self.info.package)
|
|
899
|
+
else:
|
|
900
|
+
log.warning("===>>>> 测试: %s 失败", self.info.package)
|
|
901
|
+
|
|
902
|
+
def _path_define(self):
|
|
903
|
+
self.temp_path = os.path.join(self.folder, "temp")
|
|
904
|
+
os.makedirs(self.temp_path, exist_ok=True)
|
|
905
|
+
self.temp_service_json = os.path.join(self.temp_path, "service.json")
|
|
906
|
+
self.tools.copy("mds/service.json", self.temp_service_json)
|
|
907
|
+
|
|
908
|
+
self.cov_path = os.path.join(self.folder, "temp", "coverage")
|
|
909
|
+
self.luacov_path = os.path.join(self.temp_path, "opt/bmc/lualib/luacov")
|
|
910
|
+
self.cov_config = os.path.join(self.luacov_path, "luacov/defaults.lua")
|
|
911
|
+
self.test_lib = ';'.join([os.path.join(self.temp_path, v) for v in ["lib", 'lib64', 'usr/lib', "usr/lib64"]])
|
|
912
|
+
self.test_config = os.path.join(self.temp_path, "opt/bmc/libmc/lualib/test_common/test_config.cfg")
|
|
913
|
+
self.preloader = os.path.join(self.temp_path, "opt/bmc/libmc/lualib/test_common/app_preloader.lua")
|
|
914
|
+
self.lua_bin = os.path.join(self.temp_path, "opt/bmc/skynet/lua")
|
|
915
|
+
self.skynet_path = os.path.join(self.temp_path, "opt/bmc/skynet/skynet")
|
|
916
|
+
self.luacov_bin = os.path.join(self.luacov_path, "bin/luacov")
|
|
917
|
+
self.luacov_env = os.path.join(self.luacov_path, "?.lua")
|
|
918
|
+
self.luafilesystem = os.path.join(self.temp_path, "opt/bmc/luaclib/?.so")
|
|
919
|
+
# WSL环境ASAN库路径(只用于DT场景)
|
|
920
|
+
self.libasan_path = "/usr/lib/x86_64-linux-gnu/libasan.so.5"
|
|
921
|
+
# 地址消毒相关文件存储路径
|
|
922
|
+
self.asan_path = os.path.join(self.temp_path, "asan")
|
|
923
|
+
self.asan_log = os.path.join(self.asan_path, "asan.log")
|
|
924
|
+
# 打桩的dlcose库路径
|
|
925
|
+
self.dlclose_path = os.path.join(self.asan_path, "dlclose.so")
|
|
926
|
+
self.preload_option = "{} {}".format(self.libasan_path, self.dlclose_path)
|
|
927
|
+
|
|
928
|
+
def _save_c_test_result(self):
|
|
929
|
+
test_package_build_dir = os.path.join(self.folder, "test_package", "build")
|
|
930
|
+
test_build = os.path.join(test_package_build_dir, os.listdir(test_package_build_dir)[0])
|
|
931
|
+
outputs = []
|
|
932
|
+
for dir_or_file in os.listdir(test_build):
|
|
933
|
+
file_path = os.path.join(test_build, dir_or_file)
|
|
934
|
+
if os.path.isfile(file_path) and re.match(r"gtester.*.xml", dir_or_file):
|
|
935
|
+
outputs.append(file_path)
|
|
936
|
+
|
|
937
|
+
results = self._get_c_test_results(outputs)
|
|
938
|
+
if not results:
|
|
939
|
+
return
|
|
940
|
+
|
|
941
|
+
self.ut_output = os.path.join(self.cov_path, "output", "ut_output.txt")
|
|
942
|
+
os.makedirs(os.path.dirname(self.ut_output), exist_ok=True)
|
|
943
|
+
self._clear_result(self.ut_output)
|
|
944
|
+
with os.fdopen(os.open(self.ut_output, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
945
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as fp:
|
|
946
|
+
for line in results:
|
|
947
|
+
fp.write(f"{line}\n")
|