From 231d3fe12b916f8c3f3421ecf86043499e2c0647 Mon Sep 17 00:00:00 2001 From: deveco_xdevice Date: Thu, 20 Apr 2023 18:10:32 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BF=AE=E5=A4=8D=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E6=97=B6=E9=97=B4=E8=AE=A1=E7=AE=97=E9=97=AE?= =?UTF-8?q?=E9=A2=98=202=E3=80=81C++=E9=A9=B1=E5=8A=A8=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=B1=81=E5=85=8D=203=E3=80=81=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dretry=E5=91=BD=E4=BB=A4=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: deveco_xdevice --- plugins/ohos/src/ohos/drivers/openharmony.py | 41 ++++++---- plugins/ohos/src/ohos/environment/device.py | 7 +- .../ohos/src/ohos/environment/device_lite.py | 1 + .../ohos/src/ohos/environment/dmlib_lite.py | 4 +- plugins/ohos/src/ohos/parser/parser.py | 80 ++++++++++--------- src/xdevice/__init__.py | 2 + src/xdevice/_core/environment/env_pool.py | 4 +- src/xdevice/_core/report/suite_reporter.py | 4 +- src/xdevice/_core/testkit/kit.py | 67 +++++++++------- src/xdevice/_core/utils.py | 6 ++ 10 files changed, 126 insertions(+), 90 deletions(-) diff --git a/plugins/ohos/src/ohos/drivers/openharmony.py b/plugins/ohos/src/ohos/drivers/openharmony.py index 8ab480e..98f2283 100644 --- a/plugins/ohos/src/ohos/drivers/openharmony.py +++ b/plugins/ohos/src/ohos/drivers/openharmony.py @@ -405,6 +405,8 @@ class OHJSUnitTestDriver(IDriver): json_config.get_driver(), False) if testcase_timeout: self.runner.add_arg("timeout", int(testcase_timeout)) + self.runner.compile_mode = get_config_value( + 'compile-mode', json_config.get_driver(), False) def _do_test_run(self, listener): test_to_run = self._collect_test_to_run() @@ -561,6 +563,7 @@ class OHJSUnitTestRunner: self.expect_tests_dict = dict() self.finished_observer = None self.retry_times = 1 + self.compile_mode = "" def dry_run(self): parsers = get_plugin(Plugin.PARSER, CommonParserType.oh_jsunit_list) @@ -628,34 +631,40 @@ class OHJSUnitTestRunner: if self.config.package_name: # aa test -p ${packageName} -b ${bundleName}-s # unittest OpenHarmonyTestRunner - command = "aa test -p %s -b %s -s unittest OpenHarmonyTestRunner" \ - " %s" % (self.config.package_name, - self.config.bundle_name, - self.get_args_command()) + command = "aa test -p {} -b {} -s unittest OpenHarmonyTestRunner" \ + " {}".format(self.config.package_name, + self.config.bundle_name, + self.get_args_command()) elif self.config.module_name: # aa test -m ${moduleName} -b ${bundleName} # -s unittest OpenHarmonyTestRunner - command = "aa test -m %s -b %s -s unittest OpenHarmonyTestRunner" \ - " %s" % (self.config.module_name, - self.config.bundle_name, - self.get_args_command()) + command = "aa test -m {} -b {} -s unittest {} {}".format( + self.config.module_name, self.config.bundle_name, + self.get_oh_test_runner_path(), self.get_args_command()) return command def _get_dry_run_command(self): command = "" if self.config.package_name: - command = "aa test -p %s -b %s -s unittest OpenHarmonyTestRunner" \ - " %s -s dryRun true" % (self.config.package_name, - self.config.bundle_name, - self.get_args_command()) + command = "aa test -p {} -b {} -s unittest OpenHarmonyTestRunner" \ + " {} -s dryRun true".format(self.config.package_name, + self.config.bundle_name, + self.get_args_command()) elif self.config.module_name: - command = "aa test -m %s -b %s -s unittest OpenHarmonyTestRunner" \ - " %s -s dryRun true" % (self.config.module_name, - self.config.bundle_name, - self.get_args_command()) + command = "aa test -m {} -b {} -s unittest {}" \ + " {} -s dryRun true".format(self.config.module_name, + self.config.bundle_name, + self.get_oh_test_runner_path(), + self.get_args_command()) return command + def get_oh_test_runner_path(self): + if self.compile_mode == "esmodule": + return "/ets/testrunner/OpenHarmonyTestRunner" + else: + return "OpenHarmonyTestRunner" + @Plugin(type=Plugin.DRIVER, id=DeviceTestType.oh_rust_test) class OHRustTestDriver(IDriver): diff --git a/plugins/ohos/src/ohos/environment/device.py b/plugins/ohos/src/ohos/environment/device.py index 5a0ea23..2330f19 100644 --- a/plugins/ohos/src/ohos/environment/device.py +++ b/plugins/ohos/src/ohos/environment/device.py @@ -215,7 +215,10 @@ class Device(IDevice): return False LOG.debug("Wait device %s to recover" % self.device_sn) - return self.device_state_monitor.wait_for_device_available() + result = self.device_state_monitor.wait_for_device_available() + if result: + self.device_log_collector.restart_catch_device_log() + return result def get_device_type(self): self.label = self.model_dict.get("default", None) @@ -770,7 +773,7 @@ class DeviceLogCollector: # 清空日志 cmd = "hilog -r" out = self.device.execute_shell_command(cmd) - cmd = "rm -rf /data/log/hilog/*" + cmd = "rm -rf /data/log/hilog/*.gz" out = self.device.execute_shell_command(cmd) # 开始日志任务 设置落盘文件个数最大值1000, 单个文件20M,链接https://gitee.com/openharmony/hiviewdfx_hilog cmd = "hilog -w start -l {} -n 1000".format(log_size) diff --git a/plugins/ohos/src/ohos/environment/device_lite.py b/plugins/ohos/src/ohos/environment/device_lite.py index d82d726..1d9649a 100644 --- a/plugins/ohos/src/ohos/environment/device_lite.py +++ b/plugins/ohos/src/ohos/environment/device_lite.py @@ -124,6 +124,7 @@ class DeviceLite(IDevice): self.device_kernel = "" self.device = None self.ifconfig = None + self.device_id = None self.extend_value = {} self.device_lock = threading.RLock() diff --git a/plugins/ohos/src/ohos/environment/dmlib_lite.py b/plugins/ohos/src/ohos/environment/dmlib_lite.py index ccd8240..006d159 100644 --- a/plugins/ohos/src/ohos/environment/dmlib_lite.py +++ b/plugins/ohos/src/ohos/environment/dmlib_lite.py @@ -189,7 +189,9 @@ class LiteHelper: while time.time() - start_time < timeout: if not Scheduler.is_execute: raise ExecuteTerminate("Execute terminate", error_no="00300") - data = com.readline().decode('gbk', errors='ignore') + if com.in_waiting == 0: + continue + data = com.read(com.in_waiting).decode('gbk', errors='ignore') data = PATTERN.sub('', data).replace("\r", "") result = "{}{}".format(result, data) if receiver and data: diff --git a/plugins/ohos/src/ohos/parser/parser.py b/plugins/ohos/src/ohos/parser/parser.py index 49a4f5d..8dbe32d 100644 --- a/plugins/ohos/src/ohos/parser/parser.py +++ b/plugins/ohos/src/ohos/parser/parser.py @@ -33,6 +33,7 @@ from xdevice import TestDescription from xdevice import ResultCode from xdevice import CommonParserType from xdevice import get_cst_time +from xdevice import get_delta_time_ms __all__ = ["CppTestParser", "CppTestListParser", "JunitParser", "JSUnitParser", "OHKernelTestParser", "OHJSUnitTestParser", @@ -83,6 +84,8 @@ class CppTestParser(IParser): self.product_info = {} self.is_params = False self.result_data = "" + self.start_time = get_cst_time() + self.suite_start_time = get_cst_time() def get_suite_name(self): return self.suite_name @@ -199,6 +202,7 @@ class CppTestParser(IParser): test_result = self.state_machine.test(reset=True) test_result.test_class = test_class test_result.test_name = test_name + self.start_time = get_cst_time() for listener in self.get_listeners(): test_result = copy.copy(test_result) listener.__started__(LifeCycle.TestCase, test_result) @@ -218,7 +222,9 @@ class CppTestParser(IParser): test_class, test_name, run_time = self.parse_test_description( message) test_result = self.state_machine.test() - test_result.run_time = int(run_time) + test_result.run_time = get_delta_time_ms(self.start_time) + if test_result.run_time == 0 or test_result.run_time < run_time: + test_result.run_time = run_time test_result.code = test_status.value test_result.current = self.state_machine.running_test_index + 1 if not test_result.is_running(): @@ -277,6 +283,7 @@ class CppTestParser(IParser): test_suite = self.state_machine.suite() test_suite.suite_name = matcher.group(2) test_suite.test_num = expected_test_num + self.suite_start_time = get_cst_time() for listener in self.get_listeners(): suite_report = copy.copy(test_suite) listener.__started__(LifeCycle.TestSuite, suite_report) @@ -284,8 +291,9 @@ class CppTestParser(IParser): def handle_suite_ended_tag(self, message): self.state_machine.running_test_index = 0 suite_result = self.state_machine.suite() + suite_result.run_time = get_delta_time_ms(self.suite_start_time) matcher = re.match(r'.*\((\d+) ms total\)', message) - if matcher: + if matcher and suite_result.run_time == 0: suite_result.run_time = int(matcher.group(1)) suite_result.is_completed = True for listener in self.get_listeners(): @@ -672,7 +680,7 @@ class JSUnitParser(IParser): def parse_test_description(self, message): pattern = r".*\[(pass|fail|error)\]" year = time.strftime("%Y") - match_list = ["app Log:", "JSApp:", "JsApp:"] + match_list = ["app Log:", "JSApp:", "JsApp:", "JSAPP:"] filter_message = "" for keyword in match_list: if keyword in message: @@ -1039,6 +1047,7 @@ class OHJSUnitItemConstants(Enum): NUM_TESTS = "numtests" STACK = "stack" SUITE_CONSUMING = "suiteconsuming" + CONSUMING = "consuming" APP_DIED = "App died" @@ -1052,6 +1061,7 @@ class OHJSUnitTestParser(IParser): self.current_key = None self.current_value = None self.start_time = get_cst_time() + self.suite_start_time = get_cst_time() self.test_time = 0 self.test_run_finished = False self.cur_sum = -1 @@ -1106,6 +1116,7 @@ class OHJSUnitTestParser(IParser): self.current_key = None self.current_value = None self.state_machine.running_test_index = 0 + self.suite_start_time = get_cst_time() for listener in self.get_listeners(): suite = copy.copy(current_suite) listener.__started__(LifeCycle.TestSuite, suite) @@ -1114,6 +1125,9 @@ class OHJSUnitTestParser(IParser): if self.current_key == OHJSUnitItemConstants.SUITE_CONSUMING.value: self.test_time = int(self.current_value) self.handle_suite_end() + elif self.current_key == OHJSUnitItemConstants.CONSUMING.value: + self.test_time = int(self.current_value) + self.handle_case_end() else: self.submit_current_key_value() self.parse_key(line, len(OHJSUnitPrefixes.STATUS.value)) @@ -1147,7 +1161,6 @@ class OHJSUnitTestParser(IParser): if self.check_legality(test_info.test_class) and \ self.check_legality(test_info.test_name): self.report_result(test_info) - self.clear_current_test_info() def clear_current_test_info(self): self.state_machine.current_test = None @@ -1165,44 +1178,18 @@ class OHJSUnitTestParser(IParser): if test_info.code == StatusCodes.FAILURE.value: self.state_machine.running_test_index += 1 test_info.current = self.state_machine.running_test_index - end_time = get_cst_time() - run_time = (end_time - self.start_time).total_seconds() - test_info.run_time = int(run_time * 1000) - for listener in self.get_listeners(): - result = copy.copy(test_info) - result.code = ResultCode.FAILED.value - listener.__ended__(LifeCycle.TestCase, result) - if listener.__class__.__name__ == "ReportListener" \ - and self.runner.retry_times > 1: - index = list(listener.tests.keys())[-1] - listener.tests.pop(index) - test_info.is_completed = True + test_info.code = ResultCode.FAILED.value + test_info.run_time = get_delta_time_ms(self.start_time) elif test_info.code == StatusCodes.ERROR.value: self.state_machine.running_test_index += 1 test_info.current = self.state_machine.running_test_index - end_time = get_cst_time() - run_time = (end_time - self.start_time).total_seconds() - test_info.run_time = int(run_time * 1000) - for listener in self.get_listeners(): - result = copy.copy(test_info) - result.code = ResultCode.FAILED.value - listener.__ended__(LifeCycle.TestCase, result) - if listener.__class__.__name__ == "ReportListener" \ - and self.runner.retry_times > 1: - index = list(listener.tests.keys())[-1] - listener.tests.pop(index) - test_info.is_completed = True + test_info.code = ResultCode.FAILED.value + test_info.run_time = get_delta_time_ms(self.start_time) elif test_info.code == StatusCodes.SUCCESS.value: self.state_machine.running_test_index += 1 test_info.current = self.state_machine.running_test_index - end_time = get_cst_time() - run_time = (end_time - self.start_time).total_seconds() - test_info.run_time = int(run_time * 1000) - for listener in self.get_listeners(): - result = copy.copy(test_info) - result.code = ResultCode.PASSED.value - listener.__ended__(LifeCycle.TestCase, result) - test_info.is_completed = True + test_info.code = ResultCode.PASSED.value + test_info.run_time = get_delta_time_ms(self.start_time) @classmethod def output_stack_trace(cls, test_info): @@ -1227,9 +1214,26 @@ class OHJSUnitTestParser(IParser): LOG.debug(self.result_data) self.result_data = "" + def handle_case_end(self): + test_info = self.state_machine.test() + if test_info.run_time == 0 or test_info.run_time < self.test_time: + test_info.run_time = self.test_time + for listener in self.get_listeners(): + result = copy.copy(test_info) + result.code = test_info.code + listener.__ended__(LifeCycle.TestCase, result) + if listener.__class__.__name__ == "ReportListener" \ + and self.runner.retry_times > 1: + index = list(listener.tests.keys())[-1] + listener.tests.pop(index) + test_info.is_completed = True + self.clear_current_test_info() + def handle_suite_end(self): suite_result = self.state_machine.suite() - suite_result.run_time = self.test_time + suite_result.run_time = get_delta_time_ms(self.suite_start_time) + if suite_result.run_time == 0: + suite_result.run_time = self.test_time suite_result.is_completed = True for listener in self.get_listeners(): suite = copy.copy(suite_result) @@ -1264,7 +1268,7 @@ class OHJSUnitTestParser(IParser): for suite in report_listener.suites.values(): test_des_list = self.runner.expect_tests_dict.get( suite.suite_name, []) - pos = self.runner.suite_recorder.get(suite.suite_name)[0] + pos = self.runner.suite_recorder.get(suite.suite_name)[0] if len(test_des_list) == len(report_listener.result[pos][1]): continue interval = len(test_des_list) - len(report_listener.result[pos][1]) diff --git a/src/xdevice/__init__.py b/src/xdevice/__init__.py index 8624577..d0826a3 100755 --- a/src/xdevice/__init__.py +++ b/src/xdevice/__init__.py @@ -104,6 +104,7 @@ from _core.utils import modify_props from _core.utils import get_shell_handler from _core.utils import get_decode from _core.utils import get_cst_time +from _core.utils import get_delta_time_ms from _core.utils import get_device_proc_pid from _core.utils import start_standing_subprocess from _core.utils import stop_standing_subprocess @@ -238,6 +239,7 @@ __all__ = [ "get_shell_handler", "get_decode", "get_cst_time", + "get_delta_time_ms", "get_device_proc_pid", "start_standing_subprocess", "stop_standing_subprocess", diff --git a/src/xdevice/_core/environment/env_pool.py b/src/xdevice/_core/environment/env_pool.py index c66fb0c..48f1bef 100644 --- a/src/xdevice/_core/environment/env_pool.py +++ b/src/xdevice/_core/environment/env_pool.py @@ -20,6 +20,7 @@ import os import time import datetime import sys +import tempfile from abc import abstractmethod from abc import ABCMeta @@ -354,8 +355,7 @@ class DeviceSelector(Selector): class Cache: def __init__(self): - from xdevice import Variables - self.cache_file = os.path.join(Variables.res_dir, "cache.dat") + self.cache_file = os.path.join(tempfile.gettempdir(), "cache.dat") self.expire_time = 1 # days def check_cache_if_expire(self): diff --git a/src/xdevice/_core/report/suite_reporter.py b/src/xdevice/_core/report/suite_reporter.py index 1436d9d..f818d75 100644 --- a/src/xdevice/_core/report/suite_reporter.py +++ b/src/xdevice/_core/report/suite_reporter.py @@ -261,8 +261,8 @@ class SuiteReporter: case_stacktrace = case_stacktrace.replace(chr(char_index), "") test_case_attributes = {ReportConstant.name: case_result.test_name, ReportConstant.status: "", - ReportConstant.time: float( - case_result.run_time) / 1000, + ReportConstant.time: round(float( + case_result.run_time) / 1000, 3), ReportConstant.class_name: case_result.test_class, ReportConstant.result: "", diff --git a/src/xdevice/_core/testkit/kit.py b/src/xdevice/_core/testkit/kit.py index 10920b0..827cfaf 100644 --- a/src/xdevice/_core/testkit/kit.py +++ b/src/xdevice/_core/testkit/kit.py @@ -137,6 +137,37 @@ def junit_para_parse(device, junit_paras, prefix_char="-e"): return " ".join(ret_str) +def get_include_tests(para_datas, test_types, runner): + case_list = [] + if test_types == "class": + case_list = para_datas + else: + for case_file in para_datas: + flags = os.O_RDONLY + modes = stat.S_IWUSR | stat.S_IRUSR + with os.fdopen(os.open(case_file, flags, modes), "r") as file_desc: + case_list.extend(file_desc.read().splitlines()) + runner.add_instrumentation_arg("gtest_filter", ":".join(case_list).replace("#", ".")) + + +def get_all_test_include(para_datas, test_types, runner, request): + case_list = [] + if test_types == "notClass": + case_list = para_datas + else: + if para_datas: + flags = os.O_RDONLY + modes = stat.S_IWUSR | stat.S_IRUSR + with os.fdopen(os.open(para_datas[0], flags, modes), "r") as file_handler: + json_data = json.load(file_handler) + exclude_list = json_data.get(DeviceTestType.cpp_test, []) + for exclude in exclude_list: + if request.get_module_name() in exclude: + temp = exclude.get(request.get_module_name()) + case_list.extend(temp) + runner.add_instrumentation_arg("gtest_filter", "{}{}".format("-", ":".join(case_list)).replace("#", ".")) + + def gtest_para_parse(gtest_paras, runner, request): """To parse the para of gtest Args: @@ -144,40 +175,18 @@ def gtest_para_parse(gtest_paras, runner, request): Returns: the new para using in gtest """ - ret_str = [] if not isinstance(gtest_paras, dict): LOG.warning("The para of gtest is not the dict format as required") return "" for para in gtest_paras.keys(): - if para.strip() == 'test-file-include-filter': - case_list = [] - files = gtest_paras.get(para) - for case_file in files: - flags = os.O_RDONLY - modes = stat.S_IWUSR | stat.S_IRUSR - with os.fdopen(os.open(case_file, flags, modes), - "r") as file_desc: - case_list.extend(file_desc.read().splitlines()) - - runner.add_instrumentation_arg("gtest_filter", ":".join(case_list)) - - if para.strip() == 'all-test-file-exclude-filter': - json_file_list = gtest_paras.get("all-test-file-exclude-filter") - if json_file_list: - flags = os.O_RDONLY - modes = stat.S_IWUSR | stat.S_IRUSR - with os.fdopen(os.open(json_file_list[0], flags, modes), - "r") as file_handler: - json_data = json.load(file_handler) - exclude_list = json_data.get(DeviceTestType.cpp_test, []) - for exclude in exclude_list: - if request.get_module_name() in exclude: - case_list = exclude.get(request.get_module_name()) - runner.add_instrumentation_arg( - "gtest_filter", - "%s%s" % ("-", ":".join(case_list))) - return " ".join(ret_str) + test_types = para.strip() + para_datas = gtest_paras.get(para) + if test_types in ["test-file-include-filter", "class"]: + get_include_tests(para_datas, test_types, runner) + elif test_types in ["all-test-file-exclude-filter", "notClass"]: + get_all_test_include(para_datas, test_types, runner, request) + return "" def reset_junit_para(junit_para_str, prefix_char="-e", ignore_keys=None): diff --git a/src/xdevice/_core/utils.py b/src/xdevice/_core/utils.py index 7e7009c..5228234 100644 --- a/src/xdevice/_core/utils.py +++ b/src/xdevice/_core/utils.py @@ -702,6 +702,12 @@ def get_cst_time(): return datetime.now(tz=cn_tz) +def get_delta_time_ms(start_time): + end_time = get_cst_time() + delta = round(float((end_time - start_time).total_seconds()) * 1000, 3) + return delta + + def get_device_proc_pid(device, proc_name, double_check=False): if not hasattr(device, "execute_shell_command") or \ not hasattr(device, "log") or \