From f91ad5125f991756bb0f93f275adf873218cf254 Mon Sep 17 00:00:00 2001 From: XiaGuochao Date: Tue, 28 Apr 2020 15:02:31 +0800 Subject: [PATCH] remove encoding and dry_run args --- test/README.md | 31 ++++++++++---------- test/maple_test/compare.py | 2 +- test/maple_test/configs.py | 30 ++++--------------- test/maple_test/main.py | 2 +- test/maple_test/run.py | 59 +++++++++++++++++++++++++++++--------- test/maple_test/task.py | 27 ++++++++++------- test/maple_test/test.py | 27 ++++++++++------- test/maple_test/utils.py | 21 +++----------- 8 files changed, 107 insertions(+), 92 deletions(-) diff --git a/test/README.md b/test/README.md index 021c0c1ee7..a8f3406809 100644 --- a/test/README.md +++ b/test/README.md @@ -69,16 +69,16 @@ python3 test/main.py -j20 --timeout=120 参数说明:指定参数会覆盖框架配置文件中的设置 -```shell +```txt usage: main.py [-h] [--cfg CFG] [-j ] [--retry ] [--output ] - [--debug] - [-p {PASS,FAIL,XFAIL,XPASS,NOT_RUN,UNRESOLVED,UNSUPPORTED}] - [--progress {silent,normal,no_flush_progress}] [--dry_run] + [--debug] [--fail_exit] + [-p {PASS,FAIL,XFAIL,XPASS,UNSUPPORTED,UNRESOLVED}] + [--progress {silent,normal,no_flush_progress}] [--test_cfg ] [--test_list ] [-c config set path] [-C key=value] [-E key=value] [--temp_dir ] [--timeout TIMEOUT] - [--encoding ENCODING] [--log_dir ] - [--log_level LOG_LEVEL] [--verbose] + [--log_dir ] [--log_level LOG_LEVEL] + [--verbose] [test_paths [test_paths ...]] optional arguments: @@ -90,16 +90,18 @@ Test FrameWork arguments: --retry Re-run unsuccessful test cases --output Store test result at --debug keep test temp file - -p {PASS,FAIL,XFAIL,XPASS,NOT_RUN,UNRESOLVED,UNSUPPORTED} + --fail_exit Execute test framework with a non-zero exit code if + any tests fail + -p {PASS,FAIL,XFAIL,XPASS,UNSUPPORTED,UNRESOLVED} Print test cases with specified results, -pPASS - -pFAIL, to print all test case that failed or passed + -pFAIL, to print all test case that failed or passed, + UNRESOLVED test case results are not displayed by + default. --progress {silent,normal,no_flush_progress} set progress type, silent: Don't show progress, normal: one line progress bar, update per second,no_flush_progress: print test progress per 10 seconds - --dry_run enable dry run, will generate test.sh under test case - temp dir Test Suite arguments: test_paths Test suite path @@ -120,10 +122,6 @@ Running arguments: --temp_dir Location for test execute. --timeout TIMEOUT test case timeout - --encoding ENCODING Specify the test case encoding format, default - encoding is platform dependent, but any encoding - supported by Python can be passed. Can specify - multiple encoding formats. Log arguments: --log_dir @@ -132,9 +130,12 @@ Log arguments: set log level from: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET --verbose enable verbose output - ``` +## 测试框架编码支持说明 + +当前测试框架仅支持编码格式为 `UTF-8`,测试用例和配置文件仅支持 `UTF-8` 编码格式,如果测试用例编码非 `UTF-8` 测试用例会被认定为 `UNRESOLVED` + ## irbuild测试套配置说明 irbuild测试套配置:testsuite/irbuild_test/test.cfg diff --git a/test/maple_test/compare.py b/test/maple_test/compare.py index a2f9c2ef98..a5f1d92b39 100644 --- a/test/maple_test/compare.py +++ b/test/maple_test/compare.py @@ -257,7 +257,7 @@ def gen_compare_regex(comment, assert_flags, expected_flag): def extract_compare_lines(file_path, regex): - with file_path.open() as f: + with file_path.open(encoding="utf-8") as f: content = f.read() matches = re.finditer(regex, content, re.MULTILINE) diff --git a/test/maple_test/configs.py b/test/maple_test/configs.py index 7749b7cc39..110486d72f 100644 --- a/test/maple_test/configs.py +++ b/test/maple_test/configs.py @@ -23,13 +23,12 @@ import logging import sys from pathlib import Path -from maple_test.utils import ALL, ENCODING, BASE_DIR +from maple_test.utils import ALL, BASE_DIR, OS_SEP from maple_test.utils import complete_path, read_config, get_config_value, is_relative TEST_CONFIG = {} LOGGER = None LOG_CONFIG = {} -CASE_ENCODING = [] def parse_args(): @@ -78,7 +77,7 @@ def parse_args(): default=[], choices=ALL[:], help="Print test cases with specified results, " - "-pPASS -pFAIL, to print all test case that failed or passed" + "-pPASS -pFAIL, to print all test case that failed or passed, " "UNRESOLVED test case results are not displayed by default.", ) test_framework_parser.add_argument( @@ -89,12 +88,7 @@ def parse_args(): "normal: one line progress bar, update per second," "no_flush_progress: print test progress per 10 seconds", ) - test_framework_parser.add_argument( - "--dry_run", - action="store_true", - help="enable dry run, will generate test.sh under test case temp dir", - ) - + test_suite_parser = parser.add_argument_group("Test Suite arguments") test_suite_parser.add_argument( "test_paths", nargs="*", type=complete_path, help="Test suite path", @@ -154,14 +148,6 @@ def parse_args(): running_parser.add_argument( "--timeout", type=float, dest="timeout", default=600, help="test case timeout" ) - running_parser.add_argument( - "--encoding", - action="append", - default=["UTF-8"], - help="Specify the test case encoding format, default encoding is platform " - "dependent, but any encoding supported by Python can be passed. " - "Can specify multiple encoding formats.", - ) log_parser = parser.add_argument_group("Log arguments") log_parser.add_argument( @@ -197,7 +183,6 @@ def parse_args(): "fail_exit": args.fail_exit, "print_type": args.print_type, "progress": args.progress, - "dry_run": args.dry_run, } test_suite_config = { @@ -214,7 +199,6 @@ def parse_args(): running_config = { "temp_dir": args.temp_dir, "timeout": args.timeout, - "encoding": args.encoding, } log_config = { @@ -292,9 +276,6 @@ def init_config(): ) log_config["dir"] = log_dir - global CASE_ENCODING - CASE_ENCODING = TEST_CONFIG.get("encoding") - global LOGGER maple_test_log_config = log_config.copy() maple_test_log_config["verbose"] = True @@ -377,12 +358,13 @@ def construct_logger( handler1.setLevel(level) logger.addHandler(handler1) - handler2 = logging.FileHandler(filename="{}/{}.log".format(log_dir, name), mode="w") + log_path = "{}{}{}.log".format(log_dir, OS_SEP, name) + handler2 = logging.FileHandler(filename=log_path, mode="w") handler2.setLevel(file_level) handler2.setFormatter(file_fmt) logger.addHandler(handler2) - logger.debug("Log file at: {}/{}.log".format(log_dir, name)) + logger.debug("Log file at: {}".format(log_path)) return logger diff --git a/test/maple_test/main.py b/test/maple_test/main.py index 636291829b..c610f93663 100644 --- a/test/maple_test/main.py +++ b/test/maple_test/main.py @@ -76,7 +76,7 @@ def main(): ) shutil.move(str(output), str(output.parent / name)) logger.info("Save test result at: {}".format(output)) - with output.open("w") as f: + with output.open("w", encoding="utf-8") as f: f.write(result) temp_dir = running_config.get("temp_dir") diff --git a/test/maple_test/run.py b/test/maple_test/run.py index 58887c4459..7c159d1bdb 100644 --- a/test/maple_test/run.py +++ b/test/maple_test/run.py @@ -21,10 +21,11 @@ import sys import time import timeit import logging +import platform from textwrap import indent, shorten from maple_test.configs import construct_logger, get_val -from maple_test.utils import PASS, FAIL, UNRESOLVED, NOT_RUN +from maple_test.utils import PASS, FAIL, UNRESOLVED, NOT_RUN, ENCODING from maple_test.utils import add_run_path @@ -32,8 +33,43 @@ class TestError(Exception): pass -def run_command(cmd, work_dir, timeout, logger, env=None): - """Run commands using subprocess""" +def run_command_win(cmd, work_dir, timeout, logger, env=None): + """Run commands using subprocess on Windows""" + new_env = add_run_path(str(work_dir)) + new_env.update(env) + process_command = subprocess.Popen( + cmd, + shell=True, + cwd=str(work_dir), + env=new_env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + logger.debug("execute cmd ===>>>: %s", cmd) + return_code = com_out = com_err = None + try: + com_out, com_err = process_command.communicate(timeout=timeout) + except subprocess.CalledProcessError as err: + return_code, com_out, com_err = err.returncode, "", err + logger.exception(err) + return return_code, com_out, com_err + except subprocess.TimeoutExpired: + return_code, com_out, com_err = 3, "TimeOut", "TimeOut" + return return_code, com_out, com_err + else: + return_code = process_command.returncode + com_out = com_out.decode(ENCODING, errors="replace") + com_err = com_err.decode(ENCODING, errors="replace") + return return_code, com_out, com_err + finally: + process_command.kill() + logger.debug("return code: %d", return_code) + logger.debug("stdout : \n%s", indent(com_out, "+\t", lambda line: True)) + logger.debug("stderr : \n%s", indent(com_err, "@\t", lambda line: True)) + + +def run_command_linux(cmd, work_dir, timeout, logger, env=None): + """Run commands using subprocess on Linux""" new_env = add_run_path(str(work_dir)) new_env.update(env) process_command = subprocess.Popen( @@ -59,8 +95,8 @@ def run_command(cmd, work_dir, timeout, logger, env=None): return return_code, com_out, com_err else: return_code = process_command.returncode - com_out = com_out.decode(sys.stdout.encoding, errors="replace") - com_err = com_err.decode(sys.stderr.encoding, errors="replace") + com_out = com_out.decode(ENCODING, errors="replace") + com_err = com_err.decode(ENCODING, errors="replace") return return_code, com_out, com_err finally: process_command.kill() @@ -91,14 +127,11 @@ def run_commands( remain_time = timeout result = (PASS, None) logger.debug("Work directory: {}".format(work_dir)) - if get_val("dry_run"): - with (work_dir / "test.sh").open("w") as f: - f.write("#!/bin/bash\n") - for command in commands[:-1]: - f.write(command) - f.write(" && \\\n") - f.write(commands[-1]) - return position, (NOT_RUN, None) + + if platform.system() == "Windows": + run_command = run_command_win + else: + run_command = run_command_linux for command in commands: start = timeit.default_timer() diff --git a/test/maple_test/task.py b/test/maple_test/task.py index 74e74f93ce..bb62de23a7 100644 --- a/test/maple_test/task.py +++ b/test/maple_test/task.py @@ -19,6 +19,7 @@ import multiprocessing import shlex import shutil import time +import platform from collections import defaultdict, OrderedDict from pathlib import Path @@ -136,7 +137,6 @@ class TestSuiteTask: user_config_set = cli_running_config.get("user_config_set") user_config = cli_running_config.get("user_config") user_env = cli_running_config.get("user_env") - encoding = running_config.get("encoding") raw_top_config = read_config(self.cfg_path) top_config = TaskConfig( @@ -144,9 +144,9 @@ class TestSuiteTask: ) top_dir = top_config.base_dir if user_test_list is None: - top_testlist = self._get_testlist(raw_top_config, top_dir, encoding) + top_testlist = self._get_testlist(raw_top_config, top_dir) else: - top_testlist = read_list(top_dir / user_test_list, encoding) + top_testlist = read_list(top_dir / user_test_list) if user_config_set: run_config_set = user_config_set @@ -169,11 +169,11 @@ class TestSuiteTask: config = TaskConfig(cfg, raw_config, top_config, user_config, user_env) name = config.name base_dir = config.base_dir - testlist = self._get_testlist(raw_config, base_dir, encoding) + testlist = self._get_testlist(raw_config, base_dir) self.task_set_result[name] = OrderedDict( {PASS: 0, FAIL: 0, NOT_RUN: 0, UNRESOLVED: 0} ) - for case in self._search_list(base_dir, testlist, encoding): + for case in self._search_list(base_dir, testlist): task = SingleTask(case, config, running_config) self.task_set[name].append(task) self.task_set_result[name][task.result[0]] += 1 @@ -183,16 +183,16 @@ class TestSuiteTask: ) @staticmethod - def _get_testlist(config, base_dir, encoding): + def _get_testlist(config, base_dir): testlist_path = get_config_value(config, "testlist", "path") if testlist_path is None: testlist_path = base_dir / "testlist" else: testlist_path = base_dir / testlist_path - testlist = read_list(testlist_path, encoding) + testlist = read_list(testlist_path) return testlist - def _search_list(self, base_dir, testlist, encoding): + def _search_list(self, base_dir, testlist): logger = configs.LOGGER suffixes = self.suffix_comments.keys() include, exclude = testlist @@ -211,7 +211,7 @@ class TestSuiteTask: case_name = str(case_file).replace(".", "_") comment = self.suffix_comments[case_file.suffix[1:]] if case_name not in self.all_cases: - case = Case(case_file, self.path, comment, encoding,) + case = Case(case_file, self.path, comment,) self.all_cases[case_name] = case cases.append(self.all_cases[case_name]) return cases @@ -271,7 +271,12 @@ class TestSuiteTask: def run(self, process_num=1): logger = configs.LOGGER - if process_num == 1: + if platform.system() == "Windows": + logger.info( + "You are running on windows, currently only serial execution is supported" + ) + self.serial_run_task() + elif process_num == 1: logger.debug("The number of running processes is 1, which will run serial") self.serial_run_task() else: @@ -345,7 +350,7 @@ class TestSuiteTask: class SingleTask: def __init__(self, case, config, running_config): - self.name = "{}/{}_{}".format(case.test_name, case.name, config.name) + self.name = "{}{}{}_{}".format(case.test_name, OS_SEP, case.name, config.name) self.path = Path(self.name) config = config.get_case_config(case) temp_dir = "{}_{}".format(self.path.name.replace(".", "_"), int(time.time())) diff --git a/test/maple_test/test.py b/test/maple_test/test.py index b3d9214d7b..924920fa27 100644 --- a/test/maple_test/test.py +++ b/test/maple_test/test.py @@ -17,12 +17,12 @@ import shlex from maple_test.utils import PASS, EXEC_FLAG, EXPECT_FLAG, DEPENDENCE_FLAG -from maple_test.utils import read_file_with_multi_encoding +from maple_test.utils import read_file from maple_test.utils import split_comment, filter_line class Case: - def __init__(self, path, test_path, comment, encoding): + def __init__(self, path, test_path, comment): if path != test_path: self.name = str(path).replace(".", "_") self.path = test_path / path @@ -34,12 +34,19 @@ class Case: self.test_path = test_path self.relative_path = path self.comment = comment - _, comment_lines = split_comment( - comment, read_file_with_multi_encoding(self.path, encoding), - ) - self.commands = extract_commands(comment_lines) - self.expect = extract_expect(comment_lines) - self.dependence = extract_dependence(comment_lines) + try: + _, comment_lines = split_comment( + comment, read_file(self.path), + ) + except UnicodeDecodeError as e: + print(e) + self.commands = [] + self.expect = [] + self.dependence = {} + else: + self.commands = extract_commands(comment_lines) + self.expect = extract_expect(comment_lines) + self.dependence = extract_dependence(comment_lines) def __repr__(self): return str(self.relative_path) @@ -92,10 +99,10 @@ def extract_commands(comment_lines): return commands -def read_list(path, encoding): +def read_list(path): if not path.exists(): return {"**"}, {} - valid_lines, _ = split_comment("#", read_file_with_multi_encoding(path, encoding)) + valid_lines, _ = split_comment("#", read_file(path)) include_flag = "[ALL-TEST-CASE]" exclude_flag = "[EXCLUDE-TEST-CASE]" case_list = set() diff --git a/test/maple_test/utils.py b/test/maple_test/utils.py index 782c6645aa..26f9cb0d8a 100644 --- a/test/maple_test/utils.py +++ b/test/maple_test/utils.py @@ -47,13 +47,13 @@ RESULT = { } BASE_DIR = Path(__file__).parent.absolute() -ENCODING = locale.getdefaultlocale()[1] if locale.getdefaultlocale()[1] else "UTF-8" +ENCODING = locale.getpreferredencoding(False) OS_SEP = os.path.sep EXECUTABLE = sys.executable COMPARE = BASE_DIR / "compare.py" -def read_file(file_path, encoding=ENCODING): +def read_file(file_path): """Read files based on encoding and return all file lines :param file_path: Path @@ -61,7 +61,7 @@ def read_file(file_path, encoding=ENCODING): :return: """ lines = [] - with file_path.open(encoding=encoding) as file: + with file_path.open(encoding="utf-8") as file: all_lines = file.readlines() for line in all_lines: if line.strip(): @@ -69,26 +69,13 @@ def read_file(file_path, encoding=ENCODING): return lines -def read_file_with_multi_encoding(file_path, encoding_list): - """Read files according to the encoding list and return all file lines""" - if not isinstance(encoding_list, list): - return [] - lines = [] - for encoding in encoding_list: - try: - return read_file(file_path, encoding=encoding) - except UnicodeDecodeError: - pass - return lines - - def read_config(file_path): """Read config file based on encoding and return test config""" if not file_path.exists(): return None config = configparser.ConfigParser() config.optionxform = str - config.read(str(file_path), encoding=ENCODING) + config.read(str(file_path), encoding="utf-8") return config -- Gitee