14514f5e3Sopenharmony_ci#!/usr/bin/env python3
24514f5e3Sopenharmony_ci# -*- coding: utf-8 -*-
34514f5e3Sopenharmony_ci
44514f5e3Sopenharmony_ci"""
54514f5e3Sopenharmony_ciCopyright (c) 2023-2024 Huawei Device Co., Ltd.
64514f5e3Sopenharmony_ciLicensed under the Apache License, Version 2.0 (the "License");
74514f5e3Sopenharmony_ciyou may not use this file except in compliance with the License.
84514f5e3Sopenharmony_ciYou may obtain a copy of the License at
94514f5e3Sopenharmony_ci
104514f5e3Sopenharmony_ci    http://www.apache.org/licenses/LICENSE-2.0
114514f5e3Sopenharmony_ci
124514f5e3Sopenharmony_ciUnless required by applicable law or agreed to in writing, software
134514f5e3Sopenharmony_cidistributed under the License is distributed on an "AS IS" BASIS,
144514f5e3Sopenharmony_ciWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
154514f5e3Sopenharmony_ciSee the License for the specific language governing permissions and
164514f5e3Sopenharmony_cilimitations under the License.
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ciDescription: run regress test case
194514f5e3Sopenharmony_ci"""
204514f5e3Sopenharmony_ciimport argparse
214514f5e3Sopenharmony_ciimport dataclasses
224514f5e3Sopenharmony_ciimport datetime
234514f5e3Sopenharmony_ciimport json
244514f5e3Sopenharmony_ciimport logging
254514f5e3Sopenharmony_ciimport multiprocessing
264514f5e3Sopenharmony_ciimport os
274514f5e3Sopenharmony_ciimport platform
284514f5e3Sopenharmony_ciimport re
294514f5e3Sopenharmony_ciimport shutil
304514f5e3Sopenharmony_ciimport stat
314514f5e3Sopenharmony_ciimport subprocess
324514f5e3Sopenharmony_ciimport sys
334514f5e3Sopenharmony_cifrom abc import ABC
344514f5e3Sopenharmony_cifrom typing import Optional, List, Type, Dict, Set, Tuple, Callable
354514f5e3Sopenharmony_cifrom os.path import dirname, join
364514f5e3Sopenharmony_cifrom pathlib import Path
374514f5e3Sopenharmony_ciimport xml.etree.cElementTree as XTree
384514f5e3Sopenharmony_cifrom enum import Enum, auto
394514f5e3Sopenharmony_ci
404514f5e3Sopenharmony_cifrom regress_test_config import RegressTestConfig
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ciENV_PATTERN = re.compile(r"//\s+Environment Variables:(.*)")
434514f5e3Sopenharmony_ci
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_cidef init_log_file(args):
464514f5e3Sopenharmony_ci    logging.basicConfig(filename=args.out_log, format=RegressTestConfig.DEFAULT_LOG_FORMAT, level=logging.INFO)
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_cidef parse_args():
504514f5e3Sopenharmony_ci    parser = argparse.ArgumentParser()
514514f5e3Sopenharmony_ci    parser.add_argument('--test-dir', metavar='DIR',
524514f5e3Sopenharmony_ci                        help='Directory to test ')
534514f5e3Sopenharmony_ci    parser.add_argument('--test-file', metavar='FILE',
544514f5e3Sopenharmony_ci                        help='File to test')
554514f5e3Sopenharmony_ci    parser.add_argument('--test-list', metavar='FILE', dest="test_list", default=None,
564514f5e3Sopenharmony_ci                        help='File with list of tests to run')
574514f5e3Sopenharmony_ci    parser.add_argument('--ignore-list', metavar='FILE', dest="ignore_list", default=None,
584514f5e3Sopenharmony_ci                        help='File with known failed tests list')
594514f5e3Sopenharmony_ci    parser.add_argument('--timeout', default=RegressTestConfig.DEFAULT_TIMEOUT, type=int,
604514f5e3Sopenharmony_ci                        help='Set a custom test timeout in seconds !!!\n')
614514f5e3Sopenharmony_ci    parser.add_argument('--processes', default=RegressTestConfig.DEFAULT_PROCESSES, type=int,
624514f5e3Sopenharmony_ci                        help='set number of processes to use. Default value: 1\n')
634514f5e3Sopenharmony_ci    parser.add_argument('--merge-abc-binary',
644514f5e3Sopenharmony_ci                        help="merge-abc's binary tool")
654514f5e3Sopenharmony_ci    parser.add_argument('--ark-tool',
664514f5e3Sopenharmony_ci                        help="ark's binary tool")
674514f5e3Sopenharmony_ci    parser.add_argument('--ark-aot-tool',
684514f5e3Sopenharmony_ci                        help="ark_aot's binary tool")
694514f5e3Sopenharmony_ci    parser.add_argument('--ark-aot', default=False, action='store_true',
704514f5e3Sopenharmony_ci                        help="runs in ark-aot mode")
714514f5e3Sopenharmony_ci    parser.add_argument('--run-pgo', default=False, action='store_true',
724514f5e3Sopenharmony_ci                        help="runs in pgo mode")
734514f5e3Sopenharmony_ci    parser.add_argument('--enable-litecg', default=False, action='store_true',
744514f5e3Sopenharmony_ci                        help="runs in litecg mode")
754514f5e3Sopenharmony_ci    parser.add_argument('--ark-frontend-binary',
764514f5e3Sopenharmony_ci                        help="ark frontend conversion binary tool")
774514f5e3Sopenharmony_ci    parser.add_argument('--stub-path',
784514f5e3Sopenharmony_ci                        help="stub file for run in AOT modes")
794514f5e3Sopenharmony_ci    parser.add_argument('--LD_LIBRARY_PATH', '--libs-dir',
804514f5e3Sopenharmony_ci                        dest='ld_library_path', default=None, help='LD_LIBRARY_PATH')
814514f5e3Sopenharmony_ci    parser.add_argument('--icu-path',
824514f5e3Sopenharmony_ci                        dest='icu_path', help='icu-data-path')
834514f5e3Sopenharmony_ci    parser.add_argument('--out-dir',
844514f5e3Sopenharmony_ci                        default=None, help='target out dir')
854514f5e3Sopenharmony_ci    parser.add_argument('--force-clone', action="store_true",
864514f5e3Sopenharmony_ci                        default=False, help='Force to clone tests folder')
874514f5e3Sopenharmony_ci    parser.add_argument('--ark-arch',
884514f5e3Sopenharmony_ci                        default=RegressTestConfig.DEFAULT_ARK_ARCH,
894514f5e3Sopenharmony_ci                        required=False,
904514f5e3Sopenharmony_ci                        nargs='?', choices=RegressTestConfig.ARK_ARCH_LIST, type=str)
914514f5e3Sopenharmony_ci    parser.add_argument('--ark-arch-root',
924514f5e3Sopenharmony_ci                        default=RegressTestConfig.DEFAULT_ARK_ARCH,
934514f5e3Sopenharmony_ci                        required=False,
944514f5e3Sopenharmony_ci                        help="the root path for qemu-aarch64 or qemu-arm")
954514f5e3Sopenharmony_ci    parser.add_argument('--disable-force-gc', action='store_true',
964514f5e3Sopenharmony_ci                        help="Run regress tests with close force-gc")
974514f5e3Sopenharmony_ci    return parser.parse_args()
984514f5e3Sopenharmony_ci
994514f5e3Sopenharmony_ci
1004514f5e3Sopenharmony_cidef check_ark_frontend_binary(args) -> bool:
1014514f5e3Sopenharmony_ci    if args.ark_frontend_binary is None:
1024514f5e3Sopenharmony_ci        output('ark_frontend_binary is required, please add this parameter')
1034514f5e3Sopenharmony_ci        return False
1044514f5e3Sopenharmony_ci    return True
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_ci
1074514f5e3Sopenharmony_cidef check_frontend_library(args) -> bool:
1084514f5e3Sopenharmony_ci    current_dir = str(os.getcwd())
1094514f5e3Sopenharmony_ci    current_frontend_binary = os.path.join(current_dir, str(args.ark_frontend_binary))
1104514f5e3Sopenharmony_ci    test_tool_frontend_binary = os.path.join(RegressTestConfig.TEST_TOOL_FILE_DIR, args.ark_frontend_binary)
1114514f5e3Sopenharmony_ci    if not os.path.exists(current_frontend_binary) and not os.path.exists(test_tool_frontend_binary):
1124514f5e3Sopenharmony_ci        output('entered ark_frontend_binary does not exist. please confirm')
1134514f5e3Sopenharmony_ci        return False
1144514f5e3Sopenharmony_ci    args.ark_frontend_binary = current_frontend_binary if os.path.exists(
1154514f5e3Sopenharmony_ci        current_frontend_binary) else test_tool_frontend_binary
1164514f5e3Sopenharmony_ci    args.ark_frontend_binary = os.path.abspath(args.ark_frontend_binary)
1174514f5e3Sopenharmony_ci    return True
1184514f5e3Sopenharmony_ci
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_cidef check_ark_tool(args) -> bool:
1214514f5e3Sopenharmony_ci    current_dir = str(os.getcwd())
1224514f5e3Sopenharmony_ci    if args.ark_tool is None:
1234514f5e3Sopenharmony_ci        output('ark_tool is required, please add this parameter')
1244514f5e3Sopenharmony_ci        return False
1254514f5e3Sopenharmony_ci
1264514f5e3Sopenharmony_ci    current_ark_tool = os.path.join(current_dir, str(args.ark_tool))
1274514f5e3Sopenharmony_ci    test_tool_ark_tool = os.path.join(RegressTestConfig.TEST_TOOL_FILE_DIR, args.ark_tool)
1284514f5e3Sopenharmony_ci    if not os.path.exists(current_ark_tool) and not os.path.exists(test_tool_ark_tool):
1294514f5e3Sopenharmony_ci        output('entered ark_tool does not exist. please confirm')
1304514f5e3Sopenharmony_ci        return False
1314514f5e3Sopenharmony_ci
1324514f5e3Sopenharmony_ci    args.ark_tool = current_ark_tool if os.path.exists(current_ark_tool) else test_tool_ark_tool
1334514f5e3Sopenharmony_ci    args.ark_tool = os.path.abspath(args.ark_tool)
1344514f5e3Sopenharmony_ci    return True
1354514f5e3Sopenharmony_ci
1364514f5e3Sopenharmony_ci
1374514f5e3Sopenharmony_cidef check_ark_aot(args) -> bool:
1384514f5e3Sopenharmony_ci    if args.ark_aot:
1394514f5e3Sopenharmony_ci        current_dir = str(os.getcwd())
1404514f5e3Sopenharmony_ci        current_ark_aot_tool = os.path.join(current_dir, str(args.ark_aot_tool))
1414514f5e3Sopenharmony_ci        test_tool_ark_aot_tool = os.path.join(RegressTestConfig.TEST_TOOL_FILE_DIR, args.ark_aot_tool)
1424514f5e3Sopenharmony_ci        if not os.path.exists(current_ark_aot_tool) and not os.path.exists(test_tool_ark_aot_tool):
1434514f5e3Sopenharmony_ci            output(f'entered ark_aot_tool "{args.ark_aot_tool}" does not exist. Please check')
1444514f5e3Sopenharmony_ci            return False
1454514f5e3Sopenharmony_ci        args.ark_aot_tool = current_ark_aot_tool if os.path.exists(current_ark_aot_tool) else test_tool_ark_aot_tool
1464514f5e3Sopenharmony_ci        args.ark_aot_tool = os.path.abspath(args.ark_aot_tool)
1474514f5e3Sopenharmony_ci        return True
1484514f5e3Sopenharmony_ci    if args.run_pgo and not args.ark_aot:
1494514f5e3Sopenharmony_ci        output('pgo mode cannot be used without aot')
1504514f5e3Sopenharmony_ci        return False
1514514f5e3Sopenharmony_ci    return True
1524514f5e3Sopenharmony_ci
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_cidef check_stub_path(args) -> bool:
1554514f5e3Sopenharmony_ci    if args.stub_path:
1564514f5e3Sopenharmony_ci        current_dir = str(os.getcwd())
1574514f5e3Sopenharmony_ci        stub_path = os.path.join(current_dir, str(args.stub_path))
1584514f5e3Sopenharmony_ci        if not os.path.exists(stub_path):
1594514f5e3Sopenharmony_ci            output(f'entered stub-file "{args.stub_path}" does not exist. Please check')
1604514f5e3Sopenharmony_ci            return False
1614514f5e3Sopenharmony_ci        args.stub_path = os.path.abspath(args.stub_path)
1624514f5e3Sopenharmony_ci    return True
1634514f5e3Sopenharmony_ci
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_cidef is_ignore_file_present(ignore_path: str) -> bool:
1664514f5e3Sopenharmony_ci    if os.path.exists(ignore_path):
1674514f5e3Sopenharmony_ci        return True
1684514f5e3Sopenharmony_ci    output(f"Cannot find ignore list '{ignore_path}'")
1694514f5e3Sopenharmony_ci    return False
1704514f5e3Sopenharmony_ci
1714514f5e3Sopenharmony_ci
1724514f5e3Sopenharmony_cidef check_ignore_list(args) -> bool:
1734514f5e3Sopenharmony_ci    if args.ignore_list:
1744514f5e3Sopenharmony_ci        if os.path.isabs(args.ignore_list):
1754514f5e3Sopenharmony_ci            return is_ignore_file_present(args.ignore_list)
1764514f5e3Sopenharmony_ci        args.ignore_list = str(os.path.join(RegressTestConfig.TEST_TOOL_FILE_DIR, args.ignore_list))
1774514f5e3Sopenharmony_ci        return is_ignore_file_present(args.ignore_list)
1784514f5e3Sopenharmony_ci    return True
1794514f5e3Sopenharmony_ci
1804514f5e3Sopenharmony_ci
1814514f5e3Sopenharmony_cidef check_args(args):
1824514f5e3Sopenharmony_ci    result = check_ark_frontend_binary(args)
1834514f5e3Sopenharmony_ci    result = result and check_frontend_library(args)
1844514f5e3Sopenharmony_ci    result = result and check_ark_tool(args)
1854514f5e3Sopenharmony_ci    result = result and check_ark_aot(args)
1864514f5e3Sopenharmony_ci    result = result and check_stub_path(args)
1874514f5e3Sopenharmony_ci    result = result and check_ignore_list(args)
1884514f5e3Sopenharmony_ci
1894514f5e3Sopenharmony_ci    if not result:
1904514f5e3Sopenharmony_ci        return False
1914514f5e3Sopenharmony_ci
1924514f5e3Sopenharmony_ci    if args.ld_library_path is not None:
1934514f5e3Sopenharmony_ci        libs = args.ld_library_path.split(":")
1944514f5e3Sopenharmony_ci        current_dir = str(os.getcwd())
1954514f5e3Sopenharmony_ci        libs = [os.path.abspath(os.path.join(current_dir, str(lib))) for lib in libs]
1964514f5e3Sopenharmony_ci        args.ld_library_path = ":".join(libs)
1974514f5e3Sopenharmony_ci    else:
1984514f5e3Sopenharmony_ci        args.ld_library_path = RegressTestConfig.DEFAULT_LIBS_DIR
1994514f5e3Sopenharmony_ci    if args.icu_path is None:
2004514f5e3Sopenharmony_ci        args.icu_path = RegressTestConfig.ICU_PATH
2014514f5e3Sopenharmony_ci    if args.out_dir is None:
2024514f5e3Sopenharmony_ci        args.out_dir = RegressTestConfig.PROJECT_BASE_OUT_DIR
2034514f5e3Sopenharmony_ci    else:
2044514f5e3Sopenharmony_ci        args.out_dir = os.path.abspath(os.path.join(RegressTestConfig.CURRENT_PATH, args.out_dir))
2054514f5e3Sopenharmony_ci    if not args.out_dir.endswith("/"):
2064514f5e3Sopenharmony_ci        args.out_dir = f"{args.out_dir}/"
2074514f5e3Sopenharmony_ci    args.regress_out_dir = os.path.join(args.out_dir, "regresstest")
2084514f5e3Sopenharmony_ci    args.out_result = os.path.join(args.regress_out_dir, 'result.txt')
2094514f5e3Sopenharmony_ci    args.junit_report = os.path.join(args.regress_out_dir, 'report.xml')
2104514f5e3Sopenharmony_ci    args.out_log = os.path.join(args.regress_out_dir, 'test.log')
2114514f5e3Sopenharmony_ci    args.test_case_out_dir = os.path.join(args.regress_out_dir, RegressTestConfig.REGRESS_GIT_REPO)
2124514f5e3Sopenharmony_ci    return True
2134514f5e3Sopenharmony_ci
2144514f5e3Sopenharmony_ci
2154514f5e3Sopenharmony_cidef remove_dir(path):
2164514f5e3Sopenharmony_ci    if os.path.exists(path):
2174514f5e3Sopenharmony_ci        shutil.rmtree(path)
2184514f5e3Sopenharmony_ci
2194514f5e3Sopenharmony_ci
2204514f5e3Sopenharmony_cidef output(msg):
2214514f5e3Sopenharmony_ci    print(str(msg))
2224514f5e3Sopenharmony_ci    logging.info(str(msg))
2234514f5e3Sopenharmony_ci
2244514f5e3Sopenharmony_ci
2254514f5e3Sopenharmony_cidef output_debug(msg):
2264514f5e3Sopenharmony_ci    logging.debug(str(msg))
2274514f5e3Sopenharmony_ci
2284514f5e3Sopenharmony_ci
2294514f5e3Sopenharmony_cidef get_extra_error_message(ret_code: int) -> str:
2304514f5e3Sopenharmony_ci    error_messages = {
2314514f5e3Sopenharmony_ci        0: '',
2324514f5e3Sopenharmony_ci        -6: 'Aborted (core dumped)',
2334514f5e3Sopenharmony_ci        -4: 'Aborted (core dumped)',
2344514f5e3Sopenharmony_ci        -11: 'Segmentation fault (core dumped)',
2354514f5e3Sopenharmony_ci        255: '(uncaught error)'
2364514f5e3Sopenharmony_ci    }
2374514f5e3Sopenharmony_ci    error_message = error_messages.get(ret_code, f'Unknown Error: {str(ret_code)}')
2384514f5e3Sopenharmony_ci    return error_message
2394514f5e3Sopenharmony_ci
2404514f5e3Sopenharmony_ci
2414514f5e3Sopenharmony_ci@dataclasses.dataclass
2424514f5e3Sopenharmony_ciclass StepResult:
2434514f5e3Sopenharmony_ci    step_name: str  # a copy of the step name
2444514f5e3Sopenharmony_ci    is_passed: bool = False  # True if passed, any other state is False
2454514f5e3Sopenharmony_ci    command: List[str] = dataclasses.field(default_factory=list)  # command to run
2464514f5e3Sopenharmony_ci    return_code: int = -1
2474514f5e3Sopenharmony_ci    stdout: Optional[str] = None  # present only if there is some output
2484514f5e3Sopenharmony_ci    stderr: Optional[str] = None  # can be present only if is_passed == False
2494514f5e3Sopenharmony_ci    fileinfo: Optional[str] = None  # content of fileinfo file if present
2504514f5e3Sopenharmony_ci
2514514f5e3Sopenharmony_ci    def report(self) -> str:
2524514f5e3Sopenharmony_ci        stdout = self.stdout if self.stdout else ''
2534514f5e3Sopenharmony_ci        stderr = self.stderr if self.stderr else ''
2544514f5e3Sopenharmony_ci        cmd = " ".join([str(cmd) for cmd in self.command])
2554514f5e3Sopenharmony_ci        result: List[str] = [
2564514f5e3Sopenharmony_ci            f"{self.step_name}:",
2574514f5e3Sopenharmony_ci            f"\tCommand: {cmd}",
2584514f5e3Sopenharmony_ci            f"\treturn code={self.return_code}",
2594514f5e3Sopenharmony_ci            f"\toutput='{stdout}'",
2604514f5e3Sopenharmony_ci            f"\terrors='{stderr}'"]
2614514f5e3Sopenharmony_ci        if self.fileinfo:
2624514f5e3Sopenharmony_ci            result.append(f"\tFileInfo:\n{self.fileinfo}")
2634514f5e3Sopenharmony_ci        return "\n".join(result)
2644514f5e3Sopenharmony_ci
2654514f5e3Sopenharmony_ci
2664514f5e3Sopenharmony_ci@dataclasses.dataclass
2674514f5e3Sopenharmony_ciclass TestReport:
2684514f5e3Sopenharmony_ci    src_path: str  # full path to the source test
2694514f5e3Sopenharmony_ci    test_id: str = ""  # path starting from regresstest
2704514f5e3Sopenharmony_ci    out_path: str = ""  # full path to intermediate files up to folder
2714514f5e3Sopenharmony_ci    passed: bool = False  # False if the test has not started or failed
2724514f5e3Sopenharmony_ci    is_skipped: bool = False  # True if the test has found in the skipped (excluded) list
2734514f5e3Sopenharmony_ci    is_ignored: bool = False  # True if the test has found in the ignored list
2744514f5e3Sopenharmony_ci    steps: List[StepResult] = dataclasses.field(default_factory=list)  # list of results
2754514f5e3Sopenharmony_ci
2764514f5e3Sopenharmony_ci    def report(self) -> str:
2774514f5e3Sopenharmony_ci        result: List[str] = [f"{self.test_id}:"]
2784514f5e3Sopenharmony_ci        if self.steps is None:
2794514f5e3Sopenharmony_ci            return ""
2804514f5e3Sopenharmony_ci        for step in self.steps:
2814514f5e3Sopenharmony_ci            result.append(f"\t{step.report()}")
2824514f5e3Sopenharmony_ci        return "\n".join(result)
2834514f5e3Sopenharmony_ci
2844514f5e3Sopenharmony_ci
2854514f5e3Sopenharmony_ciclass RegressTestStep(ABC):
2864514f5e3Sopenharmony_ci    step_obj: Optional['RegressTestStep'] = None
2874514f5e3Sopenharmony_ci
2884514f5e3Sopenharmony_ci    def __init__(self, args, name):
2894514f5e3Sopenharmony_ci        output(f"--- Start step {name} ---")
2904514f5e3Sopenharmony_ci        self.args = args
2914514f5e3Sopenharmony_ci        self.__start: Optional[datetime.datetime] = None
2924514f5e3Sopenharmony_ci        self.__end: Optional[datetime.datetime] = None
2934514f5e3Sopenharmony_ci        self.__duration: Optional[datetime.timedelta] = None
2944514f5e3Sopenharmony_ci        self.name: str = name
2954514f5e3Sopenharmony_ci
2964514f5e3Sopenharmony_ci    @staticmethod
2974514f5e3Sopenharmony_ci    def run(args, test_reports: Optional[List[TestReport]] = None) -> List[TestReport]:
2984514f5e3Sopenharmony_ci        pass
2994514f5e3Sopenharmony_ci
3004514f5e3Sopenharmony_ci    def get_duration(self) -> datetime.timedelta:
3014514f5e3Sopenharmony_ci        if self.__duration is None:
3024514f5e3Sopenharmony_ci            output(f"Step {self.name} not started or not completed")
3034514f5e3Sopenharmony_ci            sys.exit(1)
3044514f5e3Sopenharmony_ci        return self.__duration
3054514f5e3Sopenharmony_ci
3064514f5e3Sopenharmony_ci    def _start(self):
3074514f5e3Sopenharmony_ci        self.__start = datetime.datetime.now()
3084514f5e3Sopenharmony_ci
3094514f5e3Sopenharmony_ci    def _end(self):
3104514f5e3Sopenharmony_ci        self.__end = datetime.datetime.now()
3114514f5e3Sopenharmony_ci        self.__duration = self.__end - self.__start
3124514f5e3Sopenharmony_ci
3134514f5e3Sopenharmony_ci
3144514f5e3Sopenharmony_ciclass RegressTestRepoPrepare(RegressTestStep):
3154514f5e3Sopenharmony_ci    def __init__(self, args):
3164514f5e3Sopenharmony_ci        RegressTestStep.__init__(self, args, "Repo preparation")
3174514f5e3Sopenharmony_ci        self.test_list: List[str] = self.read_test_list(args.test_list)
3184514f5e3Sopenharmony_ci
3194514f5e3Sopenharmony_ci    @staticmethod
3204514f5e3Sopenharmony_ci    def read_test_list(test_list_name: Optional[str]) -> List[str]:
3214514f5e3Sopenharmony_ci        if test_list_name is None:
3224514f5e3Sopenharmony_ci            return []
3234514f5e3Sopenharmony_ci        filename = join(dirname(__file__), test_list_name)
3244514f5e3Sopenharmony_ci        if not Path(filename).exists():
3254514f5e3Sopenharmony_ci            output(f"File {filename} set as --test-list value cannot be found")
3264514f5e3Sopenharmony_ci            exit(1)
3274514f5e3Sopenharmony_ci        with open(filename, 'r') as stream:
3284514f5e3Sopenharmony_ci            return stream.read().split("\n")
3294514f5e3Sopenharmony_ci
3304514f5e3Sopenharmony_ci    @staticmethod
3314514f5e3Sopenharmony_ci    def run(args, test_reports: Optional[List[TestReport]] = None) -> List[TestReport]:
3324514f5e3Sopenharmony_ci        repo = RegressTestRepoPrepare(args)
3334514f5e3Sopenharmony_ci        RegressTestRepoPrepare.step_obj = repo
3344514f5e3Sopenharmony_ci        repo._start()
3354514f5e3Sopenharmony_ci
3364514f5e3Sopenharmony_ci        repo.run_regress_test_prepare()
3374514f5e3Sopenharmony_ci        repo.prepare_clean_data()
3384514f5e3Sopenharmony_ci        repo.get_test_case()
3394514f5e3Sopenharmony_ci        test_list = repo.get_regress_test_files()
3404514f5e3Sopenharmony_ci        skip_list = repo.get_skip_test_cases()
3414514f5e3Sopenharmony_ci        if test_reports is None:
3424514f5e3Sopenharmony_ci            test_reports = []
3434514f5e3Sopenharmony_ci        for test in test_list:
3444514f5e3Sopenharmony_ci            shorten = Utils.get_inside_path(test)
3454514f5e3Sopenharmony_ci            test_id = f"regresstest/ark-regress/{shorten}"
3464514f5e3Sopenharmony_ci            if shorten not in skip_list:
3474514f5e3Sopenharmony_ci                report = TestReport(src_path=test, test_id=test_id)
3484514f5e3Sopenharmony_ci                test_reports.append(report)
3494514f5e3Sopenharmony_ci
3504514f5e3Sopenharmony_ci        repo._end()
3514514f5e3Sopenharmony_ci        return test_reports
3524514f5e3Sopenharmony_ci
3534514f5e3Sopenharmony_ci    @staticmethod
3544514f5e3Sopenharmony_ci    def git_checkout(checkout_options, check_out_dir=os.getcwd()):
3554514f5e3Sopenharmony_ci        cmds = ['git', 'checkout', checkout_options]
3564514f5e3Sopenharmony_ci        result = True
3574514f5e3Sopenharmony_ci        with subprocess.Popen(cmds, cwd=check_out_dir) as proc:
3584514f5e3Sopenharmony_ci            ret = proc.wait()
3594514f5e3Sopenharmony_ci            if ret:
3604514f5e3Sopenharmony_ci                output(f"\n error: git checkout '{checkout_options}' failed.")
3614514f5e3Sopenharmony_ci                result = False
3624514f5e3Sopenharmony_ci        return result
3634514f5e3Sopenharmony_ci
3644514f5e3Sopenharmony_ci    @staticmethod
3654514f5e3Sopenharmony_ci    def git_pull(check_out_dir=os.getcwd()):
3664514f5e3Sopenharmony_ci        cmds = ['git', 'pull', '--rebase']
3674514f5e3Sopenharmony_ci        with subprocess.Popen(cmds, cwd=check_out_dir) as proc:
3684514f5e3Sopenharmony_ci            proc.wait()
3694514f5e3Sopenharmony_ci
3704514f5e3Sopenharmony_ci    @staticmethod
3714514f5e3Sopenharmony_ci    def git_clean(clean_dir=os.getcwd()):
3724514f5e3Sopenharmony_ci        cmds = ['git', 'checkout', '--', '.']
3734514f5e3Sopenharmony_ci        with subprocess.Popen(cmds, cwd=clean_dir) as proc:
3744514f5e3Sopenharmony_ci            proc.wait()
3754514f5e3Sopenharmony_ci
3764514f5e3Sopenharmony_ci    @staticmethod
3774514f5e3Sopenharmony_ci    def git_clone(git_url, code_dir):
3784514f5e3Sopenharmony_ci        cmds = ['git', 'clone', git_url, code_dir]
3794514f5e3Sopenharmony_ci        retries = RegressTestConfig.DEFAULT_RETRIES
3804514f5e3Sopenharmony_ci        while retries > 0:
3814514f5e3Sopenharmony_ci            with subprocess.Popen(cmds) as proc:
3824514f5e3Sopenharmony_ci                ret = proc.wait()
3834514f5e3Sopenharmony_ci                if ret:
3844514f5e3Sopenharmony_ci                    output(f"\n Error: Cloning '{git_url}' failed. Retry remaining '{retries}' times")
3854514f5e3Sopenharmony_ci                    retries -= 1
3864514f5e3Sopenharmony_ci                else:
3874514f5e3Sopenharmony_ci                    return True
3884514f5e3Sopenharmony_ci        sys.exit(1)
3894514f5e3Sopenharmony_ci
3904514f5e3Sopenharmony_ci    @staticmethod
3914514f5e3Sopenharmony_ci    def get_skip_test_cases() -> List[str]:
3924514f5e3Sopenharmony_ci        return Utils.read_skip_list(RegressTestConfig.SKIP_LIST_FILE)
3934514f5e3Sopenharmony_ci
3944514f5e3Sopenharmony_ci    def get_test_case(self):
3954514f5e3Sopenharmony_ci        if not os.path.isdir(os.path.join(RegressTestConfig.REGRESS_TEST_CASE_DIR, '.git')):
3964514f5e3Sopenharmony_ci            self.git_clone(RegressTestConfig.REGRESS_GIT_URL, RegressTestConfig.REGRESS_TEST_CASE_DIR)
3974514f5e3Sopenharmony_ci            return self.git_checkout(RegressTestConfig.REGRESS_GIT_HASH, RegressTestConfig.REGRESS_TEST_CASE_DIR)
3984514f5e3Sopenharmony_ci        return True
3994514f5e3Sopenharmony_ci
4004514f5e3Sopenharmony_ci    def prepare_clean_data(self):
4014514f5e3Sopenharmony_ci        self.git_clean(RegressTestConfig.REGRESS_TEST_CASE_DIR)
4024514f5e3Sopenharmony_ci        self.git_pull(RegressTestConfig.REGRESS_TEST_CASE_DIR)
4034514f5e3Sopenharmony_ci        self.git_checkout(RegressTestConfig.REGRESS_GIT_HASH, RegressTestConfig.REGRESS_TEST_CASE_DIR)
4044514f5e3Sopenharmony_ci
4054514f5e3Sopenharmony_ci    def run_regress_test_prepare(self):
4064514f5e3Sopenharmony_ci        if self.args.force_clone:
4074514f5e3Sopenharmony_ci            remove_dir(self.args.regress_out_dir)
4084514f5e3Sopenharmony_ci            remove_dir(RegressTestConfig.REGRESS_TEST_CASE_DIR)
4094514f5e3Sopenharmony_ci        os.makedirs(self.args.regress_out_dir, exist_ok=True)
4104514f5e3Sopenharmony_ci        os.makedirs(RegressTestConfig.REGRESS_TEST_CASE_DIR, exist_ok=True)
4114514f5e3Sopenharmony_ci        init_log_file(self.args)
4124514f5e3Sopenharmony_ci
4134514f5e3Sopenharmony_ci    def get_regress_test_files(self) -> List[str]:
4144514f5e3Sopenharmony_ci        result: List[str] = []
4154514f5e3Sopenharmony_ci        if self.args.test_file is not None and len(self.args.test_file) > 0:
4164514f5e3Sopenharmony_ci            test_file_list = os.path.join(RegressTestConfig.REGRESS_TEST_CASE_DIR, self.args.test_file)
4174514f5e3Sopenharmony_ci            result.append(str(test_file_list))
4184514f5e3Sopenharmony_ci            return result
4194514f5e3Sopenharmony_ci        elif self.args.test_dir is not None and len(self.args.test_dir) > 0:
4204514f5e3Sopenharmony_ci            test_file_list = os.path.join(RegressTestConfig.REGRESS_TEST_CASE_DIR, self.args.test_dir)
4214514f5e3Sopenharmony_ci        else:
4224514f5e3Sopenharmony_ci            test_file_list = RegressTestConfig.REGRESS_TEST_CASE_DIR
4234514f5e3Sopenharmony_ci        for dir_path, path, filenames in os.walk(test_file_list):
4244514f5e3Sopenharmony_ci            if dir_path.find(".git") != -1:
4254514f5e3Sopenharmony_ci                continue
4264514f5e3Sopenharmony_ci            for filename in filenames:
4274514f5e3Sopenharmony_ci                if filename.endswith(".js") or filename.endswith(".mjs"):
4284514f5e3Sopenharmony_ci                    result.append(str(os.path.join(dir_path, filename)))
4294514f5e3Sopenharmony_ci        return result
4304514f5e3Sopenharmony_ci
4314514f5e3Sopenharmony_ci
4324514f5e3Sopenharmony_ciclass RegressTestCompile(RegressTestStep):
4334514f5e3Sopenharmony_ci    def __init__(self, args, test_reports: List[TestReport]):
4344514f5e3Sopenharmony_ci        RegressTestStep.__init__(self, args, "Regress test compilation")
4354514f5e3Sopenharmony_ci        self.out_dir = args.out_dir
4364514f5e3Sopenharmony_ci        self.test_reports = test_reports
4374514f5e3Sopenharmony_ci        for test in self.test_reports:
4384514f5e3Sopenharmony_ci            test.out_path = os.path.dirname(os.path.join(self.out_dir, test.test_id))
4394514f5e3Sopenharmony_ci
4404514f5e3Sopenharmony_ci    @staticmethod
4414514f5e3Sopenharmony_ci    def run(args, test_reports: Optional[List[TestReport]] = None) -> List[TestReport]:
4424514f5e3Sopenharmony_ci        if test_reports is None:
4434514f5e3Sopenharmony_ci            output("No tests loaded")
4444514f5e3Sopenharmony_ci            exit(-1)
4454514f5e3Sopenharmony_ci        test_prepare = RegressTestCompile(args, test_reports)
4464514f5e3Sopenharmony_ci        RegressTestCompile.step_obj = test_prepare
4474514f5e3Sopenharmony_ci        test_prepare._start()
4484514f5e3Sopenharmony_ci        test_reports = test_prepare.gen_abc_files()
4494514f5e3Sopenharmony_ci        test_prepare._end()
4504514f5e3Sopenharmony_ci        return test_reports
4514514f5e3Sopenharmony_ci
4524514f5e3Sopenharmony_ci    @staticmethod
4534514f5e3Sopenharmony_ci    def create_files_info(test_report: TestReport) -> Tuple[str, str]:
4544514f5e3Sopenharmony_ci        src_files_info = [
4554514f5e3Sopenharmony_ci            RegressTestConfig.REGRESS_TEST_TOOL_DIR,
4564514f5e3Sopenharmony_ci            test_report.src_path
4574514f5e3Sopenharmony_ci        ]
4584514f5e3Sopenharmony_ci        file_info_content: List[str] = []
4594514f5e3Sopenharmony_ci        file_info_path = str(os.path.join(
4604514f5e3Sopenharmony_ci            test_report.out_path,
4614514f5e3Sopenharmony_ci            f"{Utils.get_file_only_name(test_report.src_path)}-filesInfo.txt"))
4624514f5e3Sopenharmony_ci        os.makedirs(test_report.out_path, exist_ok=True)
4634514f5e3Sopenharmony_ci        with os.fdopen(
4644514f5e3Sopenharmony_ci                os.open(file_info_path, flags=os.O_RDWR | os.O_CREAT, mode=stat.S_IRUSR | stat.S_IWUSR),
4654514f5e3Sopenharmony_ci                mode="w+", encoding="utf-8"
4664514f5e3Sopenharmony_ci        ) as fp:
4674514f5e3Sopenharmony_ci            for src_file_info in src_files_info:
4684514f5e3Sopenharmony_ci                line = f"{src_file_info};{Utils.get_file_only_name(src_file_info)};esm;xxx;yyy\n"
4694514f5e3Sopenharmony_ci                file_info_content.append(line)
4704514f5e3Sopenharmony_ci                fp.write(line)
4714514f5e3Sopenharmony_ci        return file_info_path, "\n".join(file_info_content)
4724514f5e3Sopenharmony_ci
4734514f5e3Sopenharmony_ci    def gen_abc_files(self) -> List[TestReport]:
4744514f5e3Sopenharmony_ci        with multiprocessing.Pool(processes=self.args.processes) as pool:
4754514f5e3Sopenharmony_ci            results = pool.imap_unordered(self.gen_abc_file, self.test_reports)
4764514f5e3Sopenharmony_ci            results = list(results)
4774514f5e3Sopenharmony_ci            pool.close()
4784514f5e3Sopenharmony_ci            pool.join()
4794514f5e3Sopenharmony_ci
4804514f5e3Sopenharmony_ci        return results
4814514f5e3Sopenharmony_ci
4824514f5e3Sopenharmony_ci    def gen_abc_file(self, test_report: TestReport) -> Optional[TestReport]:
4834514f5e3Sopenharmony_ci        if test_report.src_path == RegressTestConfig.REGRESS_TEST_TOOL_DIR:
4844514f5e3Sopenharmony_ci            return None
4854514f5e3Sopenharmony_ci        file_info_path, file_info_content = self.create_files_info(test_report)
4864514f5e3Sopenharmony_ci        out_file = change_extension(test_report.src_path, '.out')
4874514f5e3Sopenharmony_ci        expect_file_exists = os.path.exists(out_file)
4884514f5e3Sopenharmony_ci        output_file = change_extension(
4894514f5e3Sopenharmony_ci            os.path.join(test_report.out_path, Utils.get_file_name(test_report.test_id)),
4904514f5e3Sopenharmony_ci            ".abc")
4914514f5e3Sopenharmony_ci        command = [
4924514f5e3Sopenharmony_ci            self.args.ark_frontend_binary,
4934514f5e3Sopenharmony_ci            f"@{file_info_path}",
4944514f5e3Sopenharmony_ci            "--merge-abc",
4954514f5e3Sopenharmony_ci            "--module",
4964514f5e3Sopenharmony_ci            f'--output={output_file}'
4974514f5e3Sopenharmony_ci        ]
4984514f5e3Sopenharmony_ci        step_result = StepResult(self.name, command=command, fileinfo=file_info_content)
4994514f5e3Sopenharmony_ci        Utils.exec_command(command, test_report.test_id, step_result, self.args.timeout,
5004514f5e3Sopenharmony_ci                           lambda rt, _, _2: get_extra_error_message(rt))
5014514f5e3Sopenharmony_ci        test_report.steps.append(step_result)
5024514f5e3Sopenharmony_ci        test_report.passed = step_result.is_passed
5034514f5e3Sopenharmony_ci        if expect_file_exists:
5044514f5e3Sopenharmony_ci            out_file_path = os.path.join(test_report.out_path, change_extension(test_report.test_id, '.out'))
5054514f5e3Sopenharmony_ci            shutil.copy(str(out_file), str(out_file_path))
5064514f5e3Sopenharmony_ci        return test_report
5074514f5e3Sopenharmony_ci
5084514f5e3Sopenharmony_ci
5094514f5e3Sopenharmony_ciclass RegressTestPgo(RegressTestStep):
5104514f5e3Sopenharmony_ci    def __init__(self, args):
5114514f5e3Sopenharmony_ci        RegressTestStep.__init__(self, args, "Regress Test PGO ")
5124514f5e3Sopenharmony_ci
5134514f5e3Sopenharmony_ci    @staticmethod
5144514f5e3Sopenharmony_ci    def run(args, test_reports: Optional[List[TestReport]] = None) -> List[TestReport]:
5154514f5e3Sopenharmony_ci        pgo = RegressTestPgo(args)
5164514f5e3Sopenharmony_ci        RegressTestPgo.step_obj = pgo
5174514f5e3Sopenharmony_ci        pgo._start()
5184514f5e3Sopenharmony_ci        test_reports = pgo.generate_aps(test_reports)
5194514f5e3Sopenharmony_ci        pgo._end()
5204514f5e3Sopenharmony_ci        return test_reports
5214514f5e3Sopenharmony_ci
5224514f5e3Sopenharmony_ci    def get_test_ap_cmd(self, test_report: TestReport) -> List[str]:
5234514f5e3Sopenharmony_ci        abc_file = change_extension(
5244514f5e3Sopenharmony_ci            os.path.join(test_report.out_path, Utils.get_file_name(test_report.test_id)),
5254514f5e3Sopenharmony_ci            ".abc")
5264514f5e3Sopenharmony_ci        ap_file = change_extension(abc_file, ".ap")
5274514f5e3Sopenharmony_ci        entry_point = Utils.get_file_only_name(RegressTestConfig.TEST_TOOL_FILE_JS_NAME)
5284514f5e3Sopenharmony_ci        os.environ["LD_LIBRARY_PATH"] = self.args.ld_library_path
5294514f5e3Sopenharmony_ci        gen_ap_cmd = []
5304514f5e3Sopenharmony_ci        if self.args.ark_arch == RegressTestConfig.ARK_ARCH_LIST[1]:
5314514f5e3Sopenharmony_ci            qemu_tool = "qemu-aarch64"
5324514f5e3Sopenharmony_ci            gen_ap_cmd = [
5334514f5e3Sopenharmony_ci                qemu_tool,
5344514f5e3Sopenharmony_ci                "-L",
5354514f5e3Sopenharmony_ci                self.args.ark_arch_root
5364514f5e3Sopenharmony_ci            ]
5374514f5e3Sopenharmony_ci        gen_ap_cmd.append(self.args.ark_tool)
5384514f5e3Sopenharmony_ci        gen_ap_cmd.append("--log-level=info")
5394514f5e3Sopenharmony_ci        gen_ap_cmd.append(f"--icu-data-path={self.args.icu_path}")
5404514f5e3Sopenharmony_ci        gen_ap_cmd.append("--compiler-target-triple=aarch64-unknown-linux-gn")
5414514f5e3Sopenharmony_ci        gen_ap_cmd.append("--enable-pgo-profiler=true")
5424514f5e3Sopenharmony_ci        gen_ap_cmd.append("--compiler-opt-inlining=true")
5434514f5e3Sopenharmony_ci        gen_ap_cmd.append(f"--compiler-pgo-profiler-path={ap_file}")
5444514f5e3Sopenharmony_ci        gen_ap_cmd.append("--asm-interpreter=true")
5454514f5e3Sopenharmony_ci        gen_ap_cmd.append(f"--entry-point={entry_point}")
5464514f5e3Sopenharmony_ci        gen_ap_cmd.append(f"{abc_file}")
5474514f5e3Sopenharmony_ci        return gen_ap_cmd
5484514f5e3Sopenharmony_ci
5494514f5e3Sopenharmony_ci    def generate_ap(self, test_report: Optional[TestReport]) -> Optional[TestReport]:
5504514f5e3Sopenharmony_ci        if test_report is None or not test_report.passed:
5514514f5e3Sopenharmony_ci            return test_report
5524514f5e3Sopenharmony_ci        command = self.get_test_ap_cmd(test_report)
5534514f5e3Sopenharmony_ci        step = StepResult(self.name, command=command)
5544514f5e3Sopenharmony_ci        Utils.exec_command(command, test_report.test_id, step, self.args.timeout,
5554514f5e3Sopenharmony_ci                           lambda rt, _, _2: get_extra_error_message(rt))
5564514f5e3Sopenharmony_ci        test_report.steps.append(step)
5574514f5e3Sopenharmony_ci        test_report.passed = step.is_passed
5584514f5e3Sopenharmony_ci        return test_report
5594514f5e3Sopenharmony_ci
5604514f5e3Sopenharmony_ci    def generate_aps(self, test_reports: List[TestReport]) -> List[TestReport]:
5614514f5e3Sopenharmony_ci        with multiprocessing.Pool(processes=self.args.processes) as pool:
5624514f5e3Sopenharmony_ci            results = pool.imap_unordered(self.generate_ap, test_reports)
5634514f5e3Sopenharmony_ci            results = list(results)
5644514f5e3Sopenharmony_ci            pool.close()
5654514f5e3Sopenharmony_ci            pool.join()
5664514f5e3Sopenharmony_ci
5674514f5e3Sopenharmony_ci        return results
5684514f5e3Sopenharmony_ci
5694514f5e3Sopenharmony_ci
5704514f5e3Sopenharmony_ciclass Utils:
5714514f5e3Sopenharmony_ci    ark_regress = "ark-regress"
5724514f5e3Sopenharmony_ci
5734514f5e3Sopenharmony_ci    @staticmethod
5744514f5e3Sopenharmony_ci    def get_file_only_name(full_file_name: str) -> str:
5754514f5e3Sopenharmony_ci        _, file_name = os.path.split(full_file_name)
5764514f5e3Sopenharmony_ci        only_name, _ = os.path.splitext(file_name)
5774514f5e3Sopenharmony_ci        return only_name
5784514f5e3Sopenharmony_ci
5794514f5e3Sopenharmony_ci    @staticmethod
5804514f5e3Sopenharmony_ci    def get_file_name(full_file_name: str) -> str:
5814514f5e3Sopenharmony_ci        _, file_name = os.path.split(full_file_name)
5824514f5e3Sopenharmony_ci        return file_name
5834514f5e3Sopenharmony_ci
5844514f5e3Sopenharmony_ci    @staticmethod
5854514f5e3Sopenharmony_ci    def mk_dst_dir(file, src_dir, dist_dir):
5864514f5e3Sopenharmony_ci        idx = file.rfind(src_dir)
5874514f5e3Sopenharmony_ci        fpath, _ = os.path.split(file[idx:])
5884514f5e3Sopenharmony_ci        fpath = fpath.replace(src_dir, dist_dir)
5894514f5e3Sopenharmony_ci        os.makedirs(fpath, exist_ok=True)
5904514f5e3Sopenharmony_ci
5914514f5e3Sopenharmony_ci    @staticmethod
5924514f5e3Sopenharmony_ci    def get_inside_path(file_path: str, marker: Optional[str] = None) -> str:
5934514f5e3Sopenharmony_ci        if marker is None:
5944514f5e3Sopenharmony_ci            marker = Utils.ark_regress
5954514f5e3Sopenharmony_ci        index = file_path.find(marker)
5964514f5e3Sopenharmony_ci        if index > -1:
5974514f5e3Sopenharmony_ci            return file_path[index + len(marker) + 1:]
5984514f5e3Sopenharmony_ci        return file_path
5994514f5e3Sopenharmony_ci
6004514f5e3Sopenharmony_ci    @staticmethod
6014514f5e3Sopenharmony_ci    def exec_command(cmd_args, test_id: str, step_result: StepResult, timeout=RegressTestConfig.DEFAULT_TIMEOUT,
6024514f5e3Sopenharmony_ci                     get_extra_error_msg: Optional[Callable[[int, str, str], str]] = None) -> None:
6034514f5e3Sopenharmony_ci        code_format = 'utf-8'
6044514f5e3Sopenharmony_ci        if platform.system() == "Windows":
6054514f5e3Sopenharmony_ci            code_format = 'gbk'
6064514f5e3Sopenharmony_ci        cmd_string = "\n\t".join([str(arg).strip() for arg in cmd_args if arg is not None])
6074514f5e3Sopenharmony_ci        msg_cmd = "\n".join([
6084514f5e3Sopenharmony_ci            f"Run command:\n{cmd_string}",
6094514f5e3Sopenharmony_ci            f"Env: {os.environ.get('LD_LIBRARY_PATH')}"
6104514f5e3Sopenharmony_ci        ])
6114514f5e3Sopenharmony_ci        msg_result = f"TEST ({step_result.step_name.strip()}): {test_id}"
6124514f5e3Sopenharmony_ci        try:
6134514f5e3Sopenharmony_ci            with subprocess.Popen(cmd_args, stderr=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True,
6144514f5e3Sopenharmony_ci                                  start_new_session=True) as process:
6154514f5e3Sopenharmony_ci                output_res, errs = process.communicate(timeout=timeout)
6164514f5e3Sopenharmony_ci                ret_code = process.poll()
6174514f5e3Sopenharmony_ci                step_result.return_code = ret_code
6184514f5e3Sopenharmony_ci                stderr = str(errs.decode(code_format, 'ignore').strip())
6194514f5e3Sopenharmony_ci                stdout = str(output_res.decode(code_format, 'ignore').strip())
6204514f5e3Sopenharmony_ci                extra_message = get_extra_error_msg(ret_code, stdout, stderr) if get_extra_error_msg is not None else ""
6214514f5e3Sopenharmony_ci                step_result.stderr = f"{extra_message + '. ' if extra_message else '' }{stderr if stderr else ''}"
6224514f5e3Sopenharmony_ci                step_result.stdout = stdout
6234514f5e3Sopenharmony_ci                if ret_code == 0:
6244514f5e3Sopenharmony_ci                    msg_result = f"{msg_result} PASSED"
6254514f5e3Sopenharmony_ci                    step_result.is_passed = True
6264514f5e3Sopenharmony_ci                else:
6274514f5e3Sopenharmony_ci                    msg_result = f"{msg_result} FAILED"
6284514f5e3Sopenharmony_ci        except subprocess.TimeoutExpired:
6294514f5e3Sopenharmony_ci            process.kill()
6304514f5e3Sopenharmony_ci            process.terminate()
6314514f5e3Sopenharmony_ci            step_result.return_code = -1
6324514f5e3Sopenharmony_ci            step_result.stderr = f"Timeout: timed out after {timeout} seconds"
6334514f5e3Sopenharmony_ci            msg_result = f"{msg_result} FAILED"
6344514f5e3Sopenharmony_ci        except Exception as exc:
6354514f5e3Sopenharmony_ci            step_result.return_code = -1
6364514f5e3Sopenharmony_ci            step_result.stderr = f"Unknown error: {exc}"
6374514f5e3Sopenharmony_ci            msg_result = f"{msg_result} FAILED"
6384514f5e3Sopenharmony_ci        if step_result.is_passed:
6394514f5e3Sopenharmony_ci            output(msg_result)
6404514f5e3Sopenharmony_ci            output_debug(msg_cmd)
6414514f5e3Sopenharmony_ci        else:
6424514f5e3Sopenharmony_ci            output(f"{msg_result}\n{step_result.stderr}\n{msg_cmd}")
6434514f5e3Sopenharmony_ci
6444514f5e3Sopenharmony_ci    @staticmethod
6454514f5e3Sopenharmony_ci    def read_skip_list(skip_list_path: str) -> List[str]:
6464514f5e3Sopenharmony_ci        skip_tests_list = []
6474514f5e3Sopenharmony_ci        with os.fdopen(os.open(skip_list_path, os.O_RDONLY, stat.S_IRUSR), "r") as file_object:
6484514f5e3Sopenharmony_ci            json_data = json.load(file_object)
6494514f5e3Sopenharmony_ci            for key in json_data:
6504514f5e3Sopenharmony_ci                skip_tests_list.extend(key["files"])
6514514f5e3Sopenharmony_ci        return skip_tests_list
6524514f5e3Sopenharmony_ci
6534514f5e3Sopenharmony_ci    @staticmethod
6544514f5e3Sopenharmony_ci    def read_file_as_str(file_name: str) -> str:
6554514f5e3Sopenharmony_ci        with os.fdopen(os.open(file_name, os.O_RDONLY, stat.S_IRUSR), "r") as file_object:
6564514f5e3Sopenharmony_ci            content = [line.strip() for line in file_object.readlines()]
6574514f5e3Sopenharmony_ci        return "\n".join(content)
6584514f5e3Sopenharmony_ci
6594514f5e3Sopenharmony_ci
6604514f5e3Sopenharmony_ciclass RegressTestAot(RegressTestStep):
6614514f5e3Sopenharmony_ci    def __init__(self, args):
6624514f5e3Sopenharmony_ci        RegressTestStep.__init__(self, args, "Regress Test AOT mode")
6634514f5e3Sopenharmony_ci
6644514f5e3Sopenharmony_ci    @staticmethod
6654514f5e3Sopenharmony_ci    def run(args, test_reports: Optional[List[TestReport]] = None) -> List[TestReport]:
6664514f5e3Sopenharmony_ci        aot = RegressTestAot(args)
6674514f5e3Sopenharmony_ci        RegressTestAot.step_obj = aot
6684514f5e3Sopenharmony_ci        aot._start()
6694514f5e3Sopenharmony_ci        test_reports = aot.compile_aots(test_reports)
6704514f5e3Sopenharmony_ci        aot._end()
6714514f5e3Sopenharmony_ci        return test_reports
6724514f5e3Sopenharmony_ci
6734514f5e3Sopenharmony_ci    def get_test_aot_cmd(self, test_report: TestReport) -> List[str]:
6744514f5e3Sopenharmony_ci        abc_file = change_extension(
6754514f5e3Sopenharmony_ci            os.path.join(test_report.out_path, Utils.get_file_name(test_report.test_id)),
6764514f5e3Sopenharmony_ci            ".abc")
6774514f5e3Sopenharmony_ci        ap_file = change_extension(abc_file, ".ap")
6784514f5e3Sopenharmony_ci        aot_file = change_extension(abc_file, "")
6794514f5e3Sopenharmony_ci        os.environ["LD_LIBRARY_PATH"] = self.args.ld_library_path
6804514f5e3Sopenharmony_ci        if self.args.ark_arch == RegressTestConfig.ARK_ARCH_LIST[1]:
6814514f5e3Sopenharmony_ci            aot_cmd = [
6824514f5e3Sopenharmony_ci                "qemu-aarch64",
6834514f5e3Sopenharmony_ci                "-L",
6844514f5e3Sopenharmony_ci                self.args.ark_arch_root,
6854514f5e3Sopenharmony_ci                self.args.ark_aot_tool,
6864514f5e3Sopenharmony_ci                "--compiler-target-triple=aarch64-unknown-linux-gnu",
6874514f5e3Sopenharmony_ci                f"--aot-file={aot_file}"
6884514f5e3Sopenharmony_ci            ]
6894514f5e3Sopenharmony_ci        else:
6904514f5e3Sopenharmony_ci            aot_cmd = [
6914514f5e3Sopenharmony_ci            self.args.ark_aot_tool,
6924514f5e3Sopenharmony_ci            f"--aot-file={aot_file}",
6934514f5e3Sopenharmony_ci        ]
6944514f5e3Sopenharmony_ci
6954514f5e3Sopenharmony_ci        pgo = [
6964514f5e3Sopenharmony_ci            "--compiler-opt-loop-peeling=true",
6974514f5e3Sopenharmony_ci            "--compiler-fast-compile=false",
6984514f5e3Sopenharmony_ci            "--compiler-opt-track-field=true",
6994514f5e3Sopenharmony_ci            "--compiler-opt-inlining=true",
7004514f5e3Sopenharmony_ci            "--compiler-max-inline-bytecodes=45",
7014514f5e3Sopenharmony_ci            "--compiler-opt-level=2",
7024514f5e3Sopenharmony_ci            f"--compiler-pgo-profiler-path={ap_file}",
7034514f5e3Sopenharmony_ci        ]
7044514f5e3Sopenharmony_ci        litecg = [
7054514f5e3Sopenharmony_ci            "--compiler-enable-litecg=true",
7064514f5e3Sopenharmony_ci        ]
7074514f5e3Sopenharmony_ci        aot_cmd_tail = [
7084514f5e3Sopenharmony_ci            f"{abc_file}",
7094514f5e3Sopenharmony_ci        ]
7104514f5e3Sopenharmony_ci
7114514f5e3Sopenharmony_ci        if self.args.run_pgo:
7124514f5e3Sopenharmony_ci            aot_cmd.extend(pgo)
7134514f5e3Sopenharmony_ci        if self.args.enable_litecg:
7144514f5e3Sopenharmony_ci            aot_cmd.extend(litecg)
7154514f5e3Sopenharmony_ci        aot_cmd.extend(aot_cmd_tail)
7164514f5e3Sopenharmony_ci        return aot_cmd
7174514f5e3Sopenharmony_ci
7184514f5e3Sopenharmony_ci    def compile_aot(self, test_report: Optional[TestReport]) -> Optional[TestReport]:
7194514f5e3Sopenharmony_ci        if test_report is None or not test_report.passed:
7204514f5e3Sopenharmony_ci            return test_report
7214514f5e3Sopenharmony_ci        command = self.get_test_aot_cmd(test_report)
7224514f5e3Sopenharmony_ci        step = StepResult(self.name, command=command)
7234514f5e3Sopenharmony_ci        Utils.exec_command(command, test_report.test_id, step, self.args.timeout,
7244514f5e3Sopenharmony_ci                           lambda rt, _, _2: get_extra_error_message(rt))
7254514f5e3Sopenharmony_ci        test_report.steps.append(step)
7264514f5e3Sopenharmony_ci        test_report.passed = step.is_passed
7274514f5e3Sopenharmony_ci        return test_report
7284514f5e3Sopenharmony_ci
7294514f5e3Sopenharmony_ci    def compile_aots(self, test_reports: List[TestReport]) -> List[TestReport]:
7304514f5e3Sopenharmony_ci        with multiprocessing.Pool(processes=self.args.processes) as pool:
7314514f5e3Sopenharmony_ci            results = pool.imap_unordered(self.compile_aot, test_reports)
7324514f5e3Sopenharmony_ci            results = list(results)
7334514f5e3Sopenharmony_ci            pool.close()
7344514f5e3Sopenharmony_ci            pool.join()
7354514f5e3Sopenharmony_ci
7364514f5e3Sopenharmony_ci        return results
7374514f5e3Sopenharmony_ci
7384514f5e3Sopenharmony_ci
7394514f5e3Sopenharmony_ciclass RegressOption(Enum):
7404514f5e3Sopenharmony_ci    NO_FORCE_GC = auto()
7414514f5e3Sopenharmony_ci    ELEMENTS_KIND = auto()
7424514f5e3Sopenharmony_ci
7434514f5e3Sopenharmony_ci
7444514f5e3Sopenharmony_cidef get_regress_groups() -> Dict[RegressOption, List[str]]:
7454514f5e3Sopenharmony_ci    groups = {}
7464514f5e3Sopenharmony_ci    with os.fdopen(os.open(RegressTestConfig.REGRESS_TEST_OPTIONS, os.O_RDONLY, stat.S_IRUSR), "r") as file:
7474514f5e3Sopenharmony_ci        for group in json.load(file):
7484514f5e3Sopenharmony_ci            groups[RegressOption[group["name"]]] = group["files"]
7494514f5e3Sopenharmony_ci    return groups
7504514f5e3Sopenharmony_ci
7514514f5e3Sopenharmony_ci
7524514f5e3Sopenharmony_cidef get_test_options(test: str, test_groups: Dict[RegressOption, List[str]], regress_option: RegressOption) -> List[str]:
7534514f5e3Sopenharmony_ci    opt_values: Dict[RegressOption, str] = {
7544514f5e3Sopenharmony_ci        RegressOption.NO_FORCE_GC: "--enable-force-gc=",
7554514f5e3Sopenharmony_ci        RegressOption.ELEMENTS_KIND: "--enable-elements-kind="
7564514f5e3Sopenharmony_ci    }
7574514f5e3Sopenharmony_ci
7584514f5e3Sopenharmony_ci    def match(opt: RegressOption) -> bool:
7594514f5e3Sopenharmony_ci        return test in test_groups.get(opt, [])
7604514f5e3Sopenharmony_ci
7614514f5e3Sopenharmony_ci    def to_flag(b: bool) -> str:
7624514f5e3Sopenharmony_ci        return str(b).lower()
7634514f5e3Sopenharmony_ci
7644514f5e3Sopenharmony_ci    try:
7654514f5e3Sopenharmony_ci        return [opt_values.get(regress_option) + to_flag(not match(regress_option))]
7664514f5e3Sopenharmony_ci    except KeyError:
7674514f5e3Sopenharmony_ci        return []
7684514f5e3Sopenharmony_ci
7694514f5e3Sopenharmony_ci
7704514f5e3Sopenharmony_ciclass RegressTestRun(RegressTestStep):
7714514f5e3Sopenharmony_ci    def __init__(self, args):
7724514f5e3Sopenharmony_ci        RegressTestStep.__init__(self, args, "Regress Test Run ")
7734514f5e3Sopenharmony_ci        self.test_groups: Dict[RegressOption, List[str]] = get_regress_groups()
7744514f5e3Sopenharmony_ci
7754514f5e3Sopenharmony_ci    @staticmethod
7764514f5e3Sopenharmony_ci    def run(args, test_reports: Optional[List[TestReport]] = None) -> List[TestReport]:
7774514f5e3Sopenharmony_ci        runner = RegressTestRun(args)
7784514f5e3Sopenharmony_ci        RegressTestRun.step_obj = runner
7794514f5e3Sopenharmony_ci        runner._start()
7804514f5e3Sopenharmony_ci        test_reports = runner.run_test_case_dir(test_reports)
7814514f5e3Sopenharmony_ci        runner._end()
7824514f5e3Sopenharmony_ci        return test_reports
7834514f5e3Sopenharmony_ci
7844514f5e3Sopenharmony_ci    @staticmethod
7854514f5e3Sopenharmony_ci    def extra_check_with_expect(ret_code: int, test_report: TestReport, expect_file, stdout: str, stderr: str) -> str:
7864514f5e3Sopenharmony_ci        expect_output_str = read_expect_file(expect_file, test_report.src_path)
7874514f5e3Sopenharmony_ci        test_case_file = Utils.read_file_as_str(test_report.src_path)
7884514f5e3Sopenharmony_ci        if stdout == expect_output_str.strip() or stderr == expect_output_str.strip():
7894514f5e3Sopenharmony_ci            if ret_code == 0 or (ret_code == 255 and "/fail/" in test_case_file):
7904514f5e3Sopenharmony_ci                return ""
7914514f5e3Sopenharmony_ci            else:
7924514f5e3Sopenharmony_ci                return get_extra_error_message(ret_code)
7934514f5e3Sopenharmony_ci        msg = f'expect: [{expect_output_str}]\nbut got: [{stderr}]'
7944514f5e3Sopenharmony_ci        return msg
7954514f5e3Sopenharmony_ci
7964514f5e3Sopenharmony_ci    @staticmethod
7974514f5e3Sopenharmony_ci    def extra_check_with_assert(ret_code: int, stderr: Optional[str]) -> str:
7984514f5e3Sopenharmony_ci        if ret_code == 0 and stderr and "[ecmascript] Stack overflow" not in stderr:
7994514f5e3Sopenharmony_ci            return str(stderr)
8004514f5e3Sopenharmony_ci        return get_extra_error_message(ret_code)
8014514f5e3Sopenharmony_ci
8024514f5e3Sopenharmony_ci    def run_test_case_dir(self, test_reports: List[TestReport]) -> List[TestReport]:
8034514f5e3Sopenharmony_ci        with multiprocessing.Pool(processes=self.args.processes, initializer=init_worker,
8044514f5e3Sopenharmony_ci                                  initargs=(self.args,)) as pool:
8054514f5e3Sopenharmony_ci            results = pool.imap_unordered(self.run_test_case, test_reports)
8064514f5e3Sopenharmony_ci            results = list(results)
8074514f5e3Sopenharmony_ci            pool.close()
8084514f5e3Sopenharmony_ci            pool.join()
8094514f5e3Sopenharmony_ci
8104514f5e3Sopenharmony_ci        return results
8114514f5e3Sopenharmony_ci
8124514f5e3Sopenharmony_ci    def run_test_case(self, test_report: TestReport) -> Optional[TestReport]:
8134514f5e3Sopenharmony_ci        self.args = worker_wrapper_args
8144514f5e3Sopenharmony_ci        if self.args is None or test_report is None or not test_report.passed:
8154514f5e3Sopenharmony_ci            return test_report
8164514f5e3Sopenharmony_ci        if test_report.src_path.endswith(RegressTestConfig.TEST_TOOL_FILE_JS_NAME):
8174514f5e3Sopenharmony_ci            return None
8184514f5e3Sopenharmony_ci
8194514f5e3Sopenharmony_ci        abc_file = change_extension(
8204514f5e3Sopenharmony_ci            os.path.join(test_report.out_path, Utils.get_file_name(test_report.test_id)),
8214514f5e3Sopenharmony_ci            ".abc")
8224514f5e3Sopenharmony_ci        aot_file = change_extension(abc_file, "")
8234514f5e3Sopenharmony_ci        expect_file = change_extension(abc_file, ".out")
8244514f5e3Sopenharmony_ci        entry_point = Utils.get_file_only_name(RegressTestConfig.TEST_TOOL_FILE_JS_NAME)
8254514f5e3Sopenharmony_ci
8264514f5e3Sopenharmony_ci        os.environ["LD_LIBRARY_PATH"] = self.args.ld_library_path
8274514f5e3Sopenharmony_ci
8284514f5e3Sopenharmony_ci        # test environ LC_ALL/TZ
8294514f5e3Sopenharmony_ci        test_name = test_report.test_id.replace('regresstest/ark-regress/', '')
8304514f5e3Sopenharmony_ci        set_test_environ(test_report.src_path)
8314514f5e3Sopenharmony_ci        command = []
8324514f5e3Sopenharmony_ci        if self.args.ark_arch == RegressTestConfig.ARK_ARCH_LIST[1]:
8334514f5e3Sopenharmony_ci            qemu_tool = "qemu-aarch64"
8344514f5e3Sopenharmony_ci            qemu_arg1 = "-L"
8354514f5e3Sopenharmony_ci            qemu_arg2 = self.args.ark_arch_root
8364514f5e3Sopenharmony_ci            command = [qemu_tool, qemu_arg1, qemu_arg2]
8374514f5e3Sopenharmony_ci        command.append(self.args.ark_tool)
8384514f5e3Sopenharmony_ci        command.append(f"--icu-data-path={self.args.icu_path}")
8394514f5e3Sopenharmony_ci        command.append(f"--entry-point={entry_point}")
8404514f5e3Sopenharmony_ci        if self.args.ark_aot:
8414514f5e3Sopenharmony_ci            command.append(f"--stub-file={self.args.stub_path}")
8424514f5e3Sopenharmony_ci            command.append(f"--aot-file={aot_file}")
8434514f5e3Sopenharmony_ci        if self.args.disable_force_gc:
8444514f5e3Sopenharmony_ci            command.append("--enable-force-gc=false")
8454514f5e3Sopenharmony_ci        else:
8464514f5e3Sopenharmony_ci            command.extend(get_test_options(test_name, self.test_groups, RegressOption.NO_FORCE_GC))
8474514f5e3Sopenharmony_ci        command.extend(get_test_options(test_name, self.test_groups, RegressOption.ELEMENTS_KIND))
8484514f5e3Sopenharmony_ci        command.append(abc_file)
8494514f5e3Sopenharmony_ci
8504514f5e3Sopenharmony_ci        return self.run_test_case_file(command, test_report, expect_file)
8514514f5e3Sopenharmony_ci
8524514f5e3Sopenharmony_ci    def run_test_case_file(self, command, test_report: TestReport, expect_file) -> TestReport:
8534514f5e3Sopenharmony_ci        expect_file_exits = os.path.exists(expect_file)
8544514f5e3Sopenharmony_ci        step = StepResult(self.name, command=command)
8554514f5e3Sopenharmony_ci        if expect_file_exits:
8564514f5e3Sopenharmony_ci            self.run_test_case_with_expect(command, step, test_report, expect_file)
8574514f5e3Sopenharmony_ci        else:
8584514f5e3Sopenharmony_ci            self.run_test_case_with_assert(command, step, test_report)
8594514f5e3Sopenharmony_ci        test_report.steps.append(step)
8604514f5e3Sopenharmony_ci        test_report.passed = step.is_passed
8614514f5e3Sopenharmony_ci        return test_report
8624514f5e3Sopenharmony_ci
8634514f5e3Sopenharmony_ci    def run_test_case_with_expect(self, command, step: StepResult, test_report: TestReport, expect_file) -> None:
8644514f5e3Sopenharmony_ci        Utils.exec_command(command, test_report.test_id, step, self.args.timeout,
8654514f5e3Sopenharmony_ci                           lambda rt, out, err: self.extra_check_with_expect(rt, test_report, expect_file, out, err))
8664514f5e3Sopenharmony_ci
8674514f5e3Sopenharmony_ci    def run_test_case_with_assert(self, command, step: StepResult, test_report: TestReport) -> None:
8684514f5e3Sopenharmony_ci        Utils.exec_command(command, test_report.test_id, step, self.args.timeout,
8694514f5e3Sopenharmony_ci                           lambda rt, _, err: self.extra_check_with_assert(rt, err))
8704514f5e3Sopenharmony_ci
8714514f5e3Sopenharmony_ci
8724514f5e3Sopenharmony_ciclass Stats:
8734514f5e3Sopenharmony_ci    def __init__(self, args, test_reports: List[TestReport]):
8744514f5e3Sopenharmony_ci        self.args = args
8754514f5e3Sopenharmony_ci        self.pass_count = 0
8764514f5e3Sopenharmony_ci        self.fail_count = 0
8774514f5e3Sopenharmony_ci        self.test_reports = test_reports
8784514f5e3Sopenharmony_ci        self.errors: Dict[str, List[TestReport]] = {}
8794514f5e3Sopenharmony_ci
8804514f5e3Sopenharmony_ci    def read_ignore_list(self) -> Optional[Set[str]]:
8814514f5e3Sopenharmony_ci        if self.args.ignore_list is None:
8824514f5e3Sopenharmony_ci            return None
8834514f5e3Sopenharmony_ci        with os.fdopen(os.open(self.args.ignore_list, os.O_RDWR, stat.S_IRUSR), "r+") as file_object:
8844514f5e3Sopenharmony_ci            lines = file_object.readlines()
8854514f5e3Sopenharmony_ci            lines = [line.strip() for line in lines if not line.strip().startswith('#')]
8864514f5e3Sopenharmony_ci        return set(lines)
8874514f5e3Sopenharmony_ci
8884514f5e3Sopenharmony_ci    def get_new_failures(self) -> Optional[List[TestReport]]:
8894514f5e3Sopenharmony_ci        ignore_list = self.read_ignore_list()
8904514f5e3Sopenharmony_ci        if ignore_list is None:
8914514f5e3Sopenharmony_ci            return None
8924514f5e3Sopenharmony_ci        new_failures: List[TestReport] = []
8934514f5e3Sopenharmony_ci        for test_report in self.test_reports:
8944514f5e3Sopenharmony_ci            if test_report and not test_report.passed and test_report.steps:
8954514f5e3Sopenharmony_ci                if test_report.test_id not in ignore_list:
8964514f5e3Sopenharmony_ci                    new_failures.append(test_report)
8974514f5e3Sopenharmony_ci        return new_failures
8984514f5e3Sopenharmony_ci
8994514f5e3Sopenharmony_ci    def statistics(self):
9004514f5e3Sopenharmony_ci        root = XTree.Element("testsuite")
9014514f5e3Sopenharmony_ci        root.set("name", "Regression")
9024514f5e3Sopenharmony_ci
9034514f5e3Sopenharmony_ci        result_file = open_write_file(self.args.out_result, False)
9044514f5e3Sopenharmony_ci        for test_report in self.test_reports:
9054514f5e3Sopenharmony_ci            if test_report is None:
9064514f5e3Sopenharmony_ci                continue
9074514f5e3Sopenharmony_ci            testcase = XTree.SubElement(root, "testcase")
9084514f5e3Sopenharmony_ci            testcase.set("name", f"{test_report.test_id}")
9094514f5e3Sopenharmony_ci            if test_report.passed:
9104514f5e3Sopenharmony_ci                write_result_file(f"PASS: {test_report.test_id}", result_file)
9114514f5e3Sopenharmony_ci                self.pass_count += 1
9124514f5e3Sopenharmony_ci            else:
9134514f5e3Sopenharmony_ci                self.fail_count += 1
9144514f5e3Sopenharmony_ci                write_result_file(f"FAIL: {test_report.test_id}", result_file)
9154514f5e3Sopenharmony_ci                failed_step = test_report.steps[-1]
9164514f5e3Sopenharmony_ci                if failed_step.step_name not in self.errors:
9174514f5e3Sopenharmony_ci                    self.errors[failed_step.step_name] = []
9184514f5e3Sopenharmony_ci                self.errors[failed_step.step_name].append(test_report)
9194514f5e3Sopenharmony_ci                XTree.SubElement(testcase, "failure").text = f"<![CDATA[{test_report.report()}]]>"
9204514f5e3Sopenharmony_ci
9214514f5e3Sopenharmony_ci        root.set("tests", f"{self.pass_count + self.fail_count}")
9224514f5e3Sopenharmony_ci        root.set("failures", f"{self.fail_count}")
9234514f5e3Sopenharmony_ci
9244514f5e3Sopenharmony_ci        tree = XTree.ElementTree(root)
9254514f5e3Sopenharmony_ci        tree.write(self.args.junit_report, xml_declaration=True, encoding="UTF-8")
9264514f5e3Sopenharmony_ci        result_file.close()
9274514f5e3Sopenharmony_ci
9284514f5e3Sopenharmony_ci    def print_result(self, args, steps):
9294514f5e3Sopenharmony_ci        result_file = open_write_file(args.out_result, True)
9304514f5e3Sopenharmony_ci        summary_duration = datetime.timedelta()
9314514f5e3Sopenharmony_ci        for step in steps:
9324514f5e3Sopenharmony_ci            output(f"Step {step.step_obj.name} - duration {step.step_obj.get_duration()}")
9334514f5e3Sopenharmony_ci            summary_duration += step.step_obj.get_duration()
9344514f5e3Sopenharmony_ci        msg = f'\npass count: {self.pass_count}'
9354514f5e3Sopenharmony_ci        write_result_file(msg, result_file)
9364514f5e3Sopenharmony_ci        output(msg)
9374514f5e3Sopenharmony_ci        msg = f'fail count: {self.fail_count}'
9384514f5e3Sopenharmony_ci        write_result_file(msg, result_file)
9394514f5e3Sopenharmony_ci        output(msg)
9404514f5e3Sopenharmony_ci        msg = f'total count: {self.fail_count + self.pass_count}'
9414514f5e3Sopenharmony_ci        write_result_file(msg, result_file)
9424514f5e3Sopenharmony_ci        output(msg)
9434514f5e3Sopenharmony_ci        msg = f'total used time is: {str(summary_duration)}'
9444514f5e3Sopenharmony_ci        write_result_file(msg, result_file)
9454514f5e3Sopenharmony_ci        output(msg)
9464514f5e3Sopenharmony_ci        result_file.close()
9474514f5e3Sopenharmony_ci
9484514f5e3Sopenharmony_ci    def print_failed_tests(self):
9494514f5e3Sopenharmony_ci        output("=== Failed tests ===")
9504514f5e3Sopenharmony_ci        for key, values in self.errors.items():
9514514f5e3Sopenharmony_ci            output(f"{key}: {len(values)} tests")
9524514f5e3Sopenharmony_ci
9534514f5e3Sopenharmony_ci
9544514f5e3Sopenharmony_cidef change_extension(path, new_ext: str):
9554514f5e3Sopenharmony_ci    base_path, ext = os.path.splitext(path)
9564514f5e3Sopenharmony_ci    if ext:
9574514f5e3Sopenharmony_ci        new_path = base_path + new_ext
9584514f5e3Sopenharmony_ci    else:
9594514f5e3Sopenharmony_ci        new_path = path + new_ext
9604514f5e3Sopenharmony_ci    return new_path
9614514f5e3Sopenharmony_ci
9624514f5e3Sopenharmony_ci
9634514f5e3Sopenharmony_cidef get_files_by_ext(start_dir, suffix):
9644514f5e3Sopenharmony_ci    result = []
9654514f5e3Sopenharmony_ci    for dir_path, dir_names, filenames in os.walk(start_dir):
9664514f5e3Sopenharmony_ci        for filename in filenames:
9674514f5e3Sopenharmony_ci            if filename.endswith(suffix):
9684514f5e3Sopenharmony_ci                result.append(os.path.join(dir_path, filename))
9694514f5e3Sopenharmony_ci    return result
9704514f5e3Sopenharmony_ci
9714514f5e3Sopenharmony_ci
9724514f5e3Sopenharmony_cidef read_expect_file(expect_file, test_case_file):
9734514f5e3Sopenharmony_ci    with os.fdopen(os.open(expect_file, os.O_RDWR, stat.S_IRUSR), "r+") as file_object:
9744514f5e3Sopenharmony_ci        lines = file_object.readlines()
9754514f5e3Sopenharmony_ci        lines = [line for line in lines if not line.strip().startswith('#')]
9764514f5e3Sopenharmony_ci        expect_output = ''.join(lines)
9774514f5e3Sopenharmony_ci        if test_case_file.startswith("/"):
9784514f5e3Sopenharmony_ci            test_case_file = test_case_file.lstrip("/")
9794514f5e3Sopenharmony_ci        expect_file = test_case_file.replace('regresstest/', '')
9804514f5e3Sopenharmony_ci        test_file_path = os.path.join(RegressTestConfig.REGRESS_BASE_TEST_DIR, expect_file)
9814514f5e3Sopenharmony_ci        expect_output_str = expect_output.replace('*%(basename)s', test_file_path)
9824514f5e3Sopenharmony_ci    return expect_output_str
9834514f5e3Sopenharmony_ci
9844514f5e3Sopenharmony_ci
9854514f5e3Sopenharmony_cidef open_write_file(file_path, append):
9864514f5e3Sopenharmony_ci    if append:
9874514f5e3Sopenharmony_ci        args = os.O_RDWR | os.O_CREAT | os.O_APPEND
9884514f5e3Sopenharmony_ci    else:
9894514f5e3Sopenharmony_ci        args = os.O_RDWR | os.O_CREAT
9904514f5e3Sopenharmony_ci    file_descriptor = os.open(file_path, args, stat.S_IRUSR | stat.S_IWUSR)
9914514f5e3Sopenharmony_ci    file_object = os.fdopen(file_descriptor, "w+")
9924514f5e3Sopenharmony_ci    return file_object
9934514f5e3Sopenharmony_ci
9944514f5e3Sopenharmony_ci
9954514f5e3Sopenharmony_cidef open_result_excel(file_path):
9964514f5e3Sopenharmony_ci    file_descriptor = os.open(file_path, os.O_RDWR | os.O_CREAT | os.O_APPEND, stat.S_IRUSR | stat.S_IWUSR)
9974514f5e3Sopenharmony_ci    file_object = os.fdopen(file_descriptor, "w+")
9984514f5e3Sopenharmony_ci    return file_object
9994514f5e3Sopenharmony_ci
10004514f5e3Sopenharmony_ci
10014514f5e3Sopenharmony_cidef get_file_source(file):
10024514f5e3Sopenharmony_ci    with open(file, encoding='ISO-8859-1') as f:
10034514f5e3Sopenharmony_ci        return f.read()
10044514f5e3Sopenharmony_ci
10054514f5e3Sopenharmony_ci
10064514f5e3Sopenharmony_cidef set_test_environ(case):
10074514f5e3Sopenharmony_ci    # intl environ LC_ALL
10084514f5e3Sopenharmony_ci    if 'LC_ALL' in os.environ:
10094514f5e3Sopenharmony_ci        del os.environ['LC_ALL']
10104514f5e3Sopenharmony_ci    if 'TZ' in os.environ:
10114514f5e3Sopenharmony_ci        del os.environ['TZ']
10124514f5e3Sopenharmony_ci    if not os.path.exists(case):
10134514f5e3Sopenharmony_ci        return
10144514f5e3Sopenharmony_ci    source = get_file_source(case)
10154514f5e3Sopenharmony_ci    env_match = ENV_PATTERN.search(source)
10164514f5e3Sopenharmony_ci    if env_match:
10174514f5e3Sopenharmony_ci        for env_pair in env_match.group(1).strip().split():
10184514f5e3Sopenharmony_ci            var, value = env_pair.split('=')
10194514f5e3Sopenharmony_ci            if var.find('TZ') >= 0:
10204514f5e3Sopenharmony_ci                os.environ['TZ'] = value
10214514f5e3Sopenharmony_ci            if var.find('LC_ALL') >= 0:
10224514f5e3Sopenharmony_ci                os.environ['LC_ALL'] = value
10234514f5e3Sopenharmony_ci            break
10244514f5e3Sopenharmony_ci
10254514f5e3Sopenharmony_ci
10264514f5e3Sopenharmony_ci# pylint: disable=invalid-name,global-statement
10274514f5e3Sopenharmony_ciworker_wrapper_args = None
10284514f5e3Sopenharmony_ci
10294514f5e3Sopenharmony_ci
10304514f5e3Sopenharmony_cidef init_worker(args):
10314514f5e3Sopenharmony_ci    global worker_wrapper_args
10324514f5e3Sopenharmony_ci    worker_wrapper_args = args
10334514f5e3Sopenharmony_ci
10344514f5e3Sopenharmony_ci
10354514f5e3Sopenharmony_cidef write_result_file(msg: str, result_file):
10364514f5e3Sopenharmony_ci    result_file.write(f'{msg}\n')
10374514f5e3Sopenharmony_ci
10384514f5e3Sopenharmony_ci
10394514f5e3Sopenharmony_cidef main(args):
10404514f5e3Sopenharmony_ci    if not check_args(args):
10414514f5e3Sopenharmony_ci        return 1
10424514f5e3Sopenharmony_ci    output("\nStart regresstest........")
10434514f5e3Sopenharmony_ci    steps: List[Type[RegressTestStep]] = [
10444514f5e3Sopenharmony_ci        RegressTestRepoPrepare,
10454514f5e3Sopenharmony_ci        RegressTestCompile,
10464514f5e3Sopenharmony_ci    ]
10474514f5e3Sopenharmony_ci    if args.ark_aot:
10484514f5e3Sopenharmony_ci        if args.run_pgo:
10494514f5e3Sopenharmony_ci            steps.append(RegressTestPgo)
10504514f5e3Sopenharmony_ci        steps.append(RegressTestAot)
10514514f5e3Sopenharmony_ci    steps.append(RegressTestRun)
10524514f5e3Sopenharmony_ci
10534514f5e3Sopenharmony_ci    test_reports: List[TestReport] = []
10544514f5e3Sopenharmony_ci    for step in steps:
10554514f5e3Sopenharmony_ci        test_reports = step.run(args, test_reports)
10564514f5e3Sopenharmony_ci
10574514f5e3Sopenharmony_ci    stats = Stats(args, test_reports)
10584514f5e3Sopenharmony_ci    stats.statistics()
10594514f5e3Sopenharmony_ci    stats.print_result(args, steps)
10604514f5e3Sopenharmony_ci    stats.print_failed_tests()
10614514f5e3Sopenharmony_ci    new_failures = stats.get_new_failures()
10624514f5e3Sopenharmony_ci    if new_failures is None:
10634514f5e3Sopenharmony_ci        return 0
10644514f5e3Sopenharmony_ci    if len(new_failures) > 0:
10654514f5e3Sopenharmony_ci        msg = [f"Found {len(new_failures)} new failures:"]
10664514f5e3Sopenharmony_ci        for failure in new_failures:
10674514f5e3Sopenharmony_ci            msg.append(f"\t{failure.test_id}")
10684514f5e3Sopenharmony_ci        output("\n".join(msg))
10694514f5e3Sopenharmony_ci    else:
10704514f5e3Sopenharmony_ci        output("No new failures have been found")
10714514f5e3Sopenharmony_ci    return len(new_failures)
10724514f5e3Sopenharmony_ci
10734514f5e3Sopenharmony_ci
10744514f5e3Sopenharmony_ciif __name__ == "__main__":
10754514f5e3Sopenharmony_ci    sys.exit(main(parse_args()))
1076